Move client connection out of resources.py.
Client connection references are currently cached at the resource instance level, which doesn't seem very useful. This change moves the client connection and caching to clients.py, then puts a Clients instance in a Stack. This means that (for example) all requests to nova in one stack will come from the same client instance. Change-Id: I22519f8ae4278ad128d3785d090294285f3a1b89
This commit is contained in:
parent
6048c0dd6b
commit
fb5fe06866
|
@ -0,0 +1,191 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# 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 novaclient.v1_1 import client as nc
|
||||
from keystoneclient.v2_0 import client as kc
|
||||
|
||||
# swiftclient not available in all distributions - make s3 an optional
|
||||
# feature
|
||||
try:
|
||||
from swiftclient import client as swiftclient
|
||||
swiftclient_present = True
|
||||
except ImportError:
|
||||
swiftclient_present = False
|
||||
# quantumclient not available in all distributions - make quantum an optional
|
||||
# feature
|
||||
try:
|
||||
from quantumclient.v2_0 import client as quantumclient
|
||||
quantumclient_present = True
|
||||
except ImportError:
|
||||
quantumclient_present = False
|
||||
|
||||
from heat.openstack.common import log as logging
|
||||
|
||||
logger = logging.getLogger('heat.engine.clients')
|
||||
|
||||
|
||||
class Clients(object):
|
||||
'''
|
||||
Convenience class to create and cache client instances.
|
||||
'''
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self._nova = {}
|
||||
self._keystone = None
|
||||
self._swift = None
|
||||
self._quantum = None
|
||||
|
||||
def keystone(self):
|
||||
if self._keystone:
|
||||
return self._keystone
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_url': con.auth_url,
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['password'] = con.password
|
||||
args['tenant_name'] = con.tenant
|
||||
args['tenant_id'] = con.tenant_id
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['password'] = con.service_password
|
||||
args['tenant_name'] = con.service_tenant
|
||||
args['token'] = con.auth_token
|
||||
else:
|
||||
logger.error("Keystone connection failed, no password or " +
|
||||
"auth_token!")
|
||||
return None
|
||||
|
||||
client = kc.Client(**args)
|
||||
client.authenticate()
|
||||
self._keystone = client
|
||||
return self._keystone
|
||||
|
||||
def nova(self, service_type='compute'):
|
||||
if service_type in self._nova:
|
||||
return self._nova[service_type]
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'project_id': con.tenant,
|
||||
'auth_url': con.auth_url,
|
||||
'service_type': service_type,
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['api_key'] = con.password
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['api_key'] = con.service_password
|
||||
args['project_id'] = con.service_tenant
|
||||
args['proxy_token'] = con.auth_token
|
||||
args['proxy_tenant_id'] = con.tenant_id
|
||||
else:
|
||||
logger.error("Nova connection failed, no password or auth_token!")
|
||||
return None
|
||||
|
||||
client = None
|
||||
try:
|
||||
# Workaround for issues with python-keyring, need no_cache=True
|
||||
# ref https://bugs.launchpad.net/python-novaclient/+bug/1020238
|
||||
# TODO(shardy): May be able to remove when the bug above is fixed
|
||||
client = nc.Client(no_cache=True, **args)
|
||||
client.authenticate()
|
||||
self._nova[service_type] = client
|
||||
except TypeError:
|
||||
# for compatibility with essex, which doesn't have no_cache=True
|
||||
# TODO(shardy): remove when we no longer support essex
|
||||
client = nc.Client(**args)
|
||||
client.authenticate()
|
||||
self._nova[service_type] = client
|
||||
|
||||
return client
|
||||
|
||||
def swift(self):
|
||||
if swiftclient_present == False:
|
||||
return None
|
||||
if self._swift:
|
||||
return self._swift
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_version': '2'
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['user'] = con.username
|
||||
args['key'] = con.password
|
||||
args['authurl'] = con.auth_url
|
||||
args['tenant_name'] = con.tenant
|
||||
elif con.auth_token is not None:
|
||||
args['user'] = None
|
||||
args['key'] = None
|
||||
args['authurl'] = None
|
||||
args['preauthtoken'] = con.auth_token
|
||||
# Lookup endpoint for object-store service type
|
||||
service_type = 'object-store'
|
||||
endpoints = self.keystone().service_catalog.get_endpoints(
|
||||
service_type=service_type)
|
||||
if len(endpoints[service_type]) == 1:
|
||||
args['preauthurl'] = endpoints[service_type][0]['publicURL']
|
||||
else:
|
||||
logger.error("No endpoint found for %s service type" %
|
||||
service_type)
|
||||
return None
|
||||
else:
|
||||
logger.error("Swift connection failed, no password or " +
|
||||
"auth_token!")
|
||||
return None
|
||||
|
||||
self._swift = swiftclient.Connection(**args)
|
||||
return self._swift
|
||||
|
||||
def quantum(self):
|
||||
if quantumclient_present == False:
|
||||
return None
|
||||
if self._quantum:
|
||||
logger.debug('using existing _quantum')
|
||||
return self._quantum
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_url': con.auth_url,
|
||||
'service_type': 'network',
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['password'] = con.password
|
||||
args['tenant_name'] = con.tenant
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['password'] = con.service_password
|
||||
args['tenant_name'] = con.service_tenant
|
||||
args['token'] = con.auth_token
|
||||
else:
|
||||
logger.error("Quantum connection failed, "
|
||||
"no password or auth_token!")
|
||||
return None
|
||||
logger.debug('quantum args %s', args)
|
||||
|
||||
self._quantum = quantumclient.Client(**args)
|
||||
|
||||
return self._quantum
|
|
@ -26,6 +26,7 @@ from heat.engine import template
|
|||
from heat.engine import timestamp
|
||||
from heat.engine.parameters import Parameters
|
||||
from heat.engine.template import Template
|
||||
from heat.engine.clients import Clients
|
||||
from heat.db import api as db_api
|
||||
|
||||
from heat.openstack.common import log as logging
|
||||
|
@ -61,6 +62,7 @@ class Stack(object):
|
|||
'''
|
||||
self.id = stack_id
|
||||
self.context = context
|
||||
self.clients = Clients(context)
|
||||
self.t = tmpl
|
||||
self.name = stack_name
|
||||
self.state = state
|
||||
|
|
|
@ -16,24 +16,6 @@
|
|||
import base64
|
||||
from datetime import datetime
|
||||
|
||||
from novaclient.v1_1 import client as nc
|
||||
from keystoneclient.v2_0 import client as kc
|
||||
|
||||
# swiftclient not available in all distributions - make s3 an optional
|
||||
# feature
|
||||
try:
|
||||
from swiftclient import client as swiftclient
|
||||
swiftclient_present = True
|
||||
except ImportError:
|
||||
swiftclient_present = False
|
||||
# quantumclient not available in all distributions - make quantum an optional
|
||||
# feature
|
||||
try:
|
||||
from quantumclient.v2_0 import client as quantumclient
|
||||
quantumclient_present = True
|
||||
except ImportError:
|
||||
quantumclient_present = False
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import config
|
||||
from heat.db import api as db_api
|
||||
|
@ -184,145 +166,16 @@ class Resource(object):
|
|||
deps += (self, None)
|
||||
|
||||
def keystone(self):
|
||||
if self._keystone:
|
||||
return self._keystone
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_url': con.auth_url,
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['password'] = con.password
|
||||
args['tenant_name'] = con.tenant
|
||||
args['tenant_id'] = con.tenant_id
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['password'] = con.service_password
|
||||
args['tenant_name'] = con.service_tenant
|
||||
args['token'] = con.auth_token
|
||||
else:
|
||||
logger.error("Keystone connection failed, no password or " +
|
||||
"auth_token!")
|
||||
return None
|
||||
|
||||
client = kc.Client(**args)
|
||||
client.authenticate()
|
||||
self._keystone = client
|
||||
return self._keystone
|
||||
return self.stack.clients.keystone()
|
||||
|
||||
def nova(self, service_type='compute'):
|
||||
if service_type in self._nova:
|
||||
return self._nova[service_type]
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'project_id': con.tenant,
|
||||
'auth_url': con.auth_url,
|
||||
'service_type': service_type,
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['api_key'] = con.password
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['api_key'] = con.service_password
|
||||
args['project_id'] = con.service_tenant
|
||||
args['proxy_token'] = con.auth_token
|
||||
args['proxy_tenant_id'] = con.tenant_id
|
||||
else:
|
||||
logger.error("Nova connection failed, no password or auth_token!")
|
||||
return None
|
||||
|
||||
client = None
|
||||
try:
|
||||
# Workaround for issues with python-keyring, need no_cache=True
|
||||
# ref https://bugs.launchpad.net/python-novaclient/+bug/1020238
|
||||
# TODO(shardy): May be able to remove when the bug above is fixed
|
||||
client = nc.Client(no_cache=True, **args)
|
||||
client.authenticate()
|
||||
self._nova[service_type] = client
|
||||
except TypeError:
|
||||
# for compatibility with essex, which doesn't have no_cache=True
|
||||
# TODO(shardy): remove when we no longer support essex
|
||||
client = nc.Client(**args)
|
||||
client.authenticate()
|
||||
self._nova[service_type] = client
|
||||
|
||||
return client
|
||||
return self.stack.clients.nova(service_type)
|
||||
|
||||
def swift(self):
|
||||
if swiftclient_present == False:
|
||||
return None
|
||||
if self._swift:
|
||||
return self._swift
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_version': '2'
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['user'] = con.username
|
||||
args['key'] = con.password
|
||||
args['authurl'] = con.auth_url
|
||||
args['tenant_name'] = con.tenant
|
||||
elif con.auth_token is not None:
|
||||
args['user'] = None
|
||||
args['key'] = None
|
||||
args['authurl'] = None
|
||||
args['preauthtoken'] = con.auth_token
|
||||
# Lookup endpoint for object-store service type
|
||||
service_type = 'object-store'
|
||||
endpoints = self.keystone().service_catalog.get_endpoints(
|
||||
service_type=service_type)
|
||||
if len(endpoints[service_type]) == 1:
|
||||
args['preauthurl'] = endpoints[service_type][0]['publicURL']
|
||||
else:
|
||||
logger.error("No endpoint found for %s service type" %
|
||||
service_type)
|
||||
return None
|
||||
else:
|
||||
logger.error("Swift connection failed, no password or " +
|
||||
"auth_token!")
|
||||
return None
|
||||
|
||||
self._swift = swiftclient.Connection(**args)
|
||||
return self._swift
|
||||
return self.stack.clients.swift()
|
||||
|
||||
def quantum(self):
|
||||
if quantumclient_present == False:
|
||||
return None
|
||||
if self._quantum:
|
||||
logger.debug('using existing _quantum')
|
||||
return self._quantum
|
||||
|
||||
con = self.context
|
||||
args = {
|
||||
'auth_url': con.auth_url,
|
||||
'service_type': 'network',
|
||||
}
|
||||
|
||||
if con.password is not None:
|
||||
args['username'] = con.username
|
||||
args['password'] = con.password
|
||||
args['tenant_name'] = con.tenant
|
||||
elif con.auth_token is not None:
|
||||
args['username'] = con.service_user
|
||||
args['password'] = con.service_password
|
||||
args['tenant_name'] = con.service_tenant
|
||||
args['token'] = con.auth_token
|
||||
else:
|
||||
logger.error("Quantum connection failed, "
|
||||
"no password or auth_token!")
|
||||
return None
|
||||
logger.debug('quantum args %s', args)
|
||||
|
||||
self._quantum = quantumclient.Client(**args)
|
||||
|
||||
return self._quantum
|
||||
return self.stack.clients.quantum()
|
||||
|
||||
def create(self):
|
||||
'''
|
||||
|
|
Loading…
Reference in New Issue