Pages

Sunday, December 1, 2013

Rename ESXi Hosts in vCenter (Without Losing Historical Data)

Changing the display name of an ESXi host in vCenter is typically done by removing and then adding the host back into the vCenter inventory.  While this doesn't impact running virtual machines, the ESXi host's task, event and performance history is lost.  Also, the host managed object reference is modified and all custom values are cleared, which could impact 3rd party tools which track inventory objects externally.

There is, however, a way to rename the ESXi host in vCenter while retaining all of its historical data through the ReconnectHost_Task API method.

Typically, when changing an ESXi host name, steps similar to KB 1010821 are followed.  Of course, the steps are manual and require connecting to each host individually to make changes.  LucD recently put together a PowerCLI function to automate the process.

One problem with the steps as outlined by the KB article is the requirement to remove the ESXi host from the vCenter inventory.  Once removed from inventory, all the host's historical data is lost (performance metrics, event and task history, custom values).

While the vCenter clients don't provide the capability to reconnect an ESXi host with a new hostname, it can be done quite easily through the vSphere API.  For example, the following snippet sets the HostConnectSpec and calls ReconnectHost() through the VMware Perl SDK.

$conn_spec = new HostConnectSpec();
$conn_spec->{'force'} = 1;
$conn_spec->{'hostName'} = "$host_name.$domain_name";

$host_view->ReconnectHost(cnxSpec => $conn_spec);

Note: While the display name can be changed quite easily, vCenter still requires the hostname provided to be resolved by DNS for connectivity.  Changing the hostname to something that cannot be resolved by vCenter will result in the host connection failing until it is set to a proper, resolvable hostname.

Just changing the vCenter connection hostname for the ESXi hosts may be useful in some situations.  For example, hosts may have been initially added by IP address against best practice recommendations.  It would be quite simple to do the reverse lookup operation and change the connection hostname from IP to FQDN without manually removing every host from the vCenter inventory.

However, the more likely process is to change the ESXi host's FQDN name and update the vCenter display name.  The following script provides an example of doing both updates in a single workflow.

#!/usr/bin/perl

## RenameEsxHost.pl
## Created by Reuben Stump (http://www.virtuin.com)
##
## Rename ESXi host in vCenter using ReconnectHost_Task()

use strict;
use warnings;

use VMware::VIRuntime;

my %opts = (
 host => {
  type => "=s",
  help => "Current ESXi host display name in vCenter",
  required => 1,
 },
 hostname => {
  type => "=s",
  help => "New ESXi host name",
  required => 1,
 },
 domainname => {
  type => "=s",
  help => "New ESXi domain name",
  required => 1,
 },
);
 
Opts::add_options(%opts);
Opts::parse();
Opts::validate();

Util::connect();

my ($host_view, $host_net, $host_dns, $host_vcname, $host_name, $domain_name, $conn_spec);

$host_vcname = Opts::get_option('host');
$host_name = Opts::get_option('hostname');
$domain_name = Opts::get_option('domainname');

$host_view = Vim::find_entity_view(view_type => "HostSystem", 
         filter => { 'name' => $host_vcname });      
die "No ESXi host '$host_vcname' found in vCenter inventory!" unless $host_view;

$host_net = Vim::get_view(mo_ref => $host_view->{'configManager'}->{'networkSystem'});
die "Failed to get host system '$host_vcname' network configuration!" unless $host_net;

$host_dns = $host_net->{'dnsConfig'};

print "Current DNS settings for host '$host_vcname':\n";
print "  Host name  : " . $host_dns->{'hostName'} . "\n";
print "  Domain name: " . $host_dns->{'domainName'} . "\n";

## Update host dns configuration with new hostname and domainname values
$host_dns->{'hostName'}   = $host_name;
$host_dns->{'domainName'} = $domain_name;

$host_net->UpdateDnsConfig(config => $host_dns);
print "Updated DNS settings for host '$host_vcname':\n";
print "  Host name  : " . $host_name . "\n";
print "  Domain name: " . $domain_name . "\n";

## Host must be disconnected before calling ReconnectHost().
eval {
 $host_view->DisconnectHost();
};

## Get updated view of host system
$host_view->update_view_data();

if ($host_view->{'runtime'}->{'connectionState'}->{'val'} =~ m/disconnected/gi) {
 # Host was successfully disconnected, update connection spec with new hostname
 $conn_spec = new HostConnectSpec();
 $conn_spec->{'force'} = 1;
 $conn_spec->{'hostName'} = "$host_name.$domain_name";

 $host_view->ReconnectHost(cnxSpec => $conn_spec);
} else {
 # Host is not disconnected, something went wrong and manual intervention is required
 die "Failed to disconnect host '$host_vcname'!";
}

print "Host '$host_vcname' successfully renamed to '$host_name.$domain_name' in vCenter\n";

