faa381b94d12a1d042aeb65361676c84468966d6
[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, permissions):
41 """
42 Creates a new OSM role.
43
44 :param name: name of the role.
45 :param permissions: permissions 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 self._client.get_token()
50 role = {"name": name}
51
52 if permissions:
53 role_permissions = yaml.safe_load(permissions)
54
55 if not isinstance(role_permissions, dict):
56 raise ClientException('Role permissions should be provided in a key-value fashion')
57
58 for key, value in role_permissions.items():
59 if not isinstance(value, bool):
60 raise ClientException("Value of '{}' in a role permissions should be boolean".format(key))
61
62 role["permissions"] = role_permissions
63
64 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
65 postfields_dict=role)
66 # print('HTTP CODE: {}'.format(http_code))
67 # print('RESP: {}'.format(resp))
68 if http_code in (200, 201, 202, 204):
69 if resp:
70 resp = json.loads(resp)
71 if not resp or 'id' not in resp:
72 raise ClientException('Unexpected response from server - {}'.format(
73 resp))
74 print(resp['id'])
75 else:
76 msg = ""
77 if resp:
78 try:
79 msg = json.loads(resp)
80 except ValueError:
81 msg = resp
82 raise ClientException("Failed to create role {} - {}".format(name, msg))
83
84 def update(self, name, new_name, permissions, add=None, remove=None):
85 """
86 Updates an OSM role identified by name.
87
88 NOTE: definition and add/remove are mutually exclusive.
89
90 :param name: name of the role
91 :param set_name: if provided, change the name.
92 :param permissions: if provided, overwrites the existing role specification. NOT IMPLEMENTED
93 :param add: if provided, adds new rules to the definition.
94 :param remove: if provided, removes rules from the definition.
95 :raises ClientException: when receives an unexpected response from the server.
96 :raises ClientException: when fails updating a role.
97 """
98 self._client.get_token()
99 if new_name is None and permissions is None and add is None and remove is None:
100 raise ClientException('At least one option should be provided')
101 elif permissions and (add or remove):
102 raise ClientException('permissions and add/remove are mutually exclusive')
103
104 role_obj = self.get(name)
105 new_role_obj = {"permissions": {}}
106 if new_name:
107 new_role_obj["name"] = new_name
108
109 if permissions:
110 role_definition = yaml.safe_load(permissions)
111
112 if not isinstance(role_definition, dict):
113 raise ClientException('Role permissions should be provided in a key-value fashion')
114
115 for key, value in role_definition.items():
116 if not isinstance(value, bool) and value is not None:
117 raise ClientException('Value in a role permissions should be boolean or None to remove')
118
119 new_role_obj["permissions"] = role_definition
120 else:
121 if remove:
122 keys_from_remove = yaml.safe_load(remove)
123
124 if not isinstance(keys_from_remove, list):
125 raise ClientException('Keys should be provided in a list fashion')
126
127 for key in keys_from_remove:
128 if not isinstance(key, str):
129 raise ClientException('Individual keys should be strings')
130 new_role_obj["permissions"][key] = None
131
132 if add:
133 add_roles = yaml.safe_load(add)
134
135 if not isinstance(add_roles, dict):
136 raise ClientException('Add should be provided in a key-value fashion')
137
138 for key, value in add_roles.items():
139 if not isinstance(value, bool):
140 raise ClientException("Value '{}' in a role permissions should be boolean".format(key))
141
142 new_role_obj["permissions"][key] = value
143 if not new_role_obj["permissions"]:
144 del new_role_obj["permissions"]
145
146 http_code, resp = self._http.put_cmd(endpoint='{}/{}'.format(self._apiBase, role_obj['_id']),
147 postfields_dict=new_role_obj)
148 # print('HTTP CODE: {}'.format(http_code))
149 # print('RESP: {}'.format(resp))
150 if http_code in (200, 201, 202):
151 if resp:
152 resp = json.loads(resp)
153 if not resp or 'id' not in resp:
154 raise ClientException('Unexpected response from server - {}'.format(
155 resp))
156 print(resp['id'])
157 elif http_code == 204:
158 print("Updated")
159 else:
160 msg = ""
161 if resp:
162 try:
163 msg = json.loads(resp)
164 except ValueError:
165 msg = resp
166 raise ClientException("Failed to update role {} - {}".format(name, msg))
167
168 def delete(self, name, force=False):
169 """
170 Deletes an OSM role identified by name.
171
172 :param name:
173 :param force:
174 :raises ClientException: when fails to delete a role.
175 """
176 self._client.get_token()
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 self._client.get_token()
208 filter_string = ''
209 if filter:
210 filter_string = '?{}'.format(filter)
211 resp = self._http.get_cmd('{}{}'.format(self._apiBase, filter_string))
212 # print('RESP: {}'.format(resp))
213 if resp:
214 return resp
215 return list()
216
217 def get(self, name):
218 """
219 Returns a specific OSM role based on name or id.
220
221 :param name:
222 :raises NotFound: when the role is not found.
223 :returns: the specified role.
224 """
225 self._client.get_token()
226 if utils.validate_uuid4(name):
227 for role in self.list():
228 if name == role['_id']:
229 return role
230 else:
231 for role in self.list():
232 if name == role['name']:
233 return role
234 raise NotFound("Role {} not found".format(name))