Added volume_attachments
This commit is contained in:
parent
7b9888df2d
commit
1894937e1e
@ -14,3 +14,5 @@ CA/newcerts/*.pem
|
||||
CA/private/cakey.pem
|
||||
nova/vcsversion.py
|
||||
*.DS_Store
|
||||
.project
|
||||
.pydevproject
|
||||
|
@ -38,6 +38,7 @@ from nova.api.openstack import servers
|
||||
from nova.api.openstack import shared_ip_groups
|
||||
from nova.api.openstack import users
|
||||
from nova.api.openstack import volumes
|
||||
from nova.api.openstack import volume_attachments
|
||||
from nova.api.openstack import zones
|
||||
|
||||
|
||||
@ -109,6 +110,11 @@ class APIRouter(wsgi.Router):
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name='servers'))
|
||||
|
||||
mapper.resource("volume_attachment", "volume_attachment",
|
||||
controller=volume_attachments.Controller(),
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name='servers'))
|
||||
|
||||
mapper.resource("console", "consoles",
|
||||
controller=consoles.Controller(),
|
||||
parent_resource=dict(member_name='server',
|
||||
|
154
nova/api/openstack/volume_attachments.py
Normal file
154
nova/api/openstack/volume_attachments.py
Normal file
@ -0,0 +1,154 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 Justin Santa Barbara
|
||||
# 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 webob import exc
|
||||
|
||||
from nova import compute
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import volume
|
||||
from nova import wsgi
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import faults
|
||||
|
||||
|
||||
LOG = logging.getLogger("nova.api.volumes")
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def _translate_detail_view(context, volume):
|
||||
""" Maps keys for details view"""
|
||||
|
||||
v = _translate_summary_view(context, volume)
|
||||
|
||||
# No additional data / lookups at the moment
|
||||
|
||||
return v
|
||||
|
||||
|
||||
def _translate_summary_view(context, volume):
|
||||
""" Maps keys for summary view"""
|
||||
v = {}
|
||||
|
||||
volume_id = volume['id']
|
||||
|
||||
# NOTE(justinsb): We use the volume id as the id of the attachment object
|
||||
v['id'] = volume_id
|
||||
|
||||
v['volumeId'] = volume_id
|
||||
v['serverId'] = volume['instance_id']
|
||||
v['device'] = volume['mountpoint']
|
||||
|
||||
return v
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
""" The volume attachment API controller for the Openstack API
|
||||
|
||||
A child resource of the server. Note that we use the volume id
|
||||
as the ID of the attachment (though this is not guaranteed externally)"""
|
||||
|
||||
_serialization_metadata = {
|
||||
'application/xml': {
|
||||
'attributes': {
|
||||
'volumeAttachment': [ 'id',
|
||||
'serverId',
|
||||
'volumeId',
|
||||
'device' ]}}}
|
||||
|
||||
def __init__(self):
|
||||
self.compute_api = compute.API()
|
||||
self.volume_api = volume.API()
|
||||
super(Controller, self).__init__()
|
||||
|
||||
def index(self, req, server_id):
|
||||
""" Returns the list of volume attachments for a given instance """
|
||||
return self._items(req, server_id,
|
||||
entity_maker=_translate_summary_view)
|
||||
|
||||
def show(self, req, id):
|
||||
"""Return data about the given volume"""
|
||||
context = req.environ['nova.context']
|
||||
|
||||
try:
|
||||
vol = self.volume_api.get(context, id)
|
||||
except exception.NotFound:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
return {'volume': _translate_detail_view(context, vol)}
|
||||
|
||||
def create(self, req, server_id):
|
||||
""" Attach a volume to an instance """
|
||||
context = req.environ['nova.context']
|
||||
|
||||
env = self._deserialize(req.body, req)
|
||||
if not env:
|
||||
return faults.Fault(exc.HTTPUnprocessableEntity())
|
||||
|
||||
instance_id = server_id
|
||||
volume_id = env['volumeAttachment']['volumeId']
|
||||
device = env['volumeAttachment']['device']
|
||||
|
||||
msg = _("Attach volume %(volume_id)s to instance %(server_id)s"
|
||||
" at %(device)s") % locals()
|
||||
LOG.audit(msg, context=context)
|
||||
|
||||
self.compute_api.attach_volume(context,
|
||||
instance_id=instance_id,
|
||||
volume_id=volume_id,
|
||||
device=device)
|
||||
vol = self.volume_api.get(context, volume_id)
|
||||
|
||||
retval = _translate_detail_view(context, vol)
|
||||
|
||||
return {'volumeAttachment': retval}
|
||||
|
||||
def update(self, _req, _server_id, _id):
|
||||
""" Update a volume attachment. We don't currently support this."""
|
||||
return faults.Fault(exc.HTTPBadRequest())
|
||||
|
||||
def delete(self, req, server_id, id):
|
||||
""" Detach a volume from an instance """
|
||||
context = req.environ['nova.context']
|
||||
|
||||
volume_id = id
|
||||
LOG.audit(_("Detach volume %s"), volume_id, context=context)
|
||||
|
||||
vol = self.volume_api.get(context, volume_id)
|
||||
if vol['instance_id'] != server_id:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
self.compute_api.detach_volume(context,
|
||||
volume_id=volume_id)
|
||||
|
||||
return exc.HTTPAccepted()
|
||||
|
||||
def _items(self, req, server_id, entity_maker):
|
||||
"""Returns a list of attachments, transformed through entity_maker"""
|
||||
context = req.environ['nova.context']
|
||||
|
||||
try:
|
||||
instance = self.compute_api.get(context, server_id)
|
||||
except exception.NotFound:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
volumes = instance['volumes']
|
||||
limited_list = common.limited(volumes, req)
|
||||
res = [entity_maker(context, vol) for vol in limited_list]
|
||||
return {'volumeAttachments': res}
|
@ -29,52 +29,52 @@ LOG = logging.getLogger("nova.api.volumes")
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def _translate_detail_view(context, inst):
|
||||
def _translate_detail_view(context, vol):
|
||||
""" Maps keys for details view"""
|
||||
|
||||
inst_dict = _translate_summary_view(context, inst)
|
||||
d = _translate_summary_view(context, vol)
|
||||
|
||||
# No additional data / lookups at the moment
|
||||
|
||||
return inst_dict
|
||||
return d
|
||||
|
||||
|
||||
def _translate_summary_view(context, volume):
|
||||
def _translate_summary_view(_context, vol):
|
||||
""" Maps keys for summary view"""
|
||||
v = {}
|
||||
d = {}
|
||||
|
||||
instance_id = None
|
||||
# instance_data = None
|
||||
attached_to = volume.get('instance')
|
||||
attached_to = vol.get('instance')
|
||||
if attached_to:
|
||||
instance_id = attached_to['id']
|
||||
# instance_data = '%s[%s]' % (instance_ec2_id,
|
||||
# attached_to['host'])
|
||||
v['id'] = volume['id']
|
||||
v['status'] = volume['status']
|
||||
v['size'] = volume['size']
|
||||
v['availabilityZone'] = volume['availability_zone']
|
||||
v['createdAt'] = volume['created_at']
|
||||
d['id'] = vol['id']
|
||||
d['status'] = vol['status']
|
||||
d['size'] = vol['size']
|
||||
d['availabilityZone'] = vol['availability_zone']
|
||||
d['createdAt'] = vol['created_at']
|
||||
# if context.is_admin:
|
||||
# v['status'] = '%s (%s, %s, %s, %s)' % (
|
||||
# volume['status'],
|
||||
# volume['user_id'],
|
||||
# volume['host'],
|
||||
# vol['status'],
|
||||
# vol['user_id'],
|
||||
# vol['host'],
|
||||
# instance_data,
|
||||
# volume['mountpoint'])
|
||||
if volume['attach_status'] == 'attached':
|
||||
v['attachments'] = [{'attachTime': volume['attach_time'],
|
||||
# vol['mountpoint'])
|
||||
if vol['attach_status'] == 'attached':
|
||||
d['attachments'] = [{'attachTime': vol['attach_time'],
|
||||
'deleteOnTermination': False,
|
||||
'mountpoint': volume['mountpoint'],
|
||||
'mountpoint': vol['mountpoint'],
|
||||
'instanceId': instance_id,
|
||||
'status': 'attached',
|
||||
'volumeId': volume['id']}]
|
||||
'volumeId': vol['id']}]
|
||||
else:
|
||||
v['attachments'] = [{}]
|
||||
d['attachments'] = [{}]
|
||||
|
||||
v['displayName'] = volume['display_name']
|
||||
v['displayDescription'] = volume['display_description']
|
||||
return v
|
||||
d['displayName'] = vol['display_name']
|
||||
d['displayDescription'] = vol['display_description']
|
||||
return d
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
@ -102,11 +102,11 @@ class Controller(wsgi.Controller):
|
||||
context = req.environ['nova.context']
|
||||
|
||||
try:
|
||||
volume = self.volume_api.get(context, id)
|
||||
vol = self.volume_api.get(context, id)
|
||||
except exception.NotFound:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
return {'volume': _translate_detail_view(context, volume)}
|
||||
return {'volume': _translate_detail_view(context, vol)}
|
||||
|
||||
def delete(self, req, id):
|
||||
""" Delete a volume """
|
||||
@ -134,7 +134,7 @@ class Controller(wsgi.Controller):
|
||||
|
||||
volumes = self.volume_api.get_all(context)
|
||||
limited_list = common.limited(volumes, req)
|
||||
res = [entity_maker(context, inst) for inst in limited_list]
|
||||
res = [entity_maker(context, vol) for vol in limited_list]
|
||||
return {'volumes': res}
|
||||
|
||||
def create(self, req):
|
||||
@ -148,13 +148,13 @@ class Controller(wsgi.Controller):
|
||||
vol = env['volume']
|
||||
size = vol['size']
|
||||
LOG.audit(_("Create volume of %s GB"), size, context=context)
|
||||
volume = self.volume_api.create(context, size,
|
||||
vol.get('display_name'),
|
||||
vol.get('display_description'))
|
||||
new_volume = self.volume_api.create(context, size,
|
||||
vol.get('display_name'),
|
||||
vol.get('display_description'))
|
||||
|
||||
# Work around problem that instance is lazy-loaded...
|
||||
volume['instance'] = None
|
||||
|
||||
retval = _translate_detail_view(context, volume)
|
||||
retval = _translate_detail_view(context, new_volume)
|
||||
|
||||
return {'volume': retval}
|
||||
|
Loading…
Reference in New Issue
Block a user