def run(schema, file, **_):
    result = {'state': 'succeeded', 'debugInfo': None}

    try:
        if schema not in schemas:
            debug_info = 'Schema "{}" not found. Use "faice schema list" for available schemas.'.format(
                schema)
            print(debug_info, file=sys.stderr)
            result['debugInfo'] = debug_info
            result['state'] = 'failed'
            return result

        data = load_and_read(file, 'FILE')
        jsonschema.validate(data, schemas[schema])
    except ValidationError as e:
        where = '/'.join([str(s) for s in e.absolute_path
                          ]) if e.absolute_path else '/'
        debug_info = 'File "{}" does not comply with schema "{}":\n\tkey in red file: {}\n\treason: {}'\
            .format(file, schema, where, e.message)

        print_exception(RedValidationError(debug_info))
        result['debugInfo'] = exception_format()
        result['state'] = 'failed'

    except Exception as e:
        print_exception(e)
        result['debugInfo'] = exception_format()
        result['state'] = 'failed'

    return result
Beispiel #2
0
def run(red_file, fmt, prefix, **_):
    secret_values = None
    result = {'state': 'succeeded', 'debugInfo': None}
    try:
        ext = file_extension(fmt)

        red_data = load_and_read(red_file, 'REDFILE')
        secret_values = get_secret_values(red_data)

        red_validation(red_data, False)

        if 'batches' not in red_data:
            wrapped_print(['ERROR: REDFILE does not contain batches.'],
                          error=True)
            return 1

        for batch in range(len(red_data['batches'])):
            batch_data = convert_batch_experiment(red_data, batch)
            dumped_batch_file = '{}batch_{}.{}'.format(prefix, batch, ext)
            dump(batch_data, fmt, dumped_batch_file)
    except Exception as e:
        print_exception(e, secret_values)
        result['debugInfo'] = exception_format(secret_values)
        result['state'] = 'failed'

    return result
Beispiel #3
0
def run(file, fmt, **_):
    result = {'state': 'succeeded', 'debugInfo': None}

    try:
        data = load_and_read(file, 'FILE')
        dump_print(data, fmt)
    except Exception as e:
        print_exception(e)
        result['debugInfo'] = exception_format()
        result['state'] = 'failed'

    return result
Beispiel #4
0
def run(red_file, fmt, **_):
    result = {'state': 'succeeded', 'debugInfo': None}

    try:
        red_data = load_and_read(red_file, 'REDFILE')
    except AgentError as e:
        print_exception(e)
        result['debugInfo'] = exception_format()
        result['state'] = 'failed'
        return result

    if 'cli' not in red_data:
        print_exception(
            RedSpecificationError(
                'ERROR: REDFILE does not contain cli section.'))
        result['debugInfo'] = exception_format()
        result['state'] = 'failed'
        return result

    cli = red_data['cli']

    dump_print(cli, fmt)

    return result
