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
This commit is contained in:
Jerry Cai 2014-09-23 13:32:55 +08:00
parent 66ac1ea035
commit 3b9f42bf53
2 changed files with 146 additions and 1 deletions

View File

@ -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.

View File

@ -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]