def __init__(self, session, table_name=None, values=None): if not session: raise SnowClientException( 'Record.__init__: To create a Record instance' 'you need to provide a non-empty SnowRestSession object.') if not table_name: raise SnowClientException( 'Record.__init__: To create a Record instance' 'you need to provide a table_name value.') if values and type(values) is not dict: raise SnowClientException( 'Record.__init__: the values parameter needs to be a dict.') super(Record, self).__init__(session) self._table_name = table_name table_class_mapping = TableClassMapping.get() if table_name in table_class_mapping: self._can_insert = table_class_mapping[table_name][ 'can_be_inserted'] else: self._can_insert = True self.sys_id = None self.sys_class_name = None if values: self._changes = values self._set_values(values) else: self._changes = {} self._initialized = True
def __init__(self, session, table_name=None): if not session: raise SnowClientException( 'RecordQuery.__init__: To create a RecordQuery instance' 'you need to provide a non-empty SnowRestSession object.') if not table_name: raise SnowClientException( 'RecordQuery.__init__: To create a RecordQuery instance' 'you need to provide table_name value.') super(RecordQuery, self).__init__(session) self._table_name = table_name
def __setattr__(self, key, value): initialized = hasattr(self, '_initialized') and self._initialized if key == 'sys_id' and hasattr(self, 'sys_id') and self.sys_id: raise SnowClientException( "Record.__setattr__: the field ``sys_id`` is read-only if it already has a value" ) if initialized and key == 'sys_class_name': raise SnowClientException( "Record.__setattr__: the field ``sys_class_name`` is read-only" ) if value is not None and not key.startswith('_'): value = RecordField(value) if initialized and not key.startswith('_'): self._changes[key] = value object.__setattr__(self, key, value)
def query(self, query_filter=None, query_encoded=None, url_params=None): """ Executes the query. At least a `query_filter` or `query_encoded` parameter need to be provided. Args: query_filter (dict): a dictionary with field names and values. Only records where the fields have the corresponding values will be returned query_encoded (str): a ServiceNow encoded query. See https://docs.servicenow.com/bundle/helsinki-servicenow-platform/page/use/using-lists/concept/c_EncodedQueryStrings.html url_params (str): additional URL parameters, as a string: param1=value1¶m2=value2 ... See https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/integrate/inbound_rest/reference/r_TableAPI-GET.html Returns: RecordSet : A RecordSet object, which is an iterable, and which will return in each iteration an instance of the class corresponding to the ``table_name`` provided in the constructor, if available; otherwise, an instance of the Record class. Raises: SnowClientException : if neither a query_filter nor a query_encoded parameter is provided. Examples: >>> r = RecordQuery(s, 'incident') >>> >>> # Query the incidents with FE=IT Service Management Support, >>> # Visibility=CERN, and already closed >>> record_set = r.query(query_filter={ >>> 'u_functional_element': 'ea56fb210a0a8c0a015a591ddbed3676', >>> 'u_visibility': 'cern', >>> 'active': 'false' >>> }) >>> >>> # Same query with encoded query, and requesting only the sys_id, number and short_description >>> record_set = r.query( >>> query_encoded="u_functional_element=ea56fb210a0a8c0a015a591ddbed3676^" >>> "u_visibility=cern^active=false", >>> url_params="sysparm_fields=number,short_description") >>> >>> for record in record_set: >>> print record.number + " " + record.short_description >>> print record.sys_class_name # will print 'incident' even if we did not request this field >>> print type(record) # will print the Incident class """ if not query_filter and not query_encoded: raise SnowClientException( "RecordQuery.query: " "needs either a value in the query_filter or the query_encoded parameters" ) # build the URL url = '/api/now/v2/table/' + self._table_name if query_filter: if query_encoded: query_encoded = query_encoded + '^' else: query_encoded = '' query = [] for key in query_filter: query.append(key + '=' + query_filter[key]) query_encoded = query_encoded + '^'.join(query) if query_encoded: url = url + '?sysparm_query=' + query_encoded if url_params: url_params = self.__check_and_fix_url_params(url_params) url = url + '&' + url_params # execute a get self._info('RecordQuery.query: querying the table ' + self._table_name + ' with URL ' + url) result = self._session.get(url, params={'sysparm_display_value': 'all'}) self._debug('RecordQuery.query: result of querying the table ' + self._table_name + ' with URL ' + url + ': ' + result.text) # build an array of objects where each object represents a record result_array = [] result = json.loads(result.text) if 'result' not in result: return RecordSet(self._session, result_array, self._table_name) for record in result['result']: result_array.append(record) # build a RecordSet passing the array result = RecordSet(self._session, result_array, self._table_name) # return the RecordSet return result
def update(self, key=None): """ Updates a record in ServiceNow. This can be done in a record previously obtained with a get operation, or previously inserted, or also on a record where its table and sys_id (or key) are previously known. Only the changes in the fields since the last ``.insert()`` or ``.update()`` will be sent. After updating, the attributes of the Record object will be updated with the resulting values from ServiceNow. Args: key (:obj:`str`, :obj:`unicode` or :obj:`tuple`, optional): a str/unicode value with the sys_id (ServiceNow unique identifier) of the record to update; or a tuple (field_name, field_value), such as ('number', 'INC987654'). If this parameter is set, it will override the current sys_id of this record object, if any. Returns: bool: True if the record was updated succesfully, False otherwise. Raises: SnowClientException: if no key is provided and the current record has no ``sys_id`` SnowRestSessionException : if there is any authentication problem Examples: Getting an incident and then updating it: >>> r = Record(s, 'incident'), { # s is a SnowRestSession object >>> if r.get(('number', 'INC0426232')): >>> if r.watch_list: >>> r.watch_list = r.watch_list + ',' >>> r.watch_list = r.watch_list + '*****@*****.**' >>> r.update() >>> print r.watch_list # will print the new value of the watchlist, where the above address might >>> # have been replaced by the user's sys_id Updating a previously known incident: >>> r = Record(s, 'incident') # s is a SnowRestSession object >>> r.watch_list = '*****@*****.**' # will completely replace the previous value >>> r.update(('number', 'INC0426232')) >>> print r.short_description # will print the incident's short description, since all fields are returned >>> # by ServiceNow """ is_key_text = isinstance(key, str) or isinstance(key, unicode) is_key_tuple = isinstance(key, tuple) and len(key) == 2 and isinstance( key[0], str) if not key and not self.sys_id: raise SnowClientException( 'Record.update: The current Record instance does not have a sys_id. ' 'Please provide a key to specify which record to update.') elif not self.sys_id and not is_key_text and not is_key_tuple: raise SnowClientException( "Record.get: the \"key\" parameter should be a non empty str/unicode value, " "or a tuple (field_name, field_value) where field_name is a str" ) if is_key_tuple: if self.get(key): sys_id = self.sys_id else: return False else: if is_key_text: sys_id = key else: sys_id = self.sys_id if not self.sys_class_name: table_class_mapping = TableClassMapping.get() if (self._table_name in table_class_mapping and 'is_base_table' in table_class_mapping[self._table_name] and table_class_mapping[ self._table_name]['is_base_table']): self.get(sys_id) # build the URL (using self.sys_class_name as table) if self.sys_class_name: url = '/api/now/v2/table/' + self.sys_class_name + '/' else: url = '/api/now/v2/table/' + self._table_name + '/' url = url + sys_id # execute a put using the changed data : get_changed_fields() data = json.dumps(self._changes) result = self._session.put(url=url, data=data, params={'sysparm_display_value': 'all'}) # parse the JSON result result = json.loads(result.text) # reset the changed data : reset_changed_values() self.reset_changed_values() if 'result' not in result: return False # set the values inside the current object: __set_values() self._set_values(result['result']) # return True or False return True
def insert(self): """ Inserts in ServiceNow a record into the table specified in the constructor via the argument ``table_name``. After inserting, the attributes of the Record object will be updated with the resulting values from ServiceNow. Returns: bool: True if the record was inserted succesfully, False otherwise. Raises: SnowClientException: if the current record is of a table where records cannot be inserted Example: the ``task`` table is a `supertable` of ``incident`` and ``u_request_fulfillment``. Incidents and requests can be inserted, but not tasks who are neither an incident nor a request. SnowRestSessionException : if there is any authentication problem Examples: Passing the values in the constructor: >>> r = Record(s, 'incident', { # s is a SnowRestSession object >>> 'short_description' : "New incident", >>> 'u_business_service' : 'e85a3f3b0a0a8c0a006a2912f2f352d1', # Service Element "ServiceNow" >>> 'u_functional_element' : '579fb3d90a0a8c08017ac8a1137c8ee6', # Functional Element "ServiceNow" >>> 'comments' : "Initial description" >>> }) >>> r.insert() >>> print r.number # will print the number of the new incident Setting values in the fields after instantiating the class: >>> r = Record(s, 'u_request_fulfillment') # s is a SnowRestSession object >>> r.short_description = "New request" >>> r.u_business_service = 'e85a3f3b0a0a8c0a006a2912f2f352d1' # Service Element "ServiceNow" >>> r.u_functional_element = '579fb3d90a0a8c08017ac8a1137c8ee6' # Functional ELement "ServiceNow" >>> r.comments = "Initial description" >>> r.insert() """ if not self._can_insert: class_name = type(self).__name__ raise SnowClientException( 'Record.insert: The current Record is of class ' + class_name + ', ' 'which cannot be inserted. ' 'You need to instantiate a subclass of ' + class_name + '.') # build the URL url = '/api/now/v2/table/' + self._table_name # execute a post using the changed data : get_changed_fields() data = json.dumps(self._changes) result = self._session.post(url=url, data=data, params={'sysparm_display_value': 'all'}) # parse the JSON result result = json.loads(result.text) self.reset_changed_values() if 'result' not in result: return False # reset the changed data : reset_changed_values() # set the values inside the current object: _set_values() self._set_values(result['result']) # return True or False return True
def get(self, key): """ Fetches from ServiceNow a record from the table specified in the constructor via the argument ``table_name``. The record may be fetched by its ``sys_id`` (ServiceNow unique identifier), or with a (field_name, field_value) pair. The attributes of the Record will be of the RecordField class, which behaves like a unicode value (thanks to inheriting from unicode) Args: key (:obj:`str`, :obj:`unicode` or :obj:`tuple`): a str/unicode value with the sys_id (ServiceNow unique identifier) of the record to fetch; or a tuple (field_name, field_value), such as ('number', 'INC987654') Returns: bool: True if a record was fetched succesfully, False if the record did not exist Raises: SnowClientException: if the ``key`` argument is invalid. SnowRestSessionException : if there is any authentication problem Examples: Getting an incident by sys_id: >>> r = Record(s, 'incident') # s is a SnowRestSession object >>> if r.get('c1c535ba85f45540adf94de5b835cd43'): >>> >>> # short_description is a String field in ServiceNow >>> print r.short_description # 'Test' >>> print r.short_description.get_value() # 'Test' >>> print r.short_description.get_display_value() # 'Test' >>> print r.short_description.is_reference() # False >>> >>> # u_functional_element is a Reference field in ServiceNow >>> print r.u_functional_element # 'ea56fb210a0a8c0a015a591ddbed3676', the sys_id of the Functional Element "IT Service Management Support" >>> print r.u_functional_element.get_value() # 'ea56fb210a0a8c0a015a591ddbed3676' >>> print r.u_functional_element.get_display_value() # 'IT Service Management Support' >>> print r.u_functional_element.is_reference() # True >>> print r.u_functional_element.get_referenced_table() # 'u_cmdb_ci_functional_services' >>> >>> # incident_state is a Choice field in ServiceNow >>> print r.incident_status # 7 >>> print r.incident_status.get_value() # 7 >>> print r.incident_status.get_display_value() # 'Closed' >>> print r.incident_status.is_reference() # False Getting a request by number: >>> r = Record(s, 'u_request_fulfillment') # s is a SnowRestSession object >>> if r.get(('number', 'RQF0746626')): >>> print r.short_description """ self._info("Record.get: Obtaining a record in table " + repr(self._table_name) + ' with key = ' + repr(key)) is_key_text = isinstance(key, str) or isinstance(key, unicode) is_key_tuple = isinstance(key, tuple) and len(key) == 2 and isinstance( key[0], str) if not key or (not is_key_text and not is_key_tuple): raise SnowClientException( "Record.get: the \"key\" parameter should be a non empty str/unicode value, " "or a tuple (field_name, field_value) where field_name is a str" ) url = '/api/now/v2/table/' + self._table_name if is_key_text: url = url + '/' + key elif is_key_tuple: url = url + '?sysparm_query=' + key[0] + '=' + key[1] # build the URL result = self._session.get(url=url, params={'sysparm_display_value': 'all'}) # execute a get result = json.loads(result.text) # parse the JSON result if is_key_text: if 'result' not in result: return False result = result['result'] elif is_key_tuple: if 'result' not in result: return False result = result['result'] if len(result) > 0: result = result[0] else: return False # set the values inside the current object : _set_values() self._set_values(result) # return True or False return True