From 3b9f42bf5337f761c5d43b2a2cd72d7f701813c8 Mon Sep 17 00:00:00 2001 From: Jerry Cai Date: Tue, 23 Sep 2014 13:32:55 +0800 Subject: [PATCH] Add Host Maintenance Mode Get and evacuation support To support GET the "host maintenance mode" from PowerVC by PowerVC Driver, and evacuation all host out of the maintenance entered host by PowerVC Driver. The design finally goes to Implement a new nova rest-API for Get/Set maintenance status, and evacuate vm during maintenance. Change-Id: I9fba6b47e143ae8ea2165573302448fcdc61406f Closes-Bug: 1372730 --- .../powervc/common/client/extensions/nova.py | 64 +++++++++++++- .../nova/extension/host_maintenance_mode.py | 83 +++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 nova-powervc/powervc/nova/extension/host_maintenance_mode.py diff --git a/common-powervc/powervc/common/client/extensions/nova.py b/common-powervc/powervc/common/client/extensions/nova.py index 58e7f4a..5ae978c 100644 --- a/common-powervc/powervc/common/client/extensions/nova.py +++ b/common-powervc/powervc/common/client/extensions/nova.py @@ -3,6 +3,7 @@ import six import urllib from novaclient import base as client_base +from novaclient import exceptions from novaclient.v1_1 import servers from novaclient.v1_1 import hypervisors from novaclient.v1_1 import images @@ -10,6 +11,7 @@ from novaclient.v1_1 import flavors from novaclient.v1_1 import volumes from novaclient.v1_1.volume_types import VolumeType from powervc.common.client.extensions import base +from powervc.common.gettextutils import _ from powervc.common import utils import logging @@ -21,7 +23,7 @@ class Client(base.ClientExtension): def __init__(self, client): super(Client, self).__init__(client) self.manager = PVCServerManager(client) - self.hypervisors = hypervisors.HypervisorManager(client) + self.hypervisors = PVCHypervisorManager(client) self.images = images.ImageManager(client) self.flavors = flavors.FlavorManager(client) self.storage_connectivity_groups = \ @@ -31,6 +33,66 @@ class Client(base.ClientExtension): # any extensions to std nova client go below +class PVCHypervisorManager(hypervisors.HypervisorManager): + """ + This HypervisorManager class is specific for extending PowerVC driver + feature to get/set the hypervisor status and maintenance mode. + """ + + def get_host_maintenance_mode(self, hostname): + """Get host maintenance mode by host name from PowerVC driver + """ + # If cannot find hypervisor by hostname, will raise + # itemNotFoundException from novaclient, just raise + # to upper layer to handle. + hypervisors = self.search(hostname) + + if not hypervisors[0] or not self.get(hypervisors[0]): + raise exceptions.NotFound(_("No hypervisor matching '%s' could be" + " found.") + % hostname) + + hypervisor = self.get(hypervisors[0]) + + # Either "ok" (maintenance off), "entering", "on" or "error" + # compatible with previous powervc version, if no such property + # set as "ok" + maintenance_status = getattr(hypervisor, "maintenance_status", "ok") + # Either the empty string (i.e., not in maintenance), + # "none": dont migrate anything + # "active-only": migrate active-only vm + # "all": migrate all vm + maintenance_migration_action = \ + getattr(hypervisor, "maintenance_migration_action", "none") + + return {"maintenance_status": maintenance_status, + "maintenance_migration_action": maintenance_migration_action} + + def update_host_maintenance_mode(self, hostname, enabled, migrate): + """Update host maintenance mode status. + :hostname: The hostname of the hypervisor + :enabled: should be "enable" or "disable" + :migrate: should be + "none", do not migrate any vm + "active-only", migrate only active vm + "all", migrate all vm + """ + # Refer to PowerVC HLD host maintenance mode chapter + url = "/ego/prs/hypervisor_maintenance/%s" % hostname + body = {"status": enabled, + "migrate": migrate} + + # send set maintenance mode request by put http method + _resp, resp_body = self.api.client.put(url, body=body) + + # check response content + if "hypervisor_maintenance" not in resp_body: + raise exceptions.NotFound(_("response body doesn't contain " + "maintenance status info for %s.") + % hostname) + return resp_body + + class PVCServerManager(servers.ServerManager): """ This ServerManager class is specific for PowerVC booting a VM. diff --git a/nova-powervc/powervc/nova/extension/host_maintenance_mode.py b/nova-powervc/powervc/nova/extension/host_maintenance_mode.py new file mode 100644 index 0000000..7f4ed1b --- /dev/null +++ b/nova-powervc/powervc/nova/extension/host_maintenance_mode.py @@ -0,0 +1,83 @@ +# Copyright 2014 IBM Corp. + +from webob import exc +from nova.api.openstack import extensions +from nova.api.openstack import wsgi +from nova import compute +from nova.openstack.common.gettextutils import _ +from powervc.common import constants as common_constants +from powervc.common import config + +config.parse_power_config([], 'nova') + +authorize = extensions.extension_authorizer('compute', 'host-maintenance-mode') + + +class Controller(wsgi.Controller): + """Controller class to show host maintenance mode and set host maintenance + mode with evacuation operation + """ + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + self.compute_api = compute.API() + self.host_api = compute.HostAPI() + from powervc.common.client import factory + self.pvcclient = factory.POWERVC.new_client( + str(common_constants.SERVICE_TYPES.compute)) + + @wsgi.extends + def show(self, req, id): + """Describe host-maintenance-mode by hostname.""" + context = req.environ["nova.context"] + authorize(context) + host_name = id + # Get maintenance mode from powervc client + maintenance_status = self.pvcclient.hypervisors.\ + get_host_maintenance_mode(host_name) + + return maintenance_status + + @wsgi.extends + def update(self, req, id, body): + """Update host-maintenance-mode by hostname.""" + context = req.environ["nova.context"] + authorize(context) + + host_name = id + maintenance_status_candidate = ["enable", "disable"] + maintenance_status = body.get("status") + if not maintenance_status or maintenance_status.lower() not in \ + maintenance_status_candidate: + raise exc.HTTPBadRequest(_("Malformed request body, status" + "wrong in request body, should be" + "'enable' or 'disable'")) + + migrate_candidate = ["none", "active-only", "all"] + migrate = body.get("migrate", "none") + if migrate.lower() not in migrate_candidate: + raise exc.HTTPBadRequest(_("Malformed request body, migrate wrong " + "in request body, should be 'none'," + "active-only, all or empty")) + # Set maintenance mode from powervc client + maintenance_update_status = self.pvcclient.hypervisors.\ + update_host_maintenance_mode(host_name, maintenance_status, + migrate) + return maintenance_update_status + + +class Host_maintenance_mode(extensions.ExtensionDescriptor): + """Get and enable/disable Host maintenance mode, and evacuate all + servers for the maintenance mode entered host. + """ + + name = "Host-maintenance-mode" + alias = "os-host-maintenance-mode" + namespace = "http://docs.openstack.org/compute/ext/host_maintenance_mode/"\ + "api/v2" + updated = "2014-09-15T00:00:00Z" + + def get_resources(self): + controller = Controller() + res = extensions.ResourceExtension(Host_maintenance_mode.alias, + controller) + return [res]