def build(self, shutit, loglevel=logging.DEBUG): """Sets up the machine ready for building. """ cfg = shutit.cfg ssh_host = cfg[self.module_id]['ssh_host'] ssh_port = cfg[self.module_id]['ssh_port'] ssh_user = cfg[self.module_id]['ssh_user'] ssh_pass = cfg[self.module_id]['password'] ssh_key = cfg[self.module_id]['ssh_key'] ssh_cmd = cfg[self.module_id]['ssh_cmd'] opts = [ '-t', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no' ] if ssh_pass == '': opts += ['-o', 'PasswordAuthentication=no'] if ssh_port != '': opts += ['-p', ssh_port] if ssh_key != '': opts += ['-i', ssh_key] host_arg = ssh_host if host_arg == '': shutit.fail('No host specified for sshing', throw_exception=False) if ssh_user != '': host_arg = ssh_user + '@' + host_arg cmd_arg = ssh_cmd if cmd_arg == '': cmd_arg = 'sudo su -s /bin/bash -' ssh_command = ['ssh'] + opts + [host_arg, cmd_arg] if shutit.build['interactive'] >= 3: print('\n\nAbout to connect to host.' + '\n\n' + shutit_util.colourise('32', '\n[Hit return to continue]')) shutit_util.util_raw_input() shutit.build['ssh_command'] = ' '.join(ssh_command) shutit.log('Command being run is: ' + shutit.build['ssh_command'], level=logging.INFO) shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( 'target_child', ssh_command[0], ssh_command[1:]) target_child = shutit_pexpect_session.pexpect_child expect = ['assword', shutit.expect_prompts['base_prompt'].strip()] res = shutit.child_expect(target_child, expect, timeout=10) while True: shutit.log(target_child.before + target_child.after, level=logging.DEBUG) if res == 0: shutit.log('...', level=logging.DEBUG) res = shutit.send(ssh_pass, shutit_pexpect_child=target_child, expect=expect, timeout=10, check_exit=False, fail_on_empty_before=False, echo=False, loglevel=loglevel) elif res == 1: shutit.log('Prompt found, breaking out', level=logging.DEBUG) break self.setup_host_child() self.setup_target_child(target_child) return True
def build(self, shutit): """Sets up the machine ready for building. """ shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( 'target_child', '/bin/bash') target_child = shutit_pexpect_session.pexpect_child shutit_pexpect_session.expect( shutit.expect_prompts['base_prompt'].strip(), timeout=10) self.setup_host_child() self.setup_target_child(target_child) return True
def setup_host_child_environment(shutit): # Now let's have a host_child shutit.log('Spawning host child', level=logging.DEBUG) shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( 'host_child', '/bin/bash') # Set up prompts and let the user do things before the build shutit.set_default_shutit_pexpect_session(shutit_pexpect_session) shutit.set_default_shutit_pexpect_session_expect( shutit.expect_prompts['base_prompt']) # ORIGIN_ENV is a special case of the prompt maintained for performance reasons, don't change. prefix = 'ORIGIN_ENV' shutit_pexpect_session.setup_prompt('ORIGIN_ENV', prefix=prefix) shutit_pexpect_session.login_stack_append(prefix)
def _check_docker(self, shutit): """Private function. Do some docker capability checking """ # If we have sudo, kill any current sudo timeout. This is a bit of a # hammer and somewhat unfriendly, but tells us if we need a password. if spawn.find_executable('sudo') is not None: if subprocess.call(['sudo', '-k']) != 0: shutit.fail("Couldn't kill sudo timeout") # Check the executable is in the path. Not robust (as it could be sudo) # but deals with the common case of 'docker.io' being wrong. docker = shutit.host['docker_executable'].split(' ') if spawn.find_executable(docker[0]) is None: msg = ( 'Didn\'t find %s on the path, what is the executable name (or full path) of docker?' ) % (docker[0], ) shutit.host['docker_executable'] = shutit.prompt_cfg( msg, 'host', 'docker_executable') return False # First check we actually have docker and password (if needed) works check_cmd = docker + ['--version'] str_cmd = ' '.join(check_cmd) cmd_timeout = 10 needed_password = False fail_msg = '' try: shutit.log('Running: ' + str_cmd, level=logging.DEBUG) shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( 'tmp_child', check_cmd[0], check_cmd[1:], timeout=cmd_timeout) child = shutit_pexpect_session.pexpect_child except pexpect.ExceptionPexpect: msg = ( 'Failed to run %s (not sure why this has happened)...try a different docker executable?' ) % (str_cmd, ) shutit.host['docker_executable'] = shutit.prompt_cfg( msg, 'host', 'docker_executable') return False try: if shutit.child_expect(child, 'assword') == 0: needed_password = True if shutit.host['password'] == '': msg = ( 'Running "%s" has prompted for a password, please enter your host password' ) % (str_cmd, ) shutit.host['password'] = shutit.prompt_cfg(msg, 'host', 'password', ispass=True) shutit_pexpect_session.sendline(shutit.host['password']) shutit_pexpect_session.expect([]) except pexpect.ExceptionPexpect: fail_msg = '"%s" did not complete in %ss' % (str_cmd, cmd_timeout) child.close() if child.exitstatus != 0: fail_msg = '"%s" didn\'t return a 0 exit code' % (str_cmd, ) if fail_msg: # Ideally here we'd split up our checks so if it asked for a # password, kill the sudo timeout and run `sudo -l`. We then know if # the password is right or not so we know what we need to prompt # for. At the moment we assume the password if it was asked for. if needed_password: msg = ( fail_msg + ', your host password or docker_executable config may be wrong (I will assume password).\nPlease confirm your host password.' ) name, ispass = '******', True else: msg = ( fail_msg + ', your docker_executable setting seems to be wrong.\nPlease confirm your docker executable, eg "sudo docker".' ) name, ispass = '******', False shutit.host[name] = shutit.prompt_cfg(msg, 'host', name, ispass=ispass) return False return True
def start_container(self, shutit_session_name, loglevel=logging.DEBUG): shutit = shutit_global.shutit docker = shutit.host['docker_executable'].split(' ') # Always-required options if not os.path.exists(shutit.build['shutit_state_dir'] + '/cidfiles'): os.makedirs(shutit.build['shutit_state_dir'] + '/cidfiles') shutit.build['cidfile'] = shutit.build[ 'shutit_state_dir'] + '/cidfiles/' + shutit.host[ 'username'] + '_cidfile_' + shutit.build['build_id'] cidfile_arg = '--cidfile=' + shutit.build['cidfile'] # Singly-specified options privileged_arg = '' name_arg = '' hostname_arg = '' rm_arg = '' net_arg = '' mount_docker_arg = '' shell_arg = '/bin/bash' if shutit.build['privileged']: privileged_arg = '--privileged=true' if shutit.target['name'] != '': name_arg = '--name=' + shutit.target['name'] if shutit.target['hostname'] != '': hostname_arg = '-h=' + shutit.target['hostname'] if shutit.build['net'] != '': net_arg = '--net="' + shutit.build['net'] + '"' if shutit.build['mount_docker']: mount_docker_arg = '-v=/var/run/docker.sock:/var/run/docker.sock' # Incompatible with do_repository_work if shutit.target['rm']: rm_arg = '--rm=true' if shutit.build['base_image'] in ('alpine', 'busybox'): shell_arg = '/bin/ash' # Multiply-specified options port_args = [] dns_args = [] volume_args = [] volumes_from_args = [] volumes_list = shutit.target['volumes'].strip().split() volumes_from_list = shutit.target['volumes_from'].strip().split() ports_list = shutit.target['ports'].strip().split() dns_list = shutit.host['dns'].strip().split() for portmap in ports_list: port_args.append('-p=' + portmap) for dns in dns_list: dns_args.append('--dns=' + dns) for volume in volumes_list: volume_args.append('-v=' + volume) for volumes_from in volumes_from_list: volumes_from_args.append('--volumes-from=' + volumes_from) docker_command = docker + [ arg for arg in [ 'run', cidfile_arg, privileged_arg, name_arg, hostname_arg, rm_arg, net_arg, mount_docker_arg, ] + volume_args + volumes_from_args + port_args + dns_args + ['-t', '-i', shutit.target['docker_image'], shell_arg] if arg != '' ] if shutit.build['interactive'] >= 3: print( '\n\nAbout to start container. Ports mapped will be: ' + ', '.join(port_args) + '\n\n[host]\nports:<value>\n\nconfig, building on the configurable base image passed in in:\n\n --image <image>\n\nor config:\n\n [target]\n docker_image:<image>)\n\nBase image in this case is:\n\n ' + shutit.target['docker_image'] + '\n\n' + shutit_util.colourise('32', '\n[Hit return to continue]')) shutit_util.util_raw_input() shutit.build['docker_command'] = ' '.join(docker_command) shutit.log('Command being run is: ' + shutit.build['docker_command'], level=logging.DEBUG) shutit.log('Downloading image, please be patient', level=logging.INFO) was_sent = string.join(docker_command, ' ') shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( shutit_session_name, docker_command[0], docker_command[1:]) target_child = shutit_pexpect_session.pexpect_child expect = [ 'assword', shutit.expect_prompts['base_prompt'].strip(), 'Waiting', 'ulling', 'endpoint', 'Download', 'o such file' ] res = shutit_pexpect_session.expect(expect, timeout=9999) while True: try: shutit.log(target_child.before + target_child.after, level=loglevel) except: pass if res == 0: res = shutit.send(shutit.host['password'], shutit_pexpect_child=target_child, expect=expect, timeout=9999, check_exit=False, fail_on_empty_before=False, echo=False, loglevel=loglevel) elif res == 1: shutit.log('Prompt found, breaking out', level=logging.DEBUG) break elif res == 6: shutit.fail( 'Docker not installed. Is this a mac? If so, install Docker Toolbox - see https://docker.com' ) break else: res = shutit_pexpect_session.expect(expect, timeout=9999) continue # Did the pull work? if not shutit_pexpect_session.check_last_exit_values(was_sent): shutit_global.shutit.pause_point( 'Command:\n\n' + was_sent + '\n\nfailed, you have a shell to try rectifying the problem before continuing.' ) # Get the cid while True: try: cid = open(shutit.build['cidfile']).read() break except Exception: time.sleep(1) if cid == '' or re.match('^[a-z0-9]+$', cid) == None: shutit.fail( 'Could not get container_id - quitting. Check whether other containers may be clashing on port allocation or name.\nYou might want to try running: sudo docker kill ' + shutit.target['name'] + '; sudo docker rm ' + shutit.target['name'] + '\nto resolve a name clash or: ' + shutit.host['docker_executable'] + ' ps -a | grep ' + shutit.target['ports'] + " | awk '{print $1}' | " + 'xargs ' + shutit.host['docker_executable'] + ' kill\nto ' + 'resolve a port clash\n') shutit.log('cid: ' + cid, level=logging.DEBUG) shutit.target['container_id'] = cid return target_child
def conn_docker_start_container(shutit, shutit_session_name, loglevel=logging.DEBUG): docker = shutit.host['docker_executable'].split(' ') # Always-required options if not os.path.exists(shutit.build['shutit_state_dir'] + '/cidfiles'): os.makedirs(shutit.build['shutit_state_dir'] + '/cidfiles') shutit.build['cidfile'] = shutit.build[ 'shutit_state_dir'] + '/cidfiles/' + shutit.host[ 'username'] + '_cidfile_' + shutit.build['build_id'] cidfile_arg = '--cidfile=' + shutit.build['cidfile'] # Singly-specified options privileged_arg = '' name_arg = '' hostname_arg = '' rm_arg = '' net_arg = '' mount_docker_arg = '' shell_arg = '/bin/bash' if shutit.build['privileged']: privileged_arg = '--privileged=true' if shutit.target['name'] != '': name_arg = '--name=' + shutit.target['name'] if shutit.target['hostname'] != '': hostname_arg = '-h=' + shutit.target['hostname'] if shutit.build['net'] != '': net_arg = '--net="' + shutit.build['net'] + '"' if shutit.build['mount_docker']: mount_docker_arg = '-v=/var/run/docker.sock:/var/run/docker.sock' # Incompatible with do_repository_work if shutit.target['rm']: rm_arg = '--rm=true' if shutit.build['base_image'] in ('alpine', 'busybox'): shell_arg = '/bin/ash' # Multiply-specified options port_args = [] dns_args = [] volume_args = [] volumes_from_args = [] volumes_list = shutit.target['volumes'].strip().split() volumes_from_list = shutit.target['volumes_from'].strip().split() ports_list = shutit.target['ports'].strip().split() dns_list = shutit.host['dns'].strip().split() for portmap in ports_list: port_args.append('-p=' + portmap) for dns in dns_list: dns_args.append('--dns=' + dns) for volume in volumes_list: volume_args.append('-v=' + volume) for volumes_from in volumes_from_list: volumes_from_args.append('--volumes-from=' + volumes_from) docker_command = docker + [ arg for arg in [ 'run', cidfile_arg, privileged_arg, name_arg, hostname_arg, rm_arg, net_arg, mount_docker_arg, ] + volume_args + volumes_from_args + port_args + dns_args + ['-t', '-i', shutit.target['docker_image'], shell_arg] if arg != '' ] shutit.build['docker_command'] = ' '.join(docker_command) # docker run happens here shutit.log('Startup command is: ' + shutit.build['docker_command'], level=logging.INFO) shutit.log('Downloading image, please be patient', level=logging.INFO) was_sent = ' '.join(docker_command) shutit_pexpect_session = shutit_pexpect.ShutItPexpectSession( shutit_session_name, docker_command[0], docker_command[1:]) target_child = shutit_pexpect_session.pexpect_child expect = [ 'assword', shutit.expect_prompts['base_prompt'].strip(), 'Waiting', 'ulling', 'endpoint', 'Download', 'o such file' ] res = shutit_pexpect_session.expect(expect, timeout=9999) while True: if target_child.before == type(pexpect.exceptions.EOF): shutit.fail('EOF exception seen') try: shutit.log(target_child.before + target_child.after, level=logging.DEBUG) except: pass if res == 0: res = shutit.send(shutit.host['password'], shutit_pexpect_child=target_child, expect=expect, timeout=9999, check_exit=False, fail_on_empty_before=False, echo=False, loglevel=loglevel) elif res == 1: shutit.log('Prompt found, breaking out', level=logging.DEBUG) break elif res == 6: shutit.fail('Docker not installed.') break elif res == 7: shutit.log('Initial command timed out, assuming OK to continue.', level=logging.WARNING) break elif res == 8: shutit.fail('EOF seen.') else: res = shutit_pexpect_session.expect(expect, timeout=9999) continue # Did the pull work? shutit.log('Checking exit status', level=loglevel) if not shutit_pexpect_session.check_last_exit_values(was_sent): shutit_global.shutit.pause_point( 'Command:\n\n' + was_sent + '\n\nfailed, you have a shell to try rectifying the problem before continuing.' ) shutit.log('Getting cid', level=loglevel) # Get the cid while True: try: cid = open(shutit.build['cidfile']).read() break except Exception: time.sleep(1) if cid == '' or re.match('^[a-z0-9]+$', cid) == None: shutit.fail( 'Could not get container_id - quitting. Check whether other containers may be clashing on port allocation or name.\nYou might want to try running: sudo docker kill ' + shutit.target['name'] + '; sudo docker rm ' + shutit.target['name'] + '\nto resolve a name clash or: ' + shutit.host['docker_executable'] + ' ps -a | grep ' + shutit.target['ports'] + " | awk '{print $1}' | " + 'xargs ' + shutit.host['docker_executable'] + ' kill\nto ' + 'resolve a port clash\n') shutit.log('cid: ' + cid, level=logging.DEBUG) shutit.target['container_id'] = cid return target_child