Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

# -*- coding: utf-8 -*- 

# Copyright: (c) 2021, XLAB Steampunk <steampunk@xlab.si> 

# 

# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 

 

from __future__ import absolute_import, division, print_function 

 

__metaclass__ = type 

 

from . import errors 

 

 

def _path(api_path, table, *subpaths): 

return "/".join(api_path + ("table", table) + subpaths) 

 

 

def _query(original=None): 

original = original or dict() 

original.setdefault("sysparm_exclude_reference_link", "true") 

return original 

 

 

class TableClient: 

def __init__(self, client, batch_size=1000): 

# 1000 records is default batch size for ServiceNow REST API, so we also use it 

# as a default. 

self.client = client 

self.batch_size = batch_size 

 

def list_records(self, table, query=None): 

base_query = _query(query) 

base_query["sysparm_limit"] = self.batch_size 

 

offset = 0 

total = 1 # Dummy value that ensures loop executes at least once 

result = [] 

 

while offset < total: 

response = self.client.get( 

_path(self.client.api_path, table), query=dict(base_query, sysparm_offset=offset) 

) 

 

result.extend(response.json["result"]) 

total = int(response.headers["x-total-count"]) 

offset += self.batch_size 

 

return result 

 

def get_record(self, table, query, must_exist=False): 

records = self.list_records(table, query) 

 

if len(records) > 1: 

raise errors.ServiceNowError( 

"{0} {1} records match the {2} query.".format( 

len(records), table, query 

) 

) 

 

if must_exist and not records: 

raise errors.ServiceNowError( 

"No {0} records match the {1} query.".format(table, query) 

) 

 

return records[0] if records else None 

 

def get_record_by_sys_id(self, table, sys_id): 

response = self.client.get( 

_path(self.client.api_path, table, sys_id) 

) 

record = response.json["result"] 

 

return record 

 

def create_record(self, table, payload, check_mode, query=None): 

if check_mode: 

# Approximate the result using the payload. 

return payload 

 

return self.client.post(_path(self.client.api_path, table), payload, query=_query(query)).json[ 

"result" 

] 

 

def update_record(self, table, record, payload, check_mode, query=None): 

if check_mode: 

# Approximate the result by manually patching the existing state. 

return dict(record, **payload) 

 

return self.client.patch( 

_path(self.client.api_path, table, record["sys_id"]), payload, query=_query(query) 

).json["result"] 

 

def delete_record(self, table, record, check_mode): 

if not check_mode: 

self.client.delete(_path(self.client.api_path, table, record["sys_id"])) 

 

 

def find_user(table_client, user_id): 

# TODO: Maybe add a lookup-by-email option too? 

return table_client.get_record("sys_user", dict(user_name=user_id), must_exist=True) 

 

 

def find_assignment_group(table_client, assignment_id): 

return table_client.get_record( 

"sys_user_group", dict(name=assignment_id), must_exist=True 

) 

 

 

def find_standard_change_template(table_client, template_name): 

return table_client.get_record( 

"std_change_producer_version", 

dict(name=template_name), 

must_exist=True, 

) 

 

 

def find_change_request(table_client, change_request_number): 

return table_client.get_record( 

"change_request", dict(number=change_request_number), must_exist=True 

) 

 

 

def find_configuration_item(table_client, item_name): 

return table_client.get_record("cmdb_ci", dict(name=item_name), must_exist=True) 

 

 

def find_problem(table_client, problem_number): 

return table_client.get_record( 

"problem", dict(number=problem_number), must_exist=True 

)