Develop > Server Automation Platform > Web Services clients > Perl Web Services clients

Perl Web Services clients

This section contains step-by-step instructions and sample code for creating Perl Web Services clients that access the SA API.

Required software for Perl clients

Your development environment must have the following Perl modules:

  • Crypt-SSLeay-0.57
  • IO-Socket-SSL-1.31
  • Net-SSLeay-1.35
  • HTML-Parser-3.64
  • MIME-Base64-3.08
  • URI-1.40
  • libwww-perl-5.833
  • SOAP-Lite-0.710

Depending on your Perl version, newer versions of these modules could be required.

Caution If the "500 SSL negotiation failed:" error persists, then OpenSSL needs to be updated to version 1.0.1 or higher. For the RHEL family, OpenSSL needs to be updated to version 1.0.1e-30 or higher.

Running the Perl demo program

To run the demo program, perform the following steps:

  1. From the support site, obtain the SA_Platform_Developer_Guide_examples.zip file bundled with the All Manuals Download SA 10.5 folder.
  2. Obtain the demo program uapisample.pl file from SA_Platform_Developer_Guide_examples.zip\SA_Platform_Developer_Guide_examples\api_examples\web_services\perl.
  3. Edit the uapisample.pl file, changing the hard-coded values for host, username, password, and object IDs such as serverID.
  4. Run uapisample.pl.
  5. If you receive a "Certificate Verify Failed" error, you should uncomment the following line from the sample file and provide a valid path to the certificate file:

    #$ENV{HTTPS_CA_FILE} = "path_to/opsware-ca.crt";

    You can find the certificate file from an SA Core in:

    /var/opt/opsware/crypto/twist/opsware-ca.crt

Sample Perl code

The following code snippets are from uapisample.pl, a Perl program contained in the ZIP file you downloaded previously.

Set up the Service URI

# Construct the URI for the service.
#
my $username = "integration";
my $password = "integration";
my $protocol = "https";
my $host = "occ.c38.dev.example.com";
my $port = "443";
my $contextUri = "osapi/com/opsware/";
my $folderServiceName = "folder/FolderService";
my $folderUri = "http://www.example.com/" . $contextUri .
$folderServiceName;
# Create a proxy to the FolderService.
#
my $folderProxy = $protocol . "://" . $username . ":" . $password . "@" .
$host . ":" . $port . "/" . $contextUri . $folderServiceName;

Initiate a new service

my $folderPort = SOAP::Lite
-> uri($folderUri)
-> proxy($folderProxy);

Invoke a service method

my $root = $folderPort->getRoot()->result();
print 'Got root folder: ' . $root->{'name'} . "\n";
# Alternative:
my $root = $folderPort->SOAP::getRoot();
print 'Got root folder: ' . $root->{'name'} . "\n";

Get a VO

$rootVO = $folderPort->getFolderVO(SOAP::Data->name('self')
->value(\SOAP::Data->name('id')->type('long')->value(0)))
->result();
# The preceding call to getFolderVO does not pass a FolderRef
# parameter. If a method such as FolderService.remove accepts a
# FolderRef parameter, use the following code:
#
my $folderToBeRemoved = SOAP::Data->name('self')
->attr({ 'xmlns:ns_fs' => 'http://folder.example.com/FolderService'}) -
>type('ns_fs:FolderRef')->value(\SOAP::Data->name('id')->type('long') -
>value(123456));
$folderPort->remove($folderToBeRemoved);
# To see the Perl representation of the returned VO, you can use
# the Dumper method. This will help you understand how to
# construct the dirty attributes of a VO for a create or update
# method.
#
use Data::Dumper;
print Dumper($folderVO);

Get an array

