4 Ways to Publish a ServiceNow Application

Did you know there is more than one way to publish a scoped application? There are at least 4 methods that I know of, so let’s unpack them!

As a quick re-cap, scoped applications are ways to bundle configurations to ServiceNow, into a protected application scope. They can then be deployed to other instances outside of the one they are developed in via a Publish to create a new version and then a deploy.

#1 Native Studio UI

The most common way that everyone does it - through the native UI in studio.

#2 Using a Script

The undocumented mechanism to install a scoped app would be through a script.

publish: function(appID,version,devNotes){
	var trackerID;
	try { //run install command
		var progress_name = "Upload to the App Repository";
		var worker = new GlideScriptedHierarchicalWorker();
		worker.setProgressName(progress_name);
		worker.setBackground(true);
		worker.setCannotCancel(true);
		worker.setScriptIncludeName("sn_appauthor.ScopedAppUploaderAJAX");
		worker.setScriptIncludeMethod("start");
		var g_req = new GlobalRequest();
		g_req.setPreference('sysparm_sys_id',appID);
		g_req.setPreference('sysparm_version',version);
		g_req.setPreference('sysparm_dev_notes',devNotes);
		g_req.setPreference('sysparm_username', gs.getUserName());
		g_req.setPreference('sysparm_password', '');
		g_req.setPreference('sysparm_publish_to_store', 'false');
		g_req.setPreference('sysparm_target_upload_URL', '');
		worker.putConstructorArg('g_request',g_req);
			
		worker.start();
		trackerID = worker.getProgressID();
	} catch (err) {
		gs.error("Encountered error installing scoped app " + appID + ".\nError: " + err.message, this.type);
	}
	return trackerID;
},
var GlobalRequest = Class.create();
GlobalRequest.prototype = {
    initialize: function() {
		this.parms = {};
    },
	setPreference: function(key, value){
		this.parms[key] = value;
	},
	getParameter: function(key){
		return this.parms[key];
	},
    type: 'GlobalRequest'
};

#3 Update Sets

While it is officially documented, I feel like many people don’t know about this feature. You can publish a scoped app to an update set, which captures all the changes. Also a key benefit to using this method is that whichever instance you install the update set into, you can then open the app up in studio there.

#4 Using the CI/CD Spoke / API

For several releases now, ServiceNow offers a spoke and API for being able to publish an application.
Spoke Actions

  • Publish Application With ID

  • Publish Application With Scope

API: POST /sn_cicd/app_repo/publish

Publishes the specified application and all of its artifacts to the application repository.

Prototype.js, ServiceNow, and Objects

Disclaimer: This article assumes some entry level computer science concepts, and it’s a bit dry!

A well known programming concept is Classes, and their instance, Objects, which is a common staple of Object Oriented Programming (OOP) languages. Older versions of javascript (ES5 and below) which is what ServiceNow uses don’t have support for Classes. In an attempt to solve this problem, to add support for the concept of classes, ServiceNow used Prototype.js. A common place prototype is used for all the classes we define in ServiceNow's Script Includes.

Let’s take a look at an example Prototype Class that also could be a script include.

var Pirate = Class.create();
Pirate.prototype = {
  initialize: function(name) {
    this.name = name;
  },
  say: function(message) {
    return this.name + ': yarr ' + message;
  }
  type: 'Pirate'
};

The key parts are defining a class, it’s prototype, initialize method (aka the constructor, which can be optional), functions (aka methods), and the type variable which ServiceNow uses to reference script includes.

Inheritance & Polymorphism

Prototype also has support for common OOP concepts like Inheritance, with super and sub classes. A well known example for this is the GlideAjax super class. Along with Inheritance support, there is also support for method overriding and polymorphism. Since methods can be overridden, you don’t want to override like initialize function when extending the AbstractAjaxProcessor, otherwise it would break.

var myAjax = Class.create();
myAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
      getMessage: function () {
        return "success"
      }
});

Encapsulation & Private Elements

Another capability is encapsulation, and support for private functions and data variables. You can set a function or data element as private by using the “_” underscore prefix in front of the name. The data or function can only be called and accessed from within the class itself by using the this._privateVar syntax. All other methods and classes are by default considered public, and there is no concept of protected variables.

This Object

