Pages

Tuesday, August 26, 2014

Using PrimType in the vSphere Perl SDK

One of the issues that can arise with the vSphere Perl SDK is the serialization of various numeric types as strings.  For example, when trying to remove a DRS rule from a ClusterComputeResource the following error will manifest: SOAP fault: A specified parameter was not correct.  Internally, the vSphere Perl SDK is setting the removeKey property type to xsd:string and the vSphere Web Service is unable to coerce the string into the expected xsd:int type.

However, a base type called PrimType is available to set the proper SOAP XSD data type when serializing the data objects for the vSphere Web Service.

A VMTN community thread addresses the issue around removing a DRS rule.  One of the properties required to remove a Cluster DRS rule is removeKey, which is an API type of AnyType.  The AnyType property can cause these serialization problems in a few different methods and objects from the vSphere API.  For example, this same issue impacts some HostProfile properties.

As a simple solution, there a PrimType available which allows the XSD type to be set on a primitive value (string, integer, double, float, etc).  For example, to create an XSD integer type:

$int_type = new PrimType(10, "int");

Then when this value is serialized by the VI Perl SDK, the proper XSD type will be set in the XML attribute for the object property and the vSphere Web Service will properly parse the SOAP constructs.

As an example, here is a broken version of a DRS remove script that does not use PrimType.

## remove-drs-rule_broken.pl
## Created by Reuben Stump (http://www.virtuin.com)
##
## Illustrate improper XSD serialization of strings by the VI Perl SDK

use strict;
use warnings;

use VMware::VIRuntime;

my %opts = (
        'cluster' => {
        type => "=s",
        help => "The name of the cluster",
        required => 1,
        },
        'rule' => {
        type => "=s",
        help => "The name of the cluster drs rule to remove",
        required => 1,
        },
);
Opts::add_options(%opts);
Opts::parse();
Opts::validate();
Util::connect();

my ($cluster_view, $cluster_name, $drs_rules, $rule_spec, $cluster_spec, $rule_name, 
 $rule );
$cluster_name = Opts::get_option('cluster');
$rule_name = Opts::get_option('rule');

$cluster_view = Vim::find_entity_view( view_type  => 'ClusterComputeResource', 
          filter   => { 'name' => $cluster_name } );
die "Unable to locate cluster '$cluster_name' in vSphere inventory" unless $cluster_view;

if (defined $cluster_view->{'configurationEx'}{'rule'}) {
 $drs_rules = eval { $cluster_view->{'configurationEx'}{'rule'} };
} else {
 $drs_rules = [ ];
}

($rule) = grep { $_->{'name'} eq $rule_name } @$drs_rules;
die "Unable to locate rule '$rule_name' in cluster '$cluster_name'" unless $rule;

$rule_spec = new ClusterRuleSpec( removeKey => $rule->{'key'},
          operation => new ArrayUpdateOperation('remove') );
$cluster_spec = new ClusterConfigSpecEx( rulesSpec => [ $rule_spec ] );
$cluster_view->ReconfigureComputeResource(spec => $cluster_spec, modify => 1);

When executed, the above broken example should return the following error message:

SOAP Fault:
---------------
Fault string: A specified parameter was not correct.

With just a simple change to wrap the removeKey property in ClusterRuleSpec with PrimType, the operation can be serialized properly and the rule removed from the cluster.

## remove-drs-rule_working.pl
## Created by Reuben Stump (http://www.virtuin.com)
##
## Illustrate use of the PrimType to propertly serialize AnyType objects in the VI Perl SDK

use strict;
use warnings;

use VMware::VIRuntime;

my %opts = (
        'cluster' => {
        type => "=s",
        help => "The name of the cluster",
        required => 1,
        },
        'rule' => {
        type => "=s",
        help => "The name of the cluster drs rule to remove",
        required => 1,
        },
);
Opts::add_options(%opts);
Opts::parse();
Opts::validate();
Util::connect();

my ($cluster_view, $cluster_name, $drs_rules, $rule_spec, $cluster_spec, $rule_name, 
 $rule );
$cluster_name = Opts::get_option('cluster');
$rule_name = Opts::get_option('rule');

$cluster_view = Vim::find_entity_view( view_type  => 'ClusterComputeResource', 
          filter   => { 'name' => $cluster_name } );
die "Unable to locate cluster '$cluster_name' in vSphere inventory" unless $cluster_view;

if (defined $cluster_view->{'configurationEx'}{'rule'}) {
 $drs_rules = eval { $cluster_view->{'configurationEx'}{'rule'} };
} else {
 $drs_rules = [ ];
}

($rule) = grep { $_->{'name'} eq $rule_name } @$drs_rules;
die "Unable to locate rule '$rule_name' in cluster '$cluster_name'" unless $rule;

$rule_spec = new ClusterRuleSpec( removeKey => new PrimType($rule->{'key'}, 'int'),
          operation => new ArrayUpdateOperation('remove') );
$cluster_spec = new ClusterConfigSpecEx( rulesSpec => [ $rule_spec ] );
$cluster_view->ReconfigureComputeResource(spec => $cluster_spec, modify => 1);

1 comment:

  1. I admire the valuable information you offer in your articles. I will bookmark your blog and have my friends check up here often. I am quite sure they will learn lots of new stuff here than anybody else! Regards, vmware jobs in hyderabad.

    ReplyDelete