Greg George

NAME

ServiceNow::Simple - Simple yet powerful ServiceNow API interface

SYNOPSIS

Note: To use the SOAP web services API the user you use must have the appropriate 'soap' role(s) (there are a few) and the table/fields must have access for the appropriate 'soap' role(s) if they are not open. This is true, whether you use this module or other web services to interact with ServiceNow.

There is a ServiceNow demonstration instance you can play with if you are unsure. Try https://demo019.service-now.com/navpage.do using user 'admin' with password 'admin'. You will need to give the 'admin' user the 'soap' role and change the ACL for sys_user_group to allow read and write for the 'soap' role (see the Wiki http://wiki.servicenow.com/index.php?title=Main_Page on how). Tables that are open do not need the ACL changes to allow access via these API's.

  use ServiceNow::Simple;

  ## Normal (minimal) use
  #######################
  my $sn = ServiceNow::Simple->new({ instance => 'some_name', table => 'sys_user' });
  # where your instance is https://some_name.service-now.com


  ## All options to new
  #####################
  my $sn = ServiceNow::Simple->new({
      instance             => 'some_name',
      instance_url         => 'http://some_name.something/',   # Not instance_url takes precedence over 'instance'
      table                => 'sys_user',
      __display_value      => 1,            # Return the display value for a reference field
      __plus_display_value => 1,            # Return the display value for a reference field AND the sys_id
      __limit              => 23,           # Maximum records to return
      __log                => $log,         # Log to a File::Log object
      __print_results      => 1,            # Print
      __soap_debug         => 1,            # Print SOAP::Lite debug details
      __remove_env_proxy   => 1,            # Delete any http proxy settings from environment
      });


  ## Get Keys
  ###########
  my $sn = ServiceNow::Simple->new({
      instance        => 'instance',
      table           => 'sys_user_group',
      user            => 'itil',
      password        => 'itil',
      });

  my $results = $sn->get_keys({ name => 'Administration' });
  # Single match:
  # $results = {
  #   'count' => '1',
  #   'sys_id' => '23105e1f1903ac00fb54sdb1ad54dc1a'
  # };

  $results = $sn->get_keys({ __encoded_query => 'GOTOnameSTARTSWITHa' });
  # Multi record match:
  # $results = {
  #   'count' => '6',
  #   'sys_id' => '23105e1f1903ac00fb54sdb1ad54dc1a,2310421b1cae0100e6ss837b1e7aa7d0,23100ed71cae0100e6ss837b1e7aa797,23100ed71cae0100e6ss837b1e7aa79d,2310421b1cae0100e6ss837b1e7aa7d4,231079c1b84ac5009c86fe3becceed2b'
  # };

  ## Insert a record
  ##################
  # Change table before insert
  $sn->set_table('sys_user');
  # Do the insert
  my $result = $sn->insert({
      user_name => 'GNG',
      name => 'GNG Test Record',
      active => 'true',
  });
  # Check the results, if there is an error $result will be undef
  if ($result)
  {
      print Dumper($result), "\n";
      # Sample success result:
      # $VAR1 = {
      #   'name' => 'GNG Test Record',
      #   'sys_id' => '2310f10bb8d4197740ff0d351492f271'
      # };
  }
  else
  {
      print Dumper($sn->{__fault}), "\n";
      # Sample failure result:
      # $VAR1 = {
      #   'detail' => 'com.glide.processors.soap.SOAPProcessingException: Insert Aborted : Error during insert of sys_user (GNG Test Record)',
      #   'faultcode' => 'SOAP-ENV:Server',
      #   'faultstring' => 'com.glide.processors.soap.SOAPProcessingException: Insert Aborted : Error during insert of sys_user (GNG Test Record)'
      # };
  }


  ## Get Records
  ##############
  my $sn = ServiceNow::Simple->new({
      instance        => 'some_name',
      table           => 'sys_user_group',
      __print_results => 1,
      });
  my $results = $sn->get_records({ name => 'Administration', __columns => 'name,description' });
  # Sample as printed to stdout, __print_results (same as $results):
  # $data_hr = {
  #   'count' => 1,
  #   'rows' => [
  #     {
  #       'description' => 'Administrator group.',
  #       'name' => 'Administration'
  #     }
  #   ]
  # };

  # Encoded query with minimal returned fields
  $results = $sn->get_records({ __encoded_query => 'GOTOnameSTARTSWITHa', __columns => 'name,email' });
  # $results = {
  #   'count' => 2,
  #   'rows' => [
  #     {
  #       'email' => '',
  #       'name' => 'Administration'
  #     },
  #     {
  #       'email' => 'android_dev@my_org.com',
  #       'name' => 'Android'
  #     },
  #   ]
  # };


  ## Update
  #########
  my $r = $sn->update({
      sys_id => '97415d1f1903ac00fb54adb1ad54dc1a',    ## REQUIRED, sys_id must be provided
      active => 'true',                                #  Other field(s)
      });  # Administration group, which should always be defined, set 'Active' to true
  # $r eq '97415d1f1903ac00fb54adb1ad54dc1a'

  ## Change to another table
  ##########################
  $sn->set_table('sys_user');

  ## Change to another instance
  #############################
  $sn->set_instance('my_dev_instance');

  ## SOAP debug messages
  ##########################
  $sn->soap_debug(1);  # Turn on
  ... do something
  $sn->soap_debug(0);  # Turn off

