summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorMORITA Kazutaka <morita.kazutaka@gmail.com>2011-04-19 21:01:25 +0900
committerMORITA Kazutaka <morita.kazutaka@gmail.com>2011-04-19 21:01:25 +0900
commit1018a60e3194e7e283cd89af28efd689623058a8 (patch)
treefbabf729d2d0c9a6f203c46f4319c402b4695bef /nova
parentaad857a18153792d96f300732c3bb5bb16aa02c3 (diff)
Add support for creating a new volume from a existing snapshot with EC2 API.
Diffstat (limited to 'nova')
-rw-r--r--nova/api/ec2/cloud.py12
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/016_add_snapshot_id_to_volumes.py48
-rw-r--r--nova/db/sqlalchemy/models.py2
-rw-r--r--nova/volume/api.py12
-rw-r--r--nova/volume/driver.py4
-rw-r--r--nova/volume/manager.py9
6 files changed, 81 insertions, 6 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 6daf299b9..5d4d2ad27 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -639,11 +639,19 @@ class CloudController(object):
v['display_description'] = volume['display_description']
return v
- def create_volume(self, context, size, **kwargs):
- LOG.audit(_("Create volume of %s GB"), size, context=context)
+ def create_volume(self, context, **kwargs):
+ size = kwargs.get('size');
+ if kwargs.get('snapshot_id') != None:
+ snapshot_id = ec2utils.ec2_id_to_id(kwargs['snapshot_id'])
+ LOG.audit(_("Create volume from snapshot %s"), snapshot_id, context=context)
+ else:
+ snapshot_id = None
+ LOG.audit(_("Create volume of %s GB"), size, context=context)
+
volume = self.volume_api.create(
context,
size=size,
+ snapshot_id=snapshot_id,
name=kwargs.get('display_name'),
description=kwargs.get('display_description'))
# TODO(vish): Instance should be None at db layer instead of
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/016_add_snapshot_id_to_volumes.py b/nova/db/sqlalchemy/migrate_repo/versions/016_add_snapshot_id_to_volumes.py
new file mode 100644
index 000000000..0a50123bf
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/016_add_snapshot_id_to_volumes.py
@@ -0,0 +1,48 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 MORITA Kazutaka.
+# 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 sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+# Table stub-definitions
+# Just for the ForeignKey and column creation to succeed, these are not the
+# actual definitions of instances or services.
+#
+volumes = Table('volumes', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# New Column
+#
+
+snapshot_id = Column('snapshot_id', Integer())
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+
+ # Add columns to existing tables
+ volumes.create_column(snapshot_id)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 9abe4d9ae..afc2ea4e4 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -287,6 +287,8 @@ class Volume(BASE, NovaBase):
user_id = Column(String(255))
project_id = Column(String(255))
+ snapshot_id = Column(String(255))
+
host = Column(String(255)) # , ForeignKey('hosts.id'))
size = Column(Integer)
availability_zone = Column(String(255)) # TODO(vish): foreign key?
diff --git a/nova/volume/api.py b/nova/volume/api.py
index f5285f31f..bd073964d 100644
--- a/nova/volume/api.py
+++ b/nova/volume/api.py
@@ -39,7 +39,13 @@ LOG = logging.getLogger('nova.volume')
class API(base.Base):
"""API for interacting with the volume manager."""
- def create(self, context, size, name, description):
+ def create(self, context, size, snapshot_id, name, description):
+ if snapshot_id != None:
+ snapshot = self.get_snapshot(context, snapshot_id)
+ if snapshot['status'] != "available":
+ raise exception.ApiError(_("Snapshot status must be available"))
+ size = snapshot['volume_size']
+
if quota.allowed_volumes(context, 1, size) < 1:
pid = context.project_id
LOG.warn(_("Quota exceeeded for %(pid)s, tried to create"
@@ -51,6 +57,7 @@ class API(base.Base):
'size': size,
'user_id': context.user_id,
'project_id': context.project_id,
+ 'snapshot_id': snapshot_id,
'availability_zone': FLAGS.storage_availability_zone,
'status': "creating",
'attach_status': "detached",
@@ -62,7 +69,8 @@ class API(base.Base):
FLAGS.scheduler_topic,
{"method": "create_volume",
"args": {"topic": FLAGS.volume_topic,
- "volume_id": volume['id']}})
+ "volume_id": volume['id'],
+ "snapshot_id": snapshot_id}})
return volume
def delete(self, context, volume_id):
diff --git a/nova/volume/driver.py b/nova/volume/driver.py
index ba0a7efef..02b0d50f4 100644
--- a/nova/volume/driver.py
+++ b/nova/volume/driver.py
@@ -101,6 +101,10 @@ class VolumeDriver(object):
volume['name'],
FLAGS.volume_group)
+ def create_volume_from_snapshot(self, volume, snapshot):
+ """Creates a volume from a snapshot."""
+ raise NotImplementedError()
+
def delete_volume(self, volume):
"""Deletes a logical volume."""
try:
diff --git a/nova/volume/manager.py b/nova/volume/manager.py
index 87fd3bf17..7d47fc191 100644
--- a/nova/volume/manager.py
+++ b/nova/volume/manager.py
@@ -90,7 +90,7 @@ class VolumeManager(manager.SchedulerDependentManager):
else:
LOG.info(_("volume %s: skipping export"), volume['name'])
- def create_volume(self, context, volume_id):
+ def create_volume(self, context, volume_id, snapshot_id):
"""Creates and exports the volume."""
context = context.elevated()
volume_ref = self.db.volume_get(context, volume_id)
@@ -108,7 +108,12 @@ class VolumeManager(manager.SchedulerDependentManager):
vol_size = volume_ref['size']
LOG.debug(_("volume %(vol_name)s: creating lv of"
" size %(vol_size)sG") % locals())
- model_update = self.driver.create_volume(volume_ref)
+ if snapshot_id == None:
+ model_update = self.driver.create_volume(volume_ref)
+ else:
+ snapshot_ref = self.db.snapshot_get(context, snapshot_id)
+ model_update = self.driver.create_volume_from_snapshot(volume_ref,
+ snapshot_ref)
if model_update:
self.db.volume_update(context, volume_ref['id'], model_update)