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
31 def __init__(self
, http
=None, client
=None):
34 self
._apiName
= '/admin'
35 self
._apiVersion
= '/v1'
36 self
._apiResource
= '/roles'
37 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
38 self
._apiVersion
, self
._apiResource
)
40 def create(self
, name
, definition
):
42 Creates a new OSM role.
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.
52 role_definition
= yaml
.load(definition
)
54 if not isinstance(role_definition
, dict):
55 raise ClientException('Role definition should be provided in a key-value fashion')
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')
63 http_code
, resp
= self
._http
.post_cmd(endpoint
=self
._apiBase
,
65 # print('HTTP CODE: {}'.format(http_code))
66 # print('RESP: {}'.format(resp))
67 if http_code
in (200, 201, 202, 204):
69 resp
= json
.loads(resp
)
70 if not resp
or 'id' not in resp
:
71 raise ClientException('Unexpected response from server - {}'.format(
78 msg
= json
.loads(resp
)
81 raise ClientException("Failed to create role {} - {}".format(name
, msg
))
83 def update(self
, name
, definition
=None, add
=None, remove
=None):
85 Updates an OSM role identified by name.
87 NOTE: definition and add/remove are mutually exclusive.
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.
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')
101 role_obj
= self
.get(name
)
103 "_id": role_obj
["_id"],
104 "name": role_obj
["name"]
108 role_definition
= yaml
.load(definition
)
110 if not isinstance(role_definition
, dict):
111 raise ClientException('Role definition should be provided in a key-value fashion')
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')
117 new_role_obj
[key
] = value
119 ignore_fields
= ["_id", "_admin", "name"]
120 keys_from_dict
= [key
for key
in role_obj
.keys() if key
not in ignore_fields
]
123 keys_from_remove
= yaml
.load(remove
)
125 if not isinstance(keys_from_remove
, list):
126 raise ClientException('Keys should be provided in a list fashion')
128 for key
in keys_from_remove
:
129 if not isinstance(key
, str):
130 raise ClientException('Individual keys should be strings')
132 keys_from_dict
= [key
for key
in keys_from_dict
if key
not in keys_from_remove
]
134 for key
in keys_from_dict
:
135 new_role_obj
[key
] = role_obj
[key
]
138 add_roles
= yaml
.load(definition
)
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 definition should be boolean')
147 new_role_obj
[key
] = value
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):
155 resp
= json
.loads(resp
)
156 if not resp
or 'id' not in resp
:
157 raise ClientException('Unexpected response from server - {}'.format(
164 msg
= json
.loads(resp
)
167 raise ClientException("Failed to update role {} - {}".format(name
, msg
))
169 def delete(self
, name
, force
=False):
171 Deletes an OSM role identified by name.
175 :raises ClientException: when fails to delete a role.
177 role
= self
.get(name
)
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))
186 print('Deletion in progress')
187 elif http_code
== 204:
189 elif resp
and 'result' in resp
:
195 msg
= json
.loads(resp
)
198 raise ClientException("Failed to delete role {} - {}".format(name
, msg
))
200 def list(self
, filter=None):
202 Returns the list of OSM role.
209 filter_string
= '?{}'.format(filter)
210 resp
= self
._http
.get_cmd('{}{}'.format(self
._apiBase
, filter_string
))
211 # print('RESP: {}'.format(resp))
218 Returns a specific OSM role based on name or id.
221 :raises NotFound: when the role is not found.
222 :returns: the specified role.
224 if utils
.validate_uuid4(name
):
225 for role
in self
.list():
226 if name
== role
['_id']:
229 for role
in self
.list():
230 if name
== role
['name']:
232 raise NotFound("Role {} not found".format(name
))