Monday, February 09, 2015

How to change VM Network using linux command line?

Yesterday I read this Cormac's blog post and one of his reader (Philip Orleans) posted following comment ...
Just a personal favor, can you ask from the Vmware managers to enforce parity of functionality between management command line tools in Linux and Windows? It is a shame that the Linux tools are so far behind Power Shell.
Very well known PowerCLI scripting guru and VMware's Product Manager for CLIs Alan Renouf answered very quickly ...
Philip, thanks for the comment on Cormacs site, I am the Product Manager for CLIs at VMware and I can tell you we hear you loud and clear and we have a plans to bring the linux side of the house up to speed at some point in the future.

By the way, that's exactly what I really like on VMware's community and efficient communication with big corporation what VMware already is ...

Philip point out to one practical example where PowerCLI is the the only way how to automate VM network reassign to different network. I absolutely agree that PowerCLI is much simpler and feature rich scripting platform than linux alternatives. That's exactly what linux/*nix oriented vSphere administrators would like to see from VMware. However I don't agree it is not possible to achieve your goal.

Below is the question Philip raised ...
I am very happy that somebody is listening. A few weeks ago, here, I posted a question about how to change network for a VM using only Linux command line tools, and some idiot mocked me, told me to study, when in fact, there is no way, as far as I researched. This can be achieved only with Powershell. Unfortunately, one of my customers is so paranoid, that I am not allowed on premises with a Windows machine. If I did try, I would have to flee to Moscow.

In the history, the first scripting toolkit was targeted to linux administrators. It was Perl SDK nowadays known af vCLI. I used to use Perl SDK to develop several automation projects in the past. I even wrote something like VMware's "Site Recovery Manager" to achieve automated disaster recovery fail over, test, and fail back. To achieve DR testing in isolated network bubble you need to change VM networks, right? In that times I've developed perl function to do it. Based on Philip's question I've realized that it can be still valuable to some folks even the script was developed back in 2009. I spent just two hours with some quick re-factoring and below is single linux command which can be used to change virtual network on particular VM for particular VM Network Adapter.

