Adding role management
[osm/osmclient.git] / osmclient / sol005 / role.py
1 # Copyright 2019 Whitestack, LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14 #
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: esousa@whitestack.com or glavado@whitestack.com
17 ##
18
19 """
20 OSM role mgmt API
21 """
22
23 from osmclient.common import utils
24 from osmclient.common.exceptions import ClientException
25 from osmclient.common.exceptions import NotFound
26 import json
27 import yaml
28
29
30 class Role(object):
31 def __init__(self, http=None, client=None):
32 self._http = http
33 self._client = client
34 self._apiName = '/admin'
35 self._apiVersion = '/v1'
36 self._apiResource = '/roles'
37 self._apiBase = '{}{}{}'.format(self._apiName,
38 self._apiVersion, self._apiResource)
39
40 def create(self, name, definition):
41 """
42 Creates a new OSM role.
43
44 :param name: name of the role.
45 :param definition: definition of the role in YAML.
46 :raises ClientException: when receives an unexpected from the server.
47 :raises ClientException: when fails creating a role.
48 """
49 role = {"name": name}
50
51 if definition:
52 role_definition = yaml.load(definition)
53
54 if not isinstance(role_definition, dict):
55 raise ClientException('Role definition should be provided in a key-value fashion')
56
57 for key, value in role_definition.items():
58 if not isinstance(value, bool):
59 raise ClientException('Value in a role definition should be boolean')
60
61 role[key] = value
62
63 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
64 postfields_dict=role)
65 # print('HTTP CODE: {}'.format(http_code))
66 # print('RESP: {}'.format(resp))
67 if http_code in (200, 201, 202, 204):
68 if resp:
69 resp = json.loads(resp)
70 if not resp or 'id' not in resp:
71 raise ClientException('Unexpected response from server - {}'.format(
72 resp))
73 print(resp['id'])
74 else:
75 msg = ""
76 if resp:
77 try:
78 msg = json.loads(resp)
79 except ValueError:
80 msg = resp
81 raise ClientException("Failed to create role {} - {}".format(name, msg))
82
83 def update(self, name, definition=None, add=None, remove=None):
84 """
85 Updates an OSM role identified by name.
86
87 NOTE: definition and add/remove are mutually exclusive.
88
89 :param name: name of the role
90 :param definition: if provided, overwrites the existing role specification.
91 :param add: if provided, adds new rules to the definition.
92 :param remove: if provided, removes rules from the definition.
93 :raises ClientException: when receives an unexpected response from the server.
94 :raises ClientException: when fails updating a role.
95 """
96 if definition is None and add is None and remove is None:
97 raise ClientException('At least one option should be provided')
98 elif definition and (add or remove):
99 raise ClientException('Definition and add/remove are mutually exclusive')
100
101 role_obj = self.get(name)
102 new_role_obj = {
103 "_id": role_obj["_id"],
104 "name": role_obj["name"]
105 }
106
107 if definition:
108 role_definition = yaml.load(definition)
109
110 if not isinstance(role_definition, dict):
111 raise ClientException('Role definition should be provided in a key-value fashion')
112
113 for key, value in role_definition.items():
114 if not isinstance(value, bool):
115 raise ClientException('Value in a role definition should be boolean')
116
117 new_role_obj[key] = value
118 else:
119 ignore_fields = ["_id", "_admin", "name"]
120 keys_from_dict = [key for key in role_obj.keys() if key not in ignore_fields]
121
122 if remove:
123 keys_from_remove = yaml.load(remove)
124
125 if not isinstance(keys_from_remove, list):
126 raise ClientException('Keys should be provided in a list fashion')
127
128 for key in keys_from_remove:
129 if not isinstance(key, str):
130 raise ClientException('Individual keys should be strings')
131
132 keys_from_dict = [key for key in keys_from_dict if key not in keys_from_remove]
133
134 for key in keys_from_dict:
135 new_role_obj[key] = role_obj[key]
136
137 if add:
138 add_roles = yaml.load(definition)
139
140 if not isinstance(add_roles, dict):
141 raise ClientException('Add should be provided in a key-value fashion')
142
143 for key, value in add_roles.items():
144 if not isinstance(value, bool):
145 raise ClientException('Value in a role definition should be boolean')
146
147 new_role_obj[key] = value
148
149 http_code, resp = self._http.put_cmd(endpoint='{}/{}'.format(self._apiBase, role_obj['_id']),
150 postfields_dict=new_role_obj)
151 # print('HTTP CODE: {}'.format(http_code))
152 # print('RESP: {}'.format(resp))
153 if http_code in (200, 201, 202, 204):
154 if resp:
155 resp = json.loads(resp)
156 if not resp or 'id' not in resp:
157 raise ClientException('Unexpected response from server - {}'.format(
158 resp))
159 print(resp['id'])
160 else:
161 msg = ""
162 if resp:
163 try:
164 msg = json.loads(resp)
165 except ValueError:
166 msg = resp
167 raise ClientException("Failed to update role {} - {}".format(name, msg))
168
169 def delete(self, name, force=False):
170 """
171 Deletes an OSM role identified by name.
172
173 :param name:
174 :param force:
175 :raises ClientException: when fails to delete a role.
176 """
177 role = self.get(name)
178 querystring = ''
179 if force:
180 querystring = '?FORCE=True'
181 http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
182 role['_id'], querystring))
183 # print('HTTP CODE: {}'.format(http_code))
184 # print('RESP: {}'.format(resp))
185 if http_code == 202:
186 print('Deletion in progress')
187 elif http_code == 204:
188 print('Deleted')
189 elif resp and 'result' in resp:
190 print('Deleted')
191 else:
192 msg = ""
193 if resp:
194 try:
195 msg = json.loads(resp)
196 except ValueError:
197 msg = resp
198 raise ClientException("Failed to delete role {} - {}".format(name, msg))
199
200 def list(self, filter=None):
201 """
202 Returns the list of OSM role.
203
204 :param filter:
205 :returns:
206 """
207 filter_string = ''
208 if filter:
209 filter_string = '?{}'.format(filter)
210 resp = self._http.get_cmd('{}{}'.format(self._apiBase, filter_string))
211 # print('RESP: {}'.format(resp))
212 if resp:
213 return resp
214 return list()
215
216 def get(self, name):
217 """
218 Returns a specific OSM role based on name or id.
219
220 :param name:
221 :raises NotFound: when the role is not found.
222 :returns: the specified role.
223 """
224 if utils.validate_uuid4(name):
225 for role in self.list():
226 if name == role['_id']:
227 return role
228 else:
229 for role in self.list():
230 if name == role['name']:
231 return role
232 raise NotFound("Role {} not found".format(name))