I’ve referenced it in the initial example, but Prototype provides a very helpful “this” object, which allows you to store data variable and call other functions within the current function. This also is incredibly helpful because with the type variable on all script includes, it’s very easy to log and identify where something is coming from. This is very similar to the “current” object available within business rules and workflows, but provides you with real accurate information regarding the script location.

Closing Thoughts

I’m not entirely sure which version of Prototype ServiceNow is running, but it seems to be older than 1.6.0 since there isn’t support for superclass or subclass properties. I can only assume a version was selected around 2004 when ServiceNow was initially developed and released. Script includes are one of the greatest capabilities that ServiceNow has to offer for re-usable server side code snippets, and prototype.js enables it to be that much more powerful.

Undocumented: Table Extension APIs

There are many undocumented ServiceNow APIs that have existed since the beginning. These are a couple that you may come across needing either as a system administrator or developer.

The first is the GlideTableParentChange if you need to move a table to be extended from another table. An example use case is that you may have accidently created it under the wrong table, like the wrong CI or task table.

var table = ''; //table you want to extend var old_parent = ''; var new_parent = ''; //the table you want to extend to, like cmdb_ci or task var changer = new GlideTableParentChange(table); changer.change(old_parent, new_parent);

The second is GlideDBUtil.promoteColumn which is a single one line script that lets you move a column up to the parent level table. This also might be useful in CMDB management, where you may have created a column under a table, but it really need to be moved to the parent so more CIs can use the field.

GlideDBUtil.promoteColumn('table_to_move_from', 'table_to_move_to', 'field_to_move', true);

Finally there is a documented TableUtils API that also offers some useful functions around dropping tables.

https://docs.servicenow.com/bundle/rome-application-development/page/app-store/dev_portal/API_reference/TableUtils/concept/c_TableUtilsAPI.html?cshalt=yes

Monitoring Series: Research into ServiceNow Performance Dashboard

Below are some of my ramblings, thoughts and research into the ‘servlet performance metrics’ dashboard from ServiceNow, and how this custom UI page homepage really works.

servlet performance.PNG

Observation #1 - The Front End is in the Perf Dashboard Plugin

This dashboard is part of the core system plugin, ‘Performance Dashboards’ (com.glide.performance_dashboards'), which is an extremely lightweight plugin for just housing the shell UI and a couple supporting scripts.

Observation #2 - The Library used is JRobin (Derived from RRDtool)

Within the scripts you can see data references to tables starting with jrobin, and those point to the JRobin Plugin (RRDS), which is just a Java implementation of the RRDtool system. They even kept the Robin Robin heritage by letting the table labels start with ‘Round Robin’. It’s worth noting that you can’t see any of these jrobin tables OOB, they are locked down to maint, I had to go into each individual read ACL, and add roles to be able to view it.

rrdtool.png

Observation #3 - ServiceNow uses an RRDTool Database to Store Monitoring data

This leads us to a another discovery, that all this data is being parsed from an Round Robin Database (RRD), and then there are supporting tables in ServiceNow which define the data refresh intervals (spoiler, they all refresh every 2min), and information about the Round Robin Archive. I found a good introduction to RRD here.

Observation #4 - ServiceNow Undocumented Monitoring APIs

While snooping around in the client side javascript, I found reference to the APIs which are called to provide the data. The sys_id’s needed to call these APIs are the in jrobin tables, and there is also other client side parameters.

p = "/api/now/v1/performance_dashboards/data_categories",
f = "/api/now/v1/performance_dashboards/graphs/overlays",
m = "/api/now/v1/performance_dashboards/graphs/category/<dataCategoryId>",
g = "/api/now/v1/performance_dashboards/graphs/<graphSysId>",
y = "/api/now/v1/performance_dashboards/events",
v = "/api/now/v1/performance_dashboards/nodes",
_ = "api/now/v1/performance_dashboards/suggestions"

Future Observations…

I would like to look more into the list of jrobin_graph_line’s and understand how the aggregator relates to the data source (jrobin_datasource).

I want to do some testing and see what format and parameters are needed to use those Performance Dashboards APIs.

I find it interesting how rrd4j appears to be the more widely adopted java port of RRDTool, vs jrobin. I could see ServiceNow eventually move to this, if they don’t discontinue or entirely re-structure their db monitoring backend. But ServiceNow has stuck with JRobin since 2006, so I find it doubtful it would change any time soon.