1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 United States Government as represented by the
4
# Administrator of the National Aeronautics and Space Administration.
7
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8
# not use this file except in compliance with the License. You may obtain
9
# a copy of the License at
11
# http://www.apache.org/licenses/LICENSE-2.0
13
# Unless required by applicable law or agreed to in writing, software
14
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
# License for the specific language governing permissions and limitations
20
Handles all requests relating to volumes + cinder.
24
from cinderclient import service_catalog
25
from cinderclient.v1 import client as cinder_client
27
from nova.db import base
28
from nova import exception
29
from nova import flags
30
from nova.openstack.common import log as logging
34
LOG = logging.getLogger(__name__)
37
def cinderclient(context):
39
# FIXME: the cinderclient ServiceCatalog object is mis-named.
40
# It actually contains the entire access blob.
42
'access': {'serviceCatalog': context.service_catalog}
44
sc = service_catalog.ServiceCatalog(compat_catalog)
45
url = sc.url_for(service_type='volume', service_name='cinder')
47
LOG.debug('cinderclient connection created using token "%s" and url "%s"' %
48
(context.auth_token, url))
50
c = cinder_client.Client(context.user_id,
52
project_id=context.project_id,
54
c.client.auth_token = context.auth_token
55
c.client.management_url = url
59
def _untranslate_volume_summary_view(context, vol):
60
"""Maps keys for volumes summary view."""
64
d['status'] = vol.status
66
d['availability_zone'] = vol.availability_zone
67
d['created_at'] = vol.created_at
69
# TODO(jdg): The calling code expects attach_time and
70
# mountpoint to be set. When the calling
71
# code is more defensive this can be
77
att = vol.attachments[0]
78
d['attach_status'] = 'attached'
79
d['instance_uuid'] = att['server_id']
80
d['mountpoint'] = att['device']
82
d['attach_status'] = 'detached'
84
d['display_name'] = vol.display_name
85
d['display_description'] = vol.display_description
87
# TODO(jdg): Information may be lost in this translation
88
d['volume_type_id'] = vol.volume_type
89
d['snapshot_id'] = vol.snapshot_id
91
d['vol_metadata'] = []
92
for k, v in vol.metadata:
96
d['vol_metadata'].append(item)
101
def _untranslate_snapshot_summary_view(context, snapshot):
102
"""Maps keys for snapshots summary view."""
105
d['id'] = snapshot.id
106
d['status'] = snapshot.status
107
d['progress'] = snapshot.progress
108
d['size'] = snapshot.size
109
d['created_at'] = snapshot.created_at
110
d['display_name'] = snapshot.display_name
111
d['display_description'] = snapshot.display_description
112
d['volume_id'] = snapshot.volume_id
113
d['project_id'] = snapshot.project_id
114
d['volume_size'] = snapshot.size
119
class API(base.Base):
120
"""API for interacting with the volume manager."""
122
def get(self, context, volume_id):
123
item = cinderclient(context).volumes.get(volume_id)
124
return _untranslate_volume_summary_view(context, item)
126
def get_all(self, context, search_opts={}):
127
items = cinderclient(context).volumes.list(detailed=True)
131
rval.append(_untranslate_volume_summary_view(context, item))
135
def check_attach(self, context, volume):
136
# TODO(vish): abstract status checking?
137
if volume['status'] != "available":
138
msg = _("status must be available")
139
raise exception.InvalidVolume(reason=msg)
140
if volume['attach_status'] == "attached":
141
msg = _("already attached")
142
raise exception.InvalidVolume(reason=msg)
144
def check_detach(self, context, volume):
145
# TODO(vish): abstract status checking?
146
if volume['status'] == "available":
147
msg = _("already detached")
148
raise exception.InvalidVolume(reason=msg)
150
def reserve_volume(self, context, volume):
151
cinderclient(context).volumes.reserve(volume['id'])
153
def unreserve_volume(self, context, volume):
154
cinderclient(context).volumes.reserve(volume['id'])
156
def attach(self, context, volume, instance_uuid, mountpoint):
157
cinderclient(context).volumes.attach(volume['id'],
161
def detach(self, context, volume):
162
cinderclient(context).volumes.detach(volume['id'])
164
def initialize_connection(self, context, volume, connector):
165
return cinderclient(context).\
166
volumes.initialize_connection(volume['id'], connector)
168
def terminate_connection(self, context, volume, connector):
169
return cinderclient(context).\
170
volumes.terminate_connection(volume['id'], connector)
172
def create(self, context, size, name, description, snapshot=None,
173
volume_type=None, metadata=None, availability_zone=None):
175
item = cinderclient(context).volumes.create(size, snapshot,
179
volume = _untranslate_volume_summary_view(context, item)
180
return _untranslate_volume_summary_view(context, item)
182
def delete(self, context, volume):
183
cinderclient(context).volumes.delete(volume['id'])
185
def update(self, context, volume, fields):
186
raise NotImplementedError()
188
def get_snapshot(self, context, snapshot_id):
189
item = cinderclient(context).volume_snapshots.get(snapshot_id)
190
return _untranslate_snapshot_summary_view(context, item)
192
def get_all_snapshots(self, context):
193
items = cinderclient(context).volume_snapshots.list(detailed=True)
197
rvals.append(_untranslate_snapshot_summary_view(context, item))
201
def create_snapshot(self, context, volume, name, description):
202
item = cinderclient(context).volume_snapshots.create(volume['id'],
206
return _untranslate_snapshot_summary_view(context, item)
208
def create_snapshot_force(self, context, volume, name, description):
209
item = cinderclient(context).volume_snapshots.create(volume['id'],
214
return _untranslate_snapshot_summary_view(context, item)
216
def delete_snapshot(self, context, snapshot):
217
cinderclient(context).volume_snapshots.delete(snapshot['id'])
219
def get_volume_metadata(self, context, volume):
220
raise NotImplementedError()
222
def delete_volume_metadata(self, context, volume, key):
223
raise NotImplementedError()
225
def update_volume_metadata(self, context, volume, metadata, delete=False):
226
raise NotImplementedError()
228
def get_volume_metadata_value(self, volume, key):
229
raise NotImplementedError()