1 # Copyright 2019 Whitestack, LLC
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: esousa@whitestack.com or glavado@whitestack.com
23 from osmclient
.common
import utils
24 from osmclient
.common
.exceptions
import ClientException
25 from osmclient
.common
.exceptions
import NotFound
32 def __init__(self
, http
=None, client
=None):
35 self
._logger
= logging
.getLogger('osmclient')
36 self
._apiName
= '/admin'
37 self
._apiVersion
= '/v1'
38 self
._apiResource
= '/roles'
39 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
40 self
._apiVersion
, self
._apiResource
)
42 def create(self
, name
, permissions
):
44 Creates a new OSM role.
46 :param name: name of the role.
47 :param permissions: permissions of the role in YAML.
48 :raises ClientException: when receives an unexpected from the server.
49 :raises ClientException: when fails creating a role.
51 self
._logger
.debug("")
52 self
._client
.get_token()
56 role_permissions
= yaml
.safe_load(permissions
)
58 if not isinstance(role_permissions
, dict):
59 raise ClientException('Role permissions should be provided in a key-value fashion')
61 for key
, value
in role_permissions
.items():
62 if not isinstance(value
, bool):
63 raise ClientException("Value of '{}' in a role permissions should be boolean".format(key
))
65 role
["permissions"] = role_permissions
67 http_code
, resp
= self
._http
.post_cmd(endpoint
=self
._apiBase
,
69 skip_query_admin
=True)
70 # print('HTTP CODE: {}'.format(http_code))
71 # print('RESP: {}'.format(resp))
72 #if http_code in (200, 201, 202, 204):
74 resp
= json
.loads(resp
)
75 if not resp
or 'id' not in resp
:
76 raise ClientException('Unexpected response from server - {}'.format(
83 # msg = json.loads(resp)
86 # raise ClientException("Failed to create role {} - {}".format(name, msg))
88 def update(self
, name
, new_name
, permissions
, add
=None, remove
=None):
90 Updates an OSM role identified by name.
92 NOTE: definition and add/remove are mutually exclusive.
94 :param name: name of the role
95 :param set_name: if provided, change the name.
96 :param permissions: if provided, overwrites the existing role specification. NOT IMPLEMENTED
97 :param add: if provided, adds new rules to the definition.
98 :param remove: if provided, removes rules from the definition.
99 :raises ClientException: when receives an unexpected response from the server.
100 :raises ClientException: when fails updating a role.
102 self
._logger
.debug("")
103 self
._client
.get_token()
104 if new_name
is None and permissions
is None and add
is None and remove
is None:
105 raise ClientException('At least one option should be provided')
106 elif permissions
and (add
or remove
):
107 raise ClientException('permissions and add/remove are mutually exclusive')
109 role_obj
= self
.get(name
)
110 new_role_obj
= {"permissions": {}}
112 new_role_obj
["name"] = new_name
115 role_definition
= yaml
.safe_load(permissions
)
117 if not isinstance(role_definition
, dict):
118 raise ClientException('Role permissions should be provided in a key-value fashion')
120 for key
, value
in role_definition
.items():
121 if not isinstance(value
, bool) and value
is not None:
122 raise ClientException('Value in a role permissions should be boolean or None to remove')
124 new_role_obj
["permissions"] = role_definition
127 keys_from_remove
= yaml
.safe_load(remove
)
129 if not isinstance(keys_from_remove
, list):
130 raise ClientException('Keys should be provided in a list fashion')
132 for key
in keys_from_remove
:
133 if not isinstance(key
, str):
134 raise ClientException('Individual keys should be strings')
135 new_role_obj
["permissions"][key
] = None
138 add_roles
= yaml
.safe_load(add
)
140 if not isinstance(add_roles
, dict):
141 raise ClientException('Add should be provided in a key-value fashion')
143 for key
, value
in add_roles
.items():
144 if not isinstance(value
, bool):
145 raise ClientException("Value '{}' in a role permissions should be boolean".format(key
))
147 new_role_obj
["permissions"][key
] = value
148 if not new_role_obj
["permissions"]:
149 del new_role_obj
["permissions"]
151 http_code
, resp
= self
._http
.patch_cmd(endpoint
='{}/{}'.format(self
._apiBase
, role_obj
['_id']),
152 postfields_dict
=new_role_obj
,
153 skip_query_admin
=True)
154 # print('HTTP CODE: {}'.format(http_code))
155 # print('RESP: {}'.format(resp))
156 if http_code
in (200, 201, 202):
158 resp
= json
.loads(resp
)
159 if not resp
or 'id' not in resp
:
160 raise ClientException('Unexpected response from server - {}'.format(
163 elif http_code
== 204:
169 # msg = json.loads(resp)
172 # raise ClientException("Failed to update role {} - {}".format(name, msg))
174 def delete(self
, name
, force
=False):
176 Deletes an OSM role identified by name.
180 :raises ClientException: when fails to delete a role.
182 self
._logger
.debug("")
183 self
._client
.get_token()
184 role
= self
.get(name
)
187 querystring
= '?FORCE=True'
188 http_code
, resp
= self
._http
.delete_cmd('{}/{}{}'.format(self
._apiBase
,
189 role
['_id'], querystring
),
190 skip_query_admin
=True)
191 # print('HTTP CODE: {}'.format(http_code))
192 # print('RESP: {}'.format(resp))
194 print('Deletion in progress')
195 elif http_code
== 204:
197 elif resp
and 'result' in resp
:
203 # msg = json.loads(resp)
206 raise ClientException("Failed to delete role {} - {}".format(name
, msg
))
208 def list(self
, filter=None):
210 Returns the list of OSM role.
215 self
._logger
.debug("")
216 self
._client
.get_token()
219 filter_string
= '?{}'.format(filter)
220 _
, resp
= self
._http
.get2_cmd('{}{}'.format(self
._apiBase
, filter_string
),skip_query_admin
=True)
221 # print('RESP: {}'.format(resp))
223 return json
.loads(resp
)
228 Returns a specific OSM role based on name or id.
231 :raises NotFound: when the role is not found.
232 :returns: the specified role.
234 self
._logger
.debug("")
235 self
._client
.get_token()
236 if utils
.validate_uuid4(name
):
237 for role
in self
.list():
238 if name
== role
['_id']:
241 for role
in self
.list():
242 if name
== role
['name']:
244 raise NotFound("Role {} not found".format(name
))