1 # Copyright 2018 Telefonica
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
21 from osmclient
.common
.exceptions
import NotFound
22 from osmclient
.common
.exceptions
import ClientException
23 from osmclient
.common
import utils
26 from os
.path
import basename
32 def __init__(self
, http
=None, client
=None):
35 self
._logger
= logging
.getLogger("osmclient")
36 self
._apiName
= "/nsd"
37 self
._apiVersion
= "/v1"
38 self
._apiResource
= "/ns_descriptors"
39 self
._apiBase
= "{}{}{}".format(
40 self
._apiName
, self
._apiVersion
, self
._apiResource
43 def list(self
, filter=None):
44 self
._logger
.debug("")
45 self
._client
.get_token()
48 filter_string
= "?{}".format(filter)
49 _
, resp
= self
._http
.get2_cmd("{}{}".format(self
._apiBase
, filter_string
))
52 return json
.loads(resp
)
56 self
._logger
.debug("")
57 self
._client
.get_token()
58 if utils
.validate_uuid4(name
):
59 for nsd
in self
.list():
60 if name
== nsd
["_id"]:
63 for nsd
in self
.list():
64 if "name" in nsd
and name
== nsd
["name"]:
66 raise NotFound("nsd {} not found".format(name
))
68 def get_individual(self
, name
):
69 self
._logger
.debug("")
70 # Call to get_token not required, because will be implicitly called by get.
73 # It is redundant, since the previous one already gets the whole nsdinfo
74 # The only difference is that a different primitive is exercised
75 _
, resp
= self
._http
.get2_cmd("{}/{}".format(self
._apiBase
, nsd
["_id"]))
77 return json
.loads(resp
)
79 raise NotFound("nsd '{}' not found".format(name
))
80 raise NotFound("nsd '{}' not found".format(name
))
82 def get_thing(self
, name
, thing
, filename
):
83 self
._logger
.debug("")
84 # Call to get_token not required, because will be implicitly called by get.
86 headers
= self
._client
._headers
87 headers
["Accept"] = "application/binary"
88 http_code
, resp
= self
._http
.get2_cmd(
89 "{}/{}/{}".format(self
._apiBase
, nsd
["_id"], thing
)
93 return json
.loads(resp
)
96 raise ClientException(
97 "failed to get {} from {} - {}".format(thing
, name
, msg
)
100 def get_descriptor(self
, name
, filename
):
101 self
._logger
.debug("")
102 self
.get_thing(name
, "nsd", filename
)
104 def get_package(self
, name
, filename
):
105 self
._logger
.debug("")
106 self
.get_thing(name
, "package_content", filename
)
108 def get_artifact(self
, name
, artifact
, filename
):
109 self
._logger
.debug("")
110 self
.get_thing(name
, "artifacts/{}".format(artifact
), filename
)
112 def delete(self
, name
, force
=False):
113 self
._logger
.debug("")
117 querystring
= "?FORCE=True"
118 http_code
, resp
= self
._http
.delete_cmd(
119 "{}/{}{}".format(self
._apiBase
, nsd
["_id"], querystring
)
123 print("Deletion in progress")
124 elif http_code
== 204:
128 raise ClientException("failed to delete nsd {} - {}".format(name
, msg
))
131 self
, filename
, overwrite
=None, update_endpoint
=None, skip_charm_build
=False
133 self
._logger
.debug("")
134 if os
.path
.isdir(filename
):
135 filename
= filename
.rstrip("/")
136 filename
= self
._client
.package_tool
.build(
137 filename
, skip_validation
=False, skip_charm_build
=skip_charm_build
139 self
.create(filename
, overwrite
=overwrite
, update_endpoint
=update_endpoint
)
141 self
._client
.get_token()
142 mime_type
= magic
.from_file(filename
, mime
=True)
143 if mime_type
is None:
144 raise ClientException(
145 "Unexpected MIME type for file {}: MIME type {}".format(
149 headers
= self
._client
._headers
150 headers
["Content-Filename"] = basename(filename
)
151 if mime_type
in ["application/yaml", "text/plain", "application/json"]:
152 headers
["Content-Type"] = "text/plain"
153 elif mime_type
in ["application/gzip", "application/x-gzip"]:
154 headers
["Content-Type"] = "application/gzip"
155 elif mime_type
in ["application/zip"]:
156 headers
["Content-Type"] = "application/zip"
158 raise ClientException(
159 "Unexpected MIME type for file {}: MIME type {}".format(
163 headers
["Content-File-MD5"] = utils
.md5(filename
)
165 "{}: {}".format(key
, val
) for (key
, val
) in list(headers
.items())
167 self
._http
.set_http_header(http_header
)
169 http_code
, resp
= self
._http
.put_cmd(
170 endpoint
=update_endpoint
, filename
=filename
175 ow_string
= "?{}".format(overwrite
)
176 self
._apiResource
= "/ns_descriptors_content"
177 self
._apiBase
= "{}{}{}".format(
178 self
._apiName
, self
._apiVersion
, self
._apiResource
180 endpoint
= "{}{}".format(self
._apiBase
, ow_string
)
181 http_code
, resp
= self
._http
.post_cmd(
182 endpoint
=endpoint
, filename
=filename
185 if http_code
in (200, 201, 202):
187 resp
= json
.loads(resp
)
188 if not resp
or "id" not in resp
:
189 raise ClientException(
190 "unexpected response from server - {}".format(resp
)
193 elif http_code
== 204:
196 def update(self
, name
, filename
):
197 self
._logger
.debug("")
199 endpoint
= "{}/{}/nsd_content".format(self
._apiBase
, nsd
["_id"])
200 self
.create(filename
=filename
, update_endpoint
=endpoint
)