/usr/lib/vmware-vcli/apps/vm/vmchnet.pl --server 10.10.4.70 --username administrator --vmname test-vm --vnic 2 --network my-test-network
Ok, it's kind of a joke :-) There is single command above but you need the script below to achieve it ...

 #!/usr/bin/perl -w  
 ###############################################################################  
 # Author: David Pasek  
 # Email: david.pasek[at]gmail.com  
 # Blog: http://blog.igics.com  
 #  
 # Created: 01/27/2009  
 # Updated: 02/09/2015  
 #  
 # Abstract:  
 # Reconfigure particular VM Network iAdapter to be in particular network label  
 # in VMware standard virtual Switch. Network label is also known as PortGroup.  
 #  
 # Script requires VMware's PERL SDK (aka vCLI)therefore it must be placed  
 # in apropriate directory tree location to work correctly.  
 # Optimal location is at /usr/lib/vmware-vcli/apps/vm  
 #  
 # Disclaimer: Use this script at your own risk. Author is not responsible  
 # for any impacts of using this script.  
 ###############################################################################  
 use strict;  
 use warnings;  
 use FindBin;  
 use lib "$FindBin::Bin/../";  
 use VMware::VIRuntime;  
 use XML::LibXML;  
 use AppUtil::VMUtil;  
 use AppUtil::XMLInputUtil;  
 use Data::Dumper;  
 $Util::script_version = "1.0";  
 my %opts = (  
   'vmname' => {  
    type => "=s",  
    help => "Name of virtual machine",  
    required => 1,  
   },  
   'vnic' => {  
    type => "=i",  
    help => "VM Network Adapter number - 1, 2, ...",  
    required => 1,  
   },  
   'network' => {  
    type => "=s",  
    help => "Name of new virtual network",  
    required => 1,  
   },  
 );  
 Opts::add_options(%opts);  
 Opts::parse();  
 Opts::validate(\&validate);  
 # connect to the server  
 Util::connect();  
 my $vmname = Opts::get_option('vmname');  
 my $vnic = Opts::get_option('vnic');  
 my $network = Opts::get_option('network');  
 &vm_change_net('vmname' => $vmname,  
         'vnic' => $vnic,  
         'network' => $network);  
 Util::disconnect();  
 exit;  
 sub vm_change_net {  
  my %params = @_;  
  my $vmname =$params{vmname};  
  my $vnic =$params{vnic};  
  my $network = $params{network};  
  my $vm_view;  
  $vm_view = Vim::find_entity_view(view_type => 'VirtualMachine',  
        filter => {'name' => $vmname });  
  if(!defined $vm_view) {  
   print "Cannot find VM: $vmname\n";  
   return(255);  
  }  
  my $devices = $vm_view->config->hardware->device;  
  foreach my $dev (@$devices) { # DEVICE  
   my $device_type = ref($dev);  
   my $device_name = $dev->deviceInfo->label;  
   my $device_key = $dev->key;  
   #print "Device type: $device_type\n";  
   #print "Device name: $device_name\n";  
   #print "Device device key: $device_key\n";  
   if ( $device_name eq "Network adapter $vnic") { # NETWORK ADAPTER  
    print "Device type: $device_type\n";  
    print "Device name: $device_name\n";  
    print "Device key: $device_key\n";  
    # Change network information  
    my $changed_device;  
    my $backing_info = VirtualEthernetCardNetworkBackingInfo->new( deviceName => $network );  
    if ($device_type eq "VirtualPCNet32") {  
     $changed_device = VirtualPCNet32->new(key => $device_key,  
                        backing => $backing_info);  
    }  
    if ($device_type eq "VirtualE1000") {  
     $changed_device = VirtualE1000->new(key => $device_key,  
                       backing => $backing_info);  
    }  
    if ($device_type eq "VirtualVmxnet3") {  
     $changed_device = VirtualVmxnet3->new(key => $device_key,  
                        backing => $backing_info);  
    }  
    my $config_spec_operation;  
    $config_spec_operation = VirtualDeviceConfigSpecOperation->new('edit');  
    my $device_spec =  
    VirtualDeviceConfigSpec->new(operation => $config_spec_operation,  
                   device => $changed_device);  
    my @device_config_specs = ();  
    push(@device_config_specs, $device_spec);  
    my $vmspec = VirtualMachineConfigSpec->new(deviceChange => \@device_config_specs);  
    # RECONFIGURE VM  
    eval {  
     print "Changing Network Adapter $vnic in virtual machine $vmname\n";  
     $vm_view->ReconfigVM( spec => $vmspec );  
     print "Success\n";  
    };  
    if ($@) {  
     print "Reconfiguration failed:\n";  
     print($@);  
    }  
   } # NETWORK ADAPTER - END  
  } # DEVICES - END  
  return;  
 }  
 sub validate {  
   my $valid = 1;  
  return $valid;  
 }  

Script above is limited to standard VMware virtual switch. If you are looking for similar script dealing with VMware distribute virtual switch look here. There is a link to script developed by Javier Viola.

As you can see PERL SDK is not easy for normal vSphere admins and when there are no precooked vCLI commands it is almost useless for someone who doesn't have some programming background. PowerCLI is absolutely another story and as VMware is moving out of Microsoft technologies I would expect some PowerCLI alternative in PERL or Python and based on Alan's comment I believe VMware is already working on some alternative. I'm really looking forward for linux alternative and I'm not alone.

By the way, nowadays there is another possibility to achieve the goal without MS Windows systems. vCenter Orchestrator (or vRealize Orchestrator) however it is another story.

Hope this helps to someone.
 


3 comments:

William of Baskerville said...

Thanks. Believe it or not, this opens a new realm of possibilities. I will do my best to add it to my bag of tricks.
But of course, I hope that using Bash and a set of commands, like we do now in Powershell, it will be become easy to manipulate any of the properties of a VM or Host, etc. I believe that Bash process substitution and commands like Awk,etc,plus MariaDB, provide a much powerful tool for managing any kind of information flow than Powershell.

David Pasek said...

Absolutely agree. PowerCLI is more focused to administrators and helps to make admin jobs/tasks done very quickly and elegantly. And that what vSphere admins with linux/*nix background would like to have on their platform ...

I like PERL because of history but Python is probably better choice nowadays.

Absolutely understand that VMware's typical customers are usually MS shops therefore they have priority against linux guys ... but perhaps we will see change in the future.

NeelPal said...

This script works well but there's one thing it does i'm not sure, it changes the MAC address of the Network Adapter, idea is to change only the portgroup name.
Not sure if i'm missing anything.