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
._apiName
= '/vnfpkgm'
36 self
._apiVersion
= '/v1'
37 self
._apiResource
= '/vnf_packages'
38 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
39 self
._apiVersion
, self
._apiResource
)
40 #self._apiBase='/vnfds'
42 def list(self
, filter=None):
43 self
._client
.get_token()
46 filter_string
= '?{}'.format(filter)
47 resp
= self
._http
.get_cmd('{}{}'.format(self
._apiBase
,filter_string
))
53 self
._client
.get_token()
54 if utils
.validate_uuid4(name
):
55 for vnfd
in self
.list():
56 if name
== vnfd
['_id']:
59 for vnfd
in self
.list():
60 if 'name' in vnfd
and name
== vnfd
['name']:
62 raise NotFound("vnfd {} not found".format(name
))
64 def get_individual(self
, name
):
66 # It is redundant, since the previous one already gets the whole vnfpkginfo
67 # The only difference is that a different primitive is exercised
68 resp
= self
._http
.get_cmd('{}/{}'.format(self
._apiBase
, vnfd
['_id']))
69 #print(yaml.safe_dump(resp))
72 raise NotFound("vnfd {} not found".format(name
))
74 def get_thing(self
, name
, thing
, filename
):
76 headers
= self
._client
._headers
77 headers
['Accept'] = 'application/binary'
78 http_code
, resp
= self
._http
.get2_cmd('{}/{}/{}'.format(self
._apiBase
, vnfd
['_id'], thing
))
79 #print('HTTP CODE: {}'.format(http_code))
80 #print('RESP: {}'.format(resp))
81 if http_code
in (200, 201, 202, 204):
89 msg
= json
.loads(resp
)
92 raise ClientException("failed to get {} from {} - {}".format(thing
, name
, msg
))
94 def get_descriptor(self
, name
, filename
):
95 self
.get_thing(name
, 'vnfd', filename
)
97 def get_package(self
, name
, filename
):
98 self
.get_thing(name
, 'package_content', filename
)
100 def get_artifact(self
, name
, artifact
, filename
):
101 self
.get_thing(name
, 'artifacts/{}'.format(artifact
), filename
)
103 def delete(self
, name
, force
=False):
104 self
._client
.get_token()
105 vnfd
= self
.get(name
)
108 querystring
= '?FORCE=True'
109 http_code
, resp
= self
._http
.delete_cmd('{}/{}{}'.format(self
._apiBase
,
110 vnfd
['_id'], querystring
))
111 #print('HTTP CODE: {}'.format(http_code))
112 #print('RESP: {}'.format(resp))
114 print('Deletion in progress')
115 elif http_code
== 204:
121 msg
= json
.loads(resp
)
124 raise ClientException("failed to delete vnfd {} - {}".format(name
, msg
))
126 def create(self
, filename
, overwrite
=None, update_endpoint
=None):
127 self
._client
.get_token()
128 mime_type
= magic
.from_file(filename
, mime
=True)
129 if mime_type
is None:
130 raise ClientException(
131 "failed to guess MIME type for file '{}'".format(filename
))
132 headers
= self
._client
._headers
133 headers
['Content-Filename'] = basename(filename
)
134 if mime_type
in ['application/yaml', 'text/plain', 'application/json']:
135 headers
['Content-Type'] = 'text/plain'
136 elif mime_type
in ['application/gzip', 'application/x-gzip']:
137 headers
['Content-Type'] = 'application/gzip'
138 #headers['Content-Type'] = 'application/binary'
139 # Next three lines are to be removed in next version
140 #headers['Content-Filename'] = basename(filename)
141 #file_size = stat(filename).st_size
142 #headers['Content-Range'] = 'bytes 0-{}/{}'.format(file_size - 1, file_size)
144 raise ClientException(
145 "Unexpected MIME type for file {}: MIME type {}".format(
148 headers
["Content-File-MD5"] = utils
.md5(filename
)
149 http_header
= ['{}: {}'.format(key
,val
)
150 for (key
,val
) in list(headers
.items())]
151 self
._http
.set_http_header(http_header
)
153 http_code
, resp
= self
._http
.put_cmd(endpoint
=update_endpoint
, filename
=filename
)
157 ow_string
= '?{}'.format(overwrite
)
158 self
._apiResource
= '/vnf_packages_content'
159 self
._apiBase
= '{}{}{}'.format(self
._apiName
,
160 self
._apiVersion
, self
._apiResource
)
161 endpoint
= '{}{}'.format(self
._apiBase
,ow_string
)
162 http_code
, resp
= self
._http
.post_cmd(endpoint
=endpoint
, filename
=filename
)
163 #print('HTTP CODE: {}'.format(http_code))
164 #print('RESP: {}'.format(resp))
165 if http_code
in (200, 201, 202):
167 resp
= json
.loads(resp
)
168 if not resp
or 'id' not in resp
:
169 raise ClientException('unexpected response from server: '.format(
172 elif http_code
== 204:
175 msg
= "Error {}".format(http_code
)
178 msg
= "{} - {}".format(msg
, json
.loads(resp
))
180 msg
= "{} - {}".format(msg
, resp
)
181 raise ClientException("failed to create/update vnfd - {}".format(msg
))
183 def update(self
, name
, filename
):
184 self
._client
.get_token()
185 vnfd
= self
.get(name
)
186 endpoint
= '{}/{}/package_content'.format(self
._apiBase
, vnfd
['_id'])
187 self
.create(filename
=filename
, update_endpoint
=endpoint
)