From b1c02fbca16efb3353103f3056021a299f32f4ac Mon Sep 17 00:00:00 2001 From: abregman Date: Sun, 11 Nov 2018 14:29:29 +0200 Subject: [PATCH] Add a utility for setting up resources Without running the tests. This should be useful in case one wants to test the templates he/she adds to Tobiko but not run the tests themselves. Modified common modules (exceptions and stack manager) accordingly. Change-Id: I17456b998ba916935a15366d68589d7ce6cb0a43 --- tobiko/cmd/__init__.py | 13 ++++++ tobiko/cmd/base.py | 30 +++++++++++++ tobiko/cmd/create.py | 74 +++++++++++++++++++++++++++++++++ tobiko/common/exceptions.py | 20 +++++++-- tobiko/common/managers/stack.py | 28 ++++++++++--- 5 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 tobiko/cmd/__init__.py create mode 100644 tobiko/cmd/base.py create mode 100644 tobiko/cmd/create.py diff --git a/tobiko/cmd/__init__.py b/tobiko/cmd/__init__.py new file mode 100644 index 000000000..953c24a79 --- /dev/null +++ b/tobiko/cmd/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 Red Hat +# +# 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. diff --git a/tobiko/cmd/base.py b/tobiko/cmd/base.py new file mode 100644 index 000000000..504542adf --- /dev/null +++ b/tobiko/cmd/base.py @@ -0,0 +1,30 @@ +# Copyright (c) 2018 Red Hat +# 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 os + +from tobiko.common import clients +from tobiko.common.managers import stack + + +class TobikoCMD(object): + """Manages different command line utilities.""" + + def __init__(self): + self.clientManager = clients.ClientManager(use_os=True) + curr_dir = os.path.dirname(__file__) + self.templates_dir = os.path.join(curr_dir, + "../tests/scenario/templates") + self.stackManager = stack.StackManager(self.clientManager, + self.templates_dir) diff --git a/tobiko/cmd/create.py b/tobiko/cmd/create.py new file mode 100644 index 000000000..086d7a500 --- /dev/null +++ b/tobiko/cmd/create.py @@ -0,0 +1,74 @@ +# Copyright 2018 Red Hat +# +# 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 argparse +import logging +import sys +import urllib2 + +from tobiko.cmd import base +from tobiko.common import constants +from tobiko.common import exceptions as exc + +LOG = logging.getLogger(__name__) + + +class CreateUtil(base.TobikoCMD): + + def __init__(self): + super(CreateUtil, self).__init__() + self.parser = self.get_parser() + self.args = (self.parser).parse_args() + + def get_parser(self): + parser = argparse.ArgumentParser(add_help=True) + parser.add_argument( + '--stack', '-s', + help="The name of the stack to create.\n" + "This is based on the template name in templates dir") + parser.add_argument( + '--all', '-a', action='store_true', dest='all', + help="Create all the stacks defined in Tobiko.") + return parser + + def create_stack(self, stack_name=None, all_stacks=False): + """Creates a stack based on given arguments.""" + if all_stacks: + templates = self.stackManager.get_templates_names() + for template in templates: + stack_name = template.split(constants.TEMPLATE_SUFFIX)[0] + self.stackManager.create_stack( + stack_name, template, parameters=constants.DEFAULT_PARAMS) + LOG.info("Created stack: %s" % stack_name) + else: + try: + self.stackManager.create_stack( + stack_name, ''.join([stack_name, + constants.TEMPLATE_SUFFIX]), + parameters=constants.DEFAULT_PARAMS) + LOG.info("Created stack: %s" % stack_name) + except urllib2.URLError: + stacks = self.stackManager.get_templates_names( + strip_suffix=True) + raise exc.MissingTemplateException(templates="\n".join(stacks)) + + +def main(): + """Create CLI main entry.""" + create_cmd = CreateUtil() + create_cmd.create_stack(create_cmd.args.stack, + create_cmd.args.all) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tobiko/common/exceptions.py b/tobiko/common/exceptions.py index 18ffd8731..3cbb4168e 100644 --- a/tobiko/common/exceptions.py +++ b/tobiko/common/exceptions.py @@ -21,10 +21,20 @@ class TobikoException(Exception): message = "An unknown exception occurred." def __init__(self, *args, **kwargs): + super(TobikoException, self).__init__() + try: + self._message = self.message % kwargs + + except Exception: + self._message = self.message + if len(args) > 0: - self.message = args[0] - super(TobikoException, self).__init__(self.message % kwargs) - self.msg = self.message % kwargs + args = ["%s" % arg for arg in args] + self._messsage = (self._message + + "\nDetails: %s" % '\n'.join(args)) + + def __str__(self): + return self._message class PingException(TobikoException): @@ -33,3 +43,7 @@ class PingException(TobikoException): class MissingInputException(TobikoException): message = "No %(input)s was provided" + + +class MissingTemplateException(TobikoException): + message = "No such template. Existing templates:\n%(templates)s" diff --git a/tobiko/common/managers/stack.py b/tobiko/common/managers/stack.py index 0718460b1..676e0578c 100644 --- a/tobiko/common/managers/stack.py +++ b/tobiko/common/managers/stack.py @@ -19,6 +19,7 @@ from heatclient import exc as heat_exc import yaml from tobiko.common import constants +from tobiko.common import exceptions as exc class StackManager(object): @@ -67,12 +68,6 @@ class StackManager(object): time.sleep(self.wait_interval) res = self.client.resources.get(stack_id, resource_name) - def get_output(self, stack_name, index=0): - """Returns the output from the given stack by using the given index.""" - stack = self.get_stack(stack_name=stack_name) - output = stack.outputs[index]['output_value'] - return output - def wait_for_stack_status(self, stack_name, status=constants.COMPLETE_STATUS): """Waits for the stack to reach the given status.""" @@ -80,3 +75,24 @@ class StackManager(object): while (stack.stack_status != status): time.sleep(self.wait_interval) stack = self.get_stack(stack_name=stack_name) + + def get_output(self, stack, key): + """Returns a specific value from stack outputs by using a given key.""" + value = None + for output in stack.outputs: + if output['output_key'] == key: + value = output['output_value'] + if not value: + raise exc.NoSuchKey(key) + else: + return value + + def get_templates_names(self, strip_suffix=False): + """Returns a list of all the files in templates dir.""" + templates = [] + for (path, folders, files) in os.walk(self.templates_dir): + templates.extend(files) + if strip_suffix: + templates = [ + f[:-len(constants.TEMPLATE_SUFFIX)] for f in templates] + return templates