示例#1
0
    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
示例#2
0
    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
示例#3
0
    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)
示例#4
0
    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&param2=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
示例#5
0
    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
示例#6
0
    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
示例#7
0
    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