OpenStack Mitaka NOVA API 接口开发

Mitaka NOVA API 接口开发

背景: OpenStack官方默认Resize接口支持local storage 不是很好,问题很多,因此重新定制Resize接口,实现云主机套餐变更

配置 Resize 路由

vim /usr/lib/python2.7/site-packages/nova-13.1.0-py2.7.egg-info/entry_points.txt 

[nova.api.v21.extensions]

instance_resize = nova.api.openstack.compute.instance_resize:InstanceResize
access_ips = nova.api.openstack.compute.access_ips:AccessIPs
admin_actions = nova.api.openstack.compute.admin_actions:AdminActions
admin_password = nova.api.openstack.compute.admin_password:AdminPassword
agents = nova.api.openstack.compute.agents:Agents
aggregates = nova.api.openstack.compute.aggregates:Aggregates
assisted_volume_snapshots = nova.api.openstack.compute.assisted_volume_snapshots:AssistedVolumeSnapshots
attach_interfaces = nova.api.openstack.compute.attach_interfaces:AttachInterfaces
availability_zone = nova.api.openstack.compute.availability_zone:AvailabilityZone
baremetal_nodes = nova.api.openstack.compute.baremetal_nodes:BareMetalNodes
block_device_mapping = nova.api.openstack.compute.block_device_mapping:BlockDeviceMapping
cells = nova.api.openstack.compute.cells:Cells
certificates = nova.api.openstack.compute.certificates:Certificates
cloudpipe = nova.api.openstack.compute.cloudpipe:Cloudpipe
config_drive = nova.api.openstack.compute.config_drive:ConfigDrive
console_auth_tokens = nova.api.openstack.compute.console_auth_tokens:ConsoleAuthTokens
console_output = nova.api.openstack.compute.console_output:ConsoleOutput

定制API 接口

    * Mitaka 接口开发目录与Havana 版本发生变化,所有的接口放在nova/api/openstack/compute/目录中,在此目录中创建Resize 接口 
    ****************************************************************
    # Copyright 2013 Rackspace Hosting
# 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.

from webob import exc

from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova import compute
#from nova.i18n import _
from oslo_log import log as logging
from nova.extend import api as extend_api
from nova import utils

LOG = logging.getLogger(__name__)
ALIAS = "os-instance-resize"
authorize = extensions.os_compute_authorizer(ALIAS)

class InstanceResizeController(wsgi.Controller):
    def __init__(self):
        #super(InstanceResizeController, self).__init__()
        self.compute_api = compute.API(skip_policy_check=True)

    @wsgi.Controller.api_version("2.1", "2.20")
    def _get_instance(self, req, context, server_id):
        return common.get_instance(self.compute_api, context, server_id)

    @extensions.expected_errors(404)
    def index(self,req):
        """Returns the list of actions recorded for a given instance."""
        context = req.environ["nova.context"]
        LOG.info("index.dir %s" %context)
        LOG.info("index.InstanceResizeController is ok")

        return "True"

    @extensions.expected_errors(404)
    def create(self,req,body):
        try:
            """Return data about the given instance action."""
            context = req.environ["nova.context"]
            flavor = body['flavor']
            instance_uuid  = body['instance_uuid']
            resize_api = extend_api.LocalAPI()
            result = resize_api.instance_resize(context,req,flavor,instance_uuid)

            #Reboot to instances
            body = {'reboot': {'type': 'SOFT'}}
            reboot_type = body['reboot']['type'].upper()
            instance = self._get_instance(req, context, instance_uuid)

            try:
                self.compute_api.reboot(context, instance, reboot_type)
            except exception.InstanceIsLocked as e:
                raise exc.HTTPConflict(explanation=e.format_message())
            except exception.InstanceInvalidState as state_error:
                common.raise_http_conflict_for_instance_invalid_state(state_error,
                        'reboot', id)

            LOG.info("create.InstanceResizeController is ok %s.%s.%s" % (result,flavor,instance_uuid))

            return str(result )
        except:
            return "False"
            LOG.error(traceback.format_exc())

    @extensions.expected_errors(404)
    def delete(self,req):
        """Return data about the given instance action."""
        LOG.info("delete.InstanceResizeController is ok")
        return "True"

    @extensions.expected_errors(404)
    def update(self,req):
        """Return data about the given instance action."""
        LOG.info("update.InstanceResizeController is ok")
        return "True"

    @extensions.expected_errors(404)
    def show(self,req):
        """Return data about the given instance action."""
        LOG.info("show.InstanceResizeController is ok")
        return "True"


