1 # Copyright (c) 2015 SONATA-NFV and Paderborn University
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # Neither the name of the SONATA-NFV, Paderborn University
17 # nor the names of its contributors may be used to endorse or promote
18 # products derived from this software without specific prior written
21 # This work has been performed in the framework of the SONATA project,
22 # funded by the European Commission under Grant number 671517 through
23 # the Horizon 2020 and 5G-PPP programmes. The authors would like to
24 # acknowledge the contributions of their colleagues of the SONATA
25 # partner consortium (www.sonata-nfv.eu).
26 from flask_restful
import Resource
27 from flask
import Response
, request
28 from emuvim
.api
.openstack
.openstack_dummies
.base_openstack_dummy
import BaseOpenstackDummy
29 from emuvim
.api
.openstack
.helper
import get_host
34 LOG
= logging
.getLogger("api.openstack.glance")
37 class GlanceDummyApi(BaseOpenstackDummy
):
38 def __init__(self
, in_ip
, in_port
, compute
):
39 super(GlanceDummyApi
, self
).__init
__(in_ip
, in_port
)
40 self
.compute
= compute
41 self
.api
.add_resource(GlanceListApiVersions
,
43 self
.api
.add_resource(GlanceSchema
,
45 "/v2/schemas/metadefs/namespace",
46 "/v2/schemas/metadefs/resource_type")
47 self
.api
.add_resource(GlanceListImagesApi
,
52 resource_class_kwargs
={'api': self
})
53 self
.api
.add_resource(GlanceImageByIdApi
,
56 resource_class_kwargs
={'api': self
})
57 self
.api
.add_resource(GlanceImageByDockerNameApi
,
58 "/v1/images/<owner>/<container>",
59 "/v2/images/<owner>/<container>",
60 resource_class_kwargs
={'api': self
})
63 class GlanceListApiVersions(Resource
):
65 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
67 resp
['versions'] = dict()
73 "href": request
.url_root
+ '/v2',
78 resp
['versions'] = versions
79 return Response(json
.dumps(resp
), status
=200,
80 mimetype
='application/json')
83 class GlanceSchema(Resource
):
85 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
87 resp
['name'] = 'someImageName'
88 resp
['properties'] = dict()
89 # just an ugly hack to allow the openstack client to work
90 return Response(json
.dumps(resp
), status
=200,
91 mimetype
='application/json')
94 class GlanceListImagesApi(Resource
):
95 def __init__(self
, api
):
99 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
103 resp
['first'] = "/v2/images"
104 resp
['schema'] = "/v2/schemas/images"
105 resp
['images'] = list()
108 for image
in self
.api
.compute
.images
.values():
111 f
['name'] = str(image
.name
).replace(":latest", "")
112 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
113 f
['container_format'] = "docker"
114 f
['disk_format'] = "raw"
116 f
['created_at'] = "2016-03-15T15:09:07.000000"
118 f
['deleted_at'] = None
119 f
['is_public'] = True
122 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
124 f
['protected'] = False
125 f
['status'] = "active"
126 f
['updated_at'] = "2016-03-15T15:09:07.000000"
127 f
['virtual_size'] = 1
129 resp
['images'].append(f
)
131 if c
> limit
: # ugly hack to stop buggy glance client to do infinite requests
133 if "marker" in request
.args
: # ugly hack to fix pageination of openstack client
134 resp
['images'] = None
135 return Response(json
.dumps(resp
), status
=200,
136 mimetype
="application/json")
138 except Exception as ex
:
140 u
"%s: Could not retrieve the list of images." % __name__
)
141 return ex
.message
, 500
145 This one is a real fake! It does not really create anything and the mentioned image
146 should already be registered with Docker. However, this function returns a reply that looks
147 like the image was just created to make orchestrators, like OSM, happy.
149 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
151 body_data
= json
.loads(request
.data
)
152 except BaseException
:
154 # lets see what we should create
155 img_name
= request
.headers
.get("X-Image-Meta-Name")
156 img_size
= request
.headers
.get("X-Image-Meta-Size")
157 img_disk_format
= request
.headers
.get("X-Image-Meta-Disk-Format")
158 img_is_public
= request
.headers
.get("X-Image-Meta-Is-Public")
159 img_container_format
= request
.headers
.get(
160 "X-Image-Meta-Container-Format")
161 # try to use body payload if header fields are empty
163 img_name
= body_data
.get("name")
165 img_disk_format
= body_data
.get("disk_format")
166 img_is_public
= True if "public" in body_data
.get(
167 "visibility") else False
168 img_container_format
= body_data
.get("container_format")
169 # try to find ID of already existing image (matched by name)
171 for image
in self
.api
.compute
.images
.values():
172 if str(img_name
) in image
.name
:
174 LOG
.debug("Image name: %s" % img_name
)
175 LOG
.debug("Image id: %s" % img_id
)
176 # build a response body that looks like a real one
181 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
182 f
['container_format'] = img_container_format
183 f
['disk_format'] = img_disk_format
185 f
['created_at'] = "2016-03-15T15:09:07.000000"
187 f
['deleted_at'] = None
188 f
['is_public'] = img_is_public
191 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
193 f
['protected'] = False
194 f
['status'] = "active"
195 f
['updated_at'] = "2016-03-15T15:09:07.000000"
196 f
['virtual_size'] = 1
198 # build actual response with headers and everything
199 r
= Response(json
.dumps(resp
), status
=201, mimetype
="application/json")
200 r
.headers
.add("Location", "http://%s:%d/v1/images/%s" % (get_host(request
),
206 class GlanceImageByIdApi(Resource
):
207 def __init__(self
, api
):
211 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
214 for image
in self
.api
.compute
.images
.values():
215 if image
.id == id or image
.name
== id:
216 resp
['id'] = image
.id
217 resp
['name'] = image
.name
219 return Response(json
.dumps(resp
), status
=200,
220 mimetype
="application/json")
223 "Image with id or name %s does not exists." % id, status
=404)
224 response
.headers
['Access-Control-Allow-Origin'] = '*'
227 except Exception as ex
:
229 u
"%s: Could not retrieve image with id %s." % (__name__
, id))
230 return Response(ex
.message
, status
=500,
231 mimetype
='application/json')
234 LOG
.debug("API CALL: %s " % str(self
.__class
__.__name
__))
235 LOG
.warning("Endpoint not implemented")
239 class GlanceImageByDockerNameApi(Resource
):
240 def __init__(self
, api
):
243 def get(self
, owner
, container
):
244 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
246 name
= "%s/%s" % (owner
, container
)
247 if name
in self
.api
.compute
.images
:
248 image
= self
.api
.compute
.images
[name
]
250 resp
['id'] = image
.id
251 resp
['name'] = image
.name
252 return Response(json
.dumps(resp
), status
=200,
253 mimetype
="application/json")
256 "Image with id or name %s does not exists." % id, status
=404)
257 response
.headers
['Access-Control-Allow-Origin'] = '*'
260 except Exception as ex
:
262 u
"%s: Could not retrieve image with id %s." % (__name__
, id))
263 return Response(ex
.message
, status
=500,
264 mimetype
='application/json')