def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule idempotence` and return a tuple. :param exit: An optional flag to toggle the exiting of the module on command failure. :return: Return a tuple of (`exit status`, `command output`), otherwise sys.exit on command failure. """ msg = 'Idempotence test in progress (can take a few minutes)...' util.print_info(msg) c = converge.Converge(self.args, self.command_args, self.molecule) status, output = c.execute(idempotent=True, exit=False, hide_errors=True) if status is not None: msg = 'Skipping due to errors during converge.' util.print_info(msg) util.print_info(output) return status, None idempotent = self._is_idempotent(output) if idempotent: util.print_success('Idempotence test passed.') return None, None else: msg = 'Idempotence test failed because of the following tasks:' util.print_error(msg) util.print_error('\n'.join(self._non_idempotent_tasks(output))) if exit: util.sysexit() return 1, None
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule verify` and return a tuple. :param exit: An optional flag to toggle the exiting of the module on command failure. :return: Return a tuple of None, otherwise sys.exit on command failure. """ try: v = ansible_lint.AnsibleLint(self.molecule) v.execute() except sh.ErrorReturnCode: util.sysexit() v = trailing.Trailing(self.molecule) v.execute() self.molecule.write_ssh_config() try: if self.molecule.verifier == 'serverspec': v = serverspec.Serverspec(self.molecule) elif self.molecule.verifier == 'goss': v = goss.Goss(self.molecule) else: v = testinfra.Testinfra(self.molecule) v.execute() except sh.ErrorReturnCode as e: util.print_error(str(e)) if exit: util.sysexit(e.exit_code) return e.exit_code, e.stdout return None, None
def _rake(self, rakefile, debug=False, out=util.callback_info, err=util.callback_error): """ Executes rake against specified rakefile and returns a :func:`sh` response object. :param rakefile: A string containing path to the rakefile. :param debug: An optional bool to toggle debug output. :param out: An optional function to process STDOUT for underlying :func:`sh` call. :param err: An optional function to process STDERR for underlying :func:`sh` call. :return: :func:`sh` response object. """ kwargs = { '_out': out, '_err': err, 'trace': debug, 'rakefile': rakefile } msg = 'Executing serverspec tests found in {}/...'.format( self._serverspec_dir) util.print_info(msg) try: cmd = sh.rake.bake(**kwargs) except sh.CommandNotFound: msg = 'Verifier missing, gem install rake.' util.print_error(msg) util.sysexit() return util.run_command(cmd, debug=self._debug)
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule init` and exit. :param exit: (Unused) Provided to complete method signature. :return: None """ role = self.command_args.get('role') role_path = os.getcwd() driver = self._get_driver() verifier = self._get_verifier() if not role: role = os.getcwd().split(os.sep)[-1] role_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir)) self._init_existing_role(role, role_path, driver, verifier) else: if os.path.isdir(role): msg = ('The directory {} exists. ' 'Cannot create new role.').format(role) util.print_error(msg) util.sysexit() self._init_new_role(role, role_path, driver, verifier) path = os.path.join(role_path, role) msg = 'Successfully initialized new role in {}.'.format(path) util.print_success(msg) util.sysexit(0)
def _rubocop(self, serverspec_dir, debug=False, pattern='/**/*.rb', out=util.callback_info, err=util.callback_error): """ Executes rubocop against specified directory/pattern and returns a :func:`sh` response object. :param serverspec_dir: A string containing the directory with files to lint. :param debug: An optional bool to toggle debug output. :param pattern: A string containing the pattern of files to lint. :param out: An optional function to process STDOUT for underlying :func:`sh` call. :param err: An optional function to process STDERR for underlying :func:`sh` call. :return: :func:`sh` response object. """ kwargs = {'_out': out, '_err': err, 'debug': debug} msg = 'Executing rubocop on *.rb files found in {}/...'.format( serverspec_dir) util.print_info(msg) match = serverspec_dir + pattern try: cmd = sh.rubocop.bake(match, **kwargs) except sh.CommandNotFound: msg = 'Verifier missing, gem install rubocop.' util.print_error(msg) util.sysexit() return util.run_command(cmd, debug=self._debug)
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule create` and return a tuple. :param exit: An optional flag to toggle the exiting of the module on command failure. :return: Return a tuple of None, otherwise sys.exit on command failure. """ self.molecule.remove_inventory_file() self.molecule.create_templates() try: util.print_info('Creating instances...') self.molecule.driver.up(no_provision=True) self.molecule.state.change_state('created', True) if self.command_args.get('platform') == 'all': self.molecule.state.change_state('multiple_platforms', True) except subprocess.CalledProcessError as e: util.print_error(str(e)) if exit: util.sysexit(e.returncode) return e.returncode, e.message self.molecule.create_inventory_file() self.molecule.write_instances_state() return None, None
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule idempotence` and return a tuple. :param exit: An optional flag to toggle the exiting of the module on command failure. :return: Return a tuple of (`exit status`, `command output`), otherwise sys.exit on command failure. """ msg = 'Idempotence test in progress (can take a few minutes)...' util.print_info(msg) c = converge.Converge(self.args, self.command_args, self.molecule) status, output = c.execute( idempotent=True, exit=False, hide_errors=True) if status is not None: msg = 'Skipping due to errors during converge.' util.print_info(msg) return status, None idempotent = self._is_idempotent(output) if idempotent: util.print_success('Idempotence test passed.') return None, None else: msg = 'Idempotence test failed because of the following tasks:' util.print_error(msg) util.print_error('\n'.join(self._non_idempotent_tasks(output))) if exit: util.sysexit() return 1, None
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule check` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple provided by :meth:`.AnsiblePlaybook.execute`. """ if not self.molecule.state.created: msg = ('Instance(s) not created, `check` should be run ' 'against created instance(s).') util.print_error(msg) util.sysexit() debug = self.args.get('debug') ansible = ansible_playbook.AnsiblePlaybook( self.molecule.config.config['ansible'], self.molecule.driver.ansible_connection_params, debug=debug) ansible.add_cli_arg('check', True) util.print_info("Performing a 'Dry Run' of playbook...") return ansible.execute(hide_errors=True) return (None, None)
def test_print_error(capsys): util.print_error("test") result, _ = capsys.readouterr() print "{}ERROR: {}".format(colorama.Fore.RED, "test".rstrip()) expected, _ = capsys.readouterr() assert expected == result
def test_print_error(capsys): util.print_error('test') result, _ = capsys.readouterr() print '{}ERROR: {}'.format(colorama.Fore.RED, 'test'.rstrip()) expected, _ = capsys.readouterr() assert expected == result
def test_print_error_without_pretty(capsys): util.print_error('test', pretty=False) result, _ = capsys.readouterr() print '{}{}'.format(colorama.Fore.RED, 'test'.rstrip()) expected, _ = capsys.readouterr() assert expected == result
def up(self, no_provision=True): self.molecule.state.change_state('driver', self.name) kpn = self._get_keypair() active_instances = self._openstack.list_servers() active_instance_names = { instance['name']: instance['status'] for instance in active_instances } util.print_warn('Creating openstack instances...') for instance in self.instances: try: # We divide the ssh_timeout by 2, because the connect # itself takes at least a second and is followed by # a 1 sec sleep ssh_timeout = int( instance.get('ssh_timeout', self.ssh_timeout) / 2) except TypeError: util.print_error('Can not cast ssh_timeout setting "%s"' ' to int' % instance.get('ssh_timeout', self.ssh_timeout)) util.sysexit() if instance['name'] not in active_instance_names: msg = '\tBringing up {}...'.format(instance['name']) util.print_info(msg) server = self._openstack.create_server( name=instance['name'], image=self._openstack.get_image(instance['image']), flavor=self._openstack.get_flavor(instance['flavor']), auto_ip=True, wait=True, key_name=kpn, ip_pool=instance.get('ip_pool') if instance.get('ip_pool') else self.ip_pool, network=instance.get('networks', []), security_groups=instance.get('security_groups', [])) instance['created'] = True instance['reachable'] = False for _ in range(ssh_timeout): util.print_info('\t Waiting for ssh availability...') if self._check_ssh_availability( server['interface_ip'], instance['sshuser'], timeout=1, sshkey_filename=self._get_keyfile()): instance['reachable'] = True break if not instance['reachable']: util.print_error( 'Could not reach instance "%s"' ' within limit of %s seconds' % (instance['name'], instance.get('ssh_timeout', self.ssh_timeout))) util.sysexit()
def _cleanup_temp_keypair(self): # if we don't have a keypair config, delete the temp one if ('keypair' not in self.molecule.config.config['openstack']): kpn = self._get_temp_keyname() if self._openstack.search_keypairs(kpn): msg = '\tRemoving openstack keypair {}...'.format(kpn) util.print_warn(msg) if not self._openstack.delete_keypair(kpn): msg = 'Unable to remove openstack keypair {}.'.format(kpn) util.print_error(msg) else: msg = '\tRemoved openstack keypair {}.'.format(kpn) util.print_success(msg)
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule status` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple of None. """ display_all = not any([ self.command_args.get('hosts'), self.command_args.get('platforms'), self.command_args.get('providers') ]) # Retrieve the status. try: status = self.molecule.driver.status() # TODO(retr0h): Pretty sure this handling is wrong. We don't always # shell out for status. except subprocess.CalledProcessError as e: util.print_error(e.message) return e.returncode, e.message # Display the results in procelain mode. porcelain = self.command_args.get('porcelain') # Display hosts information. if display_all or self.command_args.get('hosts'): # Prepare the table for the results. headers = [] if porcelain else ['Name', 'State', 'Provider'] data = [] for item in status: if item.state != 'not_created': # pragma: no cover state = item.state else: state = item.state data.append([item.name, state, item.provider]) self.molecule.display_tabulate_data(data, headers=headers) # Display the platforms. if display_all or self.command_args.get('platforms'): self.molecule.print_valid_platforms(porcelain=porcelain) # Display the providers. if display_all or self.command_args.get('providers'): self.molecule.print_valid_providers(porcelain=porcelain) return None, None
def main(self): """ A mechanism to initialize molecule by calling its main method. This can be redefined by classes which do not want this behavior (:class:`.Init`). :returns: None """ if not self._config.molecule_file_exists(): msg = ('Unable to find {}. ' 'Exiting.').format(self._config.molecule_file) util.print_error(msg) util.sysexit() self.molecule.main()
def execute(self): """ Executes shell command and returns the command's stdout. :return: The command's output, otherwise sys.exit on command failure. """ if self._command is None: self.bake() try: return util.run_command(self._command, debug=self._debug).stdout except sh.ErrorReturnCode as e: util.print_error(str(e)) util.sysexit(e.exit_code)
def execute(self, hide_errors=False): """ Executes ansible-playbook and returns command's stdout. :param hide_errors: An optional bool to toggle output of errors. :return: The command's output, otherwise sys.exit on command failure. """ if self._ansible is None: self.bake() try: return None, util.run_command( self._ansible, debug=self._debug).stdout except sh.ErrorReturnCode as e: if not hide_errors: util.print_error(str(e)) return e.exit_code, None
def execute(self, hide_errors=False): """ Executes ansible-playbook and returns command's stdout. :param hide_errors: An optional bool to toggle output of errors. :return: The command's output, otherwise sys.exit on command failure. """ if self._ansible is None: self.bake() try: return None, unicode(util.run_command( self._ansible, debug=self._debug)) except sh.ErrorReturnCode as e: if not hide_errors: util.print_error(str(e)) return e.exit_code, None
def main(self): """ A mechanism to initialize molecule by calling its main method. This can be redefined by classes which do not want this behavior (:class:`.Init`). :returns: None """ if (not self._config.molecule_file_exists() and not self._config.molecule_local_config_file_exists()): msg = ('Unable to find {}. ' 'Exiting.').format(self._config.molecule_file) util.print_error(msg) util.sysexit() elif (not self._config.molecule_file_exists() and self._config.molecule_local_config_file_exists()): util.print_warn('No molecule.yml found in project, ' 'using config file at %s only' % self._config.molecule_local_config_file) self.molecule.main()
def main(self): if not os.path.exists(self.config.config['molecule']['molecule_dir']): os.makedirs(self.config.config['molecule']['molecule_dir']) self.state = state.State( state_file=self.config.config.get('molecule').get('state_file')) try: self.driver = self._get_driver() except basedriver.InvalidDriverSpecified: msg = "Invalid driver '{}'.".format(self._get_driver_name()) util.print_error(msg) # TODO(retr0h): Print valid drivers. util.sysexit() except basedriver.InvalidProviderSpecified: msg = "Invalid provider '{}'.".format(self.args['provider']) util.print_error(msg) self.args['provider'] = None self.args['platform'] = None self.driver = self._get_driver() self.print_valid_providers() util.sysexit() except basedriver.InvalidPlatformSpecified: msg = "Invalid platform '{}'.".format(self.args['platform']) util.print_error(msg) self.args['provider'] = None self.args['platform'] = None self.driver = self._get_driver() self.print_valid_platforms() util.sysexit() self.config.populate_instance_names(self.driver.platform) self._add_or_update_vars('group_vars') self._add_or_update_vars('host_vars')
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule test` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple of (`exit status`, `command output`), otherwise sys.exit on command failure. """ if self.command_args.get('all') == True: ts = self.molecule.config.config['molecule']['test']['sequence'] else: ts = ['destroy', 'create', 'converge'] for task in ts: command_module = getattr(molecule.command, task) command = getattr(command_module, task.capitalize()) # in case we want to re-work on an already existing vm if task == 'destroy' and self.command_args.get('from_scratch') == False: util.print_info('Keep instance up...') continue c = command(self.args, self.command_args, self.molecule) status, output = c.execute(exit=False) # Fail fast if status is not 0 and status is not None: if output: util.print_error(output) util.sysexit(status) if self.command_args.get('clean') == True: c = molecule.command.destroy.Destroy(self.args, self.command_args) c.execute() return None, None # passing (default) if status is None: return None, None
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule destroy` and return a tuple. Clears state file of all info (default platform). :param exit: An optional flag to toggle the exiting of the module on command failure. :return: Return a tuple of None, otherwise sys.exit on command failure. """ try: util.print_info('Destroying instances...') self.molecule.driver.destroy() self.molecule.state.reset() except subprocess.CalledProcessError as e: util.print_error(str(e)) if exit: util.sysexit(e.returncode) return e.returncode, e.message self.molecule.remove_templates() self.molecule.remove_inventory_file() return None, None
def destroy(self): util.print_info('Deleting openstack instances...') active_instances = self._openstack.list_servers() active_instance_names = { instance['name']: instance['id'] for instance in active_instances } for instance in self.instances: util.print_warn('\tRemoving {}...'.format(instance['name'])) if instance['name'] in active_instance_names: if not self._openstack.delete_server( active_instance_names[instance['name']], wait=True): msg = 'Unable to remove {}.'.format(instance['name']) util.print_error(msg) else: util.print_success('\tRemoved {}.'.format(instance[ 'name'])) instance['created'] = False # cleanup any molecule generated ssh keysfiles self._cleanup_temp_keypair() self._cleanup_temp_keyfile()
def destroy(self): util.print_info('Deleting openstack instances...') active_instances = self._openstack.list_servers() active_instance_names = { instance['name']: instance['id'] for instance in active_instances } for instance in self.instances: util.print_warn('\tRemoving {}...'.format(instance['name'])) if instance['name'] in active_instance_names: if not self._openstack.delete_server( active_instance_names[instance['name']], wait=True): msg = 'Unable to remove {}.'.format(instance['name']) util.print_error(msg) else: util.print_success('\tRemoved {}.'.format( instance['name'])) instance['created'] = False # cleanup any molecule generated ssh keysfiles self._cleanup_temp_keypair() self._cleanup_temp_keyfile()
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule test` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple of (`exit status`, `command output`), otherwise sys.exit on command failure. """ ts = self.molecule.config.config['molecule']['test']['sequence'] for task in ts: command_module = getattr(molecule.command, task) command = getattr(command_module, task.capitalize()) c = command(self.args, self.command_args, self.molecule) status, output = c.execute(exit=False) # Fail fast if status is not 0 and status is not None: if output: util.print_error(output) util.sysexit(status) if self.command_args.get('destroy') == 'always': c = molecule.command.destroy.Destroy(self.args, self.command_args) c.execute() return None, None if self.command_args.get('destroy') == 'never': return None, None # passing (default) if status is None: c = molecule.command.destroy.Destroy(self.args, self.command_args) c.execute() return None, None
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule test` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple of (`exit status`, `command output`), otherwise sys.exit on command failure. """ ts = self.molecule.config.config["molecule"]["test"]["sequence"] for task in ts: command_module = getattr(molecule.command, task) command = getattr(command_module, task.capitalize()) c = command(self.args, self.command_args, self.molecule) status, output = c.execute(exit=False) # Fail fast if status is not 0 and status is not None: if output: util.print_error(output) util.sysexit(status) if self.command_args.get("destroy") == "always": c = molecule.command.destroy.Destroy(self.args, self.command_args) c.execute() return None, None if self.command_args.get("destroy") == "never": return None, None # passing (default) if status is None: c = molecule.command.destroy.Destroy(self.args, self.command_args) c.execute() return None, None
def _get_driver(self): """ Return an instance of the driver as returned by `_get_driver_name()`. .. todo:: Implement a pluggable solution vs inline imports. """ driver = self._get_driver_name() if (self.state.driver is not None) and (self.state.driver != driver): msg = ("Instance(s) were converged with the '{}' driver, " "but the subcommand is using '{}' driver.") util.print_error(msg.format(self.state.driver, driver)) util.sysexit() if driver == 'vagrant': from molecule.driver import vagrantdriver return vagrantdriver.VagrantDriver(self) elif driver == 'docker': from molecule.driver import dockerdriver return dockerdriver.DockerDriver(self) elif driver == 'openstack': from molecule.driver import openstackdriver return openstackdriver.OpenstackDriver(self) raise basedriver.InvalidDriverSpecified()
def execute(self, exit=True): # pragma: no cover """ Executes trailing linters and returns None, otherwise sys.exit on command failure. :return: None :param ignore_paths: List of paths to ignore during checks. :return: None, otherwise sys.exit on command failure. """ filenames = [] pruned_filenames = [] found_error = False valid_extensions = ['py', 'yml', 'rb'] for root, dirs, files in os.walk('.'): # gets ./subdirectory/filename filenames.extend([ os.path.join(root, name) for name in files if name.split(os.extsep)[-1] in valid_extensions ]) # gets ./filename filenames.extend([ os.path.join(root, name) for name in dirs if name.split(os.extsep)[-1] in valid_extensions ]) # only work on files not in our ignore paths for f in filenames: f_parts = f.split(os.sep) try: if f_parts[1] in self._ignore_paths: continue except IndexError: continue # don't add directories if os.path.isfile(f): pruned_filenames.append(f) for filename in pruned_filenames: # don't process blank files if os.path.getsize(filename) < 1: continue data = [line for line in open(filename, 'r')] newline = self._trailing_newline(data) whitespace = self._trailing_whitespace(data) if newline: msg = 'Trailing newline found at the end of {}.'.format( filename) util.print_error(msg) found_error = True if len(whitespace) > 0: msg = 'Trailing whitespace found in {} on lines: {}' lines = ', '.join(str(x) for x in whitespace) util.print_error(msg.format(filename, lines)) found_error = True if exit and found_error: util.sysexit()
def up(self, no_provision=True): self.molecule.state.change_state('driver', self.name) kpn = self._get_keypair() active_instances = self._openstack.list_servers() active_instance_names = { instance['name']: instance['interface_ip'] for instance in active_instances } util.print_warn('Creating openstack instances...') for instance in self.instances: try: # We divide the ssh_timeout by 2, because the connect # itself takes at least a second and is followed by # a 1 sec sleep ssh_timeout = int( instance.get('ssh_timeout', self.ssh_timeout) / 2) except TypeError: util.print_error('Can not cast ssh_timeout setting "%s"' ' to int' % instance.get('ssh_timeout', self.ssh_timeout)) util.sysexit() if instance['name'] not in active_instance_names: msg = '\tBringing up {}...'.format(instance['name']) util.print_info(msg) server = self._openstack.create_server( name=instance['name'], image=self._openstack.get_image(instance['image']), flavor=self._openstack.get_flavor(instance['flavor']), auto_ip=True, wait=False, key_name=kpn, ip_pool=instance.get('ip_pool') if instance.get('ip_pool') else self.ip_pool, network=instance.get('networks', []), security_groups=instance.get('security_groups', [])) instance['created'] = True instance['reachable'] = False instance['server'] = server else: instance['address'] = active_instance_names[instance['name']] instance['reachable'] = True for instance in self.instances: if not instance.get('server'): instance['server'] = self._openstack.get_server(instance[ 'name']) if not instance.get('address'): util.print_info( '\t Waiting for instance %s to be in state active...' % instance['name']) server = self._openstack.wait_for_server( instance['server'], auto_ip=True) instance['address'] = server['interface_ip'] for instance in self.instances: for _ in range(ssh_timeout): util.print_info( '\t Waiting for ssh availability of instance %s...' % instance['name']) if self._check_ssh_availability( instance['address'], instance['sshuser'], timeout=1, sshkey_filename=self._get_keyfile()): instance['reachable'] = True break if not instance['reachable']: util.print_error( 'Could not reach instance "%s"' ' within limit of %s seconds' % (instance['name'], instance.get('ssh_timeout', self.ssh_timeout))) util.sysexit()
def execute(self, exit=True): """ Execute the actions necessary to perform a `molecule login` and return a tuple. :param exit: (Unused) Provided to complete method signature. :return: Return a tuple of None, otherwise sys.exit on command failure. """ # get list of running hosts from state if self.molecule.state.hosts: hosts = [k for k, v in self.molecule.state.hosts.iteritems()] else: hosts = [] try: # Nowhere to login to if there is no running host. if len(hosts) == 0: raise base.InvalidHost('There are no running hosts.') # Check whether a host was specified. if self.command_args.get('host') is None: # One running host is perfect. Login to it. if len(hosts) == 1: hostname = hosts[0] # But too many hosts is trouble as well. else: message = ('There are {} running hosts. Please specify ' 'which with --host.\n\n' 'Available hosts:\n{}'.format( len(hosts), '\n'.join(sorted(hosts)))) raise base.InvalidHost(message) else: # If the host was specified, try to use it. hostname = self.command_args.get('host') match = [x for x in hosts if x.startswith(hostname)] if len(match) == 0: raise subprocess.CalledProcessError(1, None) elif len(match) != 1: # If there are multiple matches, but one of them is an # exact string match, assume this is the one they're # looking for and use it if hostname in match: match = [ hostname, ] else: message = ("There are {} hosts that match '{}'. You " 'can only login to one at a time.\n\n' 'Available hosts:\n{}'.format( len(match), hostname, '\n'.join(sorted(hosts)))) raise base.InvalidHost(message) hostname = match[0] except subprocess.CalledProcessError: msg = ("Unknown host '{}'.\n\n" 'Available hosts:\n{}').format( self.command_args.get('host'), '\n'.join(hosts)) util.print_error(msg) util.sysexit() except base.InvalidHost as e: util.print_error(e.message) util.sysexit() self._get_login(hostname) return None, None
def _build_ansible_compatible_image(self): available_images = [ tag.encode('utf-8') for image in self._docker.images() for tag in image.get('RepoTags', []) ] for container in self.instances: if container.get('build_image'): msg = ('Creating Ansible compatible ' 'image of {}:{} ...').format(container['image'], container['image_version']) util.print_info(msg) if 'registry' in container: container['registry'] += '/' else: container['registry'] = '' dockerfile = ''' FROM {container_image}:{container_version} {container_environment} RUN bash -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo; fi' RUN bash -c 'if [ -x "$(command -v yum)" ]; then yum makecache fast && yum update -y && yum install -y python sudo which yum-plugin-ovl && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi' RUN bash -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo; fi' ''' # noqa if 'dockerfile' in container: dockerfile = container['dockerfile'] f = io.open(dockerfile) else: environment = container.get('environment') if environment: environment = '\n'.join( 'ENV {} {}'.format(k, v) for k, v in environment.iteritems()) else: environment = '' dockerfile = dockerfile.format( container_image=container['registry'] + container['image'], container_version=container['image_version'], container_environment=environment) f = io.BytesIO(dockerfile.encode('utf-8')) container['image'] = container['registry'].replace( '/', '_').replace(':', '_') + container['image'] tag_string = self.image_tag.format(container['image'], container['image_version']) errors = False if tag_string not in available_images or 'dockerfile' in container: util.print_info('Building ansible compatible image...') previous_line = '' for line in self._docker.build(fileobj=f, tag=tag_string): for line_split in line.split('\n'): if len(line_split) > 0: line = json.loads(line_split) if 'stream' in line: msg = '\t{}'.format(line['stream']) util.print_warn(msg) if 'errorDetail' in line: ed = line['errorDetail']['message'] msg = '\t{}'.format(ed) util.print_warn(msg) errors = True if 'status' in line: if previous_line not in line['status']: msg = '\t{} ...'.format(line['status']) util.print_warn(msg) previous_line = line['status'] if errors: msg = 'Build failed for {}.'.format(tag_string) util.print_error(msg) return else: util.print_success( 'Finished building {}.'.format(tag_string))
def _build_ansible_compatible_image(self, container): available_images = [ tag.encode('utf-8') for image in self._docker.images() if image.get('RepoTags') is not None for tag in image.get('RepoTags') ] msg = ('Creating Ansible compatible ' 'image of {}:{} ...').format(container['image'], container['image_version']) util.print_info(msg) if 'registry' in container: container['registry'] += '/' else: container['registry'] = '' dockerfile = ''' FROM {container_image}:{container_version} {container_environment} RUN /bin/sh -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo bash; fi' RUN /bin/sh -c 'if [ -x "$(command -v yum)" ]; then touch /var/lib/rpm/* && yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi' RUN /bin/sh -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash; fi' RUN /bin/sh -c 'if [ -x "$(command -v apk)" ]; then apk update && apk add python sudo bash; fi' RUN /bin/sh -c 'if [ -x "$(command -v pacman)" ]; then pacman --sync --noconfirm --refresh python2 bash; fi' RUN /bin/sh -c 'if [ -x "$(command -v dnf)" ]; then dnf makecache fast; dnf --assumeyes install python python-devel python2-dnf bash; fi' RUN /bin/sh -c 'if [ -x "$(command -v emerge)" ]; then emerge --ask n =dev-lang/python-2\* gentoolkit; fi' ''' # noqa if 'dockerfile' in container: dockerfile = container['dockerfile'] f = io.open(dockerfile) else: environment = container.get('environment') if environment: environment = '\n'.join('ENV {} {}'.format(k, v) for k, v in environment.iteritems()) else: environment = '' dockerfile = dockerfile.format( container_image=container['registry'] + container['image'], container_version=container['image_version'], container_environment=environment) f = io.BytesIO(dockerfile.encode('utf-8')) container['image'] = container['registry'].replace( '/', '_').replace(':', '_') + container['image'] tag_string = container['image_tag'].format(container['image'], container['image_version']) errors = False if tag_string not in available_images or 'dockerfile' in container: util.print_info('Building ansible compatible image...') previous_line = '' for line in self._docker.build(fileobj=f, tag=tag_string): for line_split in line.split('\n'): if len(line_split) > 0: line = json.loads(line_split) if 'stream' in line: msg = '\t{}'.format(line['stream']) util.print_warn(msg) if 'errorDetail' in line: ed = line['errorDetail']['message'] msg = '\t{}'.format(ed) util.print_warn(msg) errors = True if 'status' in line: if previous_line not in line['status']: msg = '\t{} ...'.format(line['status']) util.print_warn(msg) previous_line = line['status'] if errors: msg = 'Build failed for {}.'.format(tag_string) util.print_error(msg) return else: util.print_success('Finished building {}.'.format(tag_string))
def _build_ansible_compatible_image(self): available_images = [ tag.encode('utf-8') for image in self._docker.images() for tag in image.get('RepoTags', []) ] for container in self.instances: if container.get('build_image'): msg = ('Creating Ansible compatible ' 'image of {}:{} ...').format(container['image'], container['image_version']) util.print_info(msg) if 'registry' in container: container['registry'] += '/' else: container['registry'] = '' dockerfile = ''' FROM {container_image}:{container_version} {container_environment} RUN bash -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo; fi' RUN bash -c 'if [ -x "$(command -v yum)" ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi' RUN bash -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo; fi' ''' # noqa if 'dockerfile' in container: dockerfile = container['dockerfile'] f = io.open(dockerfile) else: environment = container.get('environment') if environment: environment = '\n'.join( 'ENV {} {}'.format(k, v) for k, v in environment.iteritems()) else: environment = '' dockerfile = dockerfile.format( container_image=container['registry'] + container['image'], container_version=container['image_version'], container_environment=environment) f = io.BytesIO(dockerfile.encode('utf-8')) container['image'] = container['registry'].replace( '/', '_').replace(':', '_') + container['image'] tag_string = self.image_tag.format(container['image'], container['image_version']) errors = False if tag_string not in available_images or 'dockerfile' in container: util.print_info('Building ansible compatible image...') previous_line = '' for line in self._docker.build(fileobj=f, tag=tag_string): for line_split in line.split('\n'): if len(line_split) > 0: line = json.loads(line_split) if 'stream' in line: msg = '\t{}'.format(line['stream']) util.print_warn(msg) if 'errorDetail' in line: ed = line['errorDetail']['message'] msg = '\t{}'.format(ed) util.print_warn(msg) errors = True if 'status' in line: if previous_line not in line['status']: msg = '\t{} ...'.format(line['status']) util.print_warn(msg) previous_line = line['status'] if errors: msg = 'Build failed for {}.'.format(tag_string) util.print_error(msg) return else: util.print_success('Finished building {}.'.format( tag_string))