def agent( config: CowaitConfig, detach: bool = False, upstream: str = None, ) -> None: logger = RunLogger(quiet=False, raw=False) try: cluster = config.get_cluster() if cluster.type == 'api': raise CliError('Error: Cant deploy agent using an API cluster') token = uuid() if cluster.type == 'docker': token = '' cluster.destroy('agent') # create task definition taskdef = TaskDefinition( id='agent', name='cowait.tasks.agent', image=DEFAULT_BASE_IMAGE, upstream=upstream, routes={ '/': 80, }, meta={ 'http_token': token, }, ) # submit task to cluster task = cluster.spawn(taskdef) if detach: logger.header('detached') return def destroy(*args): logger.header('interrupt') cluster.destroy(task.id) sys.exit(0) with ExitTrap(destroy): # capture & print logs logs = cluster.logs(task) logger.header('task output') for log in logs: logger.handle(log) logger.header() except ProviderError as e: raise CliError(f'Provider error: {e}') except TaskCreationError as e: raise CliError(f'Task creation error: {e}')
def agent( config: CowaitConfig, detach: bool = False, upstream: str = None, ) -> None: try: context = CowaitContext.open() cluster_name = context.get('cluster', config.default_cluster) cluster = config.get_cluster(cluster_name) if cluster.type == 'api': raise CliError('Error: Cant deploy agent using an API cluster') cluster.destroy('agent') # create task definition taskdef = TaskDefinition( id='agent', name='cowait.tasks.agent', image=DEFAULT_BASE_IMAGE, upstream=upstream, routes={ '/': 80, }, meta={ 'http_token': uuid(), }, ) # submit task to cluster task = cluster.spawn(taskdef) if detach: printheader('detached') return def destroy(*args): print() printheader('interrupt') cluster.destroy(task.id) sys.exit(0) with ExitTrap(destroy): # capture & print logs logs = cluster.logs(task) printheader('task output') for log in logs: print(log, flush=True) printheader() except ProviderError as e: raise CliError(f'Provider error: {e}') except TaskCreationError as e: raise CliError(f'Task creation error: {e}')
def test_max_env_length(): """ Passing too large inputs should raise a ProviderError """ random_data = uuid(2 * MAX_ENV_LENGTH, lower=False) with pytest.raises(ProviderError): cp = ClusterProvider('test') cp.create_env(TaskDefinition( 'test-task', image='imaginary-image', inputs={ 'ohshit': random_data, }, ))
def get_token(self) -> str: token = uuid(32) self.tokens[token] = True return token
def notebook(config, image: str = None, cluster_name: str = None) -> None: context = Context.open(config) if not context.notebook: print('Notebook funcitonaility is not enabled.') print('To enable, set features.notebook to True in cowait.yml and rebuild.') sys.exit(1) if image is not None: print('Remote images are currently not supported') sys.exit(1) volumes = { '/var/task': { 'bind': { 'src': os.getcwd(), 'mode': 'rw', 'inherit': 'same-image', }, } } cluster = context.get_cluster(cluster_name) # Docker if cluster.type == 'docker': return run_cmd( config=config, task='cowait.notebook', build=False, image=image, routes={ '/': '8888', }, cluster_name=cluster_name, volumes=volumes, ) # check for clientfs clientfs_executable = './clientfs-' + platform.system().lower() if not os.path.exists(clientfs_executable): print('Kubernetes notebooks are not supported in this build of Cowait') sys.exit(1) # Kubernetes core = client.CoreV1Api() notebook_id = 'notebook-' + uuid(4) core.create_namespaced_persistent_volume_claim( namespace=cluster.namespace, body=client.V1PersistentVolumeClaim( metadata=client.V1ObjectMeta( name=notebook_id, namespace=cluster.namespace, ), spec=client.V1PersistentVolumeClaimSpec( storage_class_name='clientfs', access_modes=['ReadWriteMany'], resources=client.V1ResourceRequirements( requests={ 'storage': '1G', }, ), ), ), ) def delete_pvc(task_id): print('destroy', task_id) if task_id != notebook_id: return print('* stopping clientfs') clientfs.terminate() print('* deleting volume') core.delete_namespaced_persistent_volume_claim(notebook_id, cluster.namespace) cluster.on('kill', delete_pvc) pvc_id = None while True: time.sleep(1) volume = core.read_namespaced_persistent_volume_claim(notebook_id, cluster.namespace) if volume.status.phase == 'Bound': pvc_id = 'pvc-' + volume.metadata.uid print('* created volume', notebook_id, '/', pvc_id) break volumes['/var/task'] = { 'persistent_volume_claim': { 'claim_name': notebook_id, }, } # start clientfs clientfs_host = cluster.args.get('clientfs', {}).get('host') print(f'* connecting clientfs volume to {clientfs_host}...') clientfs = subprocess.Popen([ clientfs_executable, f"--proxy={clientfs_host}", f"--volume={pvc_id}" ]) logger = RunLogger() try: # default to agent as upstream agent = cluster.find_agent() # create task definition taskdef = TaskDefinition( id=notebook_id, name='cowait.notebook', image=context.image, env={ **context.extend('environment', {}), **context.dotenv, }, routes={ '/': '8888', }, parent=None, # root task upstream=agent, owner=getpass.getuser(), volumes=context.extend('volumes', volumes), ) # print execution info logger.print_info(taskdef, cluster) # submit task to cluster task = cluster.spawn(taskdef) detach = False if detach: logger.header('detached') return def destroy(*args): logger.header('interrupt') cluster.destroy(task.id) sys.exit(1) with ExitTrap(destroy): # capture & print logs logs = cluster.logs(task.id) logger.header('task output') for msg in logs: logger.handle(msg) except Exception: traceback.print_exc() sys.exit(1)