def test_render_bash_options(self): """Testing rendering Bash options.""" bash = Bash(ShellConfig(script='''echo "hello"''')) assert_that(bash.render_bash_options(), equal_to('')) bash = Bash(ShellConfig(script='''echo "hello"''', debug=True)) assert_that(bash.render_bash_options(), equal_to('set -x\n')) bash = Bash(ShellConfig(script='''echo "hello"''', strict=True)) assert_that(bash.render_bash_options(), equal_to('set -euo pipefail\n'))
def test_internal_flag(self): """Testing simple bash script with internal flag.""" bash = Bash(ShellConfig(script='''echo "hello"''', internal=True)) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('hello')) bash = Bash( ShellConfig(script='''echo "hello"''', internal=True, dry_run=True)) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(2)) assert_that(output[0], equal_to('#!/bin/bash')) assert_that(output[1], equal_to('echo "hello"'))
def test_get_temporary_scripts_path(self): """Testing temporary scripts path.""" bash = Bash( ShellConfig(script='''echo "hello"''', temporary_scripts_path='/tmp')) assert_that(bash.get_temporary_scripts_path(), equal_to('/tmp')) bash = Bash( ShellConfig(script='''echo "hello"''', temporary_scripts_path='')) assert_that(bash.get_temporary_scripts_path(), equal_to(None)) bash = Bash( ShellConfig(script='''echo "hello"''', temporary_scripts_path='/tmp/does-not-exist')) assert_that(bash.get_temporary_scripts_path(), equal_to(None))
def test_undefined_parameter(self): """Testing undefined parameter.""" try: ShellConfig(script='echo "hello world"', XYZ='foo and bar') self.assertFalse("RuntimeError expected") except RuntimeError as exception: assert_that(str(exception), contains_string("Wrong keys 'XYZ'"))
def test_missing_mandatory(self): """Testing invalid parameter.""" try: ShellConfig() self.assertFalse("RuntimeError expected") except RuntimeError as exception: assert_that(str(exception), equal_to("Missing keys: 'script'"))
def cleanup(name, tag): """Removing Docker image.""" shell = Bash(ShellConfig(script="docker rmi %s:%s" % (name, tag))) for line in shell.process(): logging.info(line) assert_that(shell.success, equal_to(True))
def test_render_error(self): """Testing error in jinja2 rendering.""" bash = Bash(ShellConfig(script='''echo "{{ foo.bar }}"''')) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(0)) assert_that(bash.success, equal_to(False)) assert_that(bash.exit_code, equal_to(0))
def test_dry_run(self): """Testing simple bash script in dry run mode.""" bash = Bash(ShellConfig(script='''echo "hello"''', dry_run=True)) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(2)) assert_that(output[0], equal_to('''#!/bin/bash''')) assert_that(output[1], equal_to('''echo "hello"'''))
def test_python(self): """Testing using Python.""" config = ShellConfig(script='''print("name={{model.name}}, version={{env.version}}")''', title='test python', model={'name': 'test'}, env={'version': '1.0'}) script = Script.creator({'type': 'python'}, config) output = list(script.process()) assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to("name=test, version=1.0"))
def test_templ_using_model(self): """Testing using model data via Jinja templating.""" config = ShellConfig(script='''echo "foo={{ model.foo }}"''', model={'foo': 'some model foo'}) bash = Bash(config) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('foo=some model foo'))
def test_templ_using_custom_env_vars(self): """Testing using user defined environment variables.""" bash = Bash( ShellConfig(script='''echo "foo={{ env.foo }}"''', env={'foo': 'some foo'})) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('foo=some foo'))
def test_external_bash_script(self): """Testing of an external bash script.""" bash = Bash( ShellConfig(script='''{{ env.tests }}/scripts/hello.sh''', env={'tests': os.path.dirname(__file__)})) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('hello'))
def test_oserror(self): """Testing exception.""" bash = Bash(ShellConfig(script='''echo "hello"''')) with patch('subprocess.Popen') as mocked_popen: mocked_popen.side_effect = OSError('Exception: popen has failed') output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('Exception: popen has failed')) assert_that(bash.exit_code, equal_to(1))
def test_creator_complete(self): """Testing creator function using model data end env. vars via Jinja templating.""" config = ShellConfig(script='''echo "{{ env.foo }}-{{ model.foo }}"''', title='test', model={'foo': 'model foo'}, env={'foo': 'env foo'}) bash = Bash.creator(None, config) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('env foo-model foo'))
def test_individual_valid(self, kwargs): """Testing to provide mandatory and all optional parameters.""" # defaults final_kwargs = {'script': 'echo "hello world"', 'title': '', 'debug': False, 'strict': False, 'dry_run': False, 'item': None, 'env': {}, 'model': {}, 'variables': {}} final_kwargs.update(kwargs) config = ShellConfig(**final_kwargs) for key, value in final_kwargs.items(): assert_that(key in config.__dict__, equal_to(True)) assert_that(config.__dict__[key], equal_to(value))
def test_minimal_valid(self): """Testing to provide mandatory parameters only.""" config = ShellConfig(script='echo "hello world"') assert_that(config.script, equal_to('echo "hello world"')) assert_that(config.title, equal_to('')) assert_that(config.model, equal_to({})) assert_that(config.env, equal_to({})) assert_that(config.item, equal_to(None)) assert_that(config.dry_run, equal_to(False)) assert_that(config.debug, equal_to(False)) assert_that(config.strict, equal_to(False)) assert_that(config.variables, equal_to({}))
def test_creator_dry_run(self): """Testing dry run for Packer Docker image.""" filename = os.path.join(os.path.dirname(__file__), 'image.tar') script = '''{"builders": [{ "type": "docker", "image": "{{ model.image }}:{{ env.tag }}", "export_path": "{{ variables.filename }}"}]}''' config = ShellConfig(script=script, title='test image creation', model={'image': 'centos'}, env={'tag': '7'}, variables={'filename': filename}, dry_run=True) image = Packer.creator({}, config) output = [line for line in image.process() if line.find('export_path') >= 0] assert_that(len(output), equal_to(1))
def test_creator_dry_run(self): """Testing Ansible but dry run mode only.""" script = '''---\n- hosts: all\n tasks:\n - name: Print a message\n dbg: msg=hello''' config = ShellConfig(script=script, model={}, env={}, dry_run=True) ansible = Ansible.creator( { 'inventory': '''[all]\n127.0.0.1''', 'limit': '' }, config) output = list(ansible.process()) assert_that(output[-4], contains_string("rm -f ansible.inventory")) assert_that(output[-3], contains_string("rm -f ansible.playbook"))
def test_nested_templ_using_model(self): """Testing using model data via Jinja templating.""" bash = Bash( ShellConfig( script= '''echo "foo={{ model.template|render(model=model) }}"''', model={ 'foo': 'some nested foo', 'template': '{{ model.foo }}' })) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(1)) assert_that(output[0], equal_to('foo=some nested foo'))
def test_pipeline_bash_file_variable(self): """Testing the injected variable representing the script.""" bash = Bash( ShellConfig( script='''echo "PIPELINE_BASH_FILE=$PIPELINE_BASH_FILE"''')) output = [ line for line in bash.process() if line.lower().find("script") > 0 ] assert_that(len(output), equal_to(1)) assert_that( output[0], matches_regexp('PIPELINE_BASH_FILE=.*/tmp/pipeline-script-.*.sh')) bash = Bash( ShellConfig( script= '''echo "PIPELINE_BASH_FILE={{ env.PIPELINE_BASH_FILE }}"''')) output = [ line for line in bash.process() if line.lower().find("script") > 0 ] assert_that(len(output), equal_to(1)) assert_that( output[0], matches_regexp('PIPELINE_BASH_FILE=.*/tmp/pipeline-script-.*.sh'))
def test_creator_simple(self): """Testing Packer using a Docker builder.""" filename = os.path.join(os.path.dirname(__file__), 'image.tar') script = '''{"builders": [{"type": "docker", "image": "centos:7", "export_path": "%s"}]}''' % filename config = ShellConfig(script=script, model={}, env={}) image = Packer.creator({}, config) output = list(image.process()) assert_that(os.path.isfile(filename), equal_to(True), "Missing %s" % filename) os.remove(filename) assert_that(output[-4], contains_string( "Build 'docker' finished.")) assert_that(output[-2], contains_string( '==> Builds finished. The artifacts of successful builds are:')) assert_that(output[-1], contains_string( "--> docker: Exported Docker file: %s" % filename))
def test_creator_no_run(self): """Testing Ansible but dry run mode only.""" inventory = '''[all]\n127.0.0.1''' script = '''---\n- hosts: all\n tasks:\n - name: Print a message\n dbg: msg=hello''' config = ShellConfig(script=script, model={}, env={}, dry_run=False) with patch('spline.components.ansible.write_temporary_file' ) as mocked_write_temporary_file: mocked_write_temporary_file.return_value = ['first', 'second'] Ansible.creator({'inventory': inventory, 'limit': ''}, config) assert_that( mocked_write_temporary_file.mock_calls, equal_to([ call(script, 'ansible-play-', '.yaml'), call(inventory, prefix='ansible-inventory-') ]))
def cleanup(self): """Run cleanup script of pipeline when hook is configured.""" if self.data.hooks and len(self.data.hooks.cleanup) > 0: env = self.data.env_list[0].copy() env.update({'PIPELINE_RESULT': 'SUCCESS'}) env.update({'PIPELINE_SHELL_EXIT_CODE': '0'}) config = ShellConfig( script=self.data.hooks.cleanup, model=self.model, env=env, dry_run=self.options.dry_run, debug=self.options.debug, strict=self.options.strict, temporary_scripts_path=self.options.temporary_scripts_path) cleanup_shell = Bash(config) for line in cleanup_shell.process(): yield line
def test_creator_dry_run(self): """Testing dry run for docker image.""" config = ShellConfig( script= '''FROM {{ model.image }}:{{ env.tag }}\nRUN yum -y install ctags''', title='test image creation', model={'image': 'centos'}, env={'tag': '7'}, dry_run=True) image = Image.creator({ 'name': 'test', 'tag': 'latest', 'unique': True }, config) output = [ line for line in image.process() if line.find('RUN yum') >= 0 ] assert_that(len(output), equal_to(1))
def get_version(tool_name, tool_command): """ Get name and version of a tool defined by given command. Args: tool_name (str): name of the tool. tool_command (str): Bash one line command to get the version of the tool. Returns: dict: tool name and version or empty when no line has been found """ result = {} for line in Bash(ShellConfig(script=tool_command, internal=True)).process(): if line.find("command not found") >= 0: VersionsCheck.LOGGER.error("Required tool '%s' not found (stopping pipeline)!", tool_name) sys.exit(1) result = {tool_name: Version(line)} break return result
def test_creator_simple(self): """Testing image.""" config = ShellConfig( script= '''FROM {{ model.image }}:{{ env.tag }}\nRUN yum -y install ctags''', title='test image creation', model={'image': 'centos'}, env={'tag': '7'}) image = Image.creator({ 'name': 'test', 'tag': 'latest', 'unique': True }, config) output = list(image.process()) output = [ line for line in output if line.find('Successfully tagged') >= 0 ] assert_that(len(output), equal_to(1)) TestDockerImage.cleanup(name="test-%s" % os.getpid(), tag='latest')
def run_cleanup(self, env, exit_code): """Run cleanup hook when configured.""" output = [] if self.pipeline.data.hooks and len( self.pipeline.data.hooks.cleanup) > 0: env.update({'PIPELINE_RESULT': 'FAILURE'}) env.update({'PIPELINE_SHELL_EXIT_CODE': str(exit_code)}) config = ShellConfig(script=self.pipeline.data.hooks.cleanup, model=self.pipeline.model, env=env, dry_run=self.pipeline.options.dry_run, debug=self.pipeline.options.debug, strict=self.pipeline.options.strict, temporary_scripts_path=self.pipeline.options. temporary_scripts_path) cleanup_shell = Bash(config) for line in cleanup_shell.process(): output.append(line) self.logger.info(" | %s", line) return output
def worker(data): """Running on shell via multiprocessing.""" creator = get_creator_by_name(data['creator']) shell = creator( data['entry'], ShellConfig( script=data['entry']['script'], title=data['entry']['title'] if 'title' in data['entry'] else '', model=data['model'], env=data['env'], item=data['item'], dry_run=data['dry_run'], debug=data['debug'], strict=data['strict'], variables=data['variables'], temporary_scripts_path=data['temporary_scripts_path'])) output = [] for line in shell.process(): output.append(line) Logger.get_logger(__name__ + '.worker').info(" | %s", line) return {'id': data['id'], 'success': shell.success, 'output': output}
def process_shells_ordered(self, shells): """Processing a list of shells one after the other.""" output = [] for shell in shells: entry = shell['entry'] config = ShellConfig( script=entry['script'], title=entry['title'] if 'title' in entry else '', model=shell['model'], env=shell['env'], item=shell['item'], dry_run=shell['dry_run'], debug=shell['debug'], strict=shell['strict'], variables=shell['variables'], temporary_scripts_path=shell['temporary_scripts_path']) result = Adapter( self.process_shell(get_creator_by_name(shell['creator']), entry, config)) output += result.output self.__handle_variable(entry, result.output) if not result.success: return {'success': False, 'output': output} return {'success': True, 'output': output}
def test_failed_exit_not_zero(self): """testing normal failed bash script.""" bash = Bash(ShellConfig(script='''exit 1''')) output = [line for line in bash.process() if len(line) > 0] assert_that(len(output), equal_to(0)) assert_that(bash.exit_code, equal_to(1))