KEY FEATURES

  • Caching of user, password and proxy - one place to change and user and password is not scattered through many scripts

  • Results in simple perlish style. Ensures consistancy of returned types, AVOIDS an array of hashes for many items and a hash for one item, thereby keeping your code simpler

  • Arguments are 'typed' as per the WSDL. This avoids UTF-8/16 data being encoded as base64 when it should be a string.

  • Allows returning of only those fields you require by defining them, rather than defining all the fields you don't want! See __columns below. This can save a lot of bandwidth when getting records.

  • Persistant HTTP session across all SOAP calls

MAIN METHODS

The set of methods that do things on ServiceNow and return useful information

new

new creates a new 'ServiceNow::Simple' object. Parameters are passed in a hash reference. It requires that the instance of ServiceNow and the initial table be defined. The instance is the some_name in https://some_name.service-now.com. The table is the database name on the table to be operated on, for example the 'User' table is sys_user.

The parameters that can be passed are:

instance

REQUIRED unless instance_url is defined. The ServiceNow instance that ServiceNow::Simple should connect to. This is the normal approach and instance_url is only provided for special cases where the normal URL is not:

 instance.service-now.com
instance_url

Alternative to defining instance. Note: it is intended that this only be used where instance can not be used. This was added in version 0.08 after a suggestion from John Andersen.

table

REQUIRED. The table that ServiceNow::Simple will operate on unless changed with table() method

user

The user that ServiceNow::Simple will connect to the instance as. Note that this user will need to have one or more of the 'soap' roles. Note: if the configuration has been run and the user and password defined, this argument is not required. It can be used to over-ride the configuration value. See the 'simple.cfg' file located in the same location as the Simple.pm file. Note that the data in Simple.cfg is obfuscated (at least for user and password)

password

The password for the user, see user above.

__limit

Set the limit on the number of records that will be returned. By default this is 250 records. Settting this in the new method will apply this limit to all further calls unless that call defines it's own __limit.

= item __display_value

If set to true is will alter the way reference field information is returned. By default or if false a reference field will return the sys_id of the record. If set to true, the value returned is the display value (what you would see if looking at the form). This can also be set using the set_display_value() method.

= item __plus_display_value

Similar to __display_value above but the display value and the sys_id are given. The display value field is prefixed by dv_, so for example the department field on the User table [sys_user] would appear twice, once as dv_department giving the name and once as department giving the sys_id. This can also be set using the set_plus_display_value() method.

Note: Using __plus_display_value results in additional data being returned from the server, the dv_ record is always returned for fields not excluded and they themselfs can not be excluded (for a field you do want). If you have excluded (or not asked for with __columns) then the field and dv_field are excluded.

If true, results return will also be printed to STDOUT using Date::Dumper's Dump method. See the print_results() method.

__log

Used to define the log object. This can be a File::Log object or another log object that implements the msg(level, message) and exp(message) methods.

__soap_debug

If true, with activate soap debug messages. See also the soap_debug() method.

