1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 OpenStack LLC.
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
18
"""Implementation of an image service that uses Glance as the backend"""
26
from nova import utils
27
from nova import flags
28
from nova import exception
29
import nova.image.service
33
class TellerClient(object):
36
self.address = FLAGS.glance_teller_address
37
self.port = FLAGS.glance_teller_port
38
url = urlparse.urlparse(self.address)
39
self.netloc = url.netloc
40
self.connection_type = {'http': httplib.HTTPConnection,
41
'https': httplib.HTTPSConnection}[url.scheme]
44
class ParallaxClient(object):
47
self.address = FLAGS.glance_parallax_address
48
self.port = FLAGS.glance_parallax_port
49
url = urlparse.urlparse(self.address)
50
self.netloc = url.netloc
51
self.connection_type = {'http': httplib.HTTPConnection,
52
'https': httplib.HTTPSConnection}[url.scheme]
54
def get_image_index(self):
56
Returns a list of image id/name mappings from Parallax
59
c = self.connection_type(self.netloc, self.port)
60
c.request("GET", "images")
63
# Parallax returns a JSONified dict(images=image_list)
64
data = json.loads(res.read())['images']
67
logging.warn("Parallax returned HTTP error %d from "
68
"request for /images", res.status_int)
73
def get_image_details(self):
75
Returns a list of detailed image data mappings from Parallax
78
c = self.connection_type(self.netloc, self.port)
79
c.request("GET", "images/detail")
82
# Parallax returns a JSONified dict(images=image_list)
83
data = json.loads(res.read())['images']
86
logging.warn("Parallax returned HTTP error %d from "
87
"request for /images/detail", res.status_int)
92
def get_image_metadata(self, image_id):
94
Returns a mapping of image metadata from Parallax
97
c = self.connection_type(self.netloc, self.port)
98
c.request("GET", "images/%s" % image_id)
100
if res.status == 200:
101
# Parallax returns a JSONified dict(image=image_info)
102
data = json.loads(res.read())['image']
105
# TODO(jaypipes): log the error?
110
def add_image_metadata(self, image_metadata):
112
Tells parallax about an image's metadata
115
c = self.connection_type(self.netloc, self.port)
116
body = json.dumps(image_metadata)
117
c.request("POST", "images", body)
118
res = c.getresponse()
119
if res.status == 200:
120
# Parallax returns a JSONified dict(image=image_info)
121
data = json.loads(res.read())['image']
124
# TODO(jaypipes): log the error?
129
def update_image_metadata(self, image_id, image_metadata):
131
Updates Parallax's information about an image
134
c = self.connection_type(self.netloc, self.port)
135
body = json.dumps(image_metadata)
136
c.request("PUT", "images/%s" % image_id, body)
137
res = c.getresponse()
138
return res.status == 200
142
def delete_image_metadata(self, image_id):
144
Deletes Parallax's information about an image
147
c = self.connection_type(self.netloc, self.port)
148
c.request("DELETE", "images/%s" % image_id)
149
res = c.getresponse()
150
return res.status == 200
155
class GlanceImageService(nova.image.service.BaseImageService):
157
"""Provides storage and retrieval of disk image objects within Glance."""
160
self.teller = TellerClient()
161
self.parallax = ParallaxClient()
165
Calls out to Parallax for a list of images available
167
images = self.parallax.get_image_index()
172
Calls out to Parallax for a list of detailed image information
174
images = self.parallax.get_image_details()
179
Returns a dict containing image data for the given opaque image id.
181
image = self.parallax.get_image_metadata(id)
184
raise exception.NotFound
186
def create(self, data):
188
Store the image data and return the new image id.
190
:raises AlreadyExists if the image already exist.
193
return self.parallax.add_image_metadata(data)
195
def update(self, image_id, data):
196
"""Replace the contents of the given image with the new data.
198
:raises NotFound if the image does not exist.
201
self.parallax.update_image_metadata(image_id, data)
203
def delete(self, image_id):
205
Delete the given image.
207
:raises NotFound if the image does not exist.
210
self.parallax.delete_image_metadata(image_id)
212
def delete_all(self):
214
Clears out all images