class InstanceResize(extensions.V21APIExtensionBase):
    """View a log of actions and events taken on an instance."""

    name = "InstanceResize"
    alias = ALIAS
    version = 1

    def get_resources(self):
        ext = extensions.ResourceExtension(ALIAS,
                                           InstanceResizeController(),)
        return [ext]

    def get_controller_extensions(self):
        """It's an abstract function V21APIExtensionBase and the extension
        will not be loaded without it.
        """
        return []

定制extend.api

#    Copyright 2012 IBM Corp.
#
#    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.

"""Handles all requests to the extend service. Compute health checks  """

import os,sys,time,traceback,json 
from oslo_config import cfg
import nova.conf
from nova.extend import manager
from oslo_log import log as logging
from nova import utils
from nova.extend import instance_resize as InstanceResize

conductor_opts = [
    cfg.StrOpt('topic',
               default='extend',
               help='the topic extend nodes listen on'),
    cfg.StrOpt('manager',
               default='nova.extend.manager.ExtendManager',
               help='full class name for the Manager for extend'),
    cfg.IntOpt('workers',
               help='Number of workers for OpenStack Extend service')
]
extend_group = cfg.OptGroup(name='extend',
                               title='exntend Options')
CONF=nova.conf.CONF
CONF.register_group(extend_group)
CONF.register_opts(conductor_opts, extend_group)

LOG = logging.getLogger(__name__)


class LocalAPI(object):
    """A local version of the exten API that does compute health chekcs and virtual machine restart.
    """

    def __init__(self):
        # TODO(danms): This needs to be something more generic for
        # other/future users of this sort of functionality.
        self._manager = utils.ExceptionHelper(manager.ExtendManager())

    def instance_resize(self,context,req,flavor,instance_uuid):
        # instance resize for nova.extend.instance_resize 
        try:
            resize_action = InstanceResize.InstanceResize()
            resize_action.work(context,req,flavor,instance_uuid)
            LOG.info("instance_resize.Extend.API.%s.%s" %(flavor,instance_uuid))
            return True
        except:
            LOG.error(traceback.format_exc())
            return False

定制Extend.instance_resize

#opyright 2013 Rackspace Hosting
# 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.

import os
import time
import sys
import nova.conf 
import traceback 
import json 

from oslo_log import log as logging
from nova import db
from nova import compute
import base64
import re

from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_utils import strutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
import stevedore
import webob
from webob import exc

from nova.api.openstack import api_version_request
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import servers as schema_servers
from nova.api.openstack.compute.views import servers as views_servers
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api import validation
from nova import compute
from nova.compute import flavors
from nova import exception
from nova.i18n import _
from nova.i18n import _LW
from nova.image import glance
from nova import objects
from nova import utils

LOG = logging.getLogger(__name__)

class InstanceResize(object):
    def __init__(self):
        version = 'v1.0'
        self.compute_api = compute.API(skip_policy_check=True)


    def instance_system_metadata_update_havana(self,context,req,instance_uuid,metadata,delete):
        metadata = db.instance_system_metadata_update(context, instance_uuid, metadata,delete)
        LOG.info("instance_system_metadata_update %s" %metadata)

    def instance_extra_update_by_uuid_mitaka(self,context,req,instance_uuid,metadata):
        values = {'flavor':metadata}  
        update_extra = db.instance_extra_update_by_uuid(context, instance_uuid,values)

        if update_extra == 1:
            LOG.info("instance_extra_update_by_uuid_mitaka %s update is oK" %instance_uuid )

    def flavor_get_by_name_havana(self,context,req,name):
        # get flavor dict for db.flavor_get_by_name to havana version 
        meta = db.flavor_get_by_name(context,name)
        metadata = dict()
        metadata['instance_type_memory_mb'] = meta['memory_mb']
        metadata['instance_type_id'] = meta['id']
        metadata['instance_type_name'] = meta['name']
        metadata['instance_type_flavorid'] = meta['flavorid']
        LOG.info('flavor_get_by_name metadata %s' %metadata)
        return metadata

    def flavor_get_by_name_mitaka(self,context,req,flavor,instance_uuid):
        new_meta = db.flavor_get_by_name(context,flavor)
        meta = db.instance_extra_get_by_instance_uuid(context,instance_uuid)

        # get nova.instance_extra.flavor for data
        json_meta = json.loads(meta['flavor'])
        json_meta['cur']['nova_object.data'] = new_meta

        # Time format to str
        stime = json_meta['cur']['nova_object.data']['created_at']
        timestamp=time.localtime(time.mktime(stime.timetuple()))
        ntime = time.strftime("%Y-%m-%dT%H:%M:%S",timestamp)
        json_meta['cur']['nova_object.data']['created_at'] = ntime

        metadata = json.dumps(json_meta)
        LOG.info("flavor_get_by_name_mitaka.meta:%s" %metadata)
        return  metadata   

    def work(self,context,req,flavor,instance_uuid):
        LOG.info("InstanceResize.work.%s.%s"%(flavor,instance_uuid))
        metadata =  self.flavor_get_by_name_mitaka(context,req,flavor,instance_uuid)
        self.instance_extra_update_by_uuid_mitaka(context,req,instance_uuid,metadata)
        return True

