¡@

Home 

OpenStack Study: hosts.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright (c) 2011 OpenStack Foundation

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

"""The hosts admin extension."""

from oslo.config import cfg

import webob.exc

from xml.parsers import expat

from cinder.api import extensions

from cinder.api.openstack import wsgi

from cinder.api import xmlutil

from cinder import db

from cinder import exception

from cinder.openstack.common import log as logging

from cinder.openstack.common import timeutils

from cinder import utils

from cinder.volume import api as volume_api

CONF = cfg.CONF

LOG = logging.getLogger(__name__)

authorize = extensions.extension_authorizer('volume', 'hosts')

**** CubicPower OpenStack Study ****

class HostIndexTemplate(xmlutil.TemplateBuilder):

**** CubicPower OpenStack Study ****

    def construct(self):

        root = xmlutil.TemplateElement('hosts')

        elem = xmlutil.SubTemplateElement(root, 'host', selector='hosts')

        elem.set('service-status')

        elem.set('service')

        elem.set('zone')

        elem.set('service-state')

        elem.set('host_name')

        elem.set('last-update')

        return xmlutil.MasterTemplate(root, 1)

**** CubicPower OpenStack Study ****

class HostUpdateTemplate(xmlutil.TemplateBuilder):

**** CubicPower OpenStack Study ****

    def construct(self):

        root = xmlutil.TemplateElement('host')

        root.set('host')

        root.set('status')

        return xmlutil.MasterTemplate(root, 1)

**** CubicPower OpenStack Study ****

class HostActionTemplate(xmlutil.TemplateBuilder):

**** CubicPower OpenStack Study ****

    def construct(self):

        root = xmlutil.TemplateElement('host')

        root.set('host')

        return xmlutil.MasterTemplate(root, 1)

**** CubicPower OpenStack Study ****

class HostShowTemplate(xmlutil.TemplateBuilder):

**** CubicPower OpenStack Study ****

    def construct(self):

        root = xmlutil.TemplateElement('host')

        elem = xmlutil.make_flat_dict('resource', selector='host',

                                      subselector='resource')

        root.append(elem)

        return xmlutil.MasterTemplate(root, 1)

**** CubicPower OpenStack Study ****

class HostDeserializer(wsgi.XMLDeserializer):

**** CubicPower OpenStack Study ****

    def default(self, string):

        try:

            node = utils.safe_minidom_parse_string(string)

        except expat.ExpatError:

            msg = _("cannot understand XML")

            raise exception.MalformedRequestBody(reason=msg)

        updates = {}

        for child in node.childNodes[0].childNodes:

            updates[child.tagName] = self.extract_text(child)

        return dict(body=updates)

def _list_hosts(req, service=None):

    """Returns a summary list of hosts."""

    curr_time = timeutils.utcnow()

    context = req.environ['cinder.context']

    services = db.service_get_all(context, False)

    zone = ''

    if 'zone' in req.GET:

        zone = req.GET['zone']

    if zone:

        services = [s for s in services if s['availability_zone'] == zone]

    hosts = []

    for host in services:

        delta = curr_time - (host['updated_at'] or host['created_at'])

        alive = abs(utils.total_seconds(delta)) <= CONF.service_down_time

        status = (alive and "available") or "unavailable"

        active = 'enabled'

        if host['disabled']:

            active = 'disabled'

        LOG.debug('status, active and update: %s, %s, %s' %

                  (status, active, host['updated_at']))

        hosts.append({'host_name': host['host'],

                      'service': host['topic'],

                      'zone': host['availability_zone'],

                      'service-status': status,

                      'service-state': active,

                      'last-update': host['updated_at']})

    if service:

        hosts = [host for host in hosts

                 if host["service"] == service]

    return hosts

def check_host(fn):

    """Makes sure that the host exists."""

**** CubicPower OpenStack Study ****

def _list_hosts(req, service=None):

    """Returns a summary list of hosts."""

    curr_time = timeutils.utcnow()

    context = req.environ['cinder.context']

    services = db.service_get_all(context, False)

    zone = ''

    if 'zone' in req.GET:

        zone = req.GET['zone']

    if zone:

        services = [s for s in services if s['availability_zone'] == zone]

    hosts = []

    for host in services:

        delta = curr_time - (host['updated_at'] or host['created_at'])

        alive = abs(utils.total_seconds(delta)) <= CONF.service_down_time

        status = (alive and "available") or "unavailable"

        active = 'enabled'

        if host['disabled']:

            active = 'disabled'

        LOG.debug('status, active and update: %s, %s, %s' %

                  (status, active, host['updated_at']))

        hosts.append({'host_name': host['host'],

                      'service': host['topic'],

                      'zone': host['availability_zone'],

                      'service-status': status,

                      'service-state': active,

                      'last-update': host['updated_at']})

    if service:

        hosts = [host for host in hosts

                 if host["service"] == service]

    return hosts

**** CubicPower OpenStack Study ****

def check_host(fn):

    """Makes sure that the host exists."""

**** CubicPower OpenStack Study ****

    def wrapped(self, req, id, service=None, *args, **kwargs):

        listed_hosts = _list_hosts(req, service)

        hosts = [h["host_name"] for h in listed_hosts]

        if id in hosts:

            return fn(self, req, id, *args, **kwargs)

        else:

            message = _("Host '%s' could not be found.") % id

            raise webob.exc.HTTPNotFound(explanation=message)

    return wrapped

