UNPKG

maximo-dev-tools

Version:

Tools used with the development of Maximo projects

420 lines (352 loc) 14.2 kB
/* eslint-disable no-redeclare */ /* eslint-disable indent */ /* eslint-disable quotes */ /* eslint-disable no-undef */ // @ts-nocheck RESTRequest = Java.type("com.ibm.tivoli.oslc.RESTRequest"); ScriptInfo = Java.type("com.ibm.tivoli.maximo.script.ScriptInfo"); ScriptCache = Java.type("com.ibm.tivoli.maximo.script.ScriptCache"); ScriptDriverFactory = Java.type("com.ibm.tivoli.maximo.script.ScriptDriverFactory"); MessageDigest = Java.type("java.security.MessageDigest"); // eslint-disable-next-line no-global-assign Character = Java.type("java.lang.Character"); String = Java.type("java.lang.String"); StringBuilder = Java.type("java.lang.StringBuilder"); System = Java.type("java.lang.System"); MessageDigest = Java.type("java.security.MessageDigest"); ZonedDateTime = Java.type("java.time.ZonedDateTime"); DateTimeFormatter = Java.type("java.time.format.DateTimeFormatter"); HashMap = Java.type("java.util.HashMap"); SqlFormat = Java.type("psdi.mbo.SqlFormat"); MXServer = Java.type("psdi.server.MXServer"); MXApplicationException = Java.type("psdi.util.MXApplicationException"); MXLoggerFactory = Java.type("psdi.util.logging.MXLoggerFactory"); var sha256 = MessageDigest.getInstance("SHA-256"); var logger = MXLoggerFactory.getLogger("maximo.script." + service.getScriptName()); var configScript = "SHARPTREE.AUTOSCRIPT.DEPLOY.HISTORY"; main(); function main() { // initialize the configuration script if required. _initConfigScript(); try { if (typeof httpMethod !== "undefined" && !httpMethod) { var configName = _validateHttpRequestAndGetConfigName(); switch (httpMethod) { case "GET": responseBody = read(configName); break; case "PUT": var body = JSON.parse(requestBody); responseBody = update(configName, body); break; case "POST": var body = JSON.parse(requestBody); if (body._action && body._action.toLowerCase() == "delete") { responseBody = remove(configName); break; } responseBody = create(configName, body); break; case "DELETE": responseBody = remove(configName); break; default: throw ConfigError( "unhandled_method", "The configuration automation script does not support the Http method " + httpMethod + ", support Http methods are GET, PUT, POST and DELETE." ); } } } catch (error) { var response = {}; response.status = "error"; if (error instanceof Error) { response.message = error.message; } else if (error instanceof ConfigError) { response.message = error.message; response.reason = error.reason; } else { response.cause = error; } responseBody = JSON.stringify(response); return; } } function _validateHttpRequestAndGetConfigName() { if (typeof httpMethod == "undefined") { throw new ConfigError( "missing_http_method", "The configuration automation script must be invoked from an Http request and the httpMethod must be available." ); } if (typeof request == "undefined") { throw new ConfigError( "missing_oslc_request", "The configuration automation script must be invoked from an Http request and the OSLC request object must be available." ); } if (httpMethod == "PUT" || httpMethod == "POST") { if (typeof requestBody == "undefined") { throw new ConfigError("missing_request_body", "The configuration automation script request body cannot be empty for POST and PUT actions."); } } var field = RESTRequest.class.getDeclaredField("request"); field.setAccessible(true); var httpRequest = field.get(request); var requestURI = httpRequest.getRequestURI(); var contextPath = httpRequest.getContextPath(); var resourceReq = requestURI; if (contextPath && contextPath !== "") { resourceReq = requestURI.substring(contextPath.length()); } if (!resourceReq.startsWith("/")) { resourceReq = "/" + resourceReq; } if (!resourceReq.startsWith("/oslc/script/" + service.scriptName) && !resourceReq.startsWith("/api/script/" + service.scriptName)) { throw new ConfigError( "invalid_script_invocation", "The configuration automation script must be invoked as an Http OSLC script request in the form of /oslc/script/" + scriptName + " or /api/script/" + scriptName + " ." ); } var isOSLC = true; if (!resourceReq.toLowerCase().startsWith("/oslc/script/" + service.scriptName.toLowerCase())) { if (!resourceReq.toLowerCase().startsWith("/api/script/" + service.scriptName.toLowerCase())) { return null; } else { osOSLC = false; } } var baseReqPath = isOSLC ? "/oslc/script/" + service.scriptName : "/api/script/" + service.scriptName; var name = resourceReq.substring(baseReqPath.length); if (name.startsWith("/")) { name = name.substring(1); } if (!name || name.trim() === "") { throw new ConfigError( "missing_configuration_name", "The configuration automation script request must be in the form of " + baseReqPath + "/{configuration-name}." ); } return name; } function _initConfigScript() { var autoScriptSet; try { autoScriptSet = MXServer.getMXServer().getMboSet("AUTOSCRIPT", MXServer.getMXServer().getSystemUserInfo()); var sqlf = new SqlFormat("autoscript = :1"); sqlf.setObject(1, "AUTOSCRIPT", "AUTOSCRIPT", configScript); autoScriptSet.setWhere(sqlf.format()); if (autoScriptSet.isEmpty()) { var autoscript = autoScriptSet.add(); autoscript.setValue("AUTOSCRIPT", configScript); autoscript.setValue("DESCRIPTION", "Automation Script Deploy History"); autoscript.setValue("SCRIPTLANGUAGE", "nashorn"); autoscript.setValue("SOURCE", "config={};"); autoScriptSet.save(); } } finally { _close(autoScriptSet); } } function _saveConfigScript(config) { log_info("Saving the config"); var autoScriptSet; try { autoScriptSet = MXServer.getMXServer().getMboSet("AUTOSCRIPT", MXServer.getMXServer().getSystemUserInfo()); var sqlf = new SqlFormat("autoscript = :1"); sqlf.setObject(1, "AUTOSCRIPT", "AUTOSCRIPT", configScript); autoScriptSet.setWhere(sqlf.format()); if (autoScriptSet.isEmpty()) { throw ConfigError("missing_config", "The configuration automation script " + configScript + " does not exist."); } else { var autoscript = autoScriptSet.getMbo(0); var orderedConfig = Object.keys(config) .sort() .reduce(function (obj, key) { obj[key] = config[key]; return obj; }, {}); autoscript.setValue("SOURCE", "config=" + JSON.stringify(orderedConfig, null, 4) + ";"); autoScriptSet.save(); } } finally { _close(autoScriptSet); } } // eslint-disable-next-line no-unused-vars function createOrUpdateScript(scriptName, script, userName) { var scriptInfo; var toBeCreated = false; try { scriptInfo = JSON.parse(read(scriptName)); } catch (error) { if (typeof error.reason !== "undefined" && error.reason === "missing_config") { scriptInfo = {}; toBeCreated = true; } else { throw error; } } try { scriptInfo.deployed = System.currentTimeMillis(); scriptInfo.deployedBy = userName; scriptInfo.deployedAsDate = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); scriptInfo.hash = sha256Hex(script); if (toBeCreated) { create(scriptName, scriptInfo); } else { update(scriptName, scriptInfo); } } catch (error) { log_error("An error happened " + error); log_error(JSON.stringify(error)); } } function create(name, config) { var serverConfig = invokeScript(configScript).config; if (serverConfig[name]) { throw new ConfigError("config_exists", "The " + name + " configuration already exists and must be unique."); } serverConfig[name] = config; try { _saveConfigScript(serverConfig); } catch (error) { if (error instanceof Java.type("psdi.util.MXException")) { // if the error is that a record has been updated by another user then try again because we are inserting a new block. if (error.getErrorGroup() == "system" && error.getErrorKey() == "rowupdateexception") { create(name, config); } } } var result = { "status": "success" }; return JSON.stringify(result, null, 4); } function read(name) { var serverConfig = invokeScript(configScript).config; var result = serverConfig[name]; if (typeof result === "undefined") { throw new ConfigError("missing_config", "The key name " + name + " does not exists in the configuration."); } return JSON.stringify(result, null, 4); } function update(name, config) { var serverConfig = invokeScript(configScript).config; var result = serverConfig[name]; if (typeof result === "undefined") { throw new ConfigError("missing_config", "The key name " + name + " does not exists in the configuration."); } var preSignature = _calculateSignature(result); delete serverConfig[name]; serverConfig[name] = config; try { _saveConfigScript(serverConfig); } catch (error) { if (error instanceof Java.type("psdi.util.MXException")) { // if the error is that a record has been updated by another user then try again if the block we're saving wasn't modified. if (error.getErrorGroup() == "system" && error.getErrorKey() == "rowupdateexception") { var checkServerConfig = invokeScript(configScript).config; var checkResult = checkServerConfig[name]; if (typeof checkResult === "undefined") { throw new ConfigError("missing_config", "The key name " + name + " does not exists in the configuration."); } //if the part that we are updating hasn't changed then go ahead and try again. if (_calculateSignature(checkResult) === preSignature) { update(name, config); } } else { throw error; } } else { throw error; } } var result = { "status": "success" }; return JSON.stringify(result, null, 4); } // used remove function name because delete is a reserved word. function remove(name) { var serverConfig = invokeScript(configScript).config; var result = serverConfig[name]; if (typeof result === "undefined") { throw new ConfigError("missing_config", "The key name " + name + " does not exists in the configuration."); } delete serverConfig[name]; try { _saveConfigScript(serverConfig); } catch (error) { if (error instanceof Java.type("psdi.util.MXException")) { // if the error is that a record has been updated by another user then try again because we are removing the block if (error.getErrorGroup() == "system" && error.getErrorKey() == "rowupdateexception") { remove(name); } } } var result = { "status": "success" }; return JSON.stringify(result, null, 4); } function _calculateSignature(config) { // This is the ES5 version of Object.assign since Nashorn is not ES6 compatible. var evalConfig = JSON.parse(JSON.stringify(config)); // remove an existing signature so it isn't included in the hash delete evalConfig.signature; return sha256Hex(JSON.stringify(evalConfig, null, 4)); } function ConfigError(reason, message) { Error.call(this, message); this.reason = reason; this.message = message; } function invokeScript(scriptName) { scriptInfo = ScriptCache.getInstance().getScriptInfo(scriptName); if (typeof scriptInfo === "undefined" || !scriptInfo) { throw new MXApplicationException("script", "nosuchscript", Java.to([scriptName], "java.lang.String[]")); } var context = new HashMap(); ScriptDriverFactory.getInstance().getScriptDriver(scriptName).runScript(scriptName, context); return context; } // ConfigurationError derives from Error ConfigError.prototype = Object.create(Error.prototype); ConfigError.prototype.constructor = ConfigError; // Cleans up the MboSet connections and closes the set. function _close(set) { if (set) { set.cleanup(); set.close(); } } // Logging functions provided for compatibility with older versions where service.log_xxxx is not available. // eslint-disable-next-line no-unused-vars function log_debug(msg) { logger.debug(msg); } function log_info(msg) { logger.info(msg); } // eslint-disable-next-line no-unused-vars function log_warn(msg) { logger.warn(msg); } function log_error(msg) { logger.error(msg); } function sha256Hex(value) { try { return toHex(sha256.digest(value.getBytes("utf8"))); } catch (error) { logger.error(error); } } function toHex(value) { var result = new StringBuilder(); for (var j = 0; j < value.length; j++) { result.append(String.format("%02x", value[j])); } return result.toString(); }