heat infra driver
Change-Id: I7f2e985a64d2e7e8cc0ca265815df3ed498742f7
This commit is contained in:
parent
ff26d55562
commit
052ac3e0b6
|
@ -491,7 +491,8 @@ service_provider=LOADBALANCER:Haproxy:tacker.services.loadbalancer.drivers.hapro
|
|||
# Specify drivers for hosting device
|
||||
# exmpale: infra_driver = noop
|
||||
# exmpale: infra_driver = nova
|
||||
infra_driver = nova
|
||||
# exmpale: infra_driver = heat
|
||||
infra_driver = heat
|
||||
|
||||
# Specify drivers for mgmt
|
||||
# exmpale: mgmt_driver = noop
|
||||
|
@ -508,6 +509,10 @@ username = nova
|
|||
auth_url = http://127.0.0.1:35357
|
||||
auth_plugin = password
|
||||
|
||||
[servicevm_heat]
|
||||
heat_uri = http://localhost:8004/v1
|
||||
stack_retries = 5
|
||||
stack_retry_wait = 3
|
||||
|
||||
[servicevm_agent]
|
||||
# VM agent requires that an interface driver be set. Choose the one that best
|
||||
|
|
|
@ -51,6 +51,7 @@ tacker.openstack.common.cache.backends =
|
|||
tacker.servicevm.device.drivers =
|
||||
noop = tacker.tests.unit.services.vm.drivers.noop:DeviceNoop
|
||||
nova = tacker.vm.drivers.nova.nova:DeviceNova
|
||||
heat = tacker.vm.drivers.heat.heat:DeviceHeat
|
||||
tacker.servicevm.mgmt.drivers =
|
||||
noop = tacker.tests.unit.services.vm.mgmt_drivers.noop:DeviceMgmtNoop
|
||||
agent_rpc = tacker.vm.mgmt_drivers.rpc.rpc:AgentRpcMGMTDriver
|
||||
|
|
|
@ -30,6 +30,12 @@ ATTR_KEY_IMAGE = 'image'
|
|||
ATTR_KEY_FLAVOR = 'flavor'
|
||||
ATTR_KEY_MGMT_NETWORK = 'mgmt-network'
|
||||
|
||||
# attribute key for device template for heat
|
||||
ATTR_KEY_HEAT_STACK_NAME = 'stack_name'
|
||||
ATTR_KEY_HEAT_TEMPLATE_URL = 'template_url'
|
||||
ATTR_KEY_HEAT_TEMPLATE = 'template'
|
||||
ATTR_KEY_HEAT_FILES = 'files'
|
||||
ATTR_KEY_HEAT_PARAMETERS = 'parameters'
|
||||
|
||||
# Role of service context
|
||||
ROLE_NONE = 'None'
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2015 Intel Corporation.
|
||||
# Copyright 2015 Isaku Yamahata <isaku.yamahata at intel com>
|
||||
# <isaku.yamahata at gmail com>
|
||||
# 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.
|
||||
#
|
||||
# @author: Isaku Yamahata, Intel Corporation.
|
||||
# shamelessly many codes are stolen from gbp simplechain_driver.py
|
||||
|
||||
import time
|
||||
|
||||
from heatclient import client as heat_client
|
||||
from heatclient import exc as heatException
|
||||
from oslo_config import cfg
|
||||
|
||||
from tacker.common import log
|
||||
from tacker.openstack.common import jsonutils
|
||||
from tacker.openstack.common import log as logging
|
||||
from tacker.vm.drivers import abstract_driver
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
OPTS = [
|
||||
cfg.StrOpt('heat_uri',
|
||||
default='http://localhost:8004/v1',
|
||||
help=_("Heat server address to create services "
|
||||
"specified in the service chain.")),
|
||||
cfg.IntOpt('stack_retries',
|
||||
default=10,
|
||||
help=_("Number of attempts to retry for stack deletion")),
|
||||
cfg.IntOpt('stack_retry_wait',
|
||||
default=5,
|
||||
help=_("Wait time between two successive stack delete "
|
||||
"retries")),
|
||||
]
|
||||
CONF.register_opts(OPTS, group='servicevm_heat')
|
||||
STACK_RETRIES = cfg.CONF.servicevm_heat.stack_retries
|
||||
STACK_RETRY_WAIT = cfg.CONF.servicevm_heat.stack_retry_wait
|
||||
|
||||
|
||||
class DeviceHeat(abstract_driver.DeviceAbstractDriver):
|
||||
|
||||
"""Heat driver of hosting device."""
|
||||
|
||||
def __init__(self):
|
||||
super(DeviceHeat, self).__init__()
|
||||
|
||||
def get_type(self):
|
||||
return 'heat'
|
||||
|
||||
def get_name(self):
|
||||
return 'heat'
|
||||
|
||||
def get_description(self):
|
||||
return 'Heat infra driver'
|
||||
|
||||
@log.log
|
||||
def create(self, plugin, context, device):
|
||||
LOG.debug(_('device %s'), device)
|
||||
heatclient_ = HeatClient(context)
|
||||
attributes = device['device_template']['attributes'].copy()
|
||||
fields = dict((key, attributes.pop(key)) for key
|
||||
in ('stack_name', 'template_url', 'template')
|
||||
if key in attributes)
|
||||
for key in ('files', 'parameters'):
|
||||
if key in attributes:
|
||||
fields[key] = jsonutils.loads(attributes.pop(key))
|
||||
fields.setdefault('parameters', {}).update(attributes)
|
||||
|
||||
# overwrite parameters with given kwargs for device creation
|
||||
kwargs = device['kwargs'].copy()
|
||||
fields.update(dict((key, kwargs.pop(key)) for key
|
||||
in ('stack_name', 'template_url', 'template')
|
||||
if key in kwargs))
|
||||
for key in ('files', 'parameters'):
|
||||
if key in kwargs:
|
||||
kwargs[key] = jsonutils.loads(kwargs.pop(key))
|
||||
fields['parameters'].update(kwargs)
|
||||
if 'stack_name' not in fields:
|
||||
name = (__name__ + '_' + self.__class__.__name__ + '-' +
|
||||
device['id'])
|
||||
fields['stack_name'] = name
|
||||
|
||||
# service context is ignored
|
||||
LOG.debug(_('service_context: %s'), device.get('service_context', []))
|
||||
|
||||
LOG.debug(_('fields: %s'), fields)
|
||||
stack = heatclient_.create(fields)
|
||||
return stack['stack']['id']
|
||||
|
||||
def create_wait(self, plugin, context, device_id):
|
||||
heatclient_ = HeatClient(context)
|
||||
|
||||
stack = heatclient_.get(device_id)
|
||||
status = stack.stack_status
|
||||
stack_retries = STACK_RETRIES
|
||||
while status == 'CREATE_IN_PROGRESS' and stack_retries > 0:
|
||||
time.sleep(STACK_RETRY_WAIT)
|
||||
try:
|
||||
stack = heatclient_.get(device_id)
|
||||
except Exception:
|
||||
LOG.exception(_("Device Instance cleanup may not have "
|
||||
"happened because Heat API request failed "
|
||||
"while waiting for the stack %(stack)s to be "
|
||||
"deleted"), {'stack': device_id})
|
||||
break
|
||||
status = stack.stack_status
|
||||
LOG.debug(_('status: %s'), status)
|
||||
stack_retries = stack_retries - 1
|
||||
|
||||
LOG.debug(_('status: %s'), status)
|
||||
if stack_retries == 0:
|
||||
LOG.warn(_("Resource creation is"
|
||||
" not completed within %(wait)s seconds as "
|
||||
"creation of Stack %(stack)s is not completed"),
|
||||
{'wait': (STACK_RETRIES * STACK_RETRY_WAIT),
|
||||
'stack': device_id})
|
||||
if status != 'CREATE_COMPLETE':
|
||||
raise RuntimeError(_("creation of server %s faild") % device_id)
|
||||
|
||||
def update(self, plugin, context, device):
|
||||
# do nothing but checking if the stack exists at the moment
|
||||
heatclient_ = HeatClient(context)
|
||||
heatclient_.get(device['id'])
|
||||
|
||||
def update_wait(self, plugin, context, device_id):
|
||||
# do nothing but checking if the stack exists at the moment
|
||||
heatclient_ = HeatClient(context)
|
||||
heatclient_.get(device_id)
|
||||
|
||||
def delete(self, plugin, context, device_id):
|
||||
heatclient_ = HeatClient(context)
|
||||
heatclient_.delete(device_id)
|
||||
|
||||
@log.log
|
||||
def delete_wait(self, plugin, context, device_id):
|
||||
heatclient_ = HeatClient(context)
|
||||
|
||||
stack = heatclient_.get(device_id)
|
||||
status = stack.satck_status
|
||||
stack_retries = STACK_RETRIES
|
||||
while (status == 'DELETE_IN_PROGRESS' and stack_retries > 0):
|
||||
time.sleep(STACK_RETRY_WAIT)
|
||||
try:
|
||||
stack = heatclient_.get(device_id)
|
||||
except Exception:
|
||||
LOG.exception(_("Device Instance cleanup may not have "
|
||||
"happened because Heat API request failed "
|
||||
"while waiting for the stack %(stack)s to be "
|
||||
"deleted"), {'stack': device_id})
|
||||
break
|
||||
status = stack.satck_status
|
||||
stack_retries = stack_retries - 1
|
||||
|
||||
if stack_retries == 0:
|
||||
LOG.warn(_("Resource cleanup for device is"
|
||||
" not completed within %(wait)s seconds as "
|
||||
"deletion of Stack %(stack)s is not completed"),
|
||||
{'wait': (STACK_RETRIES * STACK_RETRY_WAIT),
|
||||
'stack': device_id})
|
||||
if status != 'DELETE_COMPLETE':
|
||||
LOG.warn(_("device (%(device_id)d) deletion is not completed. "
|
||||
"%(stack_status)s"),
|
||||
{'device_id': device_id, 'stack_status': status})
|
||||
|
||||
@log.log
|
||||
def attach_interface(self, plugin, context, device_id, port_id):
|
||||
raise NotImplementedError()
|
||||
|
||||
@log.log
|
||||
def dettach_interface(self, plugin, context, device_id, port_id):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class HeatClient:
|
||||
def __init__(self, context, password=None):
|
||||
api_version = "1"
|
||||
endpoint = "%s/%s" % (cfg.CONF.servicevm_heat.heat_uri, context.tenant)
|
||||
kwargs = {
|
||||
'token': context.auth_token,
|
||||
'username': context.user_name,
|
||||
'password': password
|
||||
}
|
||||
self.client = heat_client.Client(api_version, endpoint, **kwargs)
|
||||
self.stacks = self.client.stacks
|
||||
|
||||
def create(self, fields):
|
||||
fields = fields.copy()
|
||||
fields.update({
|
||||
'timeout_mins': 10,
|
||||
'disable_rollback': True})
|
||||
if 'password' in fields.get('template', {}):
|
||||
fields['password'] = fields['template']['password']
|
||||
return self.stacks.create(**fields)
|
||||
|
||||
def delete(self, stack_id):
|
||||
try:
|
||||
self.stacks.delete(stack_id)
|
||||
except heatException.HTTPNotFound:
|
||||
LOG.warn(_("Stack %(stack)s created by service chain driver is "
|
||||
"not found at cleanup"), {'stack': stack_id})
|
||||
|
||||
def get(self, stack_id):
|
||||
return self.stacks.get(stack_id)
|
|
@ -156,8 +156,8 @@ class ServiceVMPlugin(vm_db.ServiceResourcePluginDb, ServiceVMMgmtMixin):
|
|||
"""ServiceVMPlugin which supports ServiceVM framework
|
||||
"""
|
||||
OPTS = [
|
||||
cfg.MultiStrOpt(
|
||||
'infra_driver', default=[],
|
||||
cfg.ListOpt(
|
||||
'infra_driver', default=['heat'],
|
||||
help=_('Hosting device drivers servicevm plugin will use')),
|
||||
]
|
||||
cfg.CONF.register_opts(OPTS, 'servicevm')
|
||||
|
|
Loading…
Reference in New Issue