From 1d121a42f5072026a3ad19cb5fd1915d7cd2ff63 Mon Sep 17 00:00:00 2001 From: "vladimir.p" Date: Mon, 22 Aug 2011 17:31:48 -0700 Subject: initial cut on volume type APIs --- nova/db/sqlalchemy/api.py | 16 +++---- nova/db/sqlalchemy/models.py | 2 +- nova/exception.py | 4 ++ nova/volume/api.py | 8 +++- nova/volume/volume_types.py | 101 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 nova/volume/volume_types.py (limited to 'nova') diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 143162fc6..ac8aed307 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2163,7 +2163,7 @@ def volume_get(context, volume_id, session=None): if is_admin_context(context): result = session.query(models.Volume).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(id=volume_id).\ filter_by(deleted=can_read_deleted(context)).\ @@ -2171,7 +2171,7 @@ def volume_get(context, volume_id, session=None): elif is_user_context(context): result = session.query(models.Volume).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(project_id=context.project_id).\ filter_by(id=volume_id).\ @@ -2188,7 +2188,7 @@ def volume_get_all(context): session = get_session() return session.query(models.Volume).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(deleted=can_read_deleted(context)).\ all() @@ -2199,7 +2199,7 @@ def volume_get_all_by_host(context, host): session = get_session() return session.query(models.Volume).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(host=host).\ filter_by(deleted=can_read_deleted(context)).\ @@ -2210,7 +2210,7 @@ def volume_get_all_by_host(context, host): def volume_get_all_by_instance(context, instance_id): session = get_session() result = session.query(models.Volume).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(instance_id=instance_id).\ filter_by(deleted=False).\ @@ -2227,7 +2227,7 @@ def volume_get_all_by_project(context, project_id): session = get_session() return session.query(models.Volume).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ filter_by(project_id=project_id).\ filter_by(deleted=can_read_deleted(context)).\ @@ -2241,7 +2241,7 @@ def volume_get_instance(context, volume_id): filter_by(id=volume_id).\ filter_by(deleted=can_read_deleted(context)).\ options(joinedload('instance')).\ - options(joinedload('metadata')).\ + options(joinedload('volume_metadata')).\ options(joinedload('volume_type')).\ first() if not result: @@ -3634,7 +3634,7 @@ def volume_type_create(_context, values): @require_context -def volume_type_get_all(context, inactive=False): +def volume_type_get_all(context, inactive=False, filters={}): """ Returns a dict describing all volume_types with name as key. """ diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 99e6f412e..4195ca113 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -322,7 +322,7 @@ class VolumeMetadata(BASE, NovaBase): key = Column(String(255)) value = Column(String(255)) volume_id = Column(Integer, ForeignKey('volumes.id'), nullable=False) - volume = relationship(Volume, backref="metadata", + volume = relationship(Volume, backref="volume_metadata", foreign_keys=volume_id, primaryjoin='and_(' 'VolumeMetadata.volume_id == Volume.id,' diff --git a/nova/exception.py b/nova/exception.py index 1b118f6f9..01d676b54 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -197,6 +197,10 @@ class InvalidInstanceType(Invalid): message = _("Invalid instance type %(instance_type)s.") +class InvalidVolumeType(Invalid): + message = _("Invalid volume type %(volume_type)s.") + + class InvalidPortRange(Invalid): message = _("Invalid port range %(from_port)s:%(to_port)s.") diff --git a/nova/volume/api.py b/nova/volume/api.py index 52b3a9fed..7a78e244f 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -41,7 +41,8 @@ LOG = logging.getLogger('nova.volume') class API(base.Base): """API for interacting with the volume manager.""" - def create(self, context, size, snapshot_id, name, description): + def create(self, context, size, snapshot_id, name, description, + volume_type=None, metadata=None): if snapshot_id != None: snapshot = self.get_snapshot(context, snapshot_id) if snapshot['status'] != "available": @@ -66,7 +67,10 @@ class API(base.Base): 'status': "creating", 'attach_status': "detached", 'display_name': name, - 'display_description': description} + 'display_description': description, + 'volume_type_id': volume_type.get('id', None), + 'metadata' metadata, + } volume = self.db.volume_create(context, options) rpc.cast(context, diff --git a/nova/volume/volume_types.py b/nova/volume/volume_types.py new file mode 100644 index 000000000..c1fce1627 --- /dev/null +++ b/nova/volume/volume_types.py @@ -0,0 +1,101 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 Zadara Storage Inc. +# Copyright (c) 2011 OpenStack LLC. +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright (c) 2010 Citrix Systems, Inc. +# Copyright 2011 Ken Pepple +# +# 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. + +"""Built-in volume type properties.""" + +from nova import context +from nova import db +from nova import exception +from nova import flags +from nova import log as logging + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.volume_types') + + +def create(context, name, extra_specs={}): + """Creates volume types.""" + try: + db.volume_type_create( + context, + dict(name=name, + extra_specs=extra_specs)) + except exception.DBError, e: + LOG.exception(_('DB error: %s') % e) + raise exception.ApiError(_("Cannot create volume_type with " + "name %(name)s and specs %(extra_specs)s") + % locals()) + + +def destroy(context, name): + """Marks volume types as deleted.""" + if name is None: + raise exception.InvalidVolumeType(volume_type=name) + else: + try: + db.volume_type_destroy(context, name) + except exception.NotFound: + LOG.exception(_('Volume type %s not found for deletion') % name) + raise exception.ApiError(_("Unknown volume type: %s") % name) + + +def purge(context, name): + """Removes volume types from database.""" + if name is None: + raise exception.InvalidVolumeType(volume_type=name) + else: + try: + db.volume_type_purge(context, name) + except exception.NotFound: + LOG.exception(_('Volume type %s not found for purge') % name) + raise exception.ApiError(_("Unknown volume type: %s") % name) + + +def get_all_types(context, inactive=0): + """Get all non-deleted volume_types. + + Pass true as argument if you want deleted volume types returned also. + + """ + return db.volume_type_get_all(context, inactive) + + +def get_volume_type(context, id): + """Retrieves single volume type by id.""" + if id is None: + raise exception.ApiError(_("Invalid volume type: %s") % id) + + try: + return db.volume_type_get(context, id) + except exception.DBError: + raise exception.ApiError(_("Unknown volume type: %s") % id) + + +def get_volume_type_by_name(context, name): + """Retrieves single volume type by name.""" + if name is None: + raise exception.ApiError(_("Invalid volume type name: %s") % name) + + try: + return db.volume_type_get_by_name(context, name) + except exception.DBError: + raise exception.ApiError(_("Unknown volume type: %s") % name) -- cgit