Loading gitlabci_local/engine.py +38 −81 Changes for gitlabci_local/engine.py: 38 added lines, 81 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Libraries import docker import sys from enum import Enum # Components from .engines import docker # Backend enumeration class Backend(Enum): DOCKER = 1 UNKNOWN = 2 # Engine class class Engine: # Members client = None backend = Backend.UNKNOWN engine = None # Constructor def __init__(self): # Engine client self.client = docker.from_env() # Docker engine detection if not self.engine: try: self.engine = docker.Docker() self.backend = Backend.DOCKER except: self.engine = None # Unknown engine fallback if not self.engine: raise NotImplementedError('Unknown or unsupported container engine...') # Exec def exec(self, container, command): # Execute command in container container.exec_run(command) return self.engine.exec(container, command) # Help def help(self, type): # Exec help if type is 'exec': return 'docker exec -it' # Default fallback return '' def help(self, command): return self.engine.help(command) # Get def get(self, image): # Validate image exists try: self.client.images.get(image) # Pull missing image except docker.errors.ImageNotFound: pull(image) self.engine.get(image) # Logs def logs(self, container): # Return logs stream return container.logs(stream=True) return self.engine.logs(container) # Name def name(self, container): # Result return container.name return self.engine.name(container) # Pull def pull(self, image): # Pull image with logs stream for data in self.client.api.pull(image, stream=True, decode=True): # Layer progress logs if 'progress' in data: if sys.stdout.isatty(): print( '\r\033[K%s: %s %s' % (data['id'], data['status'], data['progress']), end='', flush=True) # Layer event logs elif 'progressDetail' in data: if sys.stdout.isatty(): print('\r\033[K%s: %s' % (data['id'], data['status']), end='', flush=True) # Layer completion logs elif 'id' in data: print('\r\033[K%s: %s' % (data['id'], data['status']), flush=True) # Image logs else: print('\r\033[K%s' % (data['status']), flush=True) # Footer print(' ', flush=True) self.engine.pull(image) # Remove def remove(self, container): # Remove container container.remove(force=True) self.engine.remove(container) # Run def run(self, image, command, entrypoint, variables, network, volumes, directory): # Run container image return self.client.containers.run( image, command=command, detach=True, entrypoint=entrypoint, environment=variables, network_mode=network, privileged=True, remove=False, stdout=True, stderr=True, stream=True, volumes=volumes, working_dir=directory) return self.engine.run(image, command, entrypoint, variables, network, volumes, directory) # Sockets def sockets(self, volumes): # Add socket volume volumes['/var/run/docker.sock'] = { # 'bind': '/var/run/docker.sock', 'mode': 'rw' } self.engine.sockets(volumes) # Stop def stop(self, container, timeout): self.engine.stop(container, timeout) # Stop container container.stop(timeout=timeout) # Supports def supports(self, image, container, binary): return self.engine.supports(image, container, binary) # Wait def wait(self, container): # Wait container result = container.wait() # Result return result['StatusCode'] == 0 return self.engine.wait(container) gitlabci_local/engines/__init__.py 0 → 100644 +0 −0 Empty file added. gitlabci_local/engines/docker.py 0 → 100755 +136 −0 Changes for gitlabci_local/engines/docker.py: 136 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Libraries import docker import sys # Docker class class Docker: # Members client = None # Constructor def __init__(self): # Engine client self.client = docker.from_env() self.client.ping() # Exec def exec(self, container, command): # Execute command in container return container.exec_run(command) # Help def help(self, command): # Exec command if command is 'exec': return 'docker exec -it' # Default fallback return '' # Get def get(self, image): # Validate image exists try: self.client.images.get(image) # Pull missing image except docker.errors.ImageNotFound: self.pull(image) # Logs def logs(self, container): # Return logs stream return container.logs(stream=True) # Name def name(self, container): # Result return container.name # Pull def pull(self, image): # Pull image with logs stream for data in self.client.api.pull(image, stream=True, decode=True): # Layer progress logs if 'progress' in data: if sys.stdout.isatty(): print( '\r\033[K%s: %s %s' % (data['id'], data['status'], data['progress']), end='', flush=True) # Layer event logs elif 'progressDetail' in data: if sys.stdout.isatty(): print('\r\033[K%s: %s' % (data['id'], data['status']), end='', flush=True) # Layer completion logs elif 'id' in data: print('\r\033[K%s: %s' % (data['id'], data['status']), flush=True) # Image logs else: print('\r\033[K%s' % (data['status']), flush=True) # Footer print(' ', flush=True) # Remove def remove(self, container): # Remove container container.remove(force=True) # Run def run(self, image, command, entrypoint, variables, network, volumes, directory): # Run container image return self.client.containers.run( image, command=command, detach=True, entrypoint=entrypoint, environment=variables, network_mode=network, privileged=True, remove=False, stdout=True, stderr=True, stream=True, volumes=volumes, working_dir=directory) # Sockets def sockets(self, volumes): # Add socket volume volumes['/var/run/docker.sock'] = { # 'bind': '/var/run/docker.sock', 'mode': 'rw' } # Stop def stop(self, container, timeout): # Stop container container.stop(timeout=timeout) # Supports def supports(self, image, container, binary): # Validate binary support exit_code, output = self.exec(container, 'whereis %s' % (binary)) # Result return exit_code == 0 # Wait def wait(self, container): # Wait container result = container.wait() # Result return result['StatusCode'] == 0 gitlabci_local/runner.py +14 −3 Changes for gitlabci_local/runner.py: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -308,22 +308,33 @@ def runner(options, job_data, last_result, time_launcher): # Show container logs try: for line in engine.logs(container): if isinstance(line, bytes): if marker_debug in line.decode(): break sys.stdout.buffer.write(line) sys.stdout.buffer.flush() else: if marker_debug in line: break sys.stdout.write(line) sys.stdout.flush() except: pass # Runner bash or debug mode if options.bash or options.debug: print(' ') exit_code, output = engine.exec(container, 'which bash') # Select shell shell = 'sh' if exit_code == 0: if engine.supports(image, container, 'bash'): shell = 'bash' # Acquire container informations container_exec = engine.help('exec') container_name = engine.name(container) # Footer debugging informations print(' ') print( ' %s> INFORMATION: %sUse \'%s%s %s %s%s\' commands for debugging. Interrupt with Ctrl+C...%s' % (colored.fg('yellow') + colored.attr('bold'), Loading Loading
gitlabci_local/engine.py +38 −81 Changes for gitlabci_local/engine.py: 38 added lines, 81 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Libraries import docker import sys from enum import Enum # Components from .engines import docker # Backend enumeration class Backend(Enum): DOCKER = 1 UNKNOWN = 2 # Engine class class Engine: # Members client = None backend = Backend.UNKNOWN engine = None # Constructor def __init__(self): # Engine client self.client = docker.from_env() # Docker engine detection if not self.engine: try: self.engine = docker.Docker() self.backend = Backend.DOCKER except: self.engine = None # Unknown engine fallback if not self.engine: raise NotImplementedError('Unknown or unsupported container engine...') # Exec def exec(self, container, command): # Execute command in container container.exec_run(command) return self.engine.exec(container, command) # Help def help(self, type): # Exec help if type is 'exec': return 'docker exec -it' # Default fallback return '' def help(self, command): return self.engine.help(command) # Get def get(self, image): # Validate image exists try: self.client.images.get(image) # Pull missing image except docker.errors.ImageNotFound: pull(image) self.engine.get(image) # Logs def logs(self, container): # Return logs stream return container.logs(stream=True) return self.engine.logs(container) # Name def name(self, container): # Result return container.name return self.engine.name(container) # Pull def pull(self, image): # Pull image with logs stream for data in self.client.api.pull(image, stream=True, decode=True): # Layer progress logs if 'progress' in data: if sys.stdout.isatty(): print( '\r\033[K%s: %s %s' % (data['id'], data['status'], data['progress']), end='', flush=True) # Layer event logs elif 'progressDetail' in data: if sys.stdout.isatty(): print('\r\033[K%s: %s' % (data['id'], data['status']), end='', flush=True) # Layer completion logs elif 'id' in data: print('\r\033[K%s: %s' % (data['id'], data['status']), flush=True) # Image logs else: print('\r\033[K%s' % (data['status']), flush=True) # Footer print(' ', flush=True) self.engine.pull(image) # Remove def remove(self, container): # Remove container container.remove(force=True) self.engine.remove(container) # Run def run(self, image, command, entrypoint, variables, network, volumes, directory): # Run container image return self.client.containers.run( image, command=command, detach=True, entrypoint=entrypoint, environment=variables, network_mode=network, privileged=True, remove=False, stdout=True, stderr=True, stream=True, volumes=volumes, working_dir=directory) return self.engine.run(image, command, entrypoint, variables, network, volumes, directory) # Sockets def sockets(self, volumes): # Add socket volume volumes['/var/run/docker.sock'] = { # 'bind': '/var/run/docker.sock', 'mode': 'rw' } self.engine.sockets(volumes) # Stop def stop(self, container, timeout): self.engine.stop(container, timeout) # Stop container container.stop(timeout=timeout) # Supports def supports(self, image, container, binary): return self.engine.supports(image, container, binary) # Wait def wait(self, container): # Wait container result = container.wait() # Result return result['StatusCode'] == 0 return self.engine.wait(container)
gitlabci_local/engines/docker.py 0 → 100755 +136 −0 Changes for gitlabci_local/engines/docker.py: 136 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Libraries import docker import sys # Docker class class Docker: # Members client = None # Constructor def __init__(self): # Engine client self.client = docker.from_env() self.client.ping() # Exec def exec(self, container, command): # Execute command in container return container.exec_run(command) # Help def help(self, command): # Exec command if command is 'exec': return 'docker exec -it' # Default fallback return '' # Get def get(self, image): # Validate image exists try: self.client.images.get(image) # Pull missing image except docker.errors.ImageNotFound: self.pull(image) # Logs def logs(self, container): # Return logs stream return container.logs(stream=True) # Name def name(self, container): # Result return container.name # Pull def pull(self, image): # Pull image with logs stream for data in self.client.api.pull(image, stream=True, decode=True): # Layer progress logs if 'progress' in data: if sys.stdout.isatty(): print( '\r\033[K%s: %s %s' % (data['id'], data['status'], data['progress']), end='', flush=True) # Layer event logs elif 'progressDetail' in data: if sys.stdout.isatty(): print('\r\033[K%s: %s' % (data['id'], data['status']), end='', flush=True) # Layer completion logs elif 'id' in data: print('\r\033[K%s: %s' % (data['id'], data['status']), flush=True) # Image logs else: print('\r\033[K%s' % (data['status']), flush=True) # Footer print(' ', flush=True) # Remove def remove(self, container): # Remove container container.remove(force=True) # Run def run(self, image, command, entrypoint, variables, network, volumes, directory): # Run container image return self.client.containers.run( image, command=command, detach=True, entrypoint=entrypoint, environment=variables, network_mode=network, privileged=True, remove=False, stdout=True, stderr=True, stream=True, volumes=volumes, working_dir=directory) # Sockets def sockets(self, volumes): # Add socket volume volumes['/var/run/docker.sock'] = { # 'bind': '/var/run/docker.sock', 'mode': 'rw' } # Stop def stop(self, container, timeout): # Stop container container.stop(timeout=timeout) # Supports def supports(self, image, container, binary): # Validate binary support exit_code, output = self.exec(container, 'whereis %s' % (binary)) # Result return exit_code == 0 # Wait def wait(self, container): # Wait container result = container.wait() # Result return result['StatusCode'] == 0
gitlabci_local/runner.py +14 −3 Changes for gitlabci_local/runner.py: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -308,22 +308,33 @@ def runner(options, job_data, last_result, time_launcher): # Show container logs try: for line in engine.logs(container): if isinstance(line, bytes): if marker_debug in line.decode(): break sys.stdout.buffer.write(line) sys.stdout.buffer.flush() else: if marker_debug in line: break sys.stdout.write(line) sys.stdout.flush() except: pass # Runner bash or debug mode if options.bash or options.debug: print(' ') exit_code, output = engine.exec(container, 'which bash') # Select shell shell = 'sh' if exit_code == 0: if engine.supports(image, container, 'bash'): shell = 'bash' # Acquire container informations container_exec = engine.help('exec') container_name = engine.name(container) # Footer debugging informations print(' ') print( ' %s> INFORMATION: %sUse \'%s%s %s %s%s\' commands for debugging. Interrupt with Ctrl+C...%s' % (colored.fg('yellow') + colored.attr('bold'), Loading