~rlane/nova/lp773690

« back to all changes in this revision

Viewing changes to nova/image/glance.py

  • Committer: rlane at wikimedia
  • Date: 2011-04-29 22:30:40 UTC
  • mfrom: (382.1.655 nova)
  • Revision ID: rlane@wikimedia.org-20110429223040-i0x3ds9eqwrabyru
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
15
#    License for the specific language governing permissions and limitations
16
16
#    under the License.
 
17
 
17
18
"""Implementation of an image service that uses Glance as the backend"""
18
19
 
19
20
from __future__ import absolute_import
31
32
 
32
33
LOG = logging.getLogger('nova.image.glance')
33
34
 
 
35
 
34
36
FLAGS = flags.FLAGS
35
37
 
 
38
 
36
39
GlanceClient = utils.import_class('glance.client.Client')
37
40
 
38
41
 
39
42
class GlanceImageService(service.BaseImageService):
40
43
    """Provides storage and retrieval of disk image objects within Glance."""
41
44
 
42
 
    GLANCE_ONLY_ATTRS = ["size", "location", "disk_format",
43
 
                         "container_format"]
 
45
    GLANCE_ONLY_ATTRS = ['size', 'location', 'disk_format',
 
46
                         'container_format']
44
47
 
45
48
    # NOTE(sirp): Overriding to use _translate_to_service provided by
46
49
    # BaseImageService
56
59
            self.client = client
57
60
 
58
61
    def index(self, context):
59
 
        """
60
 
        Calls out to Glance for a list of images available
61
 
        """
 
62
        """Calls out to Glance for a list of images available."""
62
63
        # NOTE(sirp): We need to use `get_images_detailed` and not
63
64
        # `get_images` here because we need `is_public` and `properties`
64
65
        # included so we can filter by user
71
72
        return filtered
72
73
 
73
74
    def detail(self, context):
74
 
        """
75
 
        Calls out to Glance for a list of detailed image information
76
 
        """
 
75
        """Calls out to Glance for a list of detailed image information."""
77
76
        filtered = []
78
77
        image_metas = self.client.get_images_detailed()
79
78
        for image_meta in image_metas:
83
82
        return filtered
84
83
 
85
84
    def show(self, context, image_id):
86
 
        """
87
 
        Returns a dict containing image data for the given opaque image id.
88
 
        """
 
85
        """Returns a dict with image data for the given opaque image id."""
89
86
        try:
90
87
            image_meta = self.client.get_image_meta(image_id)
91
88
        except glance_exception.NotFound:
92
 
            raise exception.NotFound
 
89
            raise exception.ImageNotFound(image_id=image_id)
93
90
 
94
91
        if not self._is_image_available(context, image_meta):
95
 
            raise exception.NotFound
 
92
            raise exception.ImageNotFound(image_id=image_id)
96
93
 
97
94
        base_image_meta = self._translate_to_base(image_meta)
98
95
        return base_image_meta
99
96
 
100
97
    def show_by_name(self, context, name):
101
 
        """
102
 
        Returns a dict containing image data for the given name.
103
 
        """
 
98
        """Returns a dict containing image data for the given name."""
104
99
        # TODO(vish): replace this with more efficient call when glance
105
100
        #             supports it.
106
101
        image_metas = self.detail(context)
107
102
        for image_meta in image_metas:
108
103
            if name == image_meta.get('name'):
109
104
                return image_meta
110
 
        raise exception.NotFound
 
105
        raise exception.ImageNotFound(image_id=name)
111
106
 
112
107
    def get(self, context, image_id, data):
113
 
        """
114
 
        Calls out to Glance for metadata and data and writes data.
115
 
        """
 
108
        """Calls out to Glance for metadata and data and writes data."""
116
109
        try:
117
110
            image_meta, image_chunks = self.client.get_image(image_id)
118
111
        except glance_exception.NotFound:
119
 
            raise exception.NotFound
 
112
            raise exception.ImageNotFound(image_id=image_id)
120
113
 
121
114
        for chunk in image_chunks:
122
115
            data.write(chunk)
125
118
        return base_image_meta
126
119
 
127
120
    def create(self, context, image_meta, data=None):
128
 
        """
129
 
        Store the image data and return the new image id.
130
 
 
131
 
        :raises AlreadyExists if the image already exist.
 
121
        """Store the image data and return the new image id.
 
122
 
 
123
        :raises: AlreadyExists if the image already exist.
 
124
 
