glance/glance/domain.py
Mark J. Washenberger 43ba08d8aa Add an image domain model and related helpers.
This patch is the first in a series refactoring the logic around image
manipulation. In this patch, we add a domain module that has Images and
ways of constructing them. In anticipation of proxy classes added in
subsequent patches, we also define some base classes to make proxying
simpler.

Partially implements bp:glance-domain-logic-layer

Change-Id: Ie72f2f86cfcbd15e41c32deed3626290f2bf0e6b
2012-11-14 12:52:11 -08:00

174 lines
5.9 KiB
Python

# Copyright 2012 OpenStack, LLC
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from glance.common import exception
from glance.openstack.common import timeutils
from glance.openstack.common import uuidutils
class ImageFactory(object):
_readonly_properties = ['created_at', 'updated_at', 'status', 'checksum',
'size']
_reserved_properties = ['owner', 'is_public', 'location',
'deleted', 'deleted_at', 'direct_url', 'self',
'file', 'schema']
def _check_readonly(self, kwargs):
for key in self._readonly_properties:
if key in kwargs:
raise exception.ReadonlyProperty(property=key)
def _check_unexpected(self, kwargs):
if len(kwargs) > 0:
msg = 'new_image() got unexpected keywords %s'
raise TypeError(msg % kwargs.keys())
def _check_reserved(self, properties):
if properties is not None:
for key in self._reserved_properties:
if key in properties:
raise exception.ReservedProperty(property=key)
def new_image(self, image_id=None, name=None, visibility='private',
min_disk=0, min_ram=0, protected=False, owner=None,
disk_format=None, container_format=None,
extra_properties=None, tags=None, **other_args):
self._check_readonly(other_args)
self._check_unexpected(other_args)
self._check_reserved(extra_properties)
if image_id is None:
image_id = uuidutils.generate_uuid()
created_at = timeutils.utcnow()
updated_at = created_at
status = 'queued'
return Image(image_id=image_id, name=name, status=status,
created_at=created_at, updated_at=updated_at,
visibility=visibility, min_disk=min_disk,
min_ram=min_ram, protected=protected,
owner=owner, disk_format=disk_format,
container_format=container_format,
extra_properties=extra_properties, tags=tags)
class Image(object):
def __init__(self, image_id, status, created_at, updated_at, **kwargs):
self.image_id = image_id
self.status = status
self.created_at = created_at
self.updated_at = updated_at
self.name = kwargs.pop('name', None)
self.visibility = kwargs.pop('visibility', 'private')
self.min_disk = kwargs.pop('min_disk', 0)
self.min_ram = kwargs.pop('min_ram', 0)
self.protected = kwargs.pop('protected', False)
self.location = kwargs.pop('location', None)
self.checksum = kwargs.pop('checksum', None)
self.owner = kwargs.pop('owner', None)
self.disk_format = kwargs.pop('disk_format', None)
self.container_format = kwargs.pop('container_format', None)
self.size = kwargs.pop('size', None)
self.extra_properties = kwargs.pop('extra_properties', None) or {}
self.tags = kwargs.pop('tags', None) or []
if len(kwargs) > 0:
message = "__init__() got unexpected keyword argument '%s'"
raise TypeError(message % kwargs.keys()[0])
@property
def visibility(self):
return self._visibility
@visibility.setter
def visibility(self, visibility):
if visibility not in ('public', 'private'):
raise ValueError('Visibility must be either "public" or "private"')
self._visibility = visibility
@property
def tags(self):
return self._tags
@tags.setter
def tags(self, value):
self._tags = set(value)
def delete(self):
if self.protected:
raise exception.ProtectedImageDelete(image_id=self.image_id)
self.status = 'deleted'
def _proxy(target, attr):
def get_attr(self):
return getattr(getattr(self, target), attr)
def set_attr(self, value):
return setattr(getattr(self, target), attr, value)
def del_attr(self):
return delattr(getattr(self, target), attr)
return property(get_attr, set_attr, del_attr)
class ImageRepoProxy(object):
def __init__(self, base):
self.base = base
def get(self, image_id):
return self.base.get(image_id)
def list(self, *args, **kwargs):
return self.base.list(*args, **kwargs)
def add(self, image):
return self.base.add(image)
def save(self, image):
return self.base.save(image)
def remove(self, image):
return self.base.remove(image)
class ImageProxy(object):
def __init__(self, base):
self.base = base
name = _proxy('base', 'name')
image_id = _proxy('base', 'image_id')
name = _proxy('base', 'name')
status = _proxy('base', 'status')
created_at = _proxy('base', 'created_at')
updated_at = _proxy('base', 'updated_at')
visibility = _proxy('base', 'visibility')
min_disk = _proxy('base', 'min_disk')
min_ram = _proxy('base', 'min_ram')
protected = _proxy('base', 'protected')
location = _proxy('base', 'location')
checksum = _proxy('base', 'checksum')
owner = _proxy('base', 'owner')
disk_format = _proxy('base', 'disk_format')
container_format = _proxy('base', 'container_format')
size = _proxy('base', 'size')
extra_properties = _proxy('base', 'extra_properties')
tags = _proxy('base', 'tags')
def delete(self):
self.base.delete()