Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 21st, 2012  |  syntax: Perl  |  size: 15.63 KB  |  hits: 29  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/perl -w
  2. #
  3. # Copyright (c) 2007 VMware, Inc.  All rights reserved.
  4. #
  5.  
  6. use strict;
  7. use warnings;
  8.  
  9. use FindBin;
  10. use lib "$FindBin::Bin/../";
  11. use lib "/usr/lib/vmware-viperl/apps";
  12. use lib "/usr/lib/perl5/vendor_perl/5.8.8";
  13. use lib "/opt/vmware/vcli/apps/";
  14.  
  15. use VMware::VIRuntime;
  16. use XML::LibXML;
  17. use AppUtil::XMLInputUtil;
  18. use AppUtil::HostUtil;
  19.  
  20. $Util::script_version = "1.0";
  21.  
  22. my %opts = (
  23.    filename => {
  24.       type => "=s",
  25.       help => "The location of the input config file",
  26.       required => 0,
  27.       default => "../sampledata/vmcreate.vmconf",
  28.    },
  29.    schema => {
  30.       type => "=s",
  31.       help => "The location of the schema file",
  32.       required => 0,
  33.       default => "../schema/vmcreate.xsd",
  34.    },
  35. );
  36.  
  37. my ($annotation, $guestId, $locationId, $name, $memoryMB, $deviceChange, $numCPUs, $listofdisks, $listofnics, $cdrom, $keyboard, $videocard, $datacentre, $nextkey, $nextunitnum);
  38.  
  39. Opts::add_options(%opts);
  40. Opts::parse();
  41. Opts::validate();
  42.  
  43. Util::connect();
  44.  
  45. my $configfile = Opts::get_option('filename'); if(-e $configfile) {
  46.         parseconfig($configfile);
  47. } else {
  48.         die("Couldn't read $configfile\n");
  49. }
  50.  
  51. Util::disconnect();
  52.  
  53. exit;
  54.  
  55. # create a virtual machine
  56. # ========================
  57.  
  58.  
  59. # create virtual device config spec for controller # ================================================
  60. sub create_conf_spec {
  61.         my $controller;
  62.  
  63.         $controller = VirtualLsiLogicController->new(
  64.                                 key => 0,
  65.                                 device => [0],
  66.                                 busNumber => 0,
  67.                                 sharedBus => VirtualSCSISharing->new('noSharing'));
  68.         my $controller_vm_dev_conf_spec = VirtualDeviceConfigSpec->new(device => $controller, operation => VirtualDeviceConfigSpecOperation->new('add'));
  69.         return $controller_vm_dev_conf_spec;
  70. }
  71.  
  72.  
  73. # create virtual device config spec for disk # ==========================================
  74. sub create_virtual_disk {
  75.    my %args = @_;
  76.    my $ds_path = $args{ds_path};
  77.    my $keynum = $args{keynum};
  78.    my $disksize = $args{disksize};
  79.  
  80.    my $disk_backing_info =
  81.       VirtualDiskFlatVer2BackingInfo->new(diskMode => 'persistent',
  82.                                           fileName => $ds_path);
  83.  
  84.    $nextunitnum += 1;
  85.    my $disk = VirtualDisk->new(backing => $disk_backing_info,
  86.                                controllerKey => 0,
  87.                                key => $keynum,
  88.                                unitNumber => $nextunitnum,
  89.                                capacityInKB => $disksize);
  90.  
  91.    my $disk_vm_dev_conf_spec =
  92.       VirtualDeviceConfigSpec->new(device => $disk,
  93.                fileOperation => VirtualDeviceConfigSpecFileOperation->new('create'),
  94.                operation => VirtualDeviceConfigSpecOperation->new('add'));
  95.    return $disk_vm_dev_conf_spec;
  96. }
  97.  
  98.  
  99. # get network configuration
  100. # =========================
  101. sub get_network {
  102.    my %args = @_;
  103.    my $network_name = $args{network_name};
  104.    my $poweron = $args{poweron};
  105.    my $host_view = $args{host_view};
  106.    my $address_type = $args{address_type};
  107.    my $mac_address = $args{mac_address};
  108.    my $network = undef;
  109.    my $unit_num = 1;  # 1 since 0 is used by disk
  110.  
  111.    if($network_name) {
  112.       my $network_list = Vim::get_views(mo_ref_array => $host_view->network);
  113.       foreach (@$network_list) {
  114.          if($network_name eq $_->name) {
  115.             $network = $_;
  116.             my $nic_backing_info =
  117.                VirtualEthernetCardNetworkBackingInfo->new(deviceName => $network_name,
  118.                                                           network => $network);
  119.  
  120.             my $vd_connect_info =
  121.                VirtualDeviceConnectInfo->new(allowGuestControl => 1,
  122.                                              connected => 0,
  123.                                              startConnected => $poweron);
  124.  
  125.             my $nic;
  126.             if($address_type eq "manual") {
  127.                 if(! $mac_address) {
  128.                         die("EXCEPTION: attempting manual allocation without mac_address\n");
  129.                 }
  130.                
  131.                 $nic = VirtualPCNet32->new(backing => $nic_backing_info,
  132.                                            key => 0,
  133.                                            unitNumber => $unit_num,
  134.                                            addressType => $address_type,
  135.                                            macAddress => $mac_address,
  136.                                            connectable => $vd_connect_info);
  137.             } else {
  138.                 $nic = VirtualPCNet32->new(backing => $nic_backing_info,
  139.                                            key => 0,
  140.                                            unitNumber => $unit_num,
  141.                                            addressType => $address_type,
  142.                                            connectable => $vd_connect_info);
  143.             }
  144.        
  145.             my $nic_vm_dev_conf_spec =
  146.                VirtualDeviceConfigSpec->new(device => $nic,
  147.                      operation => VirtualDeviceConfigSpecOperation->new('add'));
  148.  
  149.             return (error => 0, network_conf => $nic_vm_dev_conf_spec);
  150.          }
  151.       }
  152.       if (!defined($network)) {
  153.       # no network found
  154.        return (error => 1);
  155.       }
  156.    }
  157.     # default network will be used
  158.     return (error => 2);
  159. }
  160.  
  161.  
  162. # check the XML file
  163. # =====================
  164. sub validate {
  165.    my $valid = XMLValidation::validate_format(Opts::get_option('filename'));
  166.    if ($valid == 1) {
  167.       $valid = XMLValidation::validate_schema(Opts::get_option('filename'),
  168.                                                       Opts::get_option('schema'));
  169.       if ($valid == 1) {
  170.          $valid = check_missing_value();
  171.       }
  172.    }
  173.    return $valid;
  174. }
  175.  
  176. # check missing values of mandatory fields # ========================================
  177. sub check_missing_value {
  178.    my $valid = 1;
  179.    my $filename = Opts::get_option('filename');
  180.    my $parser = XML::LibXML->new();
  181.    my $tree = $parser->parse_file($filename);
  182.    my $root = $tree->getDocumentElement;
  183.    
  184.    # defect 223162
  185.    if($root->nodeName eq 'Virtual-Machines') {
  186.       my @vms = $root->findnodes('Virtual-Machine');
  187.       foreach (@vms) {
  188.          if (!$_->findvalue('Name')) {
  189.             Util::trace(0, "\nERROR in '$filename':\n<Name> value missing " .
  190.                            "in one of the VM specifications\n");
  191.             $valid = 0;
  192.          }
  193.          if (!$_->findvalue('Host')) {
  194.             Util::trace(0, "\nERROR in '$filename':\n<Host> value missing " .
  195.                            "in one of the VM specifications\n");
  196.             $valid = 0;
  197.          }
  198.          if (!$_->findvalue('Datacenter')) {
  199.             Util::trace(0, "\nERROR in '$filename':\n<Datacenter> value missing " .
  200.                            "in one of the VM specifications\n");
  201.             $valid = 0;
  202.          }
  203.       }
  204.    }
  205.    else {
  206.       Util::trace(0, "\nERROR in '$filename': Invalid root element ");
  207.       $valid = 0;
  208.    }
  209.    return $valid;
  210. }
  211.  
  212. sub parseconfig {
  213.         my $filename = shift;
  214.  
  215.         if(! open(CONFIG,$filename)) {
  216.                 die("Couldn't open $filename for reading.\n");
  217.         }
  218.  
  219.         while(<CONFIG>) {
  220.  
  221. # Remove carriage returns and line feeds and comments
  222.  
  223.                 s/[\r\n*]//g;
  224.                 s/#.*//;
  225.  
  226. # Skip blank lines
  227.  
  228.                 if(/^\s*$/) {
  229.                         next;
  230.                 }
  231.  
  232. # Look for lines we recognise and capture the relevant information
  233.  
  234.                 if(/^datacentre\s*(.*)/i) {
  235.                         $datacentre = $1;
  236.                         logit("  Data Centre $datacentre\n");
  237.                         next;
  238.                 }
  239.                 if(/^STARTVM\s*(.*)/i) {
  240.                         logit("Found virtual machine $1\n");
  241.                         next;
  242.                 }
  243.                 if(/^annotation\s*(.*)/i) {
  244.                         $annotation = $1;
  245.                         logit("  description $annotation\n");
  246.                         next;
  247.                 }
  248.                 if(/^guestId\s*(.*)/i) {
  249.                         $guestId = $1;
  250.                         logit("  Guest OS $guestId\n");
  251.                         next;
  252.                 }
  253.                 if(/^locationId\s*(.*)/i) {
  254.                         $locationId = $1;
  255.                         logit("  Target Host $locationId\n");
  256.                         next;
  257.                 }
  258.                 if(/^memoryMB\s*(.*)/i) {
  259.                         $memoryMB = $1;
  260.                         logit("  memory $memoryMB\n");
  261.                         next;
  262.                 }
  263.                 if(/^name\s*(.*)/i) {
  264.                         $name = $1;
  265.                         logit("  name $name\n");
  266.                         next;
  267.                 }
  268.                 if(/^numCPUs\s*(.*)/i) {
  269.                         $numCPUs = $1;
  270.                         logit("  vCPUs $numCPUs\n");
  271.                         next;
  272.                 }
  273.                 if(/^Ethernet\s*(.*)/i) {
  274.                         my $params = $1;
  275.                         my ($network,$mac) = split(/\s+/,$params);
  276.  
  277.                         my $value;
  278.                         if($mac) {
  279.                                 $value = "$network/$mac";
  280.                         } else {
  281.                                 $value = "$network/";
  282.                         }
  283.  
  284.                         if($listofnics) {
  285.                                 $listofnics .= ",$value";
  286.                         } else {
  287.                                 $listofnics = "$value";
  288.                         }
  289.                                
  290.                         if($mac) {
  291.                                 logit("  Ethernet $network using MAC $mac\n");
  292.                         } else {
  293.                                 logit("  Ethernet $network with automatically generated MAC\n");
  294.                         }
  295.                         next;
  296.                 }
  297.                 if(/^CD-ROM/i) {
  298.                         $cdrom = 1;
  299.                         logit("  CD-ROM\n");
  300.                         next;
  301.                 }
  302.                 if(/^Disk\s*(.*)/i) {
  303.                         my $diskdata = $1;
  304.                         my ($disksize,$datastore);
  305.                         ($disksize,$datastore) = split(/\s+/,$diskdata);
  306.                         logit("  Disk $disksize MB on $datastore\n");
  307.                         if($listofdisks) {
  308.                                 $listofdisks .= ",$disksize:$datastore";
  309.                         } else {
  310.                                 $listofdisks = "$disksize:$datastore";
  311.                         }
  312.                         next;
  313.                 }
  314.                 if(/^Keyboard/i) {
  315.                         $keyboard = 1;
  316.                         logit("  keyboard\n");
  317.                         next;
  318.                 }
  319.                 if(/^Videocard\s*(.*)/i) {
  320.                         $videocard = $1;
  321.                         logit("  videocard $videocard (currently ignored)\n");
  322.                         next;
  323.                 }
  324.  
  325. # Found the end of a VM, use the information collected to create that VM
  326.  
  327.                 if(/^ENDVM\s*(.*)/i) {
  328.                         my @vm_devices;
  329.  
  330.                         my $failure = 0;
  331.  
  332.                         if(! $name) {
  333.                                 logit("name is a mandatory field\n");
  334.                                 $failure = 1;
  335.                         }
  336.                         if(! $locationId) {
  337.                                 logit("locationId is a mandatory field\n");
  338.                                 $failure = 1;
  339.                         }
  340.                         if(! $annotation) {
  341.                                 logit("annotation is a mandatory field\n");
  342.                                 $failure = 1;
  343.                         }
  344.                         if(! $guestId) {
  345.                                 logit("guestId is a mandatory field\n");
  346.                                 $failure = 1;
  347.                         }
  348.                         if(! $datacentre) {
  349.                                 logit("datacentre is a mandatory field\n");
  350.                                 $failure = 1;
  351.                         }
  352.                         if(! $memoryMB) {
  353.                                 logit("memoryMB not supplied, defaulting to 1024MB\n");
  354.                                 $memoryMB = 1024;
  355.                         }
  356.                         if(! $numCPUs) {
  357.                                 logit("numCPUs not supplied, defaulting to 2\n");
  358.                                 $numCPUs = 2;
  359.                         }
  360.                         if($failure) {
  361.                                 die("aborting due to errors\n");
  362.                         }
  363.  
  364. # Get the object for the destination host
  365.                         my $host_view = Vim::find_entity_view(  view_type => 'HostSystem',
  366.                                                                 filter => {'name' => $locationId});
  367.                         if (!$host_view) {
  368.                                 Util::trace(0, "\nError creating VM '$name': Host '$locationId' not found\n");
  369.                                 return;
  370.                         }
  371.  
  372. # Create the virtual disk controller
  373.                         my $controller_vm_dev_conf_spec = create_conf_spec();
  374.                         push(@vm_devices, $controller_vm_dev_conf_spec);
  375.  
  376. # Get the datastore reference for the target datastore
  377.                         my (@disks);
  378.                         @disks = split(/,/,$listofdisks);
  379.                         my $first_ds_path;
  380.                         foreach my $disk (@disks) {
  381.                                 my ($size,$datastore) = split(/:/,$disk);
  382.                                 my %ds_info = HostUtils::get_datastore( host_view => $host_view,
  383.                                                                         datastore => $datastore,
  384.                                                                         disksize => $size);
  385. # Does the datastore exist and will the VMDK fit?
  386.                                 if ($ds_info{mor} eq 0) {
  387.                                         if ($ds_info{name} eq 'datastore_error') {
  388.                                                 Util::trace(0, "\nError creating VM '$name': Datastore $datastore not available.\n");
  389.                                                 return;
  390.                                         }
  391.                                         if ($ds_info{name} eq 'disksize_error') {
  392.                                                 Util::trace(0, "\nError creating VM '$name': The free space available is less than the specified disksize.\n");
  393.                                                 return;
  394.                                         }
  395.                                 }
  396.                                 my $ds_path = "[" . $ds_info{name} . "]";
  397.                                 if(! $first_ds_path) {
  398.                                         $first_ds_path = $ds_path;
  399.                                 }
  400.  
  401.                                 $nextkey -= 1;
  402.                                 my $disk_vm_dev_conf_spec = create_virtual_disk(ds_path => $ds_path, disksize => $size, keynum => $nextkey);
  403.                                 push(@vm_devices, $disk_vm_dev_conf_spec);
  404.                         }
  405.  
  406. # Create network interfaces
  407.  
  408.                         my (@nics);
  409.                         @nics = split(/,/,$listofnics);
  410.                         foreach my $nic (@nics) {
  411.                                 my ($network,$mac) = split(/\//,$nic);
  412.  
  413.                                 my %net_settings;
  414.                                 if($mac) {
  415.                                         %net_settings = get_network(    network_name => $network,
  416.                                                                         poweron => 1,
  417.                                                                         address_type => "manual",
  418.                                                                         mac_address => $mac,
  419.                                                                         host_view => $host_view);
  420.                                 } else {
  421.                                         %net_settings = get_network(    network_name => $network,
  422.                                                                         poweron => 1,
  423.                                                                         address_type => "generated",
  424.                                                                         host_view => $host_view);
  425.                                 }
  426.                                 if($net_settings{'error'} eq 0) {
  427.                                         push(@vm_devices, $net_settings{'network_conf'});
  428.                                 } elsif ($net_settings{'error'} eq 1) {
  429.                                         Util::trace(0, "\nError creating VM '$name': Network '$network' not found\n");
  430.                                         return;
  431.                                 }
  432.                         }
  433. # Set up virtual machine file information
  434.                         my $files = VirtualMachineFileInfo->new(logDirectory => undef,
  435.                                                                 snapshotDirectory => undef,
  436.                                                                 suspendDirectory => undef,
  437.                                                                 vmPathName => $first_ds_path);
  438.  
  439. # Add a CD-ROM
  440.                         if($cdrom) {
  441.                                 $nextkey -= 1;
  442.                                 my $cdromdev = VirtualCdrom->new(key => $nextkey,
  443.                                                                  controllerKey => 0,
  444.                                                                  unitNumber => $nextunitnum,
  445.                                                                  connectable => VirtualDeviceConnectInfo->new(
  446.                                                                         allowGuestControl => 1,
  447.                                                                         connected => 0,
  448.                                                                         startConnected => 0)
  449.                                                                  );
  450.                                 $nextunitnum += 1;
  451.                                 my $cdrom_conf_spec = VirtualDeviceConfigSpec->new(
  452.                                                 device => $cdromdev,
  453.                                                 operation => VirtualDeviceConfigSpecOperation->new('add'));
  454.                                 push(@vm_devices,$cdrom_conf_spec);
  455.                         }
  456. # Add a keyboard
  457.                         if($keyboard) {
  458.                                 $nextkey -= 1;
  459.                                 my $keyboarddev = VirtualKeyboard->new(key => $nextkey);
  460.                                 my $keyboard_conf_spec = VirtualDeviceConfigSpec->new(
  461.                                         device => $keyboarddev,
  462.                                         operation => VirtualDeviceConfigSpecOperation->new('add'));
  463.                                 push(@vm_devices,$keyboard_conf_spec);
  464.                         }
  465.  
  466. # Create the vmconfiguspec
  467.                         my $vm_config_spec = VirtualMachineConfigSpec->new(     name => $name,
  468.                                                                                 annotation => $annotation,
  469.                                                                                 memoryMB => $memoryMB,
  470.                                                                                 files => $files,
  471.                                                                                 numCPUs => $numCPUs,
  472.                                                                                 guestId => $guestId,
  473.                                                                                 deviceChange => \@vm_devices);
  474.  
  475.                         my $datacenter_views = Vim::find_entity_views (view_type => 'Datacenter',filter => { name => $datacentre});
  476.  
  477.                         unless (@$datacenter_views) {
  478.                                 Util::trace(0, "\nError creating VM '$name': " . "Datacenter '$datacentre' not found\n");
  479.                                 return;
  480.                         }
  481.  
  482.                         if ($#{$datacenter_views} != 0) {
  483.                                 Util::trace(0, "\nError creating VM '$name': " . "Datacenter '$datacentre' not unique\n");
  484.                                 return;
  485.                         }
  486.                         my $data_center = shift @$datacenter_views;
  487.  
  488.                         my $vm_folder_view = Vim::get_view(mo_ref => $data_center->vmFolder);
  489.  
  490.                         my $comp_res_view = Vim::get_view(mo_ref => $host_view->parent);
  491.  
  492.                         eval {
  493.                                 $vm_folder_view->CreateVM(config => $vm_config_spec, pool => $comp_res_view->resourcePool);
  494.                                 Util::trace(0, "\nSuccessfully created virtual machine: " ."'$name' under host $locationId\n");
  495.                         };
  496.  
  497.                         if ($@) {
  498.                                 Util::trace(0, "\nError creating VM '$name': ");
  499.                                 if (ref($@) eq 'SoapFault') {
  500.                                         if (ref($@->detail) eq 'PlatformConfigFault') {
  501.                                                 Util::trace(0, "Invalid VM configuration: " . ${$@->detail}{'text'} . "\n");
  502.                                         } elsif (ref($@->detail) eq 'InvalidDeviceSpec') {
  503.                                                 Util::trace(0, "Invalid Device configuration: " . ${$@->detail}{'property'} . "\n");
  504.                                         } elsif (ref($@->detail) eq 'DatacenterMismatch') {
  505.                                                 Util::trace(0, "DatacenterMismatch, the input arguments had entities " . "that did not belong to the same datacenter\n");
  506.                                         } elsif (ref($@->detail) eq 'HostNotConnected') {
  507.                                                 Util::trace(0, "Unable to communicate with the remote host," . " since it is disconnected\n");
  508.                                         } elsif (ref($@->detail) eq 'InvalidState') {
  509.                                                 Util::trace(0, "The operation is not allowed in the current state\n");
  510.                                         } elsif (ref($@->detail) eq 'DuplicateName') {
  511.                                                 Util::trace(0, "Virtual machine already exists.\n");
  512.                                         } else {
  513.                                                 Util::trace(0, "\n" . $@ . "\n");
  514.                                         }
  515.                                 } else {
  516.                                         Util::trace(0, "\n" . $@ . "\n");
  517.                                 }
  518.                         }
  519.                         next;
  520.                 }
  521.                 logit("Unrecognised line: $_\n");
  522.         }
  523. }
  524.  
  525. sub logit {
  526.         my $text = shift;
  527.  
  528.         print("$text");
  529. }