132
125
        """
133
126
        # Translate Base -> Service
134
 
        LOG.debug(_("Creating image in Glance. Metadata passed in %s"),
 
127
        LOG.debug(_('Creating image in Glance. Metadata passed in %s'),
135
128
                  image_meta)
136
129
        sent_service_image_meta = self._translate_to_service(image_meta)
137
 
        LOG.debug(_("Metadata after formatting for Glance %s"),
 
130
        LOG.debug(_('Metadata after formatting for Glance %s'),
138
131
                  sent_service_image_meta)
139
132
 
140
133
        recv_service_image_meta = self.client.add_image(
142
135
 
143
136
        # Translate Service -> Base
144
137
        base_image_meta = self._translate_to_base(recv_service_image_meta)
145
 
        LOG.debug(_("Metadata returned from Glance formatted for Base %s"),
 
138
        LOG.debug(_('Metadata returned from Glance formatted for Base %s'),
146
139
                  base_image_meta)
147
140
        return base_image_meta
148
141
 
149
142
    def update(self, context, image_id, image_meta, data=None):
150
143
        """Replace the contents of the given image with the new data.
151
144
 
152
 
        :raises NotFound if the image does not exist.
 
145
        :raises: ImageNotFound if the image does not exist.
 
146
 
153
147
        """
154
148
        # NOTE(vish): show is to check if image is available
155
149
        self.show(context, image_id)
156
150
        try:
157
151
            image_meta = self.client.update_image(image_id, image_meta, data)
158
152
        except glance_exception.NotFound:
159
 
            raise exception.NotFound
 
153
            raise exception.ImageNotFound(image_id=image_id)
160
154
 
161
155
        base_image_meta = self._translate_to_base(image_meta)
162
156
        return base_image_meta
163
157
 
164
158
    def delete(self, context, image_id):
165
 
        """
166
 
        Delete the given image.
167
 
 
168
 
        :raises NotFound if the image does not exist.
 
159
        """Delete the given image.
 
160
 
 
161
        :raises: ImageNotFound if the image does not exist.
 
162
 
169
163
        """
170
164
        # NOTE(vish): show is to check if image is available
171
165
        self.show(context, image_id)
172
166
        try:
173
167
            result = self.client.delete_image(image_id)
174
168
        except glance_exception.NotFound:
175
 
            raise exception.NotFound
 
169
            raise exception.ImageNotFound(image_id=image_id)
176
170
        return result
177
171
 
178
172
    def delete_all(self):
179
 
        """
180
 
        Clears out all images
181
 
        """
 
173
        """Clears out all images."""
182
174
        pass
183
175
 
184
176
    @classmethod
185
177
    def _translate_to_base(cls, image_meta):
186
 
        """Overriding the base translation to handle conversion to datetime
187
 
        objects
188
 
        """
189
 
        image_meta = service.BaseImageService._translate_to_base(image_meta)
 
178
        """Override translation to handle conversion to datetime objects."""
 
179
        image_meta = service.BaseImageService._propertify_metadata(
 
180
                        image_meta, cls.SERVICE_IMAGE_ATTRS)
190
181
        image_meta = _convert_timestamps_to_datetimes(image_meta)
191
182
        return image_meta
192
183
 
193
184
 
194
185
# utility functions
195
186
def _convert_timestamps_to_datetimes(image_meta):
196
 
    """
197
 
    Returns image with known timestamp fields converted to datetime objects
198
 
    """
 
187
    """Returns image with timestamp fields converted to datetime objects."""
199
188
    for attr in ['created_at', 'updated_at', 'deleted_at']:
200
189
        if image_meta.get(attr):
201
190
            image_meta[attr] = _parse_glance_iso8601_timestamp(
204
193
 
205
194
 
206
195
def _parse_glance_iso8601_timestamp(timestamp):
207
 
    """
208
 
    Parse a subset of iso8601 timestamps into datetime objects
209
 
    """
210
 
    iso_formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%M:%S"]
 
196
    """Parse a subset of iso8601 timestamps into datetime objects."""
 
197
    iso_formats = ['%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S']
211
198
 
212
199
    for iso_format in iso_formats:
213
200
        try:
215
202
        except ValueError:
216
203
            pass
217
204
 
218
 
    raise ValueError(_("%(timestamp)s does not follow any of the "
219
 
                       "signatures: %(ISO_FORMATS)s") % locals())
 
205
    raise ValueError(_('%(timestamp)s does not follow any of the '
 
206
                       'signatures: %(ISO_FORMATS)s') % locals())