__remove_env_proxy

If true, remove any HTTPS_proxy or HTTP_proxy environment variables (generally you should not need this)

get

Query a single record from the targeted table by sys_id and return the record and its fields. So the expected argument (hash reference) would be { sys_id => <the_sys_id> } and could also include:

__exclude_columns

Specify a list of comma delimited field names to exclude from the result set

__columns

The opposite (and more useful IMHO) of __exclude_columns, define that field name you want returned. Often this is a much smaller list.

__use_view

Specify a Form view by name, to be used for limiting and expanding the results returned. When the form view contains deep referenced fields eg. caller_id.email, this field will be returned in the result as well

The get() returns a hash reference where the keys are the field names.

Example (that should run against the ServiceNow demo instance):

 use ServiceNow::Simple;
 use Data::Dumper;

 my $sn = ServiceNow::Simple->new({
     instance => 'demo019',
     user     => 'admin',
     password => 'admin',
     table    => 'sys_user_group',
     });

 # THIS IS ONLY CALLED TO GET THE SYS_ID FOR THE GET CALL
 my $results = $sn->get_keys({ name => 'CAB Approval' });

 my $r = $sn->get({ sys_id => $results->{sys_id} });
 print Dumper($r), "\n";

 # Output from Dumper
 $VAR1 = {
   'active' => '1',
   'cost_center' => '',
   'default_assignee' => '',
   'description' => 'CAB approvers',
   'email' => '',
   'exclude_manager' => '0',
   'include_members' => '0',
   'manager' => '',
   'name' => 'CAB Approval',
   'parent' => '',
   'roles' => '',
   'source' => '',
   'sys_created_by' => 'admin',
   'sys_created_on' => '2011-09-30 16:30:34',
   'sys_id' => 'b85d44954a3623120004689b2d5dd60a',
   'sys_mod_count' => '0',
   'sys_updated_by' => 'admin',
   'sys_updated_on' => '2011-09-30 16:30:34',
   'type' => ''
 };

get_keys

Query the targeted table by example values and return a comma delimited list of sys_id. Example values are key/value pairs where the key is the field name and the value is the value you want to match. You can also use an __encoded_query. See OTHER FIELD ARGUMENTS below.

  $results = $sn->get_keys({ active => true, site_name => 'knoxfield', __limit => 6, });
  # Multi record match:
  # $results = {
  #   'count' => '6',
  #   'sys_id' => '23105e1f1903ac00fb54sdb1ad54dc1a,2310421b1cae0100e6ss837b1e7aa7d0,23100ed71cae0100e6ss837b1e7aa797,23100ed71cae0100e6ss837b1e7aa79d,2310421b1cae0100e6ss837b1e7aa7d4,231079c1b84ac5009c86fe3becceed2b'
  # };

get_records

Query the targeted table by example values and return all matching records and their fields. See OTHER FIELD ARGUMENTS.

   my $results = $sn->get_records({
       active    => true,
       site_name => 'knoxfield',
       __limit   => 2,
       __columns => 'name,description'
       });
   # Sample result set:
   # $data_hr = {
   #   'count' => 2,
   #   'rows' => [
   #     {
   #       'description' => 'Knoxfield Main Site',
   #       'name' => 'KNX Main Office'
   #     },
   #     {
   #       'description' => 'Knoxfield Warehouse',
   #       'name' => 'KNX Warehouse'
   #     },
   #   ]
   # };

get_records CHUNKED

Should you require to extract a large amount of data you can employ a callback function to handle the response records and define a suitable chunk size (depending on your system/network/...). If you define a callback function, you can define your chunk size using __chunks (default is 250) and the maximum record count to return (using __max_records). You can also define a sleep period in seconds between each chunk, should you wish to limit your impact on the system.

Example:

 __max_records    => 10000,            # Return at maximum 10000 records
 __chunks         => 300,              # Get 300 records at a time
 __callback       => \&write_csv,      # Call your function write_csv
 __callback_sleep => 1,                # Sleep for a second between chunks

The callback function will be passed the following arguments:

$results