接口验证测试

import os,sys,json,time,socket,traceback,urllib2,urllib

def post(url,data):

    cmds ="""curl -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "root", 
    "password":"Autolinux123!@#"}}}' -H "Content-type: application/json" http://127.0.0.1:35357/v2.0/tokens""" 

    info =  os.popen(cmds).readline()

    jsondata = json.loads(info)
    for x,y in jsondata.items():
        dat = y
    token_id  = dat['token']['id']
    tenant_id = dat['token']['tenant']['id']

    url = "http://127.0.0.1:8774/v2.1/%s/os-instance-resize" % tenant_id
    try:
        json_data = json.dumps(data)
        socket.setdefaulttimeout(5)
        httpsHandler = urllib2.HTTPSHandler(debuglevel = 1)
        opener = urllib2.build_opener(httpsHandler)
        urllib2.install_opener(opener)
        request = urllib2.Request(url, json_data)
        request.add_header('User-Agent',"Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20120701 Firefox/6.0.2")
        request.add_header('Content-type','application/json')
        request.add_header('Accept','application/json')
        request.add_header('charset','UTF-8')
        request.add_header('X-Auth-Token',token_id)
        response = urllib2.urlopen(request)
        #res =  json.loads(response.readlines()[0])

    except Exception,e:
        print ('Post %s is failed \n %s' %(url,traceback.format_exc()))


if __name__ == "__main__":
    url  = "http://127.0.0.1:8774/v2.1/82572642-04da-44aa-a18d-4280589b7a3d/os-instance-resize"
    data ={"flavor":"windows-16-16G-100G","instance_uuid":"351ab096-6ab1-496c-a4d7-cc91f78c6eca"}
    sc = post(url,data)

验证接口,日志输出

python extend/token.py 
    2016-09-23 12:31:26.382 5642 WARNING keystonemiddleware.auth_token [-] Using the in-process token cache is deprecated as of the 4.2.0 release and may be removed in the 5.0.0 release or the 'O'
 development cycle. The in-process cache causes inconsistent results and high memory usage. When the feature is removed the auth_token middleware will not cache tokens by default which may result in performance issues. It is recommended to use  memcache for the auth_token token cache by setting the memcached_servers option.2016-09-23 12:31:27.684 5642 INFO nova.extend.instance_resize [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] InstanceResize.
work.linux-16-16G-100G.82572642-04da-44aa-a18d-4280589b7a3d2016-09-23 12:31:27.703 5642 INFO nova.extend.instance_resize [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] flavor_get_by_n
ame_mitaka.meta:{"new": null, "old": null, "cur": {"nova_object.version": "1.1", "nova_object.name": "Flavor", "nova_object.namespace": "nova", "nova_object.data": {"memory_mb": 16384, "flavorid": "19552bc2-de5b-442d-80c8-e54907a08cc5", "name": "linux-16-16G-100G", "deleted": 0, "created_at": "2016-09-19T06:16:16", "ephemeral_gb": 100, "updated_at": null, "disabled": false, "vcpus": 16, "root_gb": 120, "extra_specs": {}, "swap": 0, "rxtx_factor": 1.0, "is_public": true, "deleted_at": null, "vcpu_weight": null, "id": 9}}}2016-09-23 12:31:27.707 5642 INFO nova.extend.instance_resize [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] instance_extra_
update_by_uuid_mitaka 82572642-04da-44aa-a18d-4280589b7a3d update is oK2016-09-23 12:31:27.707 5642 INFO nova.extend.api [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] instance_resize.Extend.API.
linux-16-16G-100G.82572642-04da-44aa-a18d-4280589b7a3d2016-09-23 12:31:27.829 5642 INFO nova.api.openstack.compute.instance_resize [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] 
create.InstanceResizeController is ok True.linux-16-16G-100G.82572642-04da-44aa-a18d-4280589b7a3d2016-09-23 12:31:27.830 5642 INFO nova.osapi_compute.wsgi.server [req-030508f7-6d44-4099-8884-76c1ab831f8b a6300ddcbfd24fbd8892a27d6a4f8328 7b98a7afb66542c7874ddec80b41a665 - - -] 127.0.0.1 "P
OST /v2.1/7b98a7afb66542c7874ddec80b41a665/os-instance-resize HTTP/1.1" status: 200 len: 202 time: 1.4489350
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值