gce-api/gceapi/api/instance_disk_api.py
Andrey Pavlov 5d3295fa89 update instance creation and disk attaching to new protocol
It must be updated because of new way of instance creation with disk.
Previously it takes disk but now it takes parameters for disk creation.

Partial-Bug: #1381173
Change-Id: Ief3a8c204bf471b9253241816fb2dd6a5b705e84
2014-10-17 18:26:31 +04:00

204 lines
7.7 KiB
Python

# Copyright 2013 Cloudscaling Group, Inc
#
# 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.
import string
from gceapi.api import base_api
from gceapi.api import clients
from gceapi.api import disk_api
from gceapi.api import operation_api
from gceapi.api import operation_util
from gceapi.api import utils
from gceapi import exception
from gceapi.openstack.common.gettextutils import _
from gceapi.openstack.common import log as logging
LOG = logging.getLogger(__name__)
GB = 1024 ** 3
class API(base_api.API):
"""GCE Attached disk API."""
KIND = "attached_disk"
PERSISTENT_ATTRIBUTES = ["id", "instance_name", "volume_id", "name",
"auto_delete"]
def __init__(self, *args, **kwargs):
super(API, self).__init__(*args, **kwargs)
operation_api.API().register_get_progress_method(
"attached_disk-delete",
self._get_delete_item_progress)
def _get_type(self):
return self.KIND
def _get_persistent_attributes(self):
return self.PERSISTENT_ATTRIBUTES
def get_item(self, context, instance_name, name):
items = self._get_db_items(context)
items = [i for i in items
if i["instance_name"] == instance_name and i["name"] == name]
if len(items) != 1:
raise exception.NotFound
return items[0]
def get_items(self, context, instance_name):
items = self._get_db_items(context)
for item in items:
item.setdefault("auto_delete", False)
return [i for i in items if i["instance_name"] == instance_name]
def add_item(self, context, instance_name, params, source, name,
auto_delete, scope):
# NOTE(apavlov): name is a 'device_name' here
if not name:
msg = _("There is no name to assign.")
raise exception.InvalidRequest(msg)
nova_client = clients.nova(context)
instances = nova_client.servers.list(
search_opts={"name": instance_name})
if not instances or len(instances) != 1:
raise exception.NotFound
instance = instances[0]
devices = list()
volumes_client = nova_client.volumes
for server_volume in volumes_client.get_server_volumes(instance.id):
devices.append(server_volume.device)
device_name = None
for letter in string.ascii_lowercase[1:]:
device_name = "vd" + letter
for device in devices:
if device_name in device:
break
else:
break
else:
raise exception.OverQuota
context.operation_data["device_name"] = device_name
if source:
volume_name = utils._extract_name_from_url(source)
if not volume_name:
msg = _("There is no volume to assign.")
raise exception.NotFound(msg)
volume = disk_api.API().get_item(context, volume_name, scope)
context.operation_data["volume_id"] = volume["id"]
elif params:
params.setdefault("diskName", instance_name)
context.operation_data["params"] = params
context.operation_data["scope"] = scope
else:
msg = _('Disk config must contain either "source" or '
'"initializeParams".')
raise exception.InvalidRequest(msg)
context.operation_data["instance_id"] = instance.id
context.operation_data["register_args"] = [instance_name, name,
auto_delete]
operation_util.start_operation(
context, base_api.API._get_complex_operation_progress)
operation_util.continue_operation(
context, lambda: self._attach_volume(context), timeout=0)
def _attach_volume(self, context):
params = context.operation_data.get("params")
if params:
scope = context.operation_data["scope"]
context.operation_data.pop("params")
body = {"sizeGb": params.get("diskSizeGb"),
"sourceImage": params["sourceImage"]}
volume = disk_api.API().add_item(context, params.get("diskName"),
body, scope=scope)
context.operation_data["disk"] = volume
return None
disk = context.operation_data.get("disk")
if disk:
volume_id = disk["id"]
item_progress = disk_api.API()._get_add_item_progress(context,
volume_id)
if not operation_util.is_final_progress(item_progress):
return None
context.operation_data.pop("disk")
context.operation_data["volume_id"] = volume_id
instance_id = context.operation_data["instance_id"]
device_name = context.operation_data["device_name"]
volume_id = context.operation_data["volume_id"]
volumes_client = clients.nova(context).volumes
volumes_client.create_server_volume(
instance_id, volume_id, "/dev/" + device_name)
args = context.operation_data["register_args"]
self.register_item(context, args[0], volume_id, args[1], args[2])
return operation_util.get_final_progress()
def register_item(self, context, instance_name, volume_id, name,
auto_delete):
if not name:
msg = _("There is no name to assign.")
raise exception.InvalidRequest(msg)
if not volume_id:
msg = _("There is no volume_id to assign.")
raise exception.InvalidRequest(msg)
new_item = {
"id": instance_name + "-" + volume_id,
"instance_name": instance_name,
"volume_id": volume_id,
"name": name,
"auto_delete": auto_delete
}
new_item = self._add_db_item(context, new_item)
return new_item
def delete_item(self, context, instance_name, name):
item = self.get_item(context, instance_name, name)
volume_id = item["volume_id"]
nova_client = clients.nova(context)
instances = nova_client.servers.list(
search_opts={"name": instance_name})
if not instances or len(instances) != 1:
raise exception.NotFound
instance = instances[0]
operation_util.start_operation(context,
self._get_delete_item_progress,
item["id"])
nova_client.volumes.delete_server_volume(instance.id, volume_id)
self._delete_db_item(context, item)
def set_disk_auto_delete(self, context, instance_name, name, auto_delete):
item = self.get_item(context, instance_name, name)
item["auto_delete"] = auto_delete
self._update_db_item(context, item)
def unregister_item(self, context, instance_name, name):
item = self.get_item(context, instance_name, name)
self._delete_db_item(context, item)
def _get_add_item_progress(self, context, dummy_id):
return operation_util.get_final_progress()
def _get_delete_item_progress(self, context, dummy_id):
return operation_util.get_final_progress()