# Construct $folder, the FolderRef before getting the array.
#
my $folder = SOAP::Data->name('self') ->attr({ 'xmlns:ns_fs' => 'http://
folder.example.com'}) ->type('ns_fs:FolderRef')->value(\SOAP::Data-
>name('id')->type('long') ->value($root->{'id'}));
# The getChildren method returns an array of FNodeReference
# objects.
#
my $children = $folderPort->getChildren($folder, SOAP::Data->name('type')-
>type('string')->value(''))->result();
foreach $child (@{$children}){
print 'Get child: ' . $child->{'name'} . "\n";
}

Construct an object array

# For a function that takes an object array as a parameter,
# such the getVOs method, take the following approach:
# First, construct the Array object elements individually
# and put them in an array.
#
my @refs = [];
foreach my $ref (@{$myRefs}){
	# Assume myRefs was returned from a previous
		# Web Services call.
	my $object = SOAP::Data->name('FacilityRef')
		->value(\SOAP::Data->name('id')
			->type('long')
			->value($ref->{'id'}	
		)
	)->attr({ 'xmlns:facility' => 'http://locality.example.com'})
	->type('facility:FacilityRef');
   push @refs, $object;
}
# Second, construct an Array Object and put the array in it.
#
my $selves = SOAP::Data->name("selves" =>\SOAP::Data->name("element" => @refs)-
>type("facility:FacilityRef"))
		->attr({ 'xmlns:facility' => 'http://locality.example.com'})
		->type("facility:ArrayOfFacilityRef");

Update or create a VO

# This example updates the description attribute of a ServerVO.
#
my $serverID = 40038;
my $server = SOAP::Data->name('self')->value(\SOAP::Data->name('id')-
>type('long')->value($serverID));
# Don’t forget to set dirtyAttributes for the attributes
# you want to update. You also need dirtyAttributes for
# create methods that pass a VO.
#
my @dirtyAttrs = ('description');
my $serverVO = SOAP::Data->name('vo') ->attr({ 'xmlns:ns_ss' => 'http://
server.example.com'}) ->value(\SOAP::Data->value( SOAP::Data-
>name('description')->value('PERL_UPDATE_DESC')->type('string'), SOAP::Data-
>name('logChange')->value('false')->type('boolean'), SOAP::Data-
>name('dirtyAttributes' => \SOAP::Data->name("element" => @dirtyAttrs)-
>type("string")) ->type("ns_ss:ArrayOf_soapenc_string"), ));
my $force = SOAP::Data->name('force')->value('true')->type('boolean');
my $refetch = SOAP::Data->name('refetch')->value('true')->type('boolean');
# Call the update method.
#
print 'Invoking method serverWSPort.update...', "\n";
my $updatedServerVO = $serverWSPort->update(
		$server,
		$serverVO,
		$force,
		$refetch)->result();
print "New description: ", $updatedServerVO->{'description'}, "\n";

Handle SOAP faults

# Make sure that you turn off on_fault subroutine in the
# "use SOAP::Lite ..." statement.
#
# The fault member of a SOAP return will be set if the Web
# Service call throws an exception.
# The following code tries to get a folder that does not exist:
#
my $testVO = $folderPort->getFolderVO(SOAP::Data->name('self') -
>value(\SOAP::Data->name('id')->type('long')->value(123456)));
if($testVO->fault){
	print $testVO->faultstring . "\n";
	# This will print the error msg.
	print "ExceptionName: " . getExceptionName($testVO) . "\n"; # A
NotFoundException should be displayed here
	# The code that deals with the error goes here....
}
. . .
# The following subroutine extracts the exception name from the
# returned faultdetail.
#
sub getExceptionName {
	my $fault = shift; #get the fault object
	if($fault->faultdetail->{'fault'}){
		return ref($fault->faultdetail->{'fault'});
	}
}
. . .
# As shown in the preceding code, it’s easier to handle SOAP
# faults if you execute functions like this:
#
# my $data = $port->function(...);
# Not like this:
# $port->SOAP::function(...);
# $port->function(...)->result;

Construction of Perl objects for Web Services

Before calling a Web Services operation, a Perl client must set up the data structures that are required for the input parameters. The information you need for setting up the data structures is in the API documentation (javadocs) and the service’s WSDL file. The Perl code example in this section shows how to construct the input parameter for the getServerVO operation. The step-by-step instructions after the code show where to get the information about the input parameter from the API documentation and the WSDL file.

Source code for calling getServerVO

The following Perl code sets up the input parameter self and then calls the getServerVO operation. This call retrieves the VO (value object) for the managed server of ID 12345.

# Create a top-level SOAP::Data object
#
$self = SOAP::Data->name(’self’)
# The namespace corresponds to the schema of the data type
# of the SOAP:Data object. The name chosen (ns_ss) is
# arbitrary.
#
$self->attr({’xmlns:ns_ss =>
’http://server.example.com/ServerService’});
# Specify the type (ServerRef) for the parameter self, using the
# name of the namespace from the preceding statement.

#
$self->type(’ns_ss:ServerRef’);
# Create the value for the parameter. The value is a pointer
# to a SOAP::Data object. The number 12345 is the SA ID of a managed server.
#
my $id = SOAP::Data->name(’id’)->type(’long’)->value(12345);
# From the self object, point to the value.
#
$self->value(\$id);
# Finally, call getServerVO:
#
my $data = $serverPort->getServerVO($self);
if($data->fault){
	# Handle exceptions here ...
}
else{
	my $serverVO = $data->result;
}
. . .

Location of information for getServerVO setup

To get the information needed to write the code for the call to getServerVO, perform the following steps:

  1. In a browser, go to the API documentation (javadocs) at the following URL:

    https://occ_host:1032/twister/docs/index.html

    The occ_host is the IP address or host name of the core server running the Command Center component. (For instructions on invoking methods with the Twister, see API Documentation and the Twister.)
  2. Examine the API documentation to determine the input parameters and return value of the method.

    The getServerVO method is defined in the interface com.opsware.server.ServerService. In the following method signature, note that getServerVO accepts a ServerRef as a parameter and returns a ServerVO:

    public ServerVO getServerVO(ServerRef self)
    	throws java.rmi.RemoteException,		
    		NotFoundException,
    		AuthorizationException
  3. In a browser, specify the following URL to open the WSDL file for the ServerService:

    https://occ_host/osapi/com/opsware/server/ServerService?wsdl

  4. In the WSDL file, locate the namespace for the ServerService:

    <schema targetNamespace="http://server.example.com" xmlns="http://www.w3.org/2001/XMLSchema">

    The following Perl statement (from the code listed previously) specifies the namespace:
    $self->attr({’xmlns:ns_ss =>
    ’http://server.example.com/ServerService’});
  5. In the WSDL file, locate the getServerVO operation and note the input message name getServerVORequest.

    <wsdl:operation name="getServerVO" parameterOrder="self">
    	<wsdl:input message="impl:getServerVORequest" name="getServerVORequest"/>
    	<wsdl:output message="impl:getServerVOResponse" name="getServerVOResponse"/
    >
    	<wsdl:fault message="impl:NotFoundException" name="NotFoundException"/>
    	<wsdl:fault message="impl:AuthorizationException"
    name="AuthorizationException"/>
    </wsdl:operation>
  6. In the WSDL file, locate the getServerVORequest message:

    <wsdl:message name="getServerVORequest">
    	<wsdl:part name="self" type="impl:ServerRef"/>
    </wsdl:message>

    The getServerVORequest message element defines the name (self) and type (ServerRef) of the input parameter of getServerVO. The following Perl statement specifies ServerRef:
    $self->type(’ns_ss:ServerRef’);

  7. In the WSDL file, locate the complexType for ServerRef:

    <complexType name="ServerRef">
    	<complexContent>
    		<extension base="tns1:ObjRef">
    			<sequence>
    				<element name="secureResourceTypeName" nillable="true"
    type="soapenc:string"/>
    				</sequence>
    			</extension>
    		</complexContent>
    	</complexType>

    Note that ServerRef extends ObjRef.

  8. In the WSDL file, locate the complexType for ObjRef:

    <complexType abstract="true" name="ObjRef">
    	<sequence>
    		<element name="id" type="xsd:long"/>
    		<element name="idAsLong" nillable="true" type="soapenc:long"/>
    		<element name="name" nillable="true" type="soapenc:string"/>
    	</sequence>
    </complexType>

    In ObjRef, note the name (id) and type (long). These data types are specified in the following Perl statement:

    my $id = SOAP::Data->name(’id’)->type(’long’)->value(12345);