Merge "Handle stack not found during inventory generation" into stable/train
This commit is contained in:
commit
8c91da0ea0
|
@ -16,6 +16,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import yaml
|
import yaml
|
||||||
|
@ -28,6 +29,10 @@ UNDERCLOUD_CONNECTION_SSH = 'ssh'
|
||||||
|
|
||||||
UNDERCLOUD_CONNECTION_LOCAL = 'local'
|
UNDERCLOUD_CONNECTION_LOCAL = 'local'
|
||||||
|
|
||||||
|
logging.basicConfig()
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
LOG.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
class TemplateDumper(yaml.SafeDumper):
|
class TemplateDumper(yaml.SafeDumper):
|
||||||
def represent_ordered_dict(self, data):
|
def represent_ordered_dict(self, data):
|
||||||
|
@ -47,26 +52,17 @@ class StackOutputs(object):
|
||||||
on unnecessary Heat calls.
|
on unnecessary Heat calls.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, plan, hclient):
|
def __init__(self, stack):
|
||||||
self.plan = plan
|
|
||||||
self.outputs = {}
|
self.outputs = {}
|
||||||
self.hclient = hclient
|
self.stack = stack
|
||||||
self.stack = None
|
|
||||||
|
|
||||||
def _load_outputs(self):
|
def _load_outputs(self):
|
||||||
"""Load outputs from the stack if necessary
|
"""Load outputs from the stack if necessary
|
||||||
|
|
||||||
Retrieves the stack outputs if that has not already happened. If it
|
Retrieves the stack outputs if that has not already happened. If it
|
||||||
has then this is a noop.
|
has then this is a noop.
|
||||||
|
|
||||||
Sets the outputs to an empty dict if the stack is not found.
|
|
||||||
"""
|
"""
|
||||||
if not self.stack:
|
if not self.outputs:
|
||||||
try:
|
|
||||||
self.stack = self.hclient.stacks.get(self.plan)
|
|
||||||
except HTTPNotFound:
|
|
||||||
self.outputs = {}
|
|
||||||
return
|
|
||||||
self.outputs = {i['output_key']: i['output_value']
|
self.outputs = {i['output_key']: i['output_value']
|
||||||
for i in self.stack.outputs
|
for i in self.stack.outputs
|
||||||
}
|
}
|
||||||
|
@ -106,7 +102,6 @@ class TripleoInventory(object):
|
||||||
self.undercloud_key_file = undercloud_key_file
|
self.undercloud_key_file = undercloud_key_file
|
||||||
self.plan_name = plan_name
|
self.plan_name = plan_name
|
||||||
self.ansible_python_interpreter = ansible_python_interpreter
|
self.ansible_python_interpreter = ansible_python_interpreter
|
||||||
self.stack_outputs = StackOutputs(self.plan_name, self.hclient)
|
|
||||||
self.hostvars = {}
|
self.hostvars = {}
|
||||||
self.undercloud_connection = undercloud_connection
|
self.undercloud_connection = undercloud_connection
|
||||||
self.serial = serial
|
self.serial = serial
|
||||||
|
@ -153,6 +148,16 @@ class TripleoInventory(object):
|
||||||
else:
|
else:
|
||||||
return alist
|
return alist
|
||||||
|
|
||||||
|
def _get_stack(self):
|
||||||
|
try:
|
||||||
|
stack = self.hclient.stacks.get(self.plan_name)
|
||||||
|
except HTTPNotFound:
|
||||||
|
LOG.warning("Stack not found: %s. Only the undercloud will "
|
||||||
|
"be added to the inventory." % self.plan_name)
|
||||||
|
stack = None
|
||||||
|
|
||||||
|
return stack
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
ret = OrderedDict({
|
ret = OrderedDict({
|
||||||
'Undercloud': {
|
'Undercloud': {
|
||||||
|
@ -191,19 +196,30 @@ class TripleoInventory(object):
|
||||||
interface='public')
|
interface='public')
|
||||||
ret['Undercloud']['vars']['undercloud_swift_url'] = swift_url
|
ret['Undercloud']['vars']['undercloud_swift_url'] = swift_url
|
||||||
|
|
||||||
keystone_url = self.stack_outputs.get('KeystoneURL')
|
ret['Undercloud']['vars']['undercloud_service_list'] = \
|
||||||
if keystone_url:
|
self.get_undercloud_service_list()
|
||||||
ret['Undercloud']['vars']['overcloud_keystone_url'] = keystone_url
|
|
||||||
admin_password = self.get_overcloud_environment().get(
|
admin_password = self.get_overcloud_environment().get(
|
||||||
'parameter_defaults', {}).get('AdminPassword')
|
'parameter_defaults', {}).get('AdminPassword')
|
||||||
if admin_password:
|
if admin_password:
|
||||||
ret['Undercloud']['vars']['overcloud_admin_password'] =\
|
ret['Undercloud']['vars']['overcloud_admin_password'] =\
|
||||||
admin_password
|
admin_password
|
||||||
|
|
||||||
|
if not self.hosts_format_dict:
|
||||||
|
# Prevent Ansible from repeatedly calling us to get empty host
|
||||||
|
# details
|
||||||
|
ret['_meta'] = {'hostvars': self.hostvars}
|
||||||
|
|
||||||
|
self.stack = self._get_stack()
|
||||||
|
if not self.stack:
|
||||||
|
return ret
|
||||||
|
self.stack_outputs = StackOutputs(self.stack)
|
||||||
|
|
||||||
|
keystone_url = self.stack_outputs.get('KeystoneURL')
|
||||||
|
if keystone_url:
|
||||||
|
ret['Undercloud']['vars']['overcloud_keystone_url'] = keystone_url
|
||||||
|
|
||||||
endpoint_map = self.stack_outputs.get('EndpointMap')
|
endpoint_map = self.stack_outputs.get('EndpointMap')
|
||||||
|
|
||||||
ret['Undercloud']['vars']['undercloud_service_list'] = \
|
|
||||||
self.get_undercloud_service_list()
|
|
||||||
|
|
||||||
if endpoint_map:
|
if endpoint_map:
|
||||||
horizon_endpoint = endpoint_map.get('HorizonPublic', {}).get('uri')
|
horizon_endpoint = endpoint_map.get('HorizonPublic', {}).get('uri')
|
||||||
if horizon_endpoint:
|
if horizon_endpoint:
|
||||||
|
@ -333,11 +349,6 @@ class TripleoInventory(object):
|
||||||
ret[svc_host]['vars']['ansible_python_interpreter'] = \
|
ret[svc_host]['vars']['ansible_python_interpreter'] = \
|
||||||
self.ansible_python_interpreter
|
self.ansible_python_interpreter
|
||||||
|
|
||||||
if not self.hosts_format_dict:
|
|
||||||
# Prevent Ansible from repeatedly calling us to get empty host
|
|
||||||
# details
|
|
||||||
ret['_meta'] = {'hostvars': self.hostvars}
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def host(self):
|
def host(self):
|
||||||
|
|
|
@ -115,7 +115,7 @@ class TestInventory(base.TestCase):
|
||||||
self.session.get_token.return_value = 'atoken'
|
self.session.get_token.return_value = 'atoken'
|
||||||
self.session.get_endpoint.return_value = 'anendpoint'
|
self.session.get_endpoint.return_value = 'anendpoint'
|
||||||
|
|
||||||
self.outputs = StackOutputs('overcloud', self.hclient)
|
self.outputs = StackOutputs(self.mock_stack)
|
||||||
self.inventory = TripleoInventory(
|
self.inventory = TripleoInventory(
|
||||||
session=self.session,
|
session=self.session,
|
||||||
hclient=self.hclient,
|
hclient=self.hclient,
|
||||||
|
@ -143,10 +143,10 @@ class TestInventory(base.TestCase):
|
||||||
}
|
}
|
||||||
self.assertDictEqual(services, expected)
|
self.assertDictEqual(services, expected)
|
||||||
|
|
||||||
def test_outputs_are_empty_if_stack_doesnt_exist(self):
|
def test_stack_not_found(self):
|
||||||
self.hclient.stacks.get.side_effect = HTTPNotFound('not found')
|
self.hclient.stacks.get.side_effect = HTTPNotFound('not found')
|
||||||
stack_outputs = StackOutputs('no-plan', self.hclient)
|
self.assertEqual(None,
|
||||||
self.assertEqual(list(stack_outputs), [])
|
self.inventory._get_stack())
|
||||||
|
|
||||||
def test_outputs_valid_key_calls_api(self):
|
def test_outputs_valid_key_calls_api(self):
|
||||||
expected = 'xyz://keystone'
|
expected = 'xyz://keystone'
|
||||||
|
|
Loading…
Reference in New Issue