**** CubicPower OpenStack Study ****

class HostController(wsgi.Controller):

"""The Hosts API controller for the OpenStack API."""

**** CubicPower OpenStack Study ****

    def __init__(self):

        self.api = volume_api.HostAPI()

        super(HostController, self).__init__()

    @wsgi.serializers(xml=HostIndexTemplate)

**** CubicPower OpenStack Study ****

    def index(self, req):

        authorize(req.environ['cinder.context'])

        return {'hosts': _list_hosts(req)}

    @wsgi.serializers(xml=HostUpdateTemplate)

    @wsgi.deserializers(xml=HostDeserializer)

    @check_host

**** CubicPower OpenStack Study ****

    def update(self, req, id, body):

        authorize(req.environ['cinder.context'])

        update_values = {}

        for raw_key, raw_val in body.iteritems():

            key = raw_key.lower().strip()

            val = raw_val.lower().strip()

            if key == "status":

                if val in ("enable", "disable"):

                    update_values['status'] = val.startswith("enable")

                else:

                    explanation = _("Invalid status: '%s'") % raw_val

                    raise webob.exc.HTTPBadRequest(explanation=explanation)

            else:

                explanation = _("Invalid update setting: '%s'") % raw_key

                raise webob.exc.HTTPBadRequest(explanation=explanation)

        update_setters = {'status': self._set_enabled_status}

        result = {}

        for key, value in update_values.iteritems():

            result.update(update_setters[key](req, id, value))

        return result

**** CubicPower OpenStack Study ****

    def _set_enabled_status(self, req, host, enabled):

        """Sets the specified host's ability to accept new volumes."""

        context = req.environ['cinder.context']

        state = "enabled" if enabled else "disabled"

        LOG.audit(_("Setting host %(host)s to %(state)s."),

                  {'host': host, 'state': state})

        result = self.api.set_host_enabled(context,

                                           host=host,

                                           enabled=enabled)

        if result not in ("enabled", "disabled"):

            # An error message was returned

            raise webob.exc.HTTPBadRequest(explanation=result)

        return {"host": host, "status": result}

    @wsgi.serializers(xml=HostShowTemplate)

**** CubicPower OpenStack Study ****

    def show(self, req, id):

        """Shows the volume usage info given by hosts.

        :param context: security context

        :param host: hostname

        :returns: expected to use HostShowTemplate.

            ex.::

                {'host': {'resource':D},..}

                D: {'host': 'hostname','project': 'admin',

                    'volume_count': 1, 'total_volume_gb': 2048}

        """

        host = id

        context = req.environ['cinder.context']

        if not context.is_admin:

            msg = _("Describe-resource is admin only functionality")

            raise webob.exc.HTTPForbidden(explanation=msg)

        try:

            host_ref = db.service_get_by_host_and_topic(context,

                                                        host,

                                                        CONF.volume_topic)

        except exception.ServiceNotFound:

            raise webob.exc.HTTPNotFound(explanation=_("Host not found"))

        # Getting total available/used resource

        # TODO(jdg): Add summary info for Snapshots

        volume_refs = db.volume_get_all_by_host(context, host_ref['host'])

        (count, sum) = db.volume_data_get_for_host(context,

                                                   host_ref['host'])

        snap_count_total = 0

        snap_sum_total = 0

        resources = [{'resource': {'host': host, 'project': '(total)',

                      'volume_count': str(count),

                      'total_volume_gb': str(sum),

                      'snapshot_count': str(snap_count_total),

                      'total_snapshot_gb': str(snap_sum_total)}}]

        project_ids = [v['project_id'] for v in volume_refs]

        project_ids = list(set(project_ids))

        for project_id in project_ids:

            (count, sum) = db.volume_data_get_for_project(context, project_id)

            (snap_count, snap_sum) = db.snapshot_data_get_for_project(

                context,

                project_id)

            resources.append(

                {'resource':

                    {'host': host,

                     'project': project_id,

                     'volume_count': str(count),

                     'total_volume_gb': str(sum),

                     'snapshot_count': str(snap_count),

                     'total_snapshot_gb': str(snap_sum)}})

            snap_count_total += int(snap_count)

            snap_sum_total += int(snap_sum)

        resources[0]['resource']['snapshot_count'] = str(snap_count_total)

        resources[0]['resource']['total_snapshot_gb'] = str(snap_sum_total)

        return {"host": resources}

**** CubicPower OpenStack Study ****

class Hosts(extensions.ExtensionDescriptor):

"""Admin-only host administration."""

name = "Hosts"

alias = "os-hosts"

namespace = "http://docs.openstack.org/volume/ext/hosts/api/v1.1"

updated = "2011-06-29T00:00:00+00:00"

**** CubicPower OpenStack Study ****

    def get_resources(self):

        resources = [extensions.ResourceExtension('os-hosts',

                                                  HostController(),

                                                  collection_actions={

                                                      'update': 'PUT'},

                                                  member_actions={

                                                      'startup': 'GET',

                                                      'shutdown': 'GET',

                                                      'reboot': 'GET'})]

        return resources