<s> """<STR_LIT>""" <EOL> from harpoon . errors import BadOption , BadImage , BadResult , UserQuit <EOL> from harpoon . option_spec . harpoon_specs import HarpoonSpec <EOL> from harpoon import helpers as hp <EOL> from harpoon . helpers import until <EOL> from docker . errors import APIError as DockerAPIError <EOL> from input_algorithms . spec_base import NotSpecified <EOL> from input_algorithms . meta import Meta <EOL> from contextlib import contextmanager <EOL> from docker . utils import utils <EOL> from harpoon import dockerpty <EOL> from six . moves import input <EOL> import docker . errors <EOL> import logging <EOL> import socket <EOL> import uuid <EOL> import time <EOL> import os <EOL> log = logging . getLogger ( "<STR_LIT>" ) <EOL> class Runner ( object ) : <EOL> """<STR_LIT>""" <EOL> def run_container ( self , conf , images , detach = False , started = None , dependency = False , tag = None ) : <EOL> """<STR_LIT>""" <EOL> if conf . container_id : <EOL> return <EOL> try : <EOL> self . run_deps ( conf , images ) <EOL> tty = not detach and ( dependency or conf . harpoon . interactive ) <EOL> container_id = self . create_container ( conf , detach , tty ) <EOL> conf . container_id = container_id <EOL> try : <EOL> self . wait_for_deps ( conf , images ) <EOL> except KeyboardInterrupt : <EOL> raise UserQuit ( ) <EOL> self . start_container ( conf , tty = tty , detach = detach , is_dependency = dependency ) <EOL> finally : <EOL> if not detach and not dependency : <EOL> self . stop_deps ( conf , images ) <EOL> self . stop_container ( conf , tag = tag ) <EOL> self . delete_deps ( conf , images ) <EOL> def delete_deps ( self , conf , images ) : <EOL> """<STR_LIT>""" <EOL> for dependency_name , _ in conf . dependency_images ( ) : <EOL> image = images [ dependency_name ] <EOL> if image . deleteable_image : <EOL> log . info ( "<STR_LIT>" . format ( image . image_name ) ) <EOL> conf . harpoon . docker_context . remove_image ( image . image_name ) <EOL> def run_deps ( self , conf , images ) : <EOL> """<STR_LIT>""" <EOL> for dependency_name , detached in conf . dependency_images ( ) : <EOL> try : <EOL> self . run_container ( images [ dependency_name ] , images , detach = detached , dependency = True ) <EOL> except Exception as error : <EOL> raise BadImage ( "<STR_LIT>" , image = conf . name , dependency = dependency_name , error = error ) <EOL> def stop_deps ( self , conf , images ) : <EOL> """<STR_LIT>""" <EOL> for dependency , _ in conf . dependency_images ( ) : <EOL> self . stop_deps ( images [ dependency ] , images ) <EOL> try : <EOL> self . stop_container ( images [ dependency ] , fail_on_bad_exit = True , fail_reason = "<STR_LIT>" ) <EOL> except BadImage : <EOL> raise <EOL> except Exception as error : <EOL> log . warning ( "<STR_LIT>" , conf . name , dependency , images [ dependency ] . container_name , error ) <EOL> def wait_for_deps ( self , conf , images ) : <EOL> """<STR_LIT>""" <EOL> from harpoon . option_spec . image_objs import WaitCondition <EOL> ctxt = conf . harpoon . docker_context_maker ( ) <EOL> waited = set ( ) <EOL> last_attempt = { } <EOL> dependencies = set ( dep for dep , _ in conf . dependency_images ( ) ) <EOL> wait_conditions = { } <EOL> for dependency in dependencies : <EOL> if conf . dependency_options is not NotSpecified and dependency in conf . dependency_options and conf . dependency_options [ dependency ] . wait_condition is not NotSpecified : <EOL> wait_conditions [ dependency ] = conf . dependency_options [ dependency ] . wait_condition <EOL> elif images [ dependency ] . wait_condition is not NotSpecified : <EOL> wait_conditions [ dependency ] = images [ dependency ] . wait_condition <EOL> if not wait_conditions : <EOL> return <EOL> start = time . time ( ) <EOL> while True : <EOL> this_round = [ ] <EOL> for dependency in dependencies : <EOL> if dependency in waited : <EOL> continue <EOL> image = images [ dependency ] <EOL> if dependency in wait_conditions : <EOL> done = self . wait_for_dep ( ctxt , image , wait_conditions [ dependency ] , start , last_attempt . get ( dependency ) ) <EOL> this_round . append ( done ) <EOL> if done is True : <EOL> waited . add ( dependency ) <EOL> elif done is False : <EOL> last_attempt [ dependency ] = time . time ( ) <EOL> elif done is WaitCondition . Timedout : <EOL> log . warning ( "<STR_LIT>" , image . container_id ) <EOL> self . stop_container ( image ) <EOL> else : <EOL> waited . add ( dependency ) <EOL> if set ( this_round ) != set ( [ WaitCondition . KeepWaiting ] ) : <EOL> if dependencies - waited == set ( ) : <EOL> log . info ( "<STR_LIT>" ) <EOL> break <EOL> else : <EOL> log . info ( "<STR_LIT>" , list ( dependencies - waited ) ) <EOL> couldnt_wait = set ( ) <EOL> container_ids = { } <EOL> for dependency in dependencies : <EOL> if dependency in waited : <EOL> continue <EOL> image = images [ dependency ] <EOL> if image . container_id is None : <EOL> stopped = True <EOL> if dependency not in container_ids : <EOL> available = sorted ( [ i for i in available if "<STR_LIT>" . format ( image . container_name ) in i [ "<STR_LIT>" ] ] , key = lambda i : i [ "<STR_LIT>" ] ) <EOL> if available : <EOL> container_ids [ dependency ] = available [ <NUM_LIT:0> ] [ "<STR_LIT>" ] <EOL> else : <EOL> if dependency not in container_ids : <EOL> container_ids [ dependency ] = image . container_id <EOL> stopped , _ = self . is_stopped ( image , image . container_id ) <EOL> if stopped : <EOL> couldnt_wait . add ( dependency ) <EOL> if couldnt_wait : <EOL> for container in couldnt_wait : <EOL> if container not in images or container not in container_ids : <EOL> continue <EOL> image = images [ container ] <EOL> container_id = container_ids [ container ] <EOL> container_name = image . container_name <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" . format ( container_id , container_name ) ) <EOL> for line in conf . harpoon . docker_context . logs ( container_id ) . split ( "<STR_LIT:\n>" ) : <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" . format ( line ) ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> raise BadImage ( "<STR_LIT>" , stopped = list ( couldnt_wait ) ) <EOL> time . sleep ( <NUM_LIT:0.1> ) <EOL> def wait_for_dep ( self , ctxt , conf , wait_condition , start , last_attempt ) : <EOL> """<STR_LIT>""" <EOL> from harpoon . option_spec . image_objs import WaitCondition <EOL> conditions = list ( wait_condition . conditions ( start , last_attempt ) ) <EOL> if conditions [ <NUM_LIT:0> ] in ( WaitCondition . KeepWaiting , WaitCondition . Timedout ) : <EOL> return conditions [ <NUM_LIT:0> ] <EOL> log . info ( "<STR_LIT>" , conf . container_name ) <EOL> for condition in conditions : <EOL> log . debug ( "<STR_LIT>" , condition ) <EOL> command = '<STR_LIT>' . format ( condition ) <EOL> try : <EOL> exec_id = ctxt . exec_create ( conf . container_id , command , tty = False ) <EOL> except DockerAPIError as error : <EOL> log . error ( "<STR_LIT>" , condition , conf . name , error ) <EOL> return False <EOL> output = ctxt . exec_start ( exec_id ) . decode ( '<STR_LIT:utf-8>' ) <EOL> inspection = ctxt . exec_inspect ( exec_id ) <EOL> exit_code = inspection [ "<STR_LIT>" ] <EOL> if exit_code != <NUM_LIT:0> : <EOL> log . error ( "<STR_LIT>" , condition , "<STR_LIT>" . join ( line for line in output . split ( '<STR_LIT:\n>' ) ) ) <EOL> return False <EOL> log . info ( "<STR_LIT>" , conf . container_name ) <EOL> return True <EOL> def create_container ( self , conf , detach , tty ) : <EOL> """<STR_LIT>""" <EOL> name = conf . name <EOL> image_name = conf . image_name <EOL> container_name = conf . container_name <EOL> with conf . assumed_role ( ) : <EOL> env = dict ( e . pair for e in conf . env ) <EOL> ports = [ port . host_port for port in conf . ports ] <EOL> links = [ link . pair for link in conf . links ] <EOL> binds = conf . volumes . binds <EOL> command = conf . formatted_command <EOL> volume_names = conf . volumes . volume_names <EOL> volumes_from = list ( conf . volumes . share_with_names ) <EOL> port_bindings = dict ( [ port . pair for port in conf . ports ] ) <EOL> no_tty_option = conf . no_tty_option <EOL> uncreated = [ ] <EOL> for name in binds : <EOL> if not os . path . exists ( name ) : <EOL> log . info ( "<STR_LIT>" , name ) <EOL> try : <EOL> os . makedirs ( name ) <EOL> except OSError as error : <EOL> uncreated . append ( ( name , error ) ) <EOL> if uncreated : <EOL> raise BadOption ( "<STR_LIT>" , uncreated = uncreated ) <EOL> log . info ( "<STR_LIT>" , image_name , name , container_name , tty ) <EOL> if binds : <EOL> log . info ( "<STR_LIT>" , volume_names ) <EOL> if env : <EOL> log . info ( "<STR_LIT>" , sorted ( env . keys ( ) ) ) <EOL> if links : <EOL> log . info ( "<STR_LIT>" , links ) <EOL> if ports : <EOL> log . info ( "<STR_LIT>" , ports ) <EOL> if port_bindings : <EOL> log . info ( "<STR_LIT>" , ports ) <EOL> if volumes_from : <EOL> log . info ( "<STR_LIT>" , volumes_from ) <EOL> host_config = conf . harpoon . docker_context . create_host_config ( <EOL> links = links <EOL> , binds = binds <EOL> , volumes_from = volumes_from <EOL> , port_bindings = port_bindings <EOL> , devices = conf . devices <EOL> , lxc_conf = conf . lxc_conf <EOL> , privileged = conf . privileged <EOL> , restart_policy = conf . restart_policy <EOL> , dns = conf . network . dns <EOL> , dns_search = conf . network . dns_search <EOL> , extra_hosts = conf . network . extra_hosts <EOL> , network_mode = conf . network . network_mode <EOL> , publish_all_ports = conf . network . publish_all_ports <EOL> , cap_add = conf . cpu . cap_add <EOL> , cap_drop = conf . cpu . cap_drop <EOL> , mem_limit = conf . cpu . mem_limit <EOL> , memswap_limit = conf . cpu . memswap_limit <EOL> , ulimits = conf . ulimits <EOL> , read_only = conf . read_only_rootfs <EOL> , log_config = conf . log_config <EOL> , security_opt = conf . security_opt <EOL> , ** conf . other_options . host_config <EOL> ) <EOL> container_id = conf . harpoon . docker_context . create_container ( image_name <EOL> , name = container_name <EOL> , detach = detach <EOL> , command = command <EOL> , volumes = volume_names <EOL> , environment = env <EOL> , tty = False if no_tty_option else tty <EOL> , user = conf . user <EOL> , ports = ports <EOL> , stdin_open = tty <EOL> , dns = conf . network . dns <EOL> , hostname = conf . network . hostname <EOL> , domainname = conf . network . domainname <EOL> , network_disabled = conf . network . disabled <EOL> , cpuset = conf . cpu . cpuset <EOL> , cpu_shares = conf . cpu . cpu_shares <EOL> , host_config = host_config <EOL> , ** conf . other_options . create <EOL> ) <EOL> if isinstance ( container_id , dict ) : <EOL> if "<STR_LIT>" in container_id : <EOL> raise BadImage ( "<STR_LIT>" , image = name , error = container_id [ "<STR_LIT>" ] ) <EOL> container_id = container_id [ "<STR_LIT>" ] <EOL> return container_id <EOL> def start_container ( self , conf , tty = True , detach = False , is_dependency = False , no_intervention = False ) : <EOL> """<STR_LIT>""" <EOL> container_id = conf . container_id <EOL> container_name = conf . container_name <EOL> log . info ( "<STR_LIT>" , container_name , container_id ) <EOL> try : <EOL> if not detach and not is_dependency : <EOL> self . start_tty ( conf , interactive = tty , ** conf . other_options . start ) <EOL> else : <EOL> conf . harpoon . docker_context . start ( container_id <EOL> , ** conf . other_options . start <EOL> ) <EOL> except docker . errors . APIError as error : <EOL> if str ( error ) . startswith ( "<STR_LIT>" ) : <EOL> log . error ( "<STR_LIT>" ) <EOL> inspection = None <EOL> if not detach and not is_dependency : <EOL> inspection = self . get_exit_code ( conf ) <EOL> if inspection and not no_intervention : <EOL> if not inspection [ "<STR_LIT>" ] [ "<STR_LIT>" ] and inspection [ "<STR_LIT>" ] [ "<STR_LIT>" ] != <NUM_LIT:0> : <EOL> self . stage_run_intervention ( conf ) <EOL> raise BadImage ( "<STR_LIT>" , container_id = container_id , container_name = container_name , reason = "<STR_LIT>" ) <EOL> if not is_dependency and conf . harpoon . intervene_afterwards and not no_intervention : <EOL> self . stage_run_intervention ( conf , just_do_it = True ) <EOL> def start_tty ( self , conf , interactive ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> ctxt = conf . harpoon . docker_context_maker ( ) <EOL> container_id = conf . container_id <EOL> stdin = conf . harpoon . tty_stdin <EOL> stdout = conf . harpoon . tty_stdout <EOL> stderr = conf . harpoon . tty_stderr <EOL> if callable ( stdin ) : stdin = stdin ( ) <EOL> if callable ( stdout ) : stdout = stdout ( ) <EOL> if callable ( stderr ) : stderr = stderr ( ) <EOL> dockerpty . start ( ctxt , container_id , interactive = interactive , stdout = stdout , stderr = stderr , stdin = stdin ) <EOL> except KeyboardInterrupt : <EOL> pass <EOL> def wait_till_stopped ( self , conf , container_id , timeout = <NUM_LIT:10> , message = None , waiting = True ) : <EOL> """<STR_LIT>""" <EOL> stopped = False <EOL> inspection = None <EOL> for _ in until ( timeout = timeout , action = message ) : <EOL> try : <EOL> inspection = conf . harpoon . docker_context . inspect_container ( container_id ) <EOL> if not isinstance ( inspection , dict ) : <EOL> log . error ( "<STR_LIT>" , inspection ) <EOL> else : <EOL> if not inspection [ "<STR_LIT>" ] [ "<STR_LIT>" ] : <EOL> stopped = True <EOL> conf . container_id = None <EOL> break <EOL> else : <EOL> break <EOL> except ( socket . timeout , ValueError ) : <EOL> log . warning ( "<STR_LIT>" , container_id ) <EOL> except DockerAPIError as error : <EOL> if error . response . status_code != <NUM_LIT> : <EOL> raise <EOL> else : <EOL> break <EOL> if not inspection : <EOL> log . warning ( "<STR_LIT>" ) <EOL> stopped = True <EOL> exit_code = <NUM_LIT:1> <EOL> else : <EOL> exit_code = inspection [ "<STR_LIT>" ] [ "<STR_LIT>" ] <EOL> return stopped , exit_code <EOL> def is_stopped ( self , * args , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> kwargs [ "<STR_LIT>" ] = False <EOL> return self . wait_till_stopped ( * args , ** kwargs ) <EOL> def stop_container ( self , conf , fail_on_bad_exit = False , fail_reason = None , tag = None , remove_volumes = False ) : <EOL> """<STR_LIT>""" <EOL> stopped = False <EOL> container_id = conf . container_id <EOL> if not container_id : <EOL> return <EOL> container_name = conf . container_name <EOL> stopped , exit_code = self . is_stopped ( conf , container_id ) <EOL> if stopped : <EOL> if exit_code != <NUM_LIT:0> and fail_on_bad_exit : <EOL> if not conf . harpoon . interactive : <EOL> print_logs = True <EOL> else : <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" . format ( container_name , container_id , exit_code ) ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> conf . harpoon . stdout . flush ( ) <EOL> answer = input ( "<STR_LIT>" ) <EOL> print_logs = not answer or answer . lower ( ) . startswith ( "<STR_LIT:y>" ) <EOL> if print_logs : <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" . format ( container_id , container_name ) ) <EOL> for line in conf . harpoon . docker_context . logs ( container_id ) . split ( "<STR_LIT:\n>" ) : <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" . format ( line ) ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> fail_reason = fail_reason or "<STR_LIT>" <EOL> raise BadImage ( fail_reason , container_id = container_id , container_name = container_name ) <EOL> else : <EOL> try : <EOL> log . info ( "<STR_LIT>" , container_name , container_id ) <EOL> conf . harpoon . docker_context . kill ( container_id , <NUM_LIT:9> ) <EOL> except DockerAPIError : <EOL> pass <EOL> self . wait_till_stopped ( conf , container_id , timeout = <NUM_LIT:10> , message = "<STR_LIT>" . format ( container_name , container_id ) ) <EOL> if tag : <EOL> log . info ( "<STR_LIT>" , container_id , tag ) <EOL> new_id = conf . harpoon . docker_context . commit ( container_id ) [ "<STR_LIT>" ] <EOL> conf [ "<STR_LIT>" ] = new_id <EOL> if tag is not True : <EOL> the_tag = "<STR_LIT>" if conf . tag is NotSpecified else conf . tag <EOL> conf . harpoon . docker_context . tag ( new_id , repository = tag , tag = the_tag , force = True ) <EOL> mounts = [ ] <EOL> if remove_volumes : <EOL> for m in conf . harpoon . docker_context . inspect_container ( container_id ) [ "<STR_LIT>" ] : <EOL> if "<STR_LIT:Name>" in m : <EOL> mounts . append ( m [ '<STR_LIT:Name>' ] ) <EOL> if not conf . harpoon . no_cleanup : <EOL> log . info ( "<STR_LIT>" , container_name , container_id ) <EOL> for _ in until ( timeout = <NUM_LIT:10> , action = "<STR_LIT>" . format ( container_name , container_id ) ) : <EOL> try : <EOL> conf . harpoon . docker_context . remove_container ( container_id ) <EOL> break <EOL> except socket . timeout : <EOL> break <EOL> except ( ValueError , DockerAPIError ) as error : <EOL> log . warning ( "<STR_LIT>" , container_id , error ) <EOL> for mount in mounts : <EOL> try : <EOL> log . info ( "<STR_LIT>" . format ( mount ) ) <EOL> conf . harpoon . docker_context . remove_volume ( mount ) <EOL> except DockerAPIError as error : <EOL> log . warning ( "<STR_LIT>" , mount , error ) <EOL> def get_exit_code ( self , conf ) : <EOL> """<STR_LIT>""" <EOL> for _ in until ( timeout = <NUM_LIT:0.5> , step = <NUM_LIT:0.1> , silent = True ) : <EOL> try : <EOL> inspection = conf . harpoon . docker_context . inspect_container ( conf . container_id ) <EOL> if not isinstance ( inspection , dict ) or "<STR_LIT>" not in inspection : <EOL> raise BadResult ( "<STR_LIT>" , found = inspection ) <EOL> elif not inspection [ "<STR_LIT>" ] [ "<STR_LIT>" ] : <EOL> return inspection <EOL> except Exception as error : <EOL> log . error ( "<STR_LIT>" , conf . container_id , error ) <EOL> def stage_run_intervention ( self , conf , just_do_it = False ) : <EOL> """<STR_LIT>""" <EOL> if not conf . harpoon . interactive or conf . harpoon . no_intervention : <EOL> return <EOL> if just_do_it : <EOL> answer = '<STR_LIT:y>' <EOL> else : <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> conf . harpoon . stdout . flush ( ) <EOL> answer = input ( "<STR_LIT>" ) <EOL> if not answer or answer . lower ( ) . startswith ( "<STR_LIT:y>" ) : <EOL> with self . commit_and_run ( conf . container_id , conf , command = "<STR_LIT>" ) : <EOL> pass <EOL> def stage_build_intervention ( self , conf , container ) : <EOL> if not container : <EOL> return <EOL> conf = conf . configuration . root ( ) . wrapped ( ) <EOL> conf . update ( { "<STR_LIT>" : "<STR_LIT>" . format ( container ) , "<STR_LIT>" : [ ] } ) <EOL> conf = HarpoonSpec ( ) . image_spec . normalise ( Meta ( conf , [ ] ) , conf ) <EOL> with self . intervention ( container , conf ) : <EOL> log . info ( "<STR_LIT>" , container ) <EOL> try : <EOL> conf . harpoon . docker_context . kill ( container , signal = <NUM_LIT:9> ) <EOL> except Exception as error : <EOL> log . error ( "<STR_LIT>" , container , error ) <EOL> try : <EOL> conf . harpoon . docker_context . remove_container ( container ) <EOL> except Exception as error : <EOL> log . error ( "<STR_LIT>" , container , error ) <EOL> @ contextmanager <EOL> def intervention ( self , commit , conf ) : <EOL> """<STR_LIT>""" <EOL> if not conf . harpoon . interactive or conf . harpoon . no_intervention : <EOL> yield <EOL> return <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> hp . write_to ( conf . harpoon . stdout , "<STR_LIT>" ) <EOL> conf . harpoon . stdout . flush ( ) <EOL> answer = input ( "<STR_LIT>" ) <EOL> if answer and not answer . lower ( ) . startswith ( "<STR_LIT:y>" ) : <EOL> yield <EOL> return <EOL> with self . commit_and_run ( commit , conf , command = "<STR_LIT>" ) : <EOL> yield <EOL> @ contextmanager <EOL> def commit_and_run ( self , commit , conf , command = "<STR_LIT>" ) : <EOL> """<STR_LIT>""" <EOL> image_hash = None <EOL> try : <EOL> image_hash = conf . harpoon . docker_context . commit ( commit ) [ "<STR_LIT>" ] <EOL> new_conf = conf . clone ( ) <EOL> new_conf . bash = NotSpecified <EOL> new_conf . command = command <EOL> new_conf . image_name = image_hash <EOL> new_conf . container_id = None <EOL> new_conf . container_name = "<STR_LIT>" . format ( conf . container_id , str ( uuid . uuid1 ( ) ) ) <EOL> container_id = self . create_container ( new_conf , False , True ) <EOL> new_conf . container_id = container_id <EOL> try : <EOL> self . start_container ( new_conf , tty = True , detach = False , is_dependency = False , no_intervention = True ) <EOL> finally : <EOL> self . stop_container ( new_conf ) <EOL> yield <EOL> except Exception as error : <EOL> log . error ( "<STR_LIT>" , error ) <EOL> raise <EOL> finally : <EOL> try : <EOL> if image_hash : <EOL> log . info ( "<STR_LIT>" , image_hash ) <EOL> conf . harpoon . docker_context . remove_image ( image_hash ) <EOL> except Exception as error : <EOL> log . error ( "<STR_LIT>" , image_hash , error ) </s>