Util::disconnect();

In lines 50-63, the script gets the current DNS configuration of the host and then calls UpdateDnsConfig() with the new DNS host and domain name values provided by the script at runtime.

In lines 66-68, DisconnectHost() is called to disconnect (but not remove) the host from vCenter.  No data from the host is lost, it is administratively disconnected.  The ReconnectHost() operation requires the host to be disconnected.

In lines 73-78, a new HostConnectSpec is created with the hostName property set to the new FQDN of the ESXi host.  Also note the force parameter is mandatory and set to true, which indicates the host should be added regardless of which vCenter was previously managing the host.  It could also have been set to false here as the host is being reconnected to the same vCenter inventory.

Finally, in line 79 the ReconnectHost() method is invoked with the new HostConnectSpec.

You can also download the example script on the VMTN Developer Communities.

13 comments:

  1. Any chance to get a PowerCLI version?

    ReplyDelete
  2. It wouldn't be too hard to write it, might just need to use ExtensionData vs cmdlets. I generally don't work on Windows OSs for coding, but if I get some cycles I'll see about a PowerCLI version.

    ReplyDelete
  3. Hi Reuben

    Great script, any change you can share the simple version? I have have the exact condition you described where i have a 3 node cluster but all 3 hosts were added with IP's not names and would like to correct this.

    ReplyDelete
  4. Here's a slightly modified version I used in my lab a while ago. It checks for valid IP addresses pretty well, using Regex::Common. You may need to CPAN that module down, but most current Perl distributions have that module already present.

    Watch for multiple DNS PTR records that could pick up unintended names. There's probably more robust error checking to be added as well, but works pretty well.

    It gets host by Cluster membership, so it would need some modification to update up non-clustered hosts.

    https://communities.vmware.com/docs/DOC-25326

    ReplyDelete
  5. Worked like a charm! I was trying to come up with something since past one week in order to solve this issue. I am glad I looked at this script! Thanks a lot Reuben!

    ReplyDelete
    Replies
    1. That's great! Thanks for letting me know well it worked out.

      Delete
    2. Hello Reuben,

      I usually use PowerCLI scripts for automation. I am using your above script for renaming the host. I am trying to add a restart command at the end of your script. Do you think I can use PowerCLI command for this inside a perl script. If not, can you give me pointers of how I can restart the ESXi host after the rename is completed in the perl script written by you.

      Thank you.

      Delete
    3. It's pretty easy to add it to the script. You might want to put the host into maintenance mode first (especially if it has VM's on it).

      Just under the ReconnectHost() call you can add the following:

      $host->EnterMaintenanceMode();
      $host->RebootHost();

      Not tested of course, but that's the basic process. If you have something more robust specific for your environment already written in PowerCLI, you can easily use back ticks or system to call the PowerCLI script from Perl:

      $cmd_result = `powershell.exe \sample.ps1`;

      You might need to be sure your PowerCLI script can run in a batch mode (without inputs).

      Delete
    4. Added the following and works:

      $fqdn = "$host_name.$domain_name";
      $host_view = Vim::find_entity_view(view_type => 'HostSystem', filter => { 'name' => $fqdn});
      $host_view->RebootHost_Task(force => 1);
      print "Rebooting host: \"" . $host_view->name . "\" ...\n";
      my $msg = "\tSuccessfully rebooted host: \"" . $host_view->name . "\"!";

      Delete
  6. Great! Thanks a lot. Will give it a shot today!

    ReplyDelete
  7. When I run the script I get the following error:

    Error: Cannot complete login due to an incorrect user name or password.

    I am using my vcenter@domain (vsphere admin account). It has rights to do anything on vCenter side. To get around this, I figured I would join my ESXi host to the domain. This did solve the authentication problem, but then I received this error:

    SOAP Fault:
    -----------
    Fault string: The operation cannot be performed while the host is part of a Windows domain.
    Fault detail: HostInDomainFault.

    So, I then chose to use the root user account which has rights on the host, but obviously not in vCenter. Didn't think this would work but gave it a try. Got this error:

    Current DNS settings for host 'ecptavm02.ECPTA.LOCAL':
    Host name : ecptavm02
    Domain name: ECPTA.LOCAL
    Updated DNS settings for host 'ecptavm02.ECPTA.LOCAL':
    Host name : ecptavm02old
    Domain name: ECPTA.LOCAL
    Failed to disconnect host 'ecptavm02.ECPTA.LOCAL'! at RenameEsxHost.pl line 82.

    So ... how do you authenticate to both the host and vCenter, without joining the host to AD. This has got me stumped.

    ReplyDelete
  8. Thanks a lot you saved my day !

    ReplyDelete
  9. Works very well, even to this day;-)
    Thanks for contributing to the community!

    ReplyDelete