Revision 0db55e1c src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb
src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | ||
---|---|---|
155 | 155 |
end.first.value rescue nil |
156 | 156 |
end |
157 | 157 |
|
158 |
def get_vcenter_instance_uuid |
|
159 |
@vi_client.vim.serviceContent.about.instanceUuid |
|
160 |
end |
|
161 |
|
|
158 | 162 |
############################################################################ |
159 | 163 |
# Getters |
160 | 164 |
############################################################################ |
... | ... | |
504 | 508 |
def reconfigure |
505 | 509 |
extraconfig = [] |
506 | 510 |
device_change = [] |
511 |
networks = {} |
|
512 |
|
|
513 |
npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) |
|
507 | 514 |
|
508 | 515 |
# get vmid |
509 | 516 |
extraconfig += extraconfig_vmid |
... | ... | |
514 | 521 |
# vnc configuration (for config_array hash) |
515 | 522 |
extraconfig += extraconfig_vnc |
516 | 523 |
|
524 |
# prepare pg and sw for vcenter nics if any |
|
525 |
configure_vcenter_network |
|
526 |
|
|
517 | 527 |
# device_change hash (nics) |
518 | 528 |
device_change += device_change_nics |
519 | 529 |
|
520 |
# device_change hash (disks) |
|
521 |
device_change += device_change_disks |
|
530 |
# track pg or dpg in case they must be removed |
|
531 |
vcenter_uuid = get_vcenter_instance_uuid |
|
532 |
device_change.each do |nic| |
|
533 |
if nic[:operation] == :remove |
|
522 | 534 |
|
523 |
num_cpus = one_item["TEMPLATE/VCPU"] || 1
|
|
535 |
vnet_ref = nil
|
|
524 | 536 |
|
525 |
spec_hash = { |
|
526 |
:numCPUs => num_cpus.to_i, |
|
527 |
:memoryMB => one_item["TEMPLATE/MEMORY"], |
|
528 |
:extraConfig => extraconfig |
|
529 |
} |
|
530 |
|
|
531 |
spec_hash[:deviceChange] = device_change if !device_change.empty? |
|
537 |
if nic[:device].backing.respond_to?(:network) |
|
538 |
vnet_ref = nic[:device].backing.network._ref |
|
539 |
end |
|
532 | 540 |
|
533 |
spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) |
|
541 |
if nic[:device].backing.respond_to?(:port) && |
|
542 |
nic[:device].backing.port.respond_to?(:portgroupKey) |
|
543 |
vnet_ref = nic[:device].backing.port.portgroupKey |
|
544 |
end |
|
534 | 545 |
|
535 |
@item.ReconfigVM_Task(:spec => spec).wait_for_completion |
|
546 |
one_network = VCenterDriver::VIHelper.find_by_ref(OpenNebula::VirtualNetworkPool, |
|
547 |
"TEMPLATE/VCENTER_NET_REF", |
|
548 |
vnet_ref, |
|
549 |
vcenter_uuid, |
|
550 |
npool) |
|
551 |
next if !one_network |
|
552 |
if one_network["VN_MAD"] == "vcenter" && !networks.key?(one_network["BRIDGE"]) |
|
553 |
networks[one_network["BRIDGE"]] = one_network |
|
554 |
end |
|
555 |
end |
|
536 | 556 |
end |
537 | 557 |
|
538 | 558 |
def extraconfig_vmid |
... | ... | |
628 | 648 |
end |
629 | 649 |
end |
630 | 650 |
|
631 |
# Returns an array of actions to be included in :deviceChange |
|
651 |
# Returns an array of actions to be included in :deviceChange
|
|
632 | 652 |
def calculate_add_nic_spec(nic) |
633 | 653 |
|
634 | 654 |
#TODO include VCENTER_NET_MODEL usage it should be in one_item |
635 | 655 |
mac = nic["MAC"] |
636 |
bridge = nic["BRIDGE"]
|
|
637 |
model = nic["VCENTER_NET_MODEL"] |
|
656 |
pg_name = nic["BRIDGE"]
|
|
657 |
model = nic["VCENTER_NET_MODEL"] || VCenterDriver::VIHelper.get_default("VM/TEMPLATE/NIC/MODEL")
|
|
638 | 658 |
vnet_ref = nic["VCENTER_NET_REF"] |
639 | 659 |
backing = nil |
640 | 660 |
|
641 |
limit_in = nic["INBOUND_PEAK_BW"] |
|
661 |
limit_in = nic["INBOUND_PEAK_BW"] || VCenterDriver::VIHelper.get_default("VM/TEMPLATE/NIC/INBOUND_PEAK_BW")
|
|
642 | 662 |
limit_out = nic["OUTBOUND_PEAK_BW"] |
643 | 663 |
limit = nil |
644 | 664 |
|
... | ... | |
654 | 674 |
rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 |
655 | 675 |
end |
656 | 676 |
|
657 |
network = self["runtime.host.network"].select do |n|
|
|
658 |
n._ref == vnet_ref |
|
677 |
network = self["runtime.host"].network.select do |n|
|
|
678 |
n._ref == vnet_ref || n.name == pg_name
|
|
659 | 679 |
end |
660 | 680 |
|
661 |
if network.empty? |
|
662 |
raise "Network #{bridge} not found in host #{self['runtime.host.name']}" |
|
663 |
else |
|
664 |
network = network.first |
|
665 |
end |
|
681 |
network = network.first |
|
666 | 682 |
|
667 | 683 |
card_num = 1 # start in one, we want the next avaliable id |
668 | 684 |
|
... | ... | |
691 | 707 |
|
692 | 708 |
if network.class == RbVmomi::VIM::Network |
693 | 709 |
backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( |
694 |
:deviceName => bridge,
|
|
710 |
:deviceName => pg_name,
|
|
695 | 711 |
:network => network) |
696 | 712 |
else |
697 | 713 |
port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( |
... | ... | |
707 | 723 |
:key => 0, |
708 | 724 |
:deviceInfo => { |
709 | 725 |
:label => "net" + card_num.to_s, |
710 |
:summary => bridge
|
|
726 |
:summary => pg_name
|
|
711 | 727 |
}, |
712 | 728 |
:backing => backing, |
713 | 729 |
:addressType => mac ? 'manual' : 'generated', |
... | ... | |
733 | 749 |
} |
734 | 750 |
end |
735 | 751 |
|
752 |
def vcenter_standard_network(nic, esx_host, vcenter_uuid) |
|
753 |
pg_name = nic["BRIDGE"] |
|
754 |
switch_name = nic["VCENTER_SWITCH_NAME"] |
|
755 |
pnics = nic["PHYDEV"] || nil |
|
756 |
mtu = nic["MTU"] || 1500 |
|
757 |
vlan_id = nic["VLAN_ID"] || nic["AUTOMATIC_VLAN_ID"] || 0 |
|
758 |
num_ports = nic["VCENTER_SWITCH_NPORTS"] || 128 |
|
759 |
|
|
760 |
begin |
|
761 |
esx_host.lock # Exclusive lock for ESX host operation |
|
762 |
|
|
763 |
pnics_available = nil |
|
764 |
pnics_available = esx_host.get_available_pnics if pnics |
|
765 |
|
|
766 |
# Get port group if it exists |
|
767 |
pg = esx_host.pg_exists(pg_name) |
|
768 |
|
|
769 |
# Disallow changes of switch name for existing pg |
|
770 |
if pg && esx_host.pg_changes_sw?(pg, switch_name) |
|
771 |
raise "The port group's switch name can not be modified"\ |
|
772 |
" for OpenNebula's virtual network, please revert"\ |
|
773 |
" it back in its definition and create a different"\ |
|
774 |
" virtual network instead." |
|
775 |
end |
|
776 |
|
|
777 |
if !pg |
|
778 |
# Get standard switch if it exists |
|
779 |
vs = esx_host.vss_exists(switch_name) |
|
780 |
|
|
781 |
if !vs |
|
782 |
switch_name = esx_host.create_vss(switch_name, pnics, num_ports, mtu, pnics_available) |
|
783 |
else |
|
784 |
#Update switch |
|
785 |
esx_host.update_vss(vs, switch_name, pnics, num_ports, mtu) |
|
786 |
end |
|
787 |
|
|
788 |
vnet_ref = esx_host.create_pg(pg_name, switch_name, vlan_id) |
|
789 |
|
|
790 |
# We must update XML so the VCENTER_NET_REF is set |
|
791 |
one_vnet = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualNetwork, nic["NETWORK_ID"]) |
|
792 |
one_vnet.delete_element("TEMPLATE/VCENTER_NET_REF") if one_vnet["TEMPLATE/VCENTER_NET_REF"] |
|
793 |
one_vnet.delete_element("TEMPLATE/VCENTER_INSTANCE_ID") if one_vnet["TEMPLATE/VCENTER_INSTANCE_ID"] |
|
794 |
rc = one_vnet.update("VCENTER_NET_REF = \"#{vnet_ref}\"\n"\ |
|
795 |
"VCENTER_INSTANCE_ID = \"#{vcenter_uuid}\"", true) |
|
796 |
if OpenNebula.is_error?(rc) |
|
797 |
raise "Could not update VCENTER_NET_REF for virtual network" |
|
798 |
end |
|
799 |
one_vnet.info |
|
800 |
|
|
801 |
else |
|
802 |
# pg exist, update |
|
803 |
esx_host.update_pg(pg, switch_name, vlan_id) |
|
804 |
|
|
805 |
# update switch if needed |
|
806 |
vs = esx_host.vss_exists(switch_name) |
|
807 |
esx_host.update_vss(vs, switch_name, pnics, num_ports, mtu) if vs |
|
808 |
end |
|
809 |
|
|
810 |
rescue Exception => e |
|
811 |
esx_host.network_rollback |
|
812 |
raise e |
|
813 |
ensure |
|
814 |
esx_host.unlock if esx_host # Remove lock |
|
815 |
end |
|
816 |
end |
|
817 |
|
|
818 |
def vcenter_distributed_network(nic, esx_host, vcenter_uuid, dc, net_folder) |
|
819 |
pg_name = nic["BRIDGE"] |
|
820 |
switch_name = nic["VCENTER_SWITCH_NAME"] |
|
821 |
pnics = nic["PHYDEV"] || nil |
|
822 |
mtu = nic["MTU"] || 1500 |
|
823 |
vlan_id = nic["VLAN_ID"] || nic["AUTOMATIC_VLAN_ID"] || 0 |
|
824 |
num_ports = nic["VCENTER_SWITCH_NPORTS"] || 8 |
|
825 |
|
|
826 |
begin |
|
827 |
# Get distributed port group if it exists |
|
828 |
dpg = dc.dpg_exists(pg_name, net_folder) |
|
829 |
|
|
830 |
# Disallow changes of switch name for existing pg |
|
831 |
if dpg && dc.pg_changes_sw?(dpg, switch_name) |
|
832 |
raise "The port group's switch name can not be modified"\ |
|
833 |
" for OpenNebula's virtual network, please revert"\ |
|
834 |
" it back in its definition and create a different"\ |
|
835 |
" virtual network instead." |
|
836 |
end |
|
837 |
|
|
838 |
if !dpg |
|
839 |
# Get distributed virtual switch if it exists |
|
840 |
dvs = dc.dvs_exists(switch_name, net_folder) |
|
841 |
|
|
842 |
if !dvs |
|
843 |
dvs = dc.create_dvs(switch_name, pnics, mtu) |
|
844 |
else |
|
845 |
#Update switch |
|
846 |
dc.update_dvs(dvs, pnics, mtu) |
|
847 |
end |
|
848 |
|
|
849 |
vnet_ref = dc.create_dpg(dvs, pg_name, vlan_id, num_ports) |
|
850 |
|
|
851 |
# We must connect portgroup to current host |
|
852 |
begin |
|
853 |
esx_host.lock |
|
854 |
|
|
855 |
pnics_available = nil |
|
856 |
pnics_available = esx_host.get_available_pnics if pnics |
|
857 |
|
|
858 |
proxy_switch = esx_host.proxy_switch_exists(switch_name) |
|
859 |
|
|
860 |
esx_host.assign_proxy_switch(dvs, switch_name, pnics, pnics_available) |
|
861 |
|
|
862 |
rescue Exception => e |
|
863 |
raise e |
|
864 |
ensure |
|
865 |
esx_host.unlock if esx_host # Remove lock |
|
866 |
end |
|
867 |
|
|
868 |
# We must update XML so the VCENTER_NET_REF is set |
|
869 |
one_vnet = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualNetwork, nic["NETWORK_ID"]) |
|
870 |
one_vnet.delete_element("TEMPLATE/VCENTER_NET_REF") if one_vnet["TEMPLATE/VCENTER_NET_REF"] |
|
871 |
one_vnet.delete_element("TEMPLATE/VCENTER_INSTANCE_ID") if one_vnet["TEMPLATE/VCENTER_INSTANCE_ID"] |
|
872 |
rc = one_vnet.update("VCENTER_NET_REF = \"#{vnet_ref}\"\n"\ |
|
873 |
"VCENTER_INSTANCE_ID = \"#{vcenter_uuid}\"", true) |
|
874 |
if OpenNebula.is_error?(rc) |
|
875 |
raise "Could not update VCENTER_NET_REF for virtual network" |
|
876 |
end |
|
877 |
one_vnet.info |
|
878 |
else |
|
879 |
# pg exist, dpg update |
|
880 |
dc.update_dpg(dpg, vlan_id, num_ports) |
|
881 |
|
|
882 |
# update switch if needed |
|
883 |
dvs = dc.dvs_exists(switch_name, net_folder) |
|
884 |
dc.update_dvs(dvs, pnics, mtu) if dvs |
|
885 |
|
|
886 |
# We must connect or update portgroup to current host (proxyswitch) |
|
887 |
begin |
|
888 |
esx_host.lock |
|
889 |
|
|
890 |
pnics_available = nil |
|
891 |
pnics_available = esx_host.get_available_pnics if pnics |
|
892 |
|
|
893 |
proxy_switch = esx_host.proxy_switch_exists(switch_name) |
|
894 |
esx_host.assign_proxy_switch(dvs, switch_name, pnics, pnics_available) |
|
895 |
|
|
896 |
rescue Exception => e |
|
897 |
raise e |
|
898 |
ensure |
|
899 |
esx_host.unlock if esx_host # Remove lock |
|
900 |
end |
|
901 |
end |
|
902 |
|
|
903 |
rescue Exception => e |
|
904 |
dc.network_rollback |
|
905 |
raise e |
|
906 |
end |
|
907 |
|
|
908 |
end |
|
909 |
|
|
910 |
def configure_vcenter_network(nic_xml=nil) |
|
911 |
nics = [] |
|
912 |
if nic_xml |
|
913 |
nics << nic_xml |
|
914 |
else |
|
915 |
nics = one_item.retrieve_xmlelements("TEMPLATE/NIC[VN_MAD=\"vcenter\"]") |
|
916 |
end |
|
917 |
|
|
918 |
return if nics.empty? |
|
919 |
|
|
920 |
vcenter_uuid = get_vcenter_instance_uuid |
|
921 |
esx_host = VCenterDriver::ESXHost.new_from_ref(self['runtime'].host._ref, vi_client) |
|
922 |
|
|
923 |
nics.each do |nic| |
|
924 |
|
|
925 |
if nic["VCENTER_INSTANCE_ID"] && nic["VCENTER_INSTANCE_ID"] != vcenter_uuid |
|
926 |
raise "The virtual network is not assigned to the right vcenter server, create a different virtual network instead" |
|
927 |
end |
|
928 |
|
|
929 |
if nic["VCENTER_PORTGROUP_TYPE"] == "Port Group" |
|
930 |
vcenter_standard_network(nic, esx_host, vcenter_uuid) |
|
931 |
end |
|
932 |
|
|
933 |
if nic["VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" |
|
934 |
dc = cluster.get_dc # Get datacenter |
|
935 |
begin |
|
936 |
dc.lock |
|
937 |
|
|
938 |
# Explore network folder in search of dpg and dvs |
|
939 |
net_folder = dc.network_folder |
|
940 |
net_folder.fetch! |
|
941 |
|
|
942 |
vcenter_distributed_network(nic, esx_host, vcenter_uuid, dc, net_folder) |
|
943 |
rescue Exception => e |
|
944 |
#TODO rollback |
|
945 |
raise e |
|
946 |
ensure |
|
947 |
dc.unlock if dc |
|
948 |
end |
|
949 |
end |
|
950 |
end |
|
951 |
end |
|
952 |
|
|
736 | 953 |
# Add NIC to VM |
737 | 954 |
def attach_nic |
738 | 955 |
spec_hash = {} |
... | ... | |
741 | 958 |
# Extract nic from driver action |
742 | 959 |
nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first |
743 | 960 |
|
744 |
# A new NIC requires a vcenter spec |
|
745 |
attach_nic_array = [] |
|
746 |
attach_nic_array << calculate_add_nic_spec(nic) |
|
747 |
spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? |
|
961 |
begin |
|
962 |
# Prepare network for vcenter networks |
|
963 |
configure_vcenter_network(nic) if nic["VN_MAD"] == "vcenter" |
|
748 | 964 |
|
749 |
# Reconfigure VM |
|
750 |
spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) |
|
965 |
# A new NIC requires a vcenter spec |
|
966 |
attach_nic_array = [] |
|
967 |
attach_nic_array << calculate_add_nic_spec(nic) |
|
968 |
spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? |
|
969 |
|
|
970 |
# Reconfigure VM |
|
971 |
spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) |
|
751 | 972 |
|
752 |
begin |
|
753 | 973 |
@item.ReconfigVM_Task(:spec => spec).wait_for_completion |
754 | 974 |
rescue Exception => e |
755 | 975 |
raise "Cannot attach NIC to VM: #{e.message}\n#{e.backtrace}" |
... | ... | |
757 | 977 |
|
758 | 978 |
end |
759 | 979 |
|
760 |
# Detach NIC from VM |
|
980 |
# Detach NIC from VM
|
|
761 | 981 |
def detach_nic |
762 | 982 |
spec_hash = {} |
763 | 983 |
nic = nil |
... | ... | |
771 | 991 |
is_nic?(device) && (device.macAddress == mac) |
772 | 992 |
end rescue nil |
773 | 993 |
|
774 |
raise "Could not find NIC with mac address #{mac}" if nic_device.nil?
|
|
994 |
return if nic_device.nil? #Silently ignore if nic is not found
|
|
775 | 995 |
|
776 | 996 |
# Remove NIC from VM in the ReconfigVM_Task |
777 | 997 |
spec_hash[:deviceChange] = [ |
... | ... | |
783 | 1003 |
rescue Exception => e |
784 | 1004 |
raise "Cannot detach NIC from VM: #{e.message}\n#{e.backtrace}" |
785 | 1005 |
end |
1006 |
end |
|
1007 |
|
|
1008 |
# Detach all nics useful when removing pg and sw so they're not in use |
|
1009 |
def detach_all_nics |
|
1010 |
spec_hash = {} |
|
1011 |
device_change = [] |
|
1012 |
|
|
1013 |
@item["config.hardware.device"].each do |device| |
|
1014 |
if is_nic?(device) |
|
1015 |
device_change << {:operation => :remove, :device => device} |
|
1016 |
end |
|
1017 |
end |
|
786 | 1018 |
|
1019 |
# Remove NIC from VM in the ReconfigVM_Task |
|
1020 |
spec_hash[:deviceChange] = device_change |
|
1021 |
|
|
1022 |
begin |
|
1023 |
@item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion |
|
1024 |
rescue Exception => e |
|
1025 |
raise "Cannot detach all NICs from VM: #{e.message}\n#{e.backtrace}" |
|
1026 |
end |
|
787 | 1027 |
end |
788 | 1028 |
|
789 | 1029 |
# Checks if a RbVmomi::VIM::VirtualDevice is a network interface |
Also available in: Unified diff