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(
40 self
._apiName
, self
._apiVersion
, self
._apiResource
43 def create(self
, name
, permissions
):
45 Creates a new OSM role.
47 :param name: name of the role.
48 :param permissions: permissions of the role in YAML.
49 :raises ClientException: when receives an unexpected from the server.
50 :raises ClientException: when fails creating a role.
52 self
._logger
.debug("")
53 self
._client
.get_token()
57 role_permissions
= yaml
.safe_load(permissions
)
59 if not isinstance(role_permissions
, dict):
60 raise ClientException(
61 "Role permissions should be provided in a key-value fashion"
64 for key
, value
in role_permissions
.items():
65 if not isinstance(value
, bool):
66 raise ClientException(
67 "Value of '{}' in a role permissions should be boolean".format(
72 role
["permissions"] = role_permissions
74 http_code
, resp
= self
._http
.post_cmd(
75 endpoint
=self
._apiBase
, postfields_dict
=role
, skip_query_admin
=True
77 # print('HTTP CODE: {}'.format(http_code))
78 # print('RESP: {}'.format(resp))
79 # if http_code in (200, 201, 202, 204):
81 resp
= json
.loads(resp
)
82 if not resp
or "id" not in resp
:
83 raise ClientException("Unexpected response from server - {}".format(resp
))
89 # msg = json.loads(resp)
92 # raise ClientException("Failed to create role {} - {}".format(name, msg))
94 def update(self
, name
, new_name
, permissions
, add
=None, remove
=None):
96 Updates an OSM role identified by name.
98 NOTE: definition and add/remove are mutually exclusive.
100 :param name: name of the role
101 :param set_name: if provided, change the name.
102 :param permissions: if provided, overwrites the existing role specification. NOT IMPLEMENTED
103 :param add: if provided, adds new rules to the definition.
104 :param remove: if provided, removes rules from the definition.
105 :raises ClientException: when receives an unexpected response from the server.
106 :raises ClientException: when fails updating a role.
108 self
._logger
.debug("")
109 self
._client
.get_token()
110 if new_name
is None and permissions
is None and add
is None and remove
is None:
111 raise ClientException("At least one option should be provided")
112 elif permissions
and (add
or remove
):
113 raise ClientException("permissions and add/remove are mutually exclusive")
115 role_obj
= self
.get(name
)
116 new_role_obj
= {"permissions": {}}
118 new_role_obj
["name"] = new_name
121 role_definition
= yaml
.safe_load(permissions
)
123 if not isinstance(role_definition
, dict):
124 raise ClientException(
125 "Role permissions should be provided in a key-value fashion"
128 for key
, value
in role_definition
.items():
129 if not isinstance(value
, bool) and value
is not None:
130 raise ClientException(
131 "Value in a role permissions should be boolean or None to remove"
134 new_role_obj
["permissions"] = role_definition
137 keys_from_remove
= yaml
.safe_load(remove
)
139 if not isinstance(keys_from_remove
, list):
140 raise ClientException("Keys should be provided in a list fashion")
142 for key
in keys_from_remove
:
143 if not isinstance(key
, str):
144 raise ClientException("Individual keys should be strings")
145 new_role_obj
["permissions"][key
] = None
148 add_roles
= yaml
.safe_load(add
)
150 if not isinstance(add_roles
, dict):
151 raise ClientException(
152 "Add should be provided in a key-value fashion"
155 for key
, value
in add_roles
.items():
156 if not isinstance(value
, bool):
157 raise ClientException(
158 "Value '{}' in a role permissions should be boolean".format(
163 new_role_obj
["permissions"][key
] = value
164 if not new_role_obj
["permissions"]:
165 del new_role_obj
["permissions"]
167 http_code
, resp
= self
._http
.patch_cmd(
168 endpoint
="{}/{}".format(self
._apiBase
, role_obj
["_id"]),
169 postfields_dict
=new_role_obj
,
170 skip_query_admin
=True,
172 # print('HTTP CODE: {}'.format(http_code))
173 # print('RESP: {}'.format(resp))
174 if http_code
in (200, 201, 202):
176 resp
= json
.loads(resp
)
177 if not resp
or "id" not in resp
:
178 raise ClientException(
179 "Unexpected response from server - {}".format(resp
)
182 elif http_code
== 204:
188 # msg = json.loads(resp)
191 # raise ClientException("Failed to update role {} - {}".format(name, msg))
193 def delete(self
, name
, force
=False):
195 Deletes an OSM role identified by name.
199 :raises ClientException: when fails to delete a role.
201 self
._logger
.debug("")
202 self
._client
.get_token()
203 role
= self
.get(name
)
206 querystring
= "?FORCE=True"
207 http_code
, resp
= self
._http
.delete_cmd(
208 "{}/{}{}".format(self
._apiBase
, role
["_id"], querystring
),
209 skip_query_admin
=True,
211 # print('HTTP CODE: {}'.format(http_code))
212 # print('RESP: {}'.format(resp))
214 print("Deletion in progress")
215 elif http_code
== 204:
217 elif resp
and "result" in resp
:
223 # msg = json.loads(resp)
226 raise ClientException("Failed to delete role {} - {}".format(name
, msg
))
228 def list(self
, filter=None):
230 Returns the list of OSM role.
235 self
._logger
.debug("")
236 self
._client
.get_token()
239 filter_string
= "?{}".format(filter)
240 _
, resp
= self
._http
.get2_cmd(
241 "{}{}".format(self
._apiBase
, filter_string
), skip_query_admin
=True
243 # print('RESP: {}'.format(resp))
245 return json
.loads(resp
)
250 Returns a specific OSM role based on name or id.
253 :raises NotFound: when the role is not found.
254 :returns: the specified role.
256 self
._logger
.debug("")
257 self
._client
.get_token()
258 if utils
.validate_uuid4(name
):
259 for role
in self
.list():
260 if name
== role
["_id"]:
263 for role
in self
.list():
264 if name
== role
["name"]:
266 raise NotFound("Role {} not found".format(name
))