def run(red_data,
        disable_pull=False,
        leave_container=False,
        preserve_environment=None,
        insecure=False,
        output_mode=OutputMode.Connectors,
        gpu_ids=None,
        disable_connector_validation=None):
    """
    Executes a RED Experiment.

    :param red_data: A dict containing red data that will be executed. This red data cannot contain template keys
    :param disable_pull: If True the docker image is not pulled from an registry
    :param leave_container: If set to True, the executed docker container will not be removed.
    :param preserve_environment: List of environment variables to preserve inside the docker container.
    :param insecure: Allow insecure capabilities
    :param output_mode: Either Connectors or Directory. If Connectors, the restricted_red agent will try to execute the
                        output connectors. If Directory faice will copy the output files into the host output directory.
    :param gpu_ids: A list of gpu ids, that should be used. If None all gpus are considered.
    :type gpu_ids: List[int] or None
    :param disable_connector_validation: If set, the execution engine will skip connector validation
    :type disable_connector_validation: bool

    :raise TemplateError: If template keys are found in the given red data
    """
    result = {'containers': [], 'debugInfo': None, 'state': 'succeeded'}

    secret_values = None

    try:
        # secrets
        secret_values = get_secret_values(red_data)

        # validation
        red_validation(red_data,
                       output_mode == OutputMode.Directory,
                       container_requirement=True,
                       allow_variables=False)
        engine_validation(red_data, 'container', ['docker'], optional=False)

        # process red data
        restricted_red_batches = convert_red_to_restricted_red(red_data)

        # docker settings
        docker_image = red_data['container']['settings']['image']['url']
        ram = red_data['container']['settings'].get('ram')
        environment = env_vars(preserve_environment)

        # create docker manager
        docker_manager = DockerManager()

        # gpus
        gpus = get_gpus(docker_manager,
                        red_data['container']['settings'].get('gpus'), gpu_ids)

        if not disable_pull:
            registry_auth = red_data['container']['settings']['image'].get(
                'auth')
            docker_manager.pull(docker_image, auth=registry_auth)

        if len(restricted_red_batches) == 1:
            host_outdir = Path('outputs')
        else:
            host_outdir = Path('outputs_{batch_index}')

        for batch_index, restricted_red_batch in enumerate(
                restricted_red_batches):
            container_execution_result = run_restricted_red_batch(
                restricted_red_batch=restricted_red_batch,
                docker_manager=docker_manager,
                docker_image=docker_image,
                host_outdir=host_outdir,
                output_mode=output_mode,
                leave_container=leave_container,
                batch_index=batch_index,
                ram=ram,
                gpus=gpus,
                environment=environment,
                insecure=insecure,
                disable_connector_validation=disable_connector_validation)

            # handle execution result
            # noinspection PyTypeChecker
            result['containers'].append(container_execution_result.to_dict())
            result[
                'furtherErrors'] = container_execution_result.get_further_errors(
                )
            container_execution_result.raise_for_state()
    except Exception as e:
        result['briefExceptionText'] = brief_exception_text(e, secret_values)
        result['debugInfo'] = exception_format(secret_values)
        result['state'] = 'failed'

    return result
Beispiel #6
0
def run(red_file, non_interactive, fmt, insecure, keyring_service, **_):
    secret_values = None
    result = {'state': 'succeeded', 'debugInfo': None}
    try:
        red_data = load_and_read(red_file, 'REDFILE')
        red_validation(red_data, False)
        engine_validation(red_data, 'execution', ['ccfaice', 'ccagency'],
                          'faice exec')

        secret_values = get_secret_values(red_data)

        # exec via CC-FAICE
        # equivalent to `faice agent red --debug --outputs`
        if 'execution' not in red_data:
            raise KeyError(
                'The key "execution" is needed in red file for usage with faice exec.'
            )
        if red_data['execution']['engine'] == 'ccfaice':
            # use connectors, if red file specifies outputs
            if _has_outputs(red_data):
                faice_output_mode = OutputMode.Connectors
            else:
                faice_output_mode = OutputMode.Directory

            result = run_faice_agent_red(red_file=red_file,
                                         disable_pull=False,
                                         leave_container=False,
                                         preserve_environment=[],
                                         non_interactive=non_interactive,
                                         insecure=insecure,
                                         output_mode=faice_output_mode,
                                         keyring_service=keyring_service,
                                         gpu_ids=None)
            return result

        complete_red_templates(red_data, keyring_service, non_interactive)

        red_data_normalized = deepcopy(red_data)
        normalize_keys(red_data_normalized)

        if 'access' not in red_data_normalized['execution']['settings']:
            result['debugInfo'] = [
                'ERROR: cannot send RED data to CC-Agency if access settings are not defined.'
            ]
            result['state'] = 'failed'
            return result

        if 'auth' not in red_data_normalized['execution']['settings'][
                'access']:
            result['debugInfo'] = [
                'ERROR: cannot send RED data to CC-Agency if auth is not defined in access '
                'settings.'
            ]
            result['state'] = 'failed'
            return result

        access = red_data_normalized['execution']['settings']['access']

        r = requests.post('{}/red'.format(access['url'].strip('/')),
                          auth=(access['auth']['username'],
                                access['auth']['password']),
                          json=red_data)
        if 400 <= r.status_code < 500:
            try:
                pprint(r.json())
            except ValueError:  # if the body does not contain json, we ignore it
                pass
        r.raise_for_status()

        dump_print(r.json(), fmt)
    except Exception as e:
        print_exception(e, secret_values)
        result['debugInfo'] = exception_format(secret_values)
        result['state'] = 'failed'

    return result