The data set hash (as per a normal return value from get_records(), which may be undef for no more records.

$first_call

Flag, if true, indicates the first callback for the data set.

$headers

The field headers expected in $results->{rows}, as an array ref (ie based on what we have in __columns or all columns). Note that if __plus_display_value is true, you will also get a dv_<fieldname> for each return field. This array can be used to select the data, print a header, act as keys to set headers from a hash, ....

get_records chunked EXAMPLE

 # get_records CHUNKED
 #
 #
 use warnings;
 use strict;
 use ServiceNow::Simple;
 use Text::CSV;
 use feature 'state';
 use Data::Dumper;

 my $sn = ServiceNow::Simple->new({
     instance              => 'demo012',
     user                  => 'admin',
     password              => 'admin',
     table                 => 'sys_user',
     __encoded_query       => 'user_nameSTARTSWITHa',
     });
 $sn->set_plus_display_value(1);
 my $results = $sn->get_records({
     __columns            => 'name,user_name,dv_department,department',
     __max_records        => 92,
     __chunks             => 10,
     __callback           => \&write_csv,
     });

 print Dumper($results), "\n";

 sub write_csv
 {
     my (
         $results,       # The data set hash, which may be undef for no more records
         $first_call,    # Flag to indicate first callback for data set, if true
         $headers        # The field headers expected in $results->{rows}, as an array ref (ie based on what we have in __columns or all columns)
         ) = @_;

     # Text::CSV object
     state $csv;
     state $fh;
     state $total_rows = 0;

     # Do initialisation if first_call
     if ($first_call)
     {
         $csv = Text::CSV->new({ binary => 1, eol => "\015\012" }) or die "Cannot use CSV: ".Text::CSV->error_diag ();
         open($fh, ">:encoding(utf8)", "new.csv") or die "new.csv: $!";
         $csv->print($fh, $headers);
     }

     # Print the row from results in the order of headers
     if ($results && $results->{count})
     {
         foreach my $row (@{ $results->{rows} })
         {
             my @data = @{$row}{@$headers};  # Hash slice
             $csv->print($fh, \@data);
             $total_rows++;
         }
     }
     else
     {
         close $fh or die "new.csv: $!";
         print "Wrote $total_rows rows to new.csv\n";
     }
 }

insert

Creates a new record for the table. Note: You need to provide all fields configured as mandatory (these are reflected in the WSDL as fileds with the attribute minOccurs=1). Example:

  $sn->set_table('sys_user');
  my $result = $sn->insert({
      user_name => 'GNG',
      name      => 'GNG Test Record',
      active    => 'true',
  });
  print Dumper($result), "\n";
  # Sample success result:
  # $VAR1 = {
  #   'name' => 'GNG Test Record',
  #   'sys_id' => '2310f10bb8d4197740ff0d351492f271'
  # };

update

Updates an existing record in the targeted table, identified by the mandatory sys_id field. Example:

  my $r = $sn->update({
      sys_id => '97415d1f1903ac00fb54adb1ad54dc1a',    ## REQUIRED, sys_id must be provided
      active => 'true',                                #  Other field(s)
      });

  $r will be the sys_id, unless there is a fault, in which case it is undef and $self->{__fault}
  will be set as follows:

  $self->{__fault}{faultcode}
  $self->{__fault}{faultstring}
  $self->{__fault}{detail}

RELATED METHODS

Allow you to change tables, instances, debug messages, printing etc

If called without an argument, returns the current value. Called with a true value sets printing of results using Data::Dumper's Dump method. Will also log to the log file if __log object is defined.

set_instance

Allows the instance to be changed from what was defined in the call to new. Note: This assumes the format of the URL is:

 instance.service-now.com

if this is not the case (it normally is) you should be using instance_url instead.

set_instance_url

Allows the instance URL to be changed from what was defined in the call to new. Note: This assumes the format of the URL is:

 https://something/

You would normally use 'instance' rather than 'instance_url'. instance_url takes precedence over instance.

set_table

Define the table the next method will work with/on. Example:

 $sn->set_table('sys_user');
 # query something on User table
 #...
 $sn->set_table('cmn_locations');
 # Now query something on Locations table

soap_debug

Turn on or off soap debug messages. Example:

 $sn->soap_debug(1); # Turn on debugging
 # do some stuff
 $sn->soap_debug(0); # Turn off debugging
 # do some more stuff

set_display_value

Affects what is returned for a reference field. By default a reference field returns the sys_id of the field referenced. Turning on set_display_value will change this to return the display value for that table. Example:

 $sn->set_display_value(1);  # Turn on 'display value'
 $sn->set_display_value(0);  # Turn off 'display value', so sys_id is returned

set_plus_display_value

Affects what is returned for a reference field. By default a reference field returns the sys_id of the field referenced. Turning on set_plus_display_value will return two fields for reference field(s), one prefixed with dv_ which has the display value for that table and the original reference field(s) which will contain the sys_id. Example:

 $sn->set_plus_display_value(1);  # Turn on 'display value & reference value'
 $sn->set_plus_display_value(0);  # Turn off 'display value & reference value', so sys_id is returned

PRIVATE METHODS

Internal, you should not use, methods. They may change without notice.

set_soap

SOAP::Transport::HTTP::Client::get_basic_credentials

_get_method

_init

_load_args

_load_wsdl

USEFUL LINKS

 http://wiki.servicenow.com/index.php?title=Direct_Web_Services

 http://wiki.servicenow.com/index.php?title=Direct_Web_Service_API_Functions

 A demo instance: https://demo019.service-now.com/

 Query building: http://wiki.servicenow.com/index.php?title=RSS_Feed_Generator

OTHER FIELD ARGUMENTS

__encoded_query

Specify an encoded query string to be used in filtering the returned results. The encoded query string format is similar to the value that may be specified in a sysparm_query URL parameter. Example:

 __encoded_query => 'active=true^nameSTARTSWITHa'

__order_by

Determines what fields the results are ordered by (ascending order). Example:

 __order_by => 'active'

__order_by_desc

Order by in descending order.

__exclude_columns

Specify a list of comma delimited field names to exclude from the results. This is, generally the opposite of what you want. See __columns below.

__columns

Define the columns you want in the results as a comma delimited list. Example:

 __columns => 'active,name,sys_id'

__limit

Limit the number of records that are returned. The default is 250. This can be set in the constructor new() in which case it is applied for all relavent calls or use it in the method calls get_keys or get_records. Example:

 __limit => 2000,  # Return up to 2000 records

__first_row

Instruct the results to be offset by this number of records, from the beginning of the set. When used with __last_row has the effect of querying for a window of results. The results are inclusive of the first row number.

Note, do not use __limit with __first_row/__last_row otherwise the system will generate a result set based on __limit rather than what is required for __first_row/__last_row.

__last_row

Instruct the results to be limited by this number of records, from the beginning of the set, or the __start_row value when specified. When used with __first_row has the effect of querying for a window of results. The results are less than the last row number, and does not include the last row. See __limit comment above for __first_row.

__use_view

Specify a Form view by name, to be used for limiting and expanding the results returned. When the form view contains deep referenced fields eg. caller_id.email, this field will be returned in the result as well

FILES

config.cache

Used to provide user, password and proxy settings for tests in /t

Simple.cfg

A configuration file that can contain the default user, password and proxy to use for all calls to method new() unless the 'user', 'password' and 'proxy' arguments are provided. The user and password are obfuscated. This is a very useful feature, only one place to change the user and password and they are not visible in a whole bunch of scripts.

VERSION

Version 0.09

AUTHOR

Greg George, <gng at cpan.org>

BUGS

Please report any bugs or feature requests to bug-ServiceNow::Simple at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=ServiceNow::Simple. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc ServiceNow::Simple

You can also look for information at:

ACKNOWLEDGEMENTS

Jay K. Slay for assistance in debugging in a proxy environment

The ServiceNow Wiki (see useful links), and authors of SOAP::Lite:

 Paul Kulchenko (paulclinger@yahoo.com)
 Randy J. Ray   (rjray@blackperl.com)
 Byrne Reese    (byrne@majordojo.com)
 Martin Kutter  (martin.kutter@fen-net.de)
 Fred Moyer     (fred@redhotpenguin.com)

John Andersen for suggesting instance_url see http://community.servicenow.com/forum/20300#comment-44864

LICENSE AND COPYRIGHT

Copyright 2013 Greg George.

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.