Merge "Handle stack not found during inventory generation" into stable/train

This commit is contained in:
Zuul 2020-01-22 22:23:36 +00:00 committed by Gerrit Code Review
commit 8c91da0ea0
2 changed files with 40 additions and 29 deletions

View File

@ -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):

View File

@ -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'