Beispiel #7
0
def run(red_file,
        disable_pull,
        leave_container,
        preserve_environment,
        non_interactive,
        insecure,
        output_mode,
        keyring_service,
        gpu_ids,
        **_
        ):
    """
    Executes a RED Experiment.

    :param red_file: The path or URL to the RED File to execute
    :param disable_pull: If True the docker image is not pulled from an registry
    :param leave_container: If set to True, the executed docker container will not be removed.
    :param preserve_environment: List of environment variables to preserve inside the docker container.
    :param non_interactive: If True, unresolved template values are not asked interactively
    :param insecure: Allow insecure capabilities
    :param output_mode: Either Connectors or Directory. If Connectors, the blue agent will try to execute the output
                        connectors. If Directory faice will copy the output files into the host output directory.
    :param keyring_service: The keyring service name to use for template substitution
    :param gpu_ids: A list of gpu ids, that should be used. If None all gpus are considered.
    :type gpu_ids: List[int] or None
    """

    result = {
        'containers': [],
        'debugInfo': None,
        'state': 'succeeded'
    }

    secret_values = None

    try:
        red_data = load_and_read(red_file, 'REDFILE')

        # validation
        red_validation(red_data, output_mode == OutputMode.Directory, container_requirement=True)
        engine_validation(red_data, 'container', ['docker'], optional=False)

        # templates and secrets
        complete_red_templates(red_data, keyring_service, non_interactive)
        secret_values = get_secret_values(red_data)
        normalize_keys(red_data)

        # process red data
        blue_batches = convert_red_to_blue(red_data)

        # docker settings
        docker_image = red_data['container']['settings']['image']['url']
        ram = red_data['container']['settings'].get('ram')
        environment = env_vars(preserve_environment)

        # create docker manager
        docker_manager = DockerManager()

        # gpus
        gpus = get_gpus(docker_manager, red_data['container']['settings'].get('gpus'), gpu_ids)

        if not disable_pull:
            registry_auth = red_data['container']['settings']['image'].get('auth')
            docker_manager.pull(docker_image, auth=registry_auth)

        if len(blue_batches) == 1:
            host_outdir = 'outputs'
        else:
            host_outdir = 'outputs_{batch_index}'

        for batch_index, blue_batch in enumerate(blue_batches):
            container_execution_result = run_blue_batch(
                blue_batch=blue_batch,
                docker_manager=docker_manager,
                docker_image=docker_image,
                host_outdir=host_outdir,
                output_mode=output_mode,
                leave_container=leave_container,
                batch_index=batch_index,
                ram=ram,
                gpus=gpus,
                environment=environment,
                insecure=insecure
            )

            # handle execution result
            result['containers'].append(container_execution_result.to_dict())
            container_execution_result.raise_for_state()
    except Exception as e:
        print_exception(e, secret_values)
        result['debugInfo'] = exception_format(secret_values)
        result['state'] = 'failed'

    return result
    def post_red():
        user = auth.verify_user(request.authorization, request.cookies,
                                request.remote_addr)

        if not request.json:
            raise BadRequest('Did not send RED data as JSON.')

        data = request.json
        disable_retry = str_to_bool(
            request.args.get('disableRetry', default=False))
        disable_connector_validation = str_to_bool(
            request.args.get('disableConnectorValidation', default=False))

        try:
            red_validation(data, False)
        except Exception as e:
            raise BadRequest(
                'Given RED data is invalid. Consider using the FAICE commandline tools for local validation.\n{}'
                .format(str(e)))

        template_keys = get_variable_keys(data)
        if template_keys:
            raise BadRequest(
                'The given red data contains the following variables: "{}". Please resolve them before submitting'
                ' to agency. Consider using CC-FAICE (faice exec).'.format(
                    ', '.join(map(str, template_keys))))

        secret_values = get_secret_values(data)

        if 'batches' in data:
            for batch in data['batches']:
                if 'outputs' not in batch:
                    raise BadRequest(
                        'CC-Agency requires all batches to have outputs defined. At least one batch does not comply.'
                    )

        elif 'outputs' not in data:
            raise BadRequest(
                'CC-Agency requires outputs to be defined in RED data.')

        try:
            engine_validation(data, 'container', ['docker'])
        except Exception:
            raise BadRequest('\n'.join(
                exception_format(secret_values=secret_values)))

        if 'ram' not in data['container']['settings']:
            raise BadRequest(
                'CC-Agency requires \'ram\' to be defined in the container settings.'
            )

        try:
            engine_validation(data, 'execution', ['ccagency'], optional=True)
            normalize_keys(data)
            _ = convert_red_to_restricted_red(data)
        except Exception:
            raise BadRequest('\n'.join(
                exception_format(secret_values=secret_values)))

        experiment, batches, secrets = _prepare_red_data(
            data, user, disable_retry, disable_connector_validation)

        response = trustee_client.store(secrets)
        if response['state'] == 'failed':
            raise InternalServerError('Trustee service failed:\n{}'.format(
                response['debug_info']))

        bson_experiment_id = mongo.db['experiments'].insert_one(
            experiment).inserted_id
        experiment_id = str(bson_experiment_id)

        for batch in batches:
            batch['experimentId'] = experiment_id

        mongo.db['batches'].insert_many(batches)

        controller.send_json({'destination': 'scheduler'})

        return create_flask_response({'experimentId': experiment_id}, auth,
                                     user.authentication_cookie)
