Use Swift to store Plan environment
Start using the plan environment file in Swift for plan environment storage instead of Mistral. Add util functions to get/update environment data. Remove CreatePlanAction and UpdatePlanAction as all they did was sync between Mistral and Swift environments. Amend the corresponding workflows to account for removal of these actions. Implements: blueprint stop-using-mistral-env Co-Authored-By: Julie Pichon <jpichon@redhat.com> Depends-On: I3bcef27413e685c498165b43a8b59c8c9cc5cf5e Change-Id: Ieedecf92113142e43925131dcbccc4c0cd5b1a18
This commit is contained in:
parent
1c162d61e2
commit
bd4e26e823
@ -0,0 +1,6 @@
|
||||
upgrade:
|
||||
- |
|
||||
The environment configuration for deployments is now stored in a
|
||||
file called ``plan-environment.yaml`` and stored in Swift with the
|
||||
templates; Mistral is no longer used to store this data. Migration
|
||||
of the existing plans is handled automatically.
|
@ -87,8 +87,6 @@ mistral.actions =
|
||||
tripleo.parameters.generate_passwords = tripleo_common.actions.parameters:GeneratePasswordsAction
|
||||
tripleo.parameters.get_passwords = tripleo_common.actions.parameters:GetPasswordsAction
|
||||
tripleo.parameters.generate_fencing = tripleo_common.actions.parameters:GenerateFencingParametersAction
|
||||
tripleo.plan.create = tripleo_common.actions.plan:CreatePlanAction
|
||||
tripleo.plan.update = tripleo_common.actions.plan:UpdatePlanAction
|
||||
tripleo.plan.create_container = tripleo_common.actions.plan:CreateContainerAction
|
||||
tripleo.plan.delete = tripleo_common.actions.plan:DeletePlanAction
|
||||
tripleo.plan.list = tripleo_common.actions.plan:ListPlansAction
|
||||
@ -111,3 +109,4 @@ mistral.actions =
|
||||
tripleo.validations.verify_profiles = tripleo_common.actions.validations:VerifyProfilesAction
|
||||
# deprecated for pike release, will be removed in queens
|
||||
tripleo.templates.upload_default = tripleo_common.actions.templates:UploadTemplatesAction
|
||||
tripleo.plan.migrate = tripleo_common.actions.plan:MigratePlanAction
|
||||
|
@ -19,13 +19,13 @@ import time
|
||||
from heatclient.common import deployment_utils
|
||||
from heatclient import exc as heat_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from mistralclient.api import base as mistralclient_exc
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.actions import templates
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import overcloudrc
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -145,8 +145,7 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
||||
stack_is_new = stack is None
|
||||
|
||||
# update StackAction, DeployIdentifier and UpdateIdentifier
|
||||
wc = self.get_workflow_client(context)
|
||||
wf_env = wc.environments.get(self.container)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
parameters = dict()
|
||||
if not self.skip_deploy_identifier:
|
||||
@ -154,15 +153,22 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
||||
parameters['UpdateIdentifier'] = ''
|
||||
parameters['StackAction'] = 'CREATE' if stack_is_new else 'UPDATE'
|
||||
|
||||
if 'parameter_defaults' not in wf_env.variables:
|
||||
wf_env.variables['parameter_defaults'] = {}
|
||||
wf_env.variables['parameter_defaults'].update(parameters)
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables,
|
||||
}
|
||||
# store params changes back to db before call to process templates
|
||||
wc.environments.update(**env_kwargs)
|
||||
try:
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
plan_utils.update_in_env(swift, env, 'parameter_defaults',
|
||||
parameters)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error updating environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
# process all plan files and create or update a stack
|
||||
processed_data = super(DeployStackAction, self).run(context)
|
||||
@ -176,13 +182,12 @@ class DeployStackAction(templates.ProcessTemplatesAction):
|
||||
stack_args['timeout_mins'] = self.timeout_mins
|
||||
|
||||
if stack_is_new:
|
||||
swift_client = self.get_object_client(context)
|
||||
try:
|
||||
swift_client.copy_object(
|
||||
swift.copy_object(
|
||||
"%s-swift-rings" % self.container, "swift-rings.tar.gz",
|
||||
"%s-swift-rings/%s-%d" % (
|
||||
self.container, "swift-rings.tar.gz", time.time()))
|
||||
swift_client.delete_object(
|
||||
swift.delete_object(
|
||||
"%s-swift-rings" % self.container, "swift-rings.tar.gz")
|
||||
except swiftexceptions.ClientException:
|
||||
pass
|
||||
@ -211,7 +216,7 @@ class OvercloudRcAction(base.TripleOAction):
|
||||
|
||||
def run(self, context):
|
||||
orchestration_client = self.get_orchestration_client(context)
|
||||
workflow_client = self.get_workflow_client(context)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
try:
|
||||
stack = orchestration_client.stacks.get(self.container)
|
||||
@ -221,26 +226,27 @@ class OvercloudRcAction(base.TripleOAction):
|
||||
"deployed before calling this action.").format(self.container)
|
||||
return mistral_workflow_utils.Result(error=error)
|
||||
|
||||
try:
|
||||
environment = workflow_client.environments.get(self.container)
|
||||
except mistralclient_exc.APIException:
|
||||
error = "The Mistral environment {} could not be found.".format(
|
||||
self.container)
|
||||
return mistral_workflow_utils.Result(error=error)
|
||||
|
||||
# We need to check parameter_defaults first for a user provided
|
||||
# password. If that doesn't exist, we then should look in the
|
||||
# automatically generated passwords.
|
||||
# TODO(d0ugal): Abstract this operation somewhere. We shouldn't need to
|
||||
# know about the structure of the environment to get a password.
|
||||
try:
|
||||
parameter_defaults = environment.variables['parameter_defaults']
|
||||
passwords = environment.variables['passwords']
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.error(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
parameter_defaults = env['parameter_defaults']
|
||||
passwords = env['passwords']
|
||||
admin_pass = parameter_defaults.get('AdminPassword')
|
||||
if admin_pass is None:
|
||||
admin_pass = passwords['AdminPassword']
|
||||
except KeyError:
|
||||
error = ("Unable to find the AdminPassword in the Mistral "
|
||||
error = ("Unable to find the AdminPassword in the plan "
|
||||
"environment.")
|
||||
return mistral_workflow_utils.Result(error=error)
|
||||
|
||||
|
@ -17,9 +17,11 @@ import logging
|
||||
import yaml
|
||||
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -40,8 +42,8 @@ class GetCapabilitiesAction(base.TripleOAction):
|
||||
|
||||
def run(self, context):
|
||||
try:
|
||||
swift_client = self.get_object_client(context)
|
||||
map_file = swift_client.get_object(
|
||||
swift = self.get_object_client(context)
|
||||
map_file = swift.get_object(
|
||||
self.container, 'capabilities-map.yaml')
|
||||
capabilities = yaml.safe_load(map_file[1])
|
||||
except Exception:
|
||||
@ -50,24 +52,23 @@ class GetCapabilitiesAction(base.TripleOAction):
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
try:
|
||||
container_files = swift_client.get_container(self.container)
|
||||
container_files = swift.get_container(self.container)
|
||||
container_file_list = [entry['name'] for entry
|
||||
in container_files[1]]
|
||||
except Exception as swift_err:
|
||||
err_msg = ("Error retrieving plan files: %s" % swift_err)
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
mistral_client = self.get_workflow_client(context)
|
||||
mistral_env = mistral_client.environments.get(self.container)
|
||||
except Exception as mistral_err:
|
||||
err_msg = ("Error retrieving mistral "
|
||||
"environment. %s" % mistral_err)
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
selected_envs = [item['path'] for item in
|
||||
mistral_env.variables['environments']
|
||||
selected_envs = [item['path'] for item in env['environments']
|
||||
if 'path' in item]
|
||||
|
||||
# extract environment files
|
||||
@ -138,20 +139,20 @@ class GetCapabilitiesAction(base.TripleOAction):
|
||||
|
||||
|
||||
class UpdateCapabilitiesAction(base.TripleOAction):
|
||||
"""Updates Mistral Environment with selected environments
|
||||
"""Updates plan environment with selected environments
|
||||
|
||||
Takes a list of environment files and depending on the value of the
|
||||
enabled flag, adds or removes them from the Mistral Environment.
|
||||
enabled flag, adds or removes them from the plan environment.
|
||||
|
||||
:param environments: map of environments {'environment_path': True}
|
||||
the value passed can be false for disabled
|
||||
environments, these will be removed from the
|
||||
mistral environment.
|
||||
plan environment.
|
||||
:param container: name of the swift container / plan name
|
||||
:param purge_missing: remove any environments from the mistral environment
|
||||
:param purge_missing: remove any environments from the plan environment
|
||||
that aren't included in the environments map
|
||||
defaults to False
|
||||
:return: the updated mistral environment
|
||||
:return: the updated plan environment
|
||||
"""
|
||||
|
||||
def __init__(self, environments,
|
||||
@ -163,46 +164,39 @@ class UpdateCapabilitiesAction(base.TripleOAction):
|
||||
self.purge_missing = purge_missing
|
||||
|
||||
def run(self, context):
|
||||
mistral_client = self.get_workflow_client(context)
|
||||
mistral_env = None
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
try:
|
||||
mistral_env = mistral_client.environments.get(self.container)
|
||||
except Exception as mistral_err:
|
||||
err_msg = (
|
||||
"Error retrieving mistral "
|
||||
"environment. %s" % mistral_err)
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
for k, v in self.environments.items():
|
||||
found = False
|
||||
if {'path': k} in mistral_env.variables['environments']:
|
||||
if {'path': k} in env['environments']:
|
||||
found = True
|
||||
if v:
|
||||
if not found:
|
||||
mistral_env.variables['environments'].append(
|
||||
{'path': k}
|
||||
)
|
||||
env['environments'].append({'path': k})
|
||||
else:
|
||||
if found:
|
||||
mistral_env.variables['environments'].remove({'path': k})
|
||||
env['environments'].remove({'path': k})
|
||||
|
||||
if self.purge_missing:
|
||||
for env in mistral_env.variables['environments']:
|
||||
if env.get('path') not in self.environments:
|
||||
mistral_env.variables['environments'].remove(env)
|
||||
for e in env['environments']:
|
||||
if e.get('path') not in self.environments:
|
||||
env['environments'].remove(e)
|
||||
|
||||
self.cache_delete(context, self.container, "tripleo.parameters.get")
|
||||
|
||||
env_kwargs = {
|
||||
'name': mistral_env.name,
|
||||
'variables': mistral_env.variables
|
||||
}
|
||||
try:
|
||||
mistral_client.environments.update(**env_kwargs)
|
||||
except Exception as mistral_err:
|
||||
err_msg = (
|
||||
"Error retrieving mistral environment. %s" % mistral_err)
|
||||
plan_utils.put_env(swift, env)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = "Error uploading to container: %s" % err
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
return mistral_env.variables
|
||||
|
||||
return env
|
||||
|
@ -18,11 +18,13 @@ import time
|
||||
from heatclient.common import template_utils
|
||||
from heatclient import exc as heat_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.actions import templates
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.update import PackageUpdateManager
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -63,24 +65,24 @@ class UpdateStackAction(templates.ProcessTemplatesAction):
|
||||
parameters['UpdateIdentifier'] = timestamp
|
||||
parameters['StackAction'] = 'UPDATE'
|
||||
|
||||
wc = self.get_workflow_client(context)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
try:
|
||||
wf_env = wc.environments.get(self.container)
|
||||
except Exception:
|
||||
msg = "Error retrieving mistral environment: %s" % self.container
|
||||
LOG.exception(msg)
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
if 'parameter_defaults' not in wf_env.variables:
|
||||
wf_env.variables['parameter_defaults'] = {}
|
||||
wf_env.variables['parameter_defaults'].update(parameters)
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables,
|
||||
}
|
||||
|
||||
# store params changes back to db before call to process templates
|
||||
wc.environments.update(**env_kwargs)
|
||||
try:
|
||||
plan_utils.update_in_env(swift, env, 'parameter_defaults',
|
||||
parameters)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error updating environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
# process all plan files and create or update a stack
|
||||
processed_data = super(UpdateStackAction, self).run(context)
|
||||
|
@ -31,6 +31,7 @@ import uuid
|
||||
|
||||
from heatclient import exc as heat_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.actions import templates
|
||||
@ -38,6 +39,7 @@ from tripleo_common import constants
|
||||
from tripleo_common.utils import nodes
|
||||
from tripleo_common.utils import parameters
|
||||
from tripleo_common.utils import passwords as password_utils
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -64,11 +66,18 @@ class GetParametersAction(templates.ProcessTemplatesAction):
|
||||
processed_data['show_nested'] = True
|
||||
|
||||
# respect previously user set param values
|
||||
wc = self.get_workflow_client(context)
|
||||
wf_env = wc.environments.get(self.container)
|
||||
orc = self.get_orchestration_client(context)
|
||||
swift = self.get_object_client(context)
|
||||
heat = self.get_orchestration_client(context)
|
||||
|
||||
params = wf_env.variables.get('parameter_defaults')
|
||||
try:
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
params = env.get('parameter_defaults')
|
||||
|
||||
fields = {
|
||||
'template': processed_data['template'],
|
||||
@ -76,9 +85,10 @@ class GetParametersAction(templates.ProcessTemplatesAction):
|
||||
'environment': processed_data['environment'],
|
||||
'show_nested': True
|
||||
}
|
||||
|
||||
result = {
|
||||
'heat_resource_tree': orc.stacks.validate(**fields),
|
||||
'mistral_environment_parameters': params,
|
||||
'heat_resource_tree': heat.stacks.validate(**fields),
|
||||
'environment_parameters': params,
|
||||
}
|
||||
self.cache_set(context,
|
||||
self.container,
|
||||
@ -95,25 +105,33 @@ class ResetParametersAction(base.TripleOAction):
|
||||
self.container = container
|
||||
|
||||
def run(self, context):
|
||||
wc = self.get_workflow_client(context)
|
||||
wf_env = wc.environments.get(self.container)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
if 'parameter_defaults' in wf_env.variables:
|
||||
wf_env.variables.pop('parameter_defaults')
|
||||
try:
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
plan_utils.update_in_env(swift, env, 'parameter_defaults',
|
||||
delete_key=True)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error updating environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables
|
||||
}
|
||||
wc.environments.update(**env_kwargs)
|
||||
self.cache_delete(context,
|
||||
self.container,
|
||||
"tripleo.parameters.get")
|
||||
return wf_env
|
||||
return env
|
||||
|
||||
|
||||
class UpdateParametersAction(base.TripleOAction):
|
||||
"""Updates Mistral Environment with parameters."""
|
||||
"""Updates plan environment with parameters."""
|
||||
|
||||
def __init__(self, parameters,
|
||||
container=constants.DEFAULT_CONTAINER_NAME):
|
||||
@ -122,24 +140,33 @@ class UpdateParametersAction(base.TripleOAction):
|
||||
self.parameters = parameters
|
||||
|
||||
def run(self, context):
|
||||
wc = self.get_workflow_client(context)
|
||||
wf_env = wc.environments.get(self.container)
|
||||
if 'parameter_defaults' not in wf_env.variables:
|
||||
wf_env.variables['parameter_defaults'] = {}
|
||||
wf_env.variables['parameter_defaults'].update(self.parameters)
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables
|
||||
}
|
||||
wc.environments.update(**env_kwargs)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
try:
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
plan_utils.update_in_env(swift, env, 'parameter_defaults',
|
||||
self.parameters)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error updating environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
self.cache_delete(context,
|
||||
self.container,
|
||||
"tripleo.parameters.get")
|
||||
return wf_env
|
||||
return env
|
||||
|
||||
|
||||
class UpdateRoleParametersAction(UpdateParametersAction):
|
||||
"""Updates role related parameters in Mistral Environment ."""
|
||||
"""Updates role related parameters in plan environment ."""
|
||||
|
||||
def __init__(self, role, container=constants.DEFAULT_CONTAINER_NAME):
|
||||
super(UpdateRoleParametersAction, self).__init__(parameters=None,
|
||||
@ -158,8 +185,8 @@ class GeneratePasswordsAction(base.TripleOAction):
|
||||
"""Generates passwords needed for Overcloud deployment
|
||||
|
||||
This method generates passwords and ensures they are stored in the
|
||||
mistral environment associated with a plan. This method respects
|
||||
previously generated passwords and adds new passwords as necessary.
|
||||
plan environment. This method respects previously generated passwords and
|
||||
adds new passwords as necessary.
|
||||
"""
|
||||
|
||||
def __init__(self, container=constants.DEFAULT_CONTAINER_NAME):
|
||||
@ -167,45 +194,47 @@ class GeneratePasswordsAction(base.TripleOAction):
|
||||
self.container = container
|
||||
|
||||
def run(self, context):
|
||||
|
||||
orchestration = self.get_orchestration_client(context)
|
||||
wc = self.get_workflow_client(context)
|
||||
try:
|
||||
wf_env = wc.environments.get(self.container)
|
||||
except Exception:
|
||||
msg = "Error retrieving mistral environment: %s" % self.container
|
||||
LOG.exception(msg)
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
heat = self.get_orchestration_client(context)
|
||||
swift = self.get_object_client(context)
|
||||
mistral = self.get_workflow_client(context)
|
||||
|
||||
try:
|
||||
stack_env = orchestration.stacks.environment(
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
stack_env = heat.stacks.environment(
|
||||
stack_id=self.container)
|
||||
except heat_exc.HTTPNotFound:
|
||||
stack_env = None
|
||||
|
||||
passwords = password_utils.generate_passwords(wc, stack_env)
|
||||
passwords = password_utils.generate_passwords(mistral, stack_env)
|
||||
|
||||
# if passwords don't yet exist in mistral environment
|
||||
if 'passwords' not in wf_env.variables:
|
||||
wf_env.variables['passwords'] = {}
|
||||
# if passwords don't yet exist in plan environment
|
||||
if 'passwords' not in env:
|
||||
env['passwords'] = {}
|
||||
|
||||
# ensure all generated passwords are present in mistral env,
|
||||
# ensure all generated passwords are present in plan env,
|
||||
# but respect any values previously generated and stored
|
||||
for name, password in passwords.items():
|
||||
if name not in wf_env.variables['passwords']:
|
||||
wf_env.variables['passwords'][name] = password
|
||||
if name not in env['passwords']:
|
||||
env['passwords'][name] = password
|
||||
|
||||
env_kwargs = {
|
||||
'name': wf_env.name,
|
||||
'variables': wf_env.variables,
|
||||
}
|
||||
try:
|
||||
plan_utils.put_env(swift, env)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = "Error uploading to container: %s" % err
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
wc.environments.update(**env_kwargs)
|
||||
self.cache_delete(context,
|
||||
self.container,
|
||||
"tripleo.parameters.get")
|
||||
|
||||
return wf_env.variables['passwords']
|
||||
return env['passwords']
|
||||
|
||||
|
||||
class GetPasswordsAction(base.TripleOAction):
|
||||
@ -221,16 +250,18 @@ class GetPasswordsAction(base.TripleOAction):
|
||||
self.container = container
|
||||
|
||||
def run(self, context):
|
||||
wc = self.get_workflow_client(context)
|
||||
try:
|
||||
wf_env = wc.environments.get(self.container)
|
||||
except Exception:
|
||||
msg = "Error retrieving mistral environment: %s" % self.container
|
||||
LOG.exception(msg)
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
parameter_defaults = wf_env.variables.get('parameter_defaults', {})
|
||||
passwords = wf_env.variables.get('passwords', {})
|
||||
try:
|
||||
env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
parameter_defaults = env.get('parameter_defaults', {})
|
||||
passwords = env.get('passwords', {})
|
||||
for name in constants.PASSWORD_PARAMETER_NAMES:
|
||||
if name in parameter_defaults:
|
||||
passwords[name] = parameter_defaults[name]
|
||||
|
@ -12,7 +12,6 @@
|
||||
# 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 json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
@ -20,6 +19,7 @@ import tempfile
|
||||
import yaml
|
||||
|
||||
from heatclient import exc as heatexceptions
|
||||
from keystoneauth1 import exceptions as keystoneauth_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from mistralclient.api import base as mistralclient_base
|
||||
from oslo_concurrency import processutils
|
||||
@ -29,6 +29,7 @@ from swiftclient import exceptions as swiftexceptions
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common import constants
|
||||
from tripleo_common import exception
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
from tripleo_common.utils import swift as swiftutils
|
||||
from tripleo_common.utils import tarball
|
||||
from tripleo_common.utils.validations import pattern_validator
|
||||
@ -41,58 +42,6 @@ default_container_headers = {
|
||||
}
|
||||
|
||||
|
||||
class PlanEnvMixin(object):
|
||||
@staticmethod
|
||||
def get_plan_env_dict(swift, container):
|
||||
"""Retrieves the plan environment from Swift.
|
||||
|
||||
Loads a plan environment file with a given container name from Swift.
|
||||
Makes sure that the file contains valid YAML and that the mandatory
|
||||
fields are present in the environment.
|
||||
|
||||
If the plan environment file is missing from Swift, fall back to the
|
||||
capabilities-map.yaml.
|
||||
|
||||
Returns the plan environment dictionary, and a boolean indicator
|
||||
whether the plan environment file was missing from Swift.
|
||||
"""
|
||||
plan_env_missing = False
|
||||
|
||||
try:
|
||||
plan_env = swift.get_object(container,
|
||||
constants.PLAN_ENVIRONMENT)[1]
|
||||
except swiftexceptions.ClientException:
|
||||
# If the plan environment file is missing from Swift, look for
|
||||
# capabilities-map.yaml instead
|
||||
plan_env_missing = True
|
||||
try:
|
||||
plan_env = swift.get_object(container,
|
||||
'capabilities-map.yaml')[1]
|
||||
except swiftexceptions.ClientException as err:
|
||||
raise exception.PlanOperationError(
|
||||
"File missing from container: %s" % err)
|
||||
|
||||
try:
|
||||
plan_env_dict = yaml.safe_load(plan_env)
|
||||
except yaml.YAMLError as err:
|
||||
raise exception.PlanOperationError(
|
||||
"Error parsing the yaml file: %s" % err)
|
||||
|
||||
if plan_env_missing:
|
||||
plan_env_dict = {
|
||||
'environments': [{'path': plan_env_dict['root_environment']}],
|
||||
'template': plan_env_dict['root_template'],
|
||||
'version': 1.0
|
||||
}
|
||||
|
||||
for key in ('environments', 'template', 'version'):
|
||||
if key not in plan_env_dict:
|
||||
raise exception.PlanOperationError(
|
||||
"%s missing key: %s" % (constants.PLAN_ENVIRONMENT, key))
|
||||
|
||||
return plan_env_dict, plan_env_missing
|
||||
|
||||
|
||||
class CreateContainerAction(base.TripleOAction):
|
||||
"""Creates an object container
|
||||
|
||||
@ -122,121 +71,51 @@ class CreateContainerAction(base.TripleOAction):
|
||||
oc.put_container(self.container, headers=default_container_headers)
|
||||
|
||||
|
||||
class CreatePlanAction(base.TripleOAction, PlanEnvMixin):
|
||||
"""Creates a plan
|
||||
class MigratePlanAction(base.TripleOAction):
|
||||
"""Migrate plan from using a Mistral environment to using Swift
|
||||
|
||||
Given a container, creates a Mistral environment with the same name.
|
||||
The contents of the environment are imported from the plan environment
|
||||
file, which must contain entries for `template`, `environments` and
|
||||
`version` at a minimum.
|
||||
This action creates a plan-environment.yaml file based on the
|
||||
Mistral environment or the default environment, if the file doesn't
|
||||
already exist in Swift.
|
||||
|
||||
This action will be deleted in Queens, as it will no longer be
|
||||
needed by then - all plans will include plan-environment.yaml by
|
||||
default.
|
||||
"""
|
||||
|
||||
def __init__(self, container):
|
||||
super(CreatePlanAction, self).__init__()
|
||||
self.container = container
|
||||
def __init__(self, plan):
|
||||
super(MigratePlanAction, self).__init__()
|
||||
self.plan = plan
|
||||
|
||||
def run(self, context):
|
||||
swift = self.get_object_client(context)
|
||||
mistral = self.get_workflow_client(context)
|
||||
env_data = {
|
||||
'name': self.container,
|
||||
}
|
||||
from_mistral = False
|
||||
|
||||
if not pattern_validator(constants.PLAN_NAME_PATTERN, self.container):
|
||||
message = ("Unable to create plan. The plan name must "
|
||||
"only contain letters, numbers or dashes")
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
|
||||
# Check to see if an environment with that name already exists
|
||||
try:
|
||||
mistral.environments.get(self.container)
|
||||
except mistralclient_base.APIException:
|
||||
# The environment doesn't exist, as expected. Proceed.
|
||||
pass
|
||||
else:
|
||||
message = ("Unable to create plan. The Mistral environment "
|
||||
"already exists")
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
|
||||
# Get plan environment from Swift
|
||||
try:
|
||||
plan_env_dict, plan_env_missing = self.get_plan_env_dict(
|
||||
swift, self.container)
|
||||
except exception.PlanOperationError as err:
|
||||
return mistral_workflow_utils.Result(error=six.text_type(err))
|
||||
|
||||
# Create mistral environment
|
||||
env_data['variables'] = json.dumps(plan_env_dict, sort_keys=True)
|
||||
try:
|
||||
mistral.environments.create(**env_data)
|
||||
except Exception as err:
|
||||
message = "Error occurred creating plan: %s" % err
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
|
||||
# Delete the plan environment file from Swift, as it is no long needed.
|
||||
# (If we were to leave the environment file behind, we would have to
|
||||
# take care to keep it in sync with the actual contents of the Mistral
|
||||
# environment. To avoid that, we simply delete it.)
|
||||
# TODO(akrivoka): Once the 'Deployment plan management changes' spec
|
||||
# (https://review.openstack.org/#/c/438918/) is implemented, we will no
|
||||
# longer use Mistral environments for holding the plan data, so this
|
||||
# code can go away.
|
||||
if not plan_env_missing:
|
||||
env = plan_utils.get_env(swift, self.plan)
|
||||
except swiftexceptions.ClientException:
|
||||
# The plan has not been migrated yet. Check if there is a
|
||||
# Mistral environment.
|
||||
try:
|
||||
swift.delete_object(self.container, constants.PLAN_ENVIRONMENT)
|
||||
except swiftexceptions.ClientException as err:
|
||||
message = "Error deleting file from container: %s" % err
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
env = mistral.environments.get(self.plan).variables
|
||||
from_mistral = True
|
||||
except (mistralclient_base.APIException,
|
||||
keystoneauth_exc.http.NotFound):
|
||||
# No Mistral env and no template: likely deploying old
|
||||
# templates aka previous version of OpenStack.
|
||||
env = {'version': 1.0,
|
||||
'name': self.plan,
|
||||
'description': '',
|
||||
'template': 'overcloud.yaml',
|
||||
'environments': [
|
||||
{'path': 'overcloud-resource-registry-puppet.yaml'}
|
||||
]}
|
||||
|
||||
|
||||
class UpdatePlanAction(base.TripleOAction, PlanEnvMixin):
|
||||
"""Updates a plan
|
||||
|
||||
Given a container, update the Mistral environment with the same name.
|
||||
The contents of the environment are imported (overwritten) from the plan
|
||||
environment file, which must contain entries for `template`, `environments`
|
||||
and `version` at a minimum.
|
||||
"""
|
||||
|
||||
def __init__(self, container):
|
||||
super(UpdatePlanAction, self).__init__()
|
||||
self.container = container
|
||||
|
||||
def run(self, context):
|
||||
swift = self.get_object_client(context)
|
||||
mistral = self.get_workflow_client(context)
|
||||
|
||||
# Get plan environment from Swift
|
||||
try:
|
||||
plan_env_dict, plan_env_missing = self.get_plan_env_dict(
|
||||
swift, self.container)
|
||||
except exception.PlanOperationError as err:
|
||||
return mistral_workflow_utils.Result(error=six.text_type(err))
|
||||
|
||||
# Update mistral environment with contents from plan environment file
|
||||
variables = json.dumps(plan_env_dict, sort_keys=True)
|
||||
self.cache_delete(context, self.container, "tripleo.parameters.get")
|
||||
try:
|
||||
mistral.environments.update(
|
||||
name=self.container, variables=variables)
|
||||
except mistralclient_base.APIException:
|
||||
message = "Error updating mistral environment: %s" % self.container
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
|
||||
# Delete the plan environment file from Swift, as it is no long needed.
|
||||
# (If we were to leave the environment file behind, we would have to
|
||||
# take care to keep it in sync with the actual contents of the Mistral
|
||||
# environment. To avoid that, we simply delete it.)
|
||||
# TODO(akrivoka): Once the 'Deployment plan management changes' spec
|
||||
# (https://review.openstack.org/#/c/438918/) is implemented, we will no
|
||||
# longer use Mistral environments for holding the plan data, so this
|
||||
# code can go away.
|
||||
if not plan_env_missing:
|
||||
try:
|
||||
swift.delete_object(self.container, constants.PLAN_ENVIRONMENT)
|
||||
except swiftexceptions.ClientException as err:
|
||||
message = "Error deleting file from container: %s" % err
|
||||
return mistral_workflow_utils.Result(error=message)
|
||||
# Store the environment info into Swift
|
||||
plan_utils.put_env(swift, env)
|
||||
if from_mistral:
|
||||
mistral.environments.delete(self.plan)
|
||||
|
||||
|
||||
class ListPlansAction(base.TripleOAction):
|
||||
@ -244,23 +123,20 @@ class ListPlansAction(base.TripleOAction):
|
||||
|
||||
This action lists all deployment plans residing in the undercloud. A
|
||||
deployment plan consists of a container marked with metadata
|
||||
'x-container-meta-usage-tripleo' and a mistral environment with the same
|
||||
name as the container.
|
||||
'x-container-meta-usage-tripleo'.
|
||||
"""
|
||||
|
||||
def run(self, context):
|
||||
# plans consist of a container object and mistral environment
|
||||
# with the same name. The container is marked with metadata
|
||||
# to ensure it isn't confused with another container
|
||||
# Plans consist of a container object marked with metadata to ensure it
|
||||
# isn't confused with another container
|
||||
plan_list = []
|
||||
oc = self.get_object_client(context)
|
||||
mc = self.get_workflow_client(context)
|
||||
|
||||
for item in oc.get_account()[1]:
|
||||
container = oc.get_container(item['name'])[0]
|
||||
if constants.TRIPLEO_META_USAGE_KEY in container.keys():
|
||||
plan_list.append(item['name'])
|
||||
return list(set(plan_list).intersection(
|
||||
[env.name for env in mc.environments.list()]))
|
||||
return list(set(plan_list))
|
||||
|
||||
|
||||
class DeletePlanAction(base.TripleOAction):
|
||||
@ -293,13 +169,6 @@ class DeletePlanAction(base.TripleOAction):
|
||||
try:
|
||||
swift = self.get_object_client(context)
|
||||
swiftutils.delete_container(swift, self.container)
|
||||
|
||||
# if mistral environment exists, delete it too
|
||||
mistral = self.get_workflow_client(context)
|
||||
if self.container in [env.name for env in
|
||||
mistral.environments.list()]:
|
||||
# deletes environment
|
||||
mistral.environments.delete(self.container)
|
||||
except swiftexceptions.ClientException as ce:
|
||||
LOG.exception("Swift error deleting plan.")
|
||||
error_text = ce.msg
|
||||
@ -326,8 +195,8 @@ class ListRolesAction(base.TripleOAction):
|
||||
|
||||
def run(self, context):
|
||||
try:
|
||||
oc = self.get_object_client(context)
|
||||
roles_data = yaml.safe_load(oc.get_object(
|
||||
swift = self.get_object_client(context)
|
||||
roles_data = yaml.safe_load(swift.get_object(
|
||||
self.container, constants.OVERCLOUD_J2_ROLES_NAME)[1])
|
||||
except Exception as err:
|
||||
err_msg = ("Error retrieving roles data from deployment plan: %s"
|
||||
@ -341,11 +210,9 @@ class ListRolesAction(base.TripleOAction):
|
||||
class ExportPlanAction(base.TripleOAction):
|
||||
"""Exports a deployment plan
|
||||
|
||||
This action exports a deployment plan with a given name. First, the plan
|
||||
templates are downloaded from the Swift container. Then the plan
|
||||
environment file is generated from the associated Mistral environment.
|
||||
Finally, both the templates and the plan environment file are packaged up
|
||||
in a tarball and uploaded to Swift.
|
||||
This action exports a deployment plan with a given name. The plan
|
||||
templates are downloaded from the Swift container, packaged up in a tarball
|
||||
and uploaded to Swift.
|
||||
"""
|
||||
|
||||
def __init__(self, plan, delete_after, exports_container):
|
||||
@ -370,15 +237,6 @@ class ExportPlanAction(base.TripleOAction):
|
||||
with open(path, 'w') as f:
|
||||
f.write(contents)
|
||||
|
||||
def _generate_plan_env_file(self, mistral, tmp_dir):
|
||||
"""Generate plan environment file and add it to specified folder."""
|
||||
environment = mistral.environments.get(self.plan).variables
|
||||
yaml_string = yaml.safe_dump(environment, default_flow_style=False)
|
||||
path = os.path.join(tmp_dir, constants.PLAN_ENVIRONMENT)
|
||||
|
||||
with open(path, 'w') as f:
|
||||
f.write(yaml_string)
|
||||
|
||||
def _create_and_upload_tarball(self, swift, tmp_dir):
|
||||
"""Create a tarball containing the tmp_dir and upload it to Swift."""
|
||||
tarball_name = '%s.tar.gz' % self.plan
|
||||
@ -397,21 +255,15 @@ class ExportPlanAction(base.TripleOAction):
|
||||
headers=headers)
|
||||
|
||||
def run(self, context):
|
||||
swift = self.get_object_client(context)
|
||||
mistral = self.get_workflow_client(context)
|
||||
swift = self.get_object_client()
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
|
||||
try:
|
||||
self._download_templates(swift, tmp_dir)
|
||||
self._generate_plan_env_file(mistral, tmp_dir)
|
||||
self._create_and_upload_tarball(swift, tmp_dir)
|
||||
except swiftexceptions.ClientException as err:
|
||||
msg = "Error attempting an operation on container: %s" % err
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
except mistralclient_base.APIException:
|
||||
msg = ("The Mistral environment %s could not be found."
|
||||
% self.plan)
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
except (OSError, IOError) as err:
|
||||
msg = "Error while writing file: %s" % err
|
||||
return mistral_workflow_utils.Result(error=msg)
|
||||
|
@ -27,6 +27,7 @@ from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
from tripleo_common.utils import tarball
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -240,14 +241,14 @@ class ProcessTemplatesAction(base.TripleOAction):
|
||||
error_text = None
|
||||
self.context = context
|
||||
swift = self.get_object_client(context)
|
||||
mistral = self.get_workflow_client(context)
|
||||
|
||||
try:
|
||||
mistral_environment = mistral.environments.get(self.container)
|
||||
except Exception as mistral_err:
|
||||
error_text = six.text_type(mistral_err)
|
||||
LOG.exception(
|
||||
"Error retrieving Mistral Environment: %s" % self.container)
|
||||
return mistral_workflow_utils.Result(error=error_text)
|
||||
plan_env = plan_utils.get_env(swift, self.container)
|
||||
except swiftexceptions.ClientException as err:
|
||||
err_msg = ("Error retrieving environment for plan %s: %s" % (
|
||||
self.container, err))
|
||||
LOG.exception(err_msg)
|
||||
return mistral_workflow_utils.Result(error=err_msg)
|
||||
|
||||
try:
|
||||
# if the jinja overcloud template exists, process it and write it
|
||||
@ -261,8 +262,8 @@ class ProcessTemplatesAction(base.TripleOAction):
|
||||
LOG.exception("Error occurred while processing custom roles.")
|
||||
return mistral_workflow_utils.Result(error=six.text_type(err))
|
||||
|
||||
template_name = mistral_environment.variables.get('template')
|
||||
environments = mistral_environment.variables.get('environments')
|
||||
template_name = plan_env.get('template')
|
||||
environments = plan_env.get('environments')
|
||||
env_paths = []
|
||||
temp_files = []
|
||||
|
||||
@ -285,12 +286,11 @@ class ProcessTemplatesAction(base.TripleOAction):
|
||||
# them in the appropriate order
|
||||
merged_params = {}
|
||||
# merge generated passwords into params first
|
||||
passwords = mistral_environment.variables.get('passwords', {})
|
||||
passwords = plan_env.get('passwords', {})
|
||||
merged_params.update(passwords)
|
||||
# handle user set parameter values next in case a user has set
|
||||
# a new value for a password parameter
|
||||
params = mistral_environment.variables.get(
|
||||
'parameter_defaults', {})
|
||||
params = plan_env.get('parameter_defaults', {})
|
||||
merged_params.update(params)
|
||||
if merged_params:
|
||||
env_temp_file = _create_temp_file(
|
||||
|
@ -13,13 +13,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from heatclient import exc as heat_exc
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from mistralclient.api import base as mistralclient_exc
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import deployment
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.tests import base
|
||||
|
||||
|
||||
@ -210,39 +211,35 @@ class DeployStackActionTest(base.TestCase):
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_orchestration_client')
|
||||
def test_run(self, get_orchestration_client_mock,
|
||||
mock_get_object_client, mock_get_workflow_client,
|
||||
mock_get_template_contents,
|
||||
mock_get_object_client, mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files,
|
||||
mock_time):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
# setup swift
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': 'overcloud',
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'random_existing_data': 'a_value'},
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2')
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
heat = mock.MagicMock()
|
||||
heat.stacks.get.return_value = None
|
||||
get_orchestration_client_mock.return_value = heat
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'random_existing_data': 'a_value'},
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
})
|
||||
@ -259,8 +256,20 @@ class DeployStackActionTest(base.TestCase):
|
||||
'StackAction': 'CREATE',
|
||||
'UpdateIdentifier': '',
|
||||
'random_existing_data': 'a_value'}
|
||||
self.assertEqual(expected_defaults,
|
||||
mock_env.variables['parameter_defaults'])
|
||||
|
||||
mock_env_updated = yaml.safe_dump({
|
||||
'name': 'overcloud',
|
||||
'temp_environment': 'temp_environment',
|
||||
'parameter_defaults': expected_defaults,
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.put_object.assert_called_once_with(
|
||||
'overcloud',
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
mock_env_updated
|
||||
)
|
||||
|
||||
heat.stacks.create.assert_called_once_with(
|
||||
environment={},
|
||||
@ -279,39 +288,36 @@ class DeployStackActionTest(base.TestCase):
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_orchestration_client')
|
||||
def test_run_skip_deploy_identifier(
|
||||
self, get_orchestration_client_mock,
|
||||
mock_get_object_client, mock_get_workflow_client,
|
||||
mock_get_template_contents,
|
||||
mock_get_object_client, mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files,
|
||||
mock_time):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
# setup swift
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
heat = mock.MagicMock()
|
||||
heat.stacks.get.return_value = None
|
||||
get_orchestration_client_mock.return_value = heat
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'random_existing_data': 'a_value'},
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2')
|
||||
)
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
@ -326,11 +332,21 @@ class DeployStackActionTest(base.TestCase):
|
||||
action.run(mock_ctx)
|
||||
|
||||
# verify parameters are as expected
|
||||
expected_defaults = {'StackAction': 'CREATE',
|
||||
'UpdateIdentifier': '',
|
||||
'random_existing_data': 'a_value'}
|
||||
self.assertEqual(expected_defaults,
|
||||
mock_env.variables['parameter_defaults'])
|
||||
mock_env_updated = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'parameter_defaults': {'StackAction': 'CREATE',
|
||||
'UpdateIdentifier': '',
|
||||
'random_existing_data': 'a_value'},
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.put_object.assert_called_once_with(
|
||||
constants.DEFAULT_CONTAINER_NAME,
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
mock_env_updated
|
||||
)
|
||||
|
||||
heat.stacks.create.assert_called_once_with(
|
||||
environment={},
|
||||
@ -347,13 +363,11 @@ class DeployStackActionTest(base.TestCase):
|
||||
|
||||
|
||||
class OvercloudRcActionTestCase(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
'get_object_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_stack(self, mock_get_orchestration,
|
||||
mock_get_workflow):
|
||||
def test_no_stack(self, mock_get_orchestration, mock_get_object):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
@ -369,59 +383,64 @@ class OvercloudRcActionTestCase(base.TestCase):
|
||||
))
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
'get_object_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_env(self, mock_get_orchestration,
|
||||
mock_get_workflow):
|
||||
def test_no_env(self, mock_get_orchestration, mock_get_object):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
not_found = mistralclient_exc.APIException()
|
||||
mock_get_workflow.return_value.environments.get.side_effect = not_found
|
||||
mock_get_object.return_value.get_object.side_effect = (
|
||||
swiftexceptions.ClientException("overcast"))
|
||||
|
||||
action = deployment.OvercloudRcAction("overcast")
|
||||
result = action.run(mock_ctx)
|
||||
self.assertEqual(result.error, "Error retrieving environment for plan "
|
||||
"overcast: overcast")
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_object_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_password(self, mock_get_orchestration, mock_get_object):
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
mock_get_object.return_value.get_object.return_value = (
|
||||
{}, "version: 1.0")
|
||||
|
||||
action = deployment.OvercloudRcAction("overcast")
|
||||
result = action.run(mock_ctx)
|
||||
|
||||
self.assertEqual(
|
||||
result.error,
|
||||
"The Mistral environment overcast could not be found.")
|
||||
"Unable to find the AdminPassword in the plan environment.")
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_password(self, mock_get_orchestration,
|
||||
mock_get_workflow):
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
mock_env = mock.MagicMock(variables={})
|
||||
mock_get_workflow.return_value.environments.get.return_value = mock_env
|
||||
|
||||
action = deployment.OvercloudRcAction("overcast")
|
||||
result = action.run(mock_ctx)
|
||||
|
||||
self.assertEqual(
|
||||
result.error,
|
||||
"Unable to find the AdminPassword in the Mistral environment.")
|
||||
|
||||
'get_object_client')
|
||||
@mock.patch('tripleo_common.utils.overcloudrc.create_overcloudrc')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_success(self, mock_get_orchestration,
|
||||
mock_get_workflow, mock_create_overcloudrc):
|
||||
def test_success(self, mock_get_orchestration, mock_create_overcloudrc,
|
||||
mock_get_object):
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
mock_env = """
|
||||
version: 1.0
|
||||
|
||||
template: overcloud.yaml
|
||||
environments:
|
||||
- path: overcloud-resource-registry-puppet.yaml
|
||||
- path: environments/services/sahara.yaml
|
||||
parameter_defaults:
|
||||
BlockStorageCount: 42
|
||||
OvercloudControlFlavor: yummy
|
||||
passwords:
|
||||
AdminPassword: SUPERSECUREPASSWORD
|
||||
"""
|
||||
mock_get_object.return_value.get_object.return_value = ({}, mock_env)
|
||||
mock_create_overcloudrc.return_value = {
|
||||
"overcloudrc": "fake overcloudrc"
|
||||
}
|
||||
mock_env = mock.MagicMock(variables={
|
||||
"parameter_defaults": {},
|
||||
"passwords": {"AdminPassword": "SUPERSECUREPASSWORD"}
|
||||
})
|
||||
mock_get_workflow.return_value.environments.get.return_value = mock_env
|
||||
|
||||
action = deployment.OvercloudRcAction("overcast")
|
||||
result = action.run(mock_ctx)
|
||||
|
@ -16,6 +16,7 @@ import mock
|
||||
import yaml
|
||||
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import heat_capabilities
|
||||
from tripleo_common.tests import base
|
||||
@ -155,38 +156,40 @@ class GetCapabilitiesActionTest(base.TestCase):
|
||||
self.assertEqual(expected, action.run(mock_ctx))
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run_mistral_error(self, get_workflow_client_mock,
|
||||
get_obj_client_mock):
|
||||
def test_run_env_missing(self, get_obj_client_mock):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
|
||||
swift.get_object.side_effect = (
|
||||
({}, MAPPING_YAML_CONTENTS),
|
||||
swiftexceptions.ClientException(self.container_name)
|
||||
)
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
mistral.environments.get = mock.Mock(
|
||||
side_effect=Exception)
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
|
||||
action = heat_capabilities.GetCapabilitiesAction(self.container_name)
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data=None,
|
||||
error="Error retrieving mistral environment. ")
|
||||
error="Error retrieving environment for plan test-container: "
|
||||
"test-container")
|
||||
self.assertEqual(expected, action.run(mock_ctx))
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run(self, get_workflow_client_mock, get_obj_client_mock):
|
||||
def test_run(self, get_obj_client_mock):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
|
||||
|
||||
mock_env = """
|
||||
template: overcloud
|
||||
environments:
|
||||
- path: /path/to/network-isolation.json
|
||||
"""
|
||||
swift.get_object.side_effect = (
|
||||
({}, MAPPING_YAML_CONTENTS),
|
||||
({}, mock_env)
|
||||
)
|
||||
swift_files_data = ({
|
||||
u'x-container-meta-usage-tripleo': u'plan',
|
||||
u'content-length': u'54271', u'x-container-object-count': u'3',
|
||||
@ -217,18 +220,6 @@ class GetCapabilitiesActionTest(base.TestCase):
|
||||
swift.get_container.return_value = swift_files_data
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = self.container_name
|
||||
mock_env.variables = {
|
||||
'template': 'overcloud',
|
||||
'environments': [{'path': '/path/to/network-isolation.json'}]
|
||||
}
|
||||
mistral.environments.get.return_value = mock_env
|
||||
|
||||
action = heat_capabilities.GetCapabilitiesAction(self.container_name)
|
||||
yaml_mapping = yaml.safe_load(MAPPING_JSON_CONTENTS)
|
||||
self.assertEqual(yaml_mapping, action.run(mock_ctx))
|
||||
@ -242,23 +233,21 @@ class UpdateCapabilitiesActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_delete')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run(self, get_workflow_client_mock, mock_cache):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, get_object_client_mock, mock_cache):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
mocked_env = mock.MagicMock()
|
||||
mocked_env.variables = {
|
||||
'environments': [
|
||||
{'path': '/path/to/overcloud-default-env.yaml'},
|
||||
{'path': '/path/to/ceph-storage-env.yaml'},
|
||||
]
|
||||
}
|
||||
mistral.environments.get.return_value = mocked_env
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
mocked_env = """
|
||||
name: test-container
|
||||
environments:
|
||||
- path: /path/to/overcloud-default-env.yaml
|
||||
- path: /path/to/ceph-storage-env.yaml
|
||||
"""
|
||||
swift.get_object.return_value = ({}, mocked_env)
|
||||
get_object_client_mock.return_value = swift
|
||||
|
||||
environments = {
|
||||
'/path/to/ceph-storage-env.yaml': False,
|
||||
@ -269,6 +258,7 @@ class UpdateCapabilitiesActionTest(base.TestCase):
|
||||
action = heat_capabilities.UpdateCapabilitiesAction(
|
||||
environments, self.container_name)
|
||||
self.assertEqual({
|
||||
'name': 'test-container',
|
||||
'environments': [
|
||||
{'path': '/path/to/overcloud-default-env.yaml'},
|
||||
{'path': '/path/to/poc-custom-env.yaml'}
|
||||
@ -284,22 +274,21 @@ class UpdateCapabilitiesActionTest(base.TestCase):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_delete')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run_purge_missing(self, get_workflow_client_mock, mock_cache):
|
||||
'tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run_purge_missing(self, get_object_client_mock, mock_cache):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
mocked_env = mock.MagicMock()
|
||||
mocked_env.variables = {
|
||||
'environments': [
|
||||
{'path': '/path/to/overcloud-default-env.yaml'},
|
||||
{'path': '/path/to/ceph-storage-env.yaml'},
|
||||
]
|
||||
}
|
||||
mistral.environments.get.return_value = mocked_env
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
mocked_env = """
|
||||
name: test-container
|
||||
environments:
|
||||
- path: /path/to/overcloud-default-env.yaml
|
||||
- path: /path/to/ceph-storage-env.yaml
|
||||
"""
|
||||
swift.get_object.return_value = ({}, mocked_env)
|
||||
get_object_client_mock.return_value = swift
|
||||
|
||||
environments = {
|
||||
'/path/to/overcloud-default-env.yaml': True,
|
||||
@ -310,6 +299,7 @@ class UpdateCapabilitiesActionTest(base.TestCase):
|
||||
action = heat_capabilities.UpdateCapabilitiesAction(
|
||||
environments, self.container_name, True)
|
||||
self.assertEqual({
|
||||
'name': 'test-container',
|
||||
'environments': [
|
||||
{'path': '/path/to/overcloud-default-env.yaml'},
|
||||
{'path': '/path/to/poc-custom-env.yaml'}
|
||||
@ -321,28 +311,21 @@ class UpdateCapabilitiesActionTest(base.TestCase):
|
||||
"tripleo.parameters.get"
|
||||
)
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run_mistral_error(self, get_workflow_client_mock,
|
||||
get_obj_client_mock):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run_env_missing(self, get_obj_client_mock):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
swift.get_object.return_value = ({}, MAPPING_YAML_CONTENTS)
|
||||
swift.get_object.side_effect = (
|
||||
swiftexceptions.ClientException(self.container_name))
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
mistral.environments.get = mock.Mock(
|
||||
side_effect=Exception)
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
|
||||
action = heat_capabilities.UpdateCapabilitiesAction(
|
||||
{}, self.container_name)
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data=None,
|
||||
error="Error retrieving mistral environment. ")
|
||||
error="Error retrieving environment for plan test-container: "
|
||||
"test-container"
|
||||
)
|
||||
self.assertEqual(expected, action.run(mock_ctx))
|
||||
|
@ -15,6 +15,7 @@
|
||||
import mock
|
||||
|
||||
from tripleo_common.actions import package_update
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.tests import base
|
||||
|
||||
|
||||
@ -57,8 +58,7 @@ class UpdateStackActionTest(base.TestCase):
|
||||
self.container = 'container'
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction.run')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
@ -69,10 +69,10 @@ class UpdateStackActionTest(base.TestCase):
|
||||
mock_time,
|
||||
mock_compute_client,
|
||||
mock_orchestration_client,
|
||||
mock_workflow_client,
|
||||
mock_templates_run
|
||||
):
|
||||
mock_object_client,
|
||||
mock_templates_run):
|
||||
mock_ctx = mock.MagicMock()
|
||||
|
||||
heat = mock.MagicMock()
|
||||
heat.stacks.get.return_value = mock.MagicMock(
|
||||
stack_name='stack', id='stack_id')
|
||||
@ -81,16 +81,17 @@ class UpdateStackActionTest(base.TestCase):
|
||||
mock_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
})
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'random_data': 'a_value'},
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_workflow_client.return_value = mock_mistral
|
||||
mock_swift = mock.MagicMock()
|
||||
mock_env = """environments:
|
||||
- path: environments/test.yaml
|
||||
name: container
|
||||
parameter_defaults:
|
||||
random_data: a_value
|
||||
temp_environment: temp_environment
|
||||
template: template
|
||||
"""
|
||||
mock_swift.get_object.return_value = ({}, mock_env)
|
||||
mock_object_client.return_value = mock_swift
|
||||
|
||||
# freeze time at datetime.datetime(2016, 9, 8, 16, 24, 24)
|
||||
mock_time.time.return_value = 1473366264
|
||||
@ -106,16 +107,21 @@ class UpdateStackActionTest(base.TestCase):
|
||||
action.run(mock_ctx)
|
||||
|
||||
# verify parameters are as expected
|
||||
expected_defaults = {
|
||||
'StackAction': 'UPDATE',
|
||||
'DeployIdentifier': 1473366264,
|
||||
'UpdateIdentifier': 1473366264,
|
||||
'random_data': 'a_value',
|
||||
}
|
||||
self.assertEqual(
|
||||
expected_defaults, mock_env.variables['parameter_defaults'])
|
||||
updated_mock_env = """environments:
|
||||
- path: environments/test.yaml
|
||||
name: container
|
||||
parameter_defaults:
|
||||
DeployIdentifier: 1473366264
|
||||
StackAction: UPDATE
|
||||
UpdateIdentifier: 1473366264
|
||||
random_data: a_value
|
||||
temp_environment: temp_environment
|
||||
template: template
|
||||
"""
|
||||
mock_swift.put_object.assert_called_once_with(
|
||||
self.container, constants.PLAN_ENVIRONMENT, updated_mock_env
|
||||
)
|
||||
|
||||
print(heat.mock_calls)
|
||||
heat.stacks.update.assert_called_once_with(
|
||||
'stack_id',
|
||||
StackAction='UPDATE',
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
@ -147,11 +148,9 @@ class GetParametersActionTest(base.TestCase):
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client,
|
||||
mock_get_workflow_client, mock_get_orchestration_client,
|
||||
mock_get_orchestration_client,
|
||||
mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files,
|
||||
mock_cache_get,
|
||||
@ -159,19 +158,17 @@ class GetParametersActionTest(base.TestCase):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
mock_env = yaml.safe_dump({
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2'),
|
||||
({}, mock_env)
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
@ -201,7 +198,7 @@ class GetParametersActionTest(base.TestCase):
|
||||
mock_ctx,
|
||||
"overcloud",
|
||||
"tripleo.parameters.get",
|
||||
{'heat_resource_tree': {}, 'mistral_environment_parameters': None}
|
||||
{'heat_resource_tree': {}, 'environment_parameters': None}
|
||||
)
|
||||
|
||||
|
||||
@ -209,31 +206,36 @@ class ResetParametersActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_delete')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
def test_run(self, mock_get_workflow_client,
|
||||
mock_cache):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client, mock_cache):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'SomeTestParameter': 42}
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
# Test
|
||||
action = parameters.ResetParametersAction()
|
||||
|
||||
action.run(mock_ctx)
|
||||
mock_mistral.environments.update.assert_called_once_with(
|
||||
name=constants.DEFAULT_CONTAINER_NAME,
|
||||
variables={
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
|
||||
mock_env_reset = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.put_object.assert_called_once_with(
|
||||
constants.DEFAULT_CONTAINER_NAME,
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
mock_env_reset
|
||||
)
|
||||
mock_cache.assert_called_once_with(
|
||||
mock_ctx,
|
||||
@ -246,34 +248,38 @@ class UpdateParametersActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_delete')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
def test_run(self, mock_get_workflow_client, mock_cache):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client, mock_cache):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
# Test
|
||||
test_parameters = {'SomeTestParameter': 42}
|
||||
action = parameters.UpdateParametersAction(test_parameters)
|
||||
action.run(mock_ctx)
|
||||
|
||||
mock_mistral.environments.update.assert_called_once_with(
|
||||
name=constants.DEFAULT_CONTAINER_NAME,
|
||||
variables={
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'parameter_defaults': {'SomeTestParameter': 42}}
|
||||
mock_env_updated = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'parameter_defaults': {'SomeTestParameter': 42},
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.put_object.assert_called_once_with(
|
||||
constants.DEFAULT_CONTAINER_NAME,
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
mock_env_updated
|
||||
)
|
||||
mock_cache.assert_called_once_with(
|
||||
mock_ctx,
|
||||
@ -291,19 +297,18 @@ class UpdateRoleParametersActionTest(base.TestCase):
|
||||
'get_baremetal_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
def test_run(self, mock_get_workflow_client,
|
||||
mock_get_compute_client, mock_get_baremetal_client,
|
||||
mock_set_count_and_flavor, mock_cache):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client, mock_get_compute_client,
|
||||
mock_get_baremetal_client, mock_set_count_and_flavor,
|
||||
mock_cache):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = 'overcast'
|
||||
mock_env.variables = {}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({'name': 'overcast'},
|
||||
default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
params = {'CephStorageCount': 1,
|
||||
'OvercloudCephStorageFlavor': 'ceph-storage'}
|
||||
@ -313,8 +318,16 @@ class UpdateRoleParametersActionTest(base.TestCase):
|
||||
'overcast')
|
||||
action.run(mock_ctx)
|
||||
|
||||
mock_mistral.environments.update.assert_called_once_with(
|
||||
name='overcast', variables={'parameter_defaults': params})
|
||||
mock_env_updated = yaml.safe_dump({
|
||||
'name': 'overcast',
|
||||
'parameter_defaults': params,
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.put_object.assert_called_once_with(
|
||||
'overcast',
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
mock_env_updated
|
||||
)
|
||||
mock_cache.assert_called_once_with(
|
||||
mock_ctx,
|
||||
"overcast",
|
||||
@ -332,23 +345,24 @@ class GeneratePasswordsActionTest(base.TestCase):
|
||||
'get_snmpd_readonly_user_password')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client', return_value="TestPassword")
|
||||
def test_run(self, mock_get_workflow_client,
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client,
|
||||
mock_get_workflow_client,
|
||||
mock_get_snmpd_readonly_user_password,
|
||||
mock_get_orchestration_client, mock_cache):
|
||||
|
||||
mock_get_snmpd_readonly_user_password.return_value = "TestPassword"
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': 'overcast',
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_orchestration.stacks.environment.return_value = {
|
||||
@ -378,7 +392,9 @@ class GeneratePasswordsActionTest(base.TestCase):
|
||||
'get_snmpd_readonly_user_password')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
def test_run_passwords_exist(self, mock_get_workflow_client,
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run_passwords_exist(self, mock_get_object_client,
|
||||
mock_get_workflow_client,
|
||||
mock_get_snmpd_readonly_user_password,
|
||||
mock_create_ssh_keypair,
|
||||
mock_get_orchestration_client,
|
||||
@ -389,17 +405,17 @@ class GeneratePasswordsActionTest(base.TestCase):
|
||||
'private_key': 'Bar'}
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'passwords': _EXISTING_PASSWORDS.copy()
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_orchestration.stacks.environment.return_value = {
|
||||
@ -428,7 +444,9 @@ class GeneratePasswordsActionTest(base.TestCase):
|
||||
'get_snmpd_readonly_user_password')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
def test_passwords_exist_in_heat(self, mock_get_workflow_client,
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_passwords_exist_in_heat(self, mock_get_object_client,
|
||||
mock_get_workflow_client,
|
||||
mock_get_snmpd_readonly_user_password,
|
||||
mock_create_ssh_keypair,
|
||||
mock_get_orchestration_client,
|
||||
@ -442,17 +460,17 @@ class GeneratePasswordsActionTest(base.TestCase):
|
||||
existing_passwords.pop("AdminPassword")
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': constants.DEFAULT_CONTAINER_NAME,
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
'passwords': existing_passwords.copy()
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_orchestration.stacks.environment.return_value = {
|
||||
@ -479,22 +497,20 @@ class GetPasswordsActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_password_from_parameter_defaults(self,
|
||||
mock_get_workflow_client,
|
||||
mock_get_object_client,
|
||||
mock_get_orchestration_client):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
"parameter_defaults": _EXISTING_PASSWORDS,
|
||||
}
|
||||
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
"name": constants.DEFAULT_CONTAINER_NAME,
|
||||
"parameter_defaults": _EXISTING_PASSWORDS,
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_get_orchestration_client.return_value = mock_orchestration
|
||||
@ -507,24 +523,22 @@ class GetPasswordsActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_password_from_generated_passwords(self,
|
||||
mock_get_workflow_client,
|
||||
mock_get_object_client,
|
||||
mock_get_orchestration_client):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
|
||||
mock_env.variables = {
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
"name": constants.DEFAULT_CONTAINER_NAME,
|
||||
"parameter_defaults": {},
|
||||
"passwords": _EXISTING_PASSWORDS,
|
||||
}
|
||||
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_get_orchestration_client.return_value = mock_orchestration
|
||||
@ -537,26 +551,25 @@ class GetPasswordsActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_password_merging_passwords(self,
|
||||
mock_get_workflow_client,
|
||||
mock_get_object_client,
|
||||
mock_get_orchestration_client):
|
||||
|
||||
parameter_defaults = _EXISTING_PASSWORDS.copy()
|
||||
passwords = {"AdminPassword": parameter_defaults.pop("AdminPassword")}
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.name = constants.DEFAULT_CONTAINER_NAME
|
||||
mock_env.variables = {
|
||||
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
mock_env = yaml.safe_dump({
|
||||
"name": constants.DEFAULT_CONTAINER_NAME,
|
||||
"parameter_defaults": parameter_defaults,
|
||||
"passwords": passwords
|
||||
}
|
||||
}, default_flow_style=False)
|
||||
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
swift.get_object.return_value = ({}, mock_env)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_orchestration = mock.MagicMock()
|
||||
mock_get_orchestration_client.return_value = mock_orchestration
|
||||
@ -570,19 +583,13 @@ class GetPasswordsActionTest(base.TestCase):
|
||||
|
||||
class GenerateFencingParametersActionTestCase(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.'
|
||||
'generate_hostmap')
|
||||
@mock.patch('tripleo_common.utils.nodes.generate_hostmap')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_baremetal_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_success(self, mock_get_orchestration,
|
||||
mock_get_workflow, mock_get_baremetal,
|
||||
mock_get_compute, mock_generate_hostmap):
|
||||
def test_no_success(self, mock_get_baremetal, mock_get_compute,
|
||||
mock_generate_hostmap):
|
||||
mock_ctx = mock.MagicMock()
|
||||
test_hostmap = {
|
||||
"00:11:22:33:44:55": {
|
||||
@ -678,35 +685,37 @@ class GenerateFencingParametersActionTestCase(base.TestCase):
|
||||
|
||||
class GetFlattenedParametersActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_set')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_get')
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_empty_resource_tree(self, mock_get_object_client,
|
||||
mock_get_workflow_client,
|
||||
mock_get_orchestration_client,
|
||||
mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files):
|
||||
mock_process_multiple_environments_and_files,
|
||||
mock_cache_get,
|
||||
mock_cache_set):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_cache_get.return_value = None
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
mock_env = yaml.safe_dump({
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2'),
|
||||
({}, mock_env)
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
@ -720,7 +729,7 @@ class GetFlattenedParametersActionTest(base.TestCase):
|
||||
|
||||
expected_value = {
|
||||
'heat_resource_tree': {},
|
||||
'mistral_environment_parameters': None,
|
||||
'environment_parameters': None,
|
||||
}
|
||||
|
||||
# Test
|
||||
@ -734,37 +743,39 @@ class GetFlattenedParametersActionTest(base.TestCase):
|
||||
)
|
||||
self.assertEqual(result, expected_value)
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_set')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'cache_get')
|
||||
@mock.patch('uuid.uuid4', side_effect=['1', '2'])
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_valid_resource_tree(self, mock_get_object_client,
|
||||
mock_get_workflow_client,
|
||||
mock_get_orchestration_client,
|
||||
mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files,
|
||||
mock_uuid):
|
||||
mock_uuid,
|
||||
mock_cache_get,
|
||||
mock_cache_set):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_cache_get.return_value = None
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
mock_env = yaml.safe_dump({
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2'),
|
||||
({}, mock_env)
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
@ -816,7 +827,7 @@ class GetFlattenedParametersActionTest(base.TestCase):
|
||||
}
|
||||
},
|
||||
},
|
||||
'mistral_environment_parameters': None,
|
||||
'environment_parameters': None,
|
||||
}
|
||||
|
||||
# Test
|
||||
|
@ -12,40 +12,19 @@
|
||||
# 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 json
|
||||
import mock
|
||||
|
||||
from heatclient import exc as heatexceptions
|
||||
from mistral.workflow import utils as mistral_workflow_utils
|
||||
from mistralclient.api import base as mistral_base
|
||||
from oslo_concurrency import processutils
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.actions import plan
|
||||
from tripleo_common import constants
|
||||
from tripleo_common import exception
|
||||
from tripleo_common.tests import base
|
||||
|
||||
JSON_CONTENTS = json.dumps({
|
||||
"environments": [{
|
||||
"path": "overcloud-resource-registry-puppet.yaml"
|
||||
}, {
|
||||
"path": "environments/services/sahara.yaml"
|
||||
}],
|
||||
"parameter_defaults": {
|
||||
"BlockStorageCount": 42,
|
||||
"OvercloudControlFlavor": "yummy"
|
||||
},
|
||||
"passwords": {
|
||||
"AdminPassword": "aaaa",
|
||||
"ZaqarPassword": "zzzz"
|
||||
},
|
||||
"template": "overcloud.yaml",
|
||||
"version": 1.0
|
||||
}, sort_keys=True)
|
||||
|
||||
|
||||
YAML_CONTENTS = """
|
||||
ENV_YAML_CONTENTS = """
|
||||
version: 1.0
|
||||
|
||||
template: overcloud.yaml
|
||||
@ -60,13 +39,6 @@ passwords:
|
||||
ZaqarPassword: zzzz
|
||||
"""
|
||||
|
||||
YAML_CONTENTS_INVALID = "{bad_yaml"
|
||||
|
||||
# `environments` is missing
|
||||
YAML_CONTENTS_MISSING_KEY = """
|
||||
template: overcloud.yaml
|
||||
"""
|
||||
|
||||
RESOURCES_YAML_CONTENTS = """heat_template_version: 2016-04-08
|
||||
resources:
|
||||
Controller:
|
||||
@ -160,197 +132,6 @@ class CreateContainerActionTest(base.TestCase):
|
||||
None, error_str))
|
||||
|
||||
|
||||
class CreatePlanActionTest(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CreatePlanActionTest, self).setUp()
|
||||
# A container that name enforces all validation rules
|
||||
self.container_name = 'Test-container-3'
|
||||
self.plan_environment_name = constants.PLAN_ENVIRONMENT
|
||||
|
||||
# setup swift
|
||||
self.swift = mock.MagicMock()
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS)
|
||||
swift_patcher = mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_object_client',
|
||||
return_value=self.swift)
|
||||
swift_patcher.start()
|
||||
self.addCleanup(swift_patcher.stop)
|
||||
|
||||
# setup mistral
|
||||
self.mistral = mock.MagicMock()
|
||||
self.mistral.environments.get.side_effect = mistral_base.APIException
|
||||
mistral_patcher = mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client',
|
||||
return_value=self.mistral)
|
||||
mistral_patcher.start()
|
||||
self.addCleanup(mistral_patcher.stop)
|
||||
self.ctx = mock.MagicMock()
|
||||
|
||||
def test_run_success(self):
|
||||
action = plan.CreatePlanAction(self.container_name)
|
||||
action.run(self.ctx)
|
||||
|
||||
self.swift.get_object.assert_called_once_with(
|
||||
self.container_name,
|
||||
self.plan_environment_name
|
||||
)
|
||||
|
||||
self.swift.delete_object.assert_called_once()
|
||||
|
||||
self.mistral.environments.create.assert_called_once_with(
|
||||
name='Test-container-3',
|
||||
variables=JSON_CONTENTS
|
||||
)
|
||||
|
||||
def test_run_invalid_plan_name(self):
|
||||
action = plan.CreatePlanAction("invalid_underscore")
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ("Unable to create plan. The plan name must only contain "
|
||||
"letters, numbers or dashes")
|
||||
# don't bother checking the exact error (python versions different)
|
||||
self.assertEqual(result.error.split(':')[0], error_str)
|
||||
|
||||
def test_run_mistral_env_already_exists(self):
|
||||
self.mistral.environments.get.side_effect = None
|
||||
self.mistral.environments.get.return_value = 'test-env'
|
||||
|
||||
action = plan.CreatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ("Unable to create plan. The Mistral environment already "
|
||||
"exists")
|
||||
self.assertEqual(result.error, error_str)
|
||||
self.mistral.environments.create.assert_not_called()
|
||||
|
||||
def test_run_missing_file(self):
|
||||
self.swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
self.plan_environment_name)
|
||||
|
||||
action = plan.CreatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ('File missing from container: %s' %
|
||||
self.plan_environment_name)
|
||||
self.assertEqual(result.error, error_str)
|
||||
|
||||
def test_run_invalid_yaml(self):
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS_INVALID)
|
||||
|
||||
action = plan.CreatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = 'Error parsing the yaml file'
|
||||
self.assertEqual(result.error.split(':')[0], error_str)
|
||||
|
||||
def test_run_missing_key(self):
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS_MISSING_KEY)
|
||||
|
||||
action = plan.CreatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ("%s missing key: environments" %
|
||||
self.plan_environment_name)
|
||||
self.assertEqual(result.error, error_str)
|
||||
|
||||
|
||||
class UpdatePlanActionTest(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(UpdatePlanActionTest, self).setUp()
|
||||
self.container_name = 'Test-container-3'
|
||||
self.plan_environment_name = constants.PLAN_ENVIRONMENT
|
||||
|
||||
# setup swift
|
||||
self.swift = mock.MagicMock()
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS)
|
||||
swift_patcher = mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_object_client',
|
||||
return_value=self.swift)
|
||||
swift_patcher.start()
|
||||
self.addCleanup(swift_patcher.stop)
|
||||
|
||||
# setup mistral
|
||||
self.mistral = mock.MagicMock()
|
||||
mistral_patcher = mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client',
|
||||
return_value=self.mistral)
|
||||
mistral_patcher.start()
|
||||
self.addCleanup(mistral_patcher.stop)
|
||||
self.ctx = mock.MagicMock()
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.cache_delete')
|
||||
def test_run_success(self, mock_cache):
|
||||
action = plan.UpdatePlanAction(self.container_name)
|
||||
action.run(self.ctx)
|
||||
|
||||
self.swift.get_object.assert_called_once_with(
|
||||
self.container_name,
|
||||
self.plan_environment_name
|
||||
)
|
||||
|
||||
self.swift.delete_object.assert_called_once()
|
||||
mock_cache.assert_called_once_with(
|
||||
self.ctx,
|
||||
"Test-container-3",
|
||||
"tripleo.parameters.get"
|
||||
)
|
||||
|
||||
self.mistral.environments.update.assert_called_once_with(
|
||||
name='Test-container-3',
|
||||
variables=JSON_CONTENTS
|
||||
)
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.cache_delete')
|
||||
def test_run_mistral_env_missing(self, mock_cache):
|
||||
self.mistral.environments.update.side_effect = (
|
||||
mistral_base.APIException)
|
||||
|
||||
action = plan.UpdatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ("Error updating mistral environment: %s" %
|
||||
self.container_name)
|
||||
self.assertEqual(result.error, error_str)
|
||||
self.swift.delete_object.assert_not_called()
|
||||
mock_cache.assert_called_once_with(
|
||||
self.ctx,
|
||||
"Test-container-3",
|
||||
"tripleo.parameters.get"
|
||||
)
|
||||
|
||||
def test_run_missing_file(self):
|
||||
self.swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
self.plan_environment_name)
|
||||
|
||||
action = plan.UpdatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ('File missing from container: %s' %
|
||||
self.plan_environment_name)
|
||||
self.assertEqual(result.error, error_str)
|
||||
|
||||
def test_run_invalid_yaml(self):
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS_INVALID)
|
||||
|
||||
action = plan.UpdatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = 'Error parsing the yaml file'
|
||||
self.assertEqual(result.error.split(':')[0], error_str)
|
||||
|
||||
def test_run_missing_key(self):
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS_MISSING_KEY)
|
||||
|
||||
action = plan.UpdatePlanAction(self.container_name)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error_str = ("%s missing key: environments" %
|
||||
self.plan_environment_name)
|
||||
self.assertEqual(result.error, error_str)
|
||||
|
||||
|
||||
class ListPlansActionTest(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@ -359,9 +140,7 @@ class ListPlansActionTest(base.TestCase):
|
||||
self.ctx = mock.MagicMock()
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run(self, get_workflow_client_mock, get_obj_client_mock):
|
||||
def test_run(self, get_obj_client_mock):
|
||||
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
@ -377,13 +156,6 @@ class ListPlansActionTest(base.TestCase):
|
||||
}, [])
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
env_item = mock.Mock()
|
||||
env_item.name = self.container
|
||||
mistral.environments.list.return_value = [env_item]
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
|
||||
# Test
|
||||
action = plan.ListPlansAction()
|
||||
action.run(self.ctx)
|
||||
@ -423,10 +195,7 @@ class DeletePlanActionTest(base.TestCase):
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_orchestration_client')
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client')
|
||||
def test_run(self, get_workflow_client_mock, get_orchestration_client,
|
||||
get_obj_client_mock):
|
||||
def test_run(self, get_orchestration_client, get_obj_client_mock):
|
||||
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
@ -445,15 +214,6 @@ class DeletePlanActionTest(base.TestCase):
|
||||
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# setup mistral
|
||||
mistral = mock.MagicMock()
|
||||
mistral_environment = mock.Mock()
|
||||
mistral_environment.name = self.container_name
|
||||
mistral.environments.list.return_value = [
|
||||
mistral_environment,
|
||||
]
|
||||
get_workflow_client_mock.return_value = mistral
|
||||
|
||||
# setup heat
|
||||
heat = mock.MagicMock()
|
||||
heat.stacks.get = mock.Mock(
|
||||
@ -474,8 +234,6 @@ class DeletePlanActionTest(base.TestCase):
|
||||
|
||||
swift.delete_container.assert_called_with(self.container_name)
|
||||
|
||||
mistral.environments.delete.assert_called_with(self.container_name)
|
||||
|
||||
|
||||
class RoleListActionTest(base.TestCase):
|
||||
|
||||
@ -486,7 +244,6 @@ class RoleListActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, get_obj_client_mock):
|
||||
|
||||
# setup swift
|
||||
swift = mock.MagicMock()
|
||||
swift.get_object.return_value = ({}, ROLES_DATA_YAML_CONTENTS)
|
||||
@ -542,21 +299,6 @@ class ExportPlanActionTest(base.TestCase):
|
||||
swift_patcher.start()
|
||||
self.addCleanup(swift_patcher.stop)
|
||||
|
||||
# setup mistral
|
||||
self.mistral = mock.MagicMock()
|
||||
env_item = mock.Mock()
|
||||
env_item.variables = {
|
||||
'template': 'overcloud.yaml',
|
||||
'environments': [
|
||||
{'path': 'overcloud-resource-registry-puppet.yaml'}
|
||||
]
|
||||
}
|
||||
self.mistral.environments.get.return_value = env_item
|
||||
mistral_patcher = mock.patch(
|
||||
'tripleo_common.actions.base.TripleOAction.get_workflow_client',
|
||||
return_value=self.mistral)
|
||||
mistral_patcher.start()
|
||||
self.addCleanup(mistral_patcher.stop)
|
||||
self.ctx = mock.MagicMock()
|
||||
|
||||
@mock.patch('tripleo_common.utils.tarball.create_tarball')
|
||||
@ -578,7 +320,6 @@ class ExportPlanActionTest(base.TestCase):
|
||||
self.swift.get_container.assert_has_calls(get_container_mock_calls)
|
||||
self.swift.get_object.assert_has_calls(
|
||||
get_object_mock_calls, any_order=True)
|
||||
self.mistral.environments.get.assert_called_once_with(self.plan)
|
||||
self.swift.put_object.assert_called_once()
|
||||
mock_create_tarball.assert_called_once()
|
||||
|
||||
@ -593,16 +334,6 @@ class ExportPlanActionTest(base.TestCase):
|
||||
error = "Error attempting an operation on container: %s" % self.plan
|
||||
self.assertIn(error, result.error)
|
||||
|
||||
def test_run_environment_does_not_exist(self):
|
||||
self.mistral.environments.get.side_effect = mistral_base.APIException
|
||||
|
||||
action = plan.ExportPlanAction(self.plan, self.delete_after,
|
||||
self.exports_container)
|
||||
result = action.run(self.ctx)
|
||||
|
||||
error = "The Mistral environment %s could not be found." % self.plan
|
||||
self.assertEqual(error, result.error)
|
||||
|
||||
@mock.patch('tripleo_common.utils.tarball.create_tarball')
|
||||
def test_run_error_creating_tarball(self, mock_create_tarball):
|
||||
mock_create_tarball.side_effect = processutils.ProcessExecutionError
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
import collections
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
@ -47,13 +48,10 @@ class ScaleDownActionTest(base.TestCase):
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client,
|
||||
mock_get_workflow_client, mock_get_template_contents,
|
||||
mock_env_files, mock_get_heat_client,
|
||||
mock_cache):
|
||||
mock_get_template_contents, mock_env_files,
|
||||
mock_get_heat_client, mock_cache):
|
||||
|
||||
mock_env_files.return_value = ({}, {})
|
||||
heatclient = mock.MagicMock()
|
||||
@ -85,8 +83,17 @@ class ScaleDownActionTest(base.TestCase):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_env = yaml.safe_dump({
|
||||
'name': 'overcloud',
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2')
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
env = {
|
||||
@ -95,16 +102,6 @@ class ScaleDownActionTest(base.TestCase):
|
||||
}
|
||||
}
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
})
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
import jinja2
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
@ -188,28 +189,23 @@ class ProcessTemplatesActionTest(base.TestCase):
|
||||
@mock.patch('heatclient.common.template_utils.'
|
||||
'process_multiple_environments_and_files')
|
||||
@mock.patch('heatclient.common.template_utils.get_template_contents')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_run(self, mock_get_object_client,
|
||||
mock_get_workflow_client, mock_get_template_contents,
|
||||
mock_get_template_contents,
|
||||
mock_process_multiple_environments_and_files):
|
||||
|
||||
mock_ctx = mock.MagicMock()
|
||||
swift = mock.MagicMock(url="http://test.com")
|
||||
swift.get_object.side_effect = swiftexceptions.ClientException(
|
||||
'atest2')
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_mistral = mock.MagicMock()
|
||||
mock_env = mock.MagicMock()
|
||||
mock_env.variables = {
|
||||
mock_env = yaml.safe_dump({
|
||||
'temp_environment': 'temp_environment',
|
||||
'template': 'template',
|
||||
'environments': [{u'path': u'environments/test.yaml'}],
|
||||
}
|
||||
mock_mistral.environments.get.return_value = mock_env
|
||||
mock_get_workflow_client.return_value = mock_mistral
|
||||
'environments': [{u'path': u'environments/test.yaml'}]
|
||||
}, default_flow_style=False)
|
||||
swift.get_object.side_effect = (
|
||||
({}, mock_env),
|
||||
swiftexceptions.ClientException('atest2')
|
||||
)
|
||||
mock_get_object_client.return_value = swift
|
||||
|
||||
mock_get_template_contents.return_value = ({}, {
|
||||
'heat_template_version': '2016-04-30'
|
||||
|
92
tripleo_common/tests/utils/test_plan.py
Normal file
92
tripleo_common/tests/utils/test_plan.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2017 Red Hat, Inc.
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common.tests import base
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
|
||||
|
||||
YAML_CONTENTS = """
|
||||
version: 1.0
|
||||
|
||||
name: overcloud
|
||||
template: overcloud.yaml
|
||||
environments:
|
||||
- path: overcloud-resource-registry-puppet.yaml
|
||||
- path: environments/services/sahara.yaml
|
||||
parameter_defaults:
|
||||
BlockStorageCount: 42
|
||||
OvercloudControlFlavor: yummy
|
||||
passwords:
|
||||
AdminPassword: aaaa
|
||||
ZaqarPassword: zzzz
|
||||
"""
|
||||
|
||||
|
||||
class PlanTest(base.TestCase):
|
||||
def setUp(self):
|
||||
super(PlanTest, self).setUp()
|
||||
self.container = 'overcloud'
|
||||
self.swift = mock.MagicMock()
|
||||
self.swift.get_object.return_value = ({}, YAML_CONTENTS)
|
||||
|
||||
def test_get_env(self):
|
||||
env = plan_utils.get_env(self.swift, self.container)
|
||||
|
||||
self.swift.get_object.assert_called()
|
||||
self.assertEqual(env['template'], 'overcloud.yaml')
|
||||
|
||||
def test_get_env_not_found(self):
|
||||
self.swift.get_object.side_effect = swiftexceptions.ClientException
|
||||
|
||||
self. assertRaises(Exception, plan_utils.get_env, self.swift,
|
||||
self.container)
|
||||
|
||||
def test_update_in_env(self):
|
||||
env = plan_utils.get_env(self.swift, self.container)
|
||||
|
||||
updated_env = plan_utils.update_in_env(
|
||||
self.swift,
|
||||
env,
|
||||
'template',
|
||||
'updated-overcloud.yaml'
|
||||
)
|
||||
self.assertEqual(updated_env['template'], 'updated-overcloud.yaml')
|
||||
|
||||
updated_env = plan_utils.update_in_env(
|
||||
self.swift,
|
||||
env,
|
||||
'parameter_defaults',
|
||||
{'another-key': 'another-value'}
|
||||
)
|
||||
self.assertEqual(updated_env['parameter_defaults'], {
|
||||
'BlockStorageCount': 42,
|
||||
'OvercloudControlFlavor': 'yummy',
|
||||
'another-key': 'another-value'
|
||||
})
|
||||
|
||||
updated_env = plan_utils.update_in_env(
|
||||
self.swift,
|
||||
env,
|
||||
'parameter_defaults',
|
||||
delete_key=True
|
||||
)
|
||||
self.assertNotIn('parameter_defaults', updated_env)
|
||||
|
||||
self.swift.get_object.assert_called()
|
||||
self.swift.put_object.assert_called()
|
58
tripleo_common/utils/plan.py
Normal file
58
tripleo_common/utils/plan.py
Normal file
@ -0,0 +1,58 @@
|
||||
# Copyright 2017 Red Hat, Inc.
|
||||
# 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 yaml
|
||||
|
||||
from tripleo_common import constants
|
||||
|
||||
|
||||
def update_in_env(swift, env, key, value='', delete_key=False):
|
||||
"""Update plan environment."""
|
||||
if delete_key:
|
||||
try:
|
||||
del env[key]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
env[key].update(value)
|
||||
except (KeyError, AttributeError):
|
||||
env[key] = value
|
||||
|
||||
put_env(swift, env)
|
||||
return env
|
||||
|
||||
|
||||
def get_env(swift, name):
|
||||
"""Get plan environment from Swift and convert it to a dictionary."""
|
||||
env = yaml.safe_load(
|
||||
swift.get_object(name, constants.PLAN_ENVIRONMENT)[1]
|
||||
)
|
||||
|
||||
# Ensure the name is correct, as it will be used to update the
|
||||
# container later
|
||||
if env.get('name') != name:
|
||||
env['name'] = name
|
||||
|
||||
return env
|
||||
|
||||
|
||||
def put_env(swift, env):
|
||||
"""Convert given environment to yaml and upload it to Swift."""
|
||||
swift.put_object(
|
||||
env['name'],
|
||||
constants.PLAN_ENVIRONMENT,
|
||||
yaml.safe_dump(env, default_flow_style=False)
|
||||
)
|
@ -68,7 +68,7 @@ workflows:
|
||||
description: >
|
||||
If using the default templates or importing templates from a git
|
||||
repository, a new container needs to be created. If using an existing
|
||||
container containing templates, skip straight to create_plan
|
||||
container containing templates, skip straight to create_plan.
|
||||
on-success:
|
||||
- verify_container_doesnt_exist: <% $.use_default_templates or $.source_url %>
|
||||
- create_plan: <% $.use_default_templates = false and $.source_url = null %>
|
||||
@ -76,18 +76,10 @@ workflows:
|
||||
verify_container_doesnt_exist:
|
||||
action: swift.head_container container=<% $.container %>
|
||||
on-success: notify_zaqar
|
||||
on-error: verify_environment_doesnt_exist
|
||||
publish:
|
||||
status: FAILED
|
||||
message: "Unable to create plan. The Swift container already exists"
|
||||
|
||||
verify_environment_doesnt_exist:
|
||||
action: mistral.environments_get name=<% $.container %>
|
||||
on-success: notify_zaqar
|
||||
on-error: create_container
|
||||
publish:
|
||||
status: FAILED
|
||||
message: "Unable to create plan. The Mistral environment already exists"
|
||||
message: "Unable to create plan. The Swift container already exists"
|
||||
|
||||
create_container:
|
||||
action: tripleo.plan.create_container container=<% $.container %>
|
||||
@ -119,11 +111,15 @@ workflows:
|
||||
on-error: upload_to_container_set_status_failed
|
||||
|
||||
create_plan:
|
||||
action: tripleo.plan.create container=<% $.container %>
|
||||
description: >
|
||||
Migrate the plan if needed, then continue with the workflow.
|
||||
TODO(jpichon) - In Queens, the tripleo.plan.migrate action and on_error will
|
||||
be removed, but the on-success will still be needed.
|
||||
action: tripleo.plan.migrate plan=<% $.container %>
|
||||
on-success:
|
||||
- ensure_passwords_exist: <% $.generate_passwords = true %>
|
||||
- process_templates: <% $.generate_passwords != true %>
|
||||
on-error: create_plan_set_status_failed
|
||||
on-error: migrate_plan_set_status_failed
|
||||
|
||||
ensure_passwords_exist:
|
||||
action: tripleo.parameters.generate_passwords container=<% $.container %>
|
||||
@ -139,7 +135,7 @@ workflows:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: SUCCESS
|
||||
message: <% task(create_plan).result %>
|
||||
message: 'Plan created.'
|
||||
|
||||
create_container_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
@ -165,12 +161,6 @@ workflows:
|
||||
status: FAILED
|
||||
message: <% task(upload_default_templates).result %>
|
||||
|
||||
create_plan_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(create_plan).result %>
|
||||
|
||||
ensure_passwords_exist_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
@ -183,6 +173,12 @@ workflows:
|
||||
status: FAILED
|
||||
message: <% task(process_templates).result %>
|
||||
|
||||
migrate_plan_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(create_plan).result %>
|
||||
|
||||
notify_zaqar:
|
||||
action: zaqar.queue_post
|
||||
retry: count=5 delay=1
|
||||
@ -225,27 +221,31 @@ workflows:
|
||||
action: tripleo.git.clean container=<% $.container %>
|
||||
|
||||
update_plan:
|
||||
action: tripleo.plan.update container=<% $.container %>
|
||||
description: >
|
||||
Migrate the plan if needed, then continue with the workflow.
|
||||
TODO(jpichon) - In Queens, the tripleo.plan.migrate action and on_error will
|
||||
be removed, but the on-success will still be needed.
|
||||
action: tripleo.plan.migrate plan=<% $.container %>
|
||||
on-success:
|
||||
- ensure_passwords_exist: <% $.generate_passwords = true %>
|
||||
- process_templates: <% $.generate_passwords != true %>
|
||||
on-error: update_plan_set_status_failed
|
||||
|
||||
process_templates:
|
||||
action: tripleo.templates.process container=<% $.container %>
|
||||
on-success: set_status_success
|
||||
on-error: process_templates_set_status_failed
|
||||
on-error: migrate_plan_set_status_failed
|
||||
|
||||
ensure_passwords_exist:
|
||||
action: tripleo.parameters.generate_passwords container=<% $.container %>
|
||||
on-success: process_templates
|
||||
on-error: ensure_passwords_exist_set_status_failed
|
||||
|
||||
process_templates:
|
||||
action: tripleo.templates.process container=<% $.container %>
|
||||
on-success: set_status_success
|
||||
on-error: process_templates_set_status_failed
|
||||
|
||||
set_status_success:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: SUCCESS
|
||||
message: <% task(update_plan).result %>
|
||||
message: 'Plan updated.'
|
||||
|
||||
clone_git_repo_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
@ -259,12 +259,6 @@ workflows:
|
||||
status: FAILED
|
||||
message: <% task(upload_templates_directory).result %>
|
||||
|
||||
update_plan_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(update_plan).result %>
|
||||
|
||||
process_templates_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
@ -277,6 +271,12 @@ workflows:
|
||||
status: FAILED
|
||||
message: <% task(ensure_passwords_exist).result %>
|
||||
|
||||
migrate_plan_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(update_plan).result %>
|
||||
|
||||
notify_zaqar:
|
||||
action: zaqar.queue_post
|
||||
retry: count=5 delay=1
|
||||
@ -302,15 +302,10 @@ workflows:
|
||||
|
||||
verify_container_exists:
|
||||
action: swift.head_container container=<% $.container %>
|
||||
on-success: verify_environment_exists
|
||||
on-success: get_environment_passwords
|
||||
on-error: verify_container_set_status_failed
|
||||
|
||||
verify_environment_exists:
|
||||
action: mistral.environments_get name=<% $.container %>
|
||||
on-success: get_environement_passwords
|
||||
on-error: verify_environment_set_status_failed
|
||||
|
||||
get_environement_passwords:
|
||||
get_environment_passwords:
|
||||
action: tripleo.parameters.get_passwords container=<% $.container %>
|
||||
on-success: get_passwords_set_status_success
|
||||
on-error: get_passwords_set_status_failed
|
||||
@ -319,13 +314,13 @@ workflows:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: SUCCESS
|
||||
message: <% task(get_environement_passwords).result %>
|
||||
message: <% task(get_environment_passwords).result %>
|
||||
|
||||
get_passwords_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(get_environement_passwords).result %>
|
||||
message: <% task(get_environment_passwords).result %>
|
||||
|
||||
verify_container_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
@ -333,12 +328,6 @@ workflows:
|
||||
status: FAILED
|
||||
message: <% task(verify_container_exists).result %>
|
||||
|
||||
verify_environment_set_status_failed:
|
||||
on-success: notify_zaqar
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(verify_environment_exists).result %>
|
||||
|
||||
notify_zaqar:
|
||||
action: zaqar.queue_post
|
||||
input:
|
||||
|
Loading…
x
Reference in New Issue
Block a user