def run(
        red_file,
        non_interactive,
        keyring_service,
        preserve_environment,
        disable_pull,
        leave_container,
        insecure,
        gpu_ids,
        disable_retry,
        disable_connector_validation,
        **_
):
    """
    Runs the RED Client.

    :param red_file: The path or URL to the RED File to execute
    :param non_interactive: If True, unresolved template values are not asked interactively
    :type non_interactive: bool
    :param keyring_service: The keyring service name to use for template substitution
    :type keyring_service: str
    :param preserve_environment: List of environment variables to preserve inside the docker container.
    :type preserve_environment: list[str]
    :param disable_pull: If True the docker image is not pulled from an registry
    :type disable_pull: bool
    :param leave_container: If set to True, the executed docker container will not be removed.
    :type leave_container: bool
    :param insecure: Allow insecure capabilities
    :type insecure: bool
    :param gpu_ids: A list of gpu ids, that should be used. If None all gpus are considered.
    :type gpu_ids: List[int] or None
    :param disable_retry: If True, the execution engine will not retry the experiment, if it fails.
    :type disable_retry: bool
    :param disable_connector_validation: If True, the execution engine will skip connector validation
    :type disable_connector_validation: bool

    :return: a dictionary containing debug information about the process
    """
    secret_values = None
    result = {
        'state': 'succeeded',
        'debugInfo': None
    }
    try:
        red_data = load_and_read(red_file, 'REDFILE')

        secret_values = get_secret_values(red_data)
        red_validation(red_data, False)
        engine_validation(red_data, 'execution', ['ccfaice', 'ccagency'], 'faice exec')
        _check_execution_arguments(
            red_data.get('execution', {}).get('engine', 'ccfaice'),
            preserve_environment=preserve_environment,
            disable_pull=disable_pull,
            leave_container=leave_container,
            insecure=insecure,
            gpu_ids=gpu_ids,
            disable_retry=disable_retry,
            disable_connector_validation=disable_connector_validation
        )

        if 'execution' not in red_data:
            raise KeyError('The key "execution" is needed in red file for usage with faice exec.')

        complete_red_variables(red_data, keyring_service, non_interactive)

        # exec via faice or agency
        if red_data['execution']['engine'] == 'ccfaice':
            return run_faice(
                red_data, preserve_environment, disable_pull, leave_container, insecure, gpu_ids,
                disable_connector_validation
            )
        elif red_data['execution']['engine'] == 'ccagency':
            return run_agency(red_data, disable_retry, disable_connector_validation)

    except Exception as e:
        print_exception(e, secret_values)
        result['debugInfo'] = exception_format(secret_values)
        result['state'] = 'failed'

    return result