コード例 #1
0
 def from_json(cls, kwargs):
     from dimensigon.domain.entities import ActionTemplate, Orchestration
     kwargs = dict(kwargs)
     if 'orchestration_id' in kwargs:
         ident = kwargs.pop('orchestration_id')
         kwargs['orchestration'] = db.session.query(Orchestration).get(ident)
         if kwargs['orchestration'] is None:
             raise errors.EntityNotFound('Orchestration', ident=ident)
     if 'action_template_id' in kwargs:
         ident = kwargs.pop('action_template_id')
         kwargs['action_template'] = db.session.query(ActionTemplate).get(ident)
         if kwargs['action_template'] is None:
             raise errors.EntityNotFound('ActionTemplate', ident=ident)
     if 'action_type' in kwargs:
         kwargs['action_type'] = ActionType[kwargs.pop('action_type')]
     if 'created_on' in kwargs:
         kwargs['created_on'] = datetime.datetime.strptime(kwargs['created_on'], defaults.DATETIME_FORMAT)
     kwargs['parent_steps'] = []
     for parent_step_id in kwargs.pop('parent_step_ids', []):
         ps = Step.query.get(parent_step_id)
         if ps:
             kwargs['parent_steps'].append(ps)
         else:
             raise errors.EntityNotFound('Step', parent_step_id)
     return super().from_json(kwargs)
コード例 #2
0
ファイル: decorators.py プロジェクト: dimensigon/dimensigon
 def wrapper(*args, **kwargs):
     # app resolution
     app = None
     if 'app' in kwargs:
         app = kwargs['app']
     else:
         for a in args:
             if isinstance(a, Flask):
                 app = a
                 break
         else:
             app = current_app
     if app:
         ctx = app.app_context()
         ctx.push()
     try:
         user = User.get_by_name(username)
         if user is None:
             raise errors.EntityNotFound("User", username, ['name'])
         from flask_jwt_extended.utils import ctx_stack
         ctx_stack.top.jwt_user = user
         jwt = {'identity': str(user.id)}
         ctx_stack.top.jwt = jwt
         return f(*args, **kwargs)
     finally:
         db.session.close()
         if app:
             ctx.pop()
コード例 #3
0
ファイル: decorators.py プロジェクト: dimensigon/dimensigon
        def wrapper_decorator(*args, **kwargs):
            destination_id = None
            if 'D-Destination' in request.headers:
                destination_id = request.headers['D-Destination']
            else:
                # Get information from content
                # Code Compatibility. Use D-Destination header instead
                data = request.get_json()
                if data is not None and 'destination' in data:
                    destination_id = data.get('destination')

            if destination_id and destination_id != str(g.server.id) and (not methods or request.method in methods):
                destination: Server = Server.query.get(destination_id)
                if destination is None:
                    return errors.format_error_response(errors.EntityNotFound('Server', destination_id))
                try:
                    if destination.route.proxy_server or destination.route.gate:
                        logger.debug(f"Forwarding request {request.method} {request.full_path} to {destination.route}")
                        resp = _proxy_request(request=request, destination=destination)
                    else:
                        return errors.format_error_response(errors.UnreachableDestination(destination, g.server))
                except requests.exceptions.RequestException as e:
                    return errors.format_error_response(errors.ProxyForwardingError(destination, e))
                else:
                    return resp.content, resp.status_code, dict(resp.headers)

            else:

                value = func(*args, **kwargs)
                return value
コード例 #4
0
    def test_server_not_found(self, mock_g):
        mock_g.server = MagicMock(id=self.srv1.id)

        resp = self.client.post('/', json={'data': None},
                                headers={'D-Destination': 'bbbbbbbb-1234-5678-1234-56781234bbb5'})

        self.validate_error_response(resp, errors.EntityNotFound('Server', 'bbbbbbbb-1234-5678-1234-56781234bbb5'))
コード例 #5
0
ファイル: software.py プロジェクト: dimensigon/dimensigon
    def delete(self, software_id):
        data = request.get_json()

        if Software.query.filter_by(id=software_id).count() == 0:
            raise errors.EntityNotFound('Software', software_id)

        for server_id in data:
            ssa = SoftwareServerAssociation.query.filter_by(
                software_id=software_id, server_id=server_id)
            if not ssa:
                raise errors.EntityNotFound('SoftwareServerAssociation',
                                            (software_id, server_id),
                                            ['software_id', 'server_id'])
            ssa.delete()

        db.session.commit()
        return {}, 204
コード例 #6
0
ファイル: use_cases.py プロジェクト: dimensigon/dimensigon
def join_acknowledge(server_id):
    server_data = servers_to_be_created.get(server_id, None)
    if not server_data:
        raise errors.EntityNotFound('Server', server_id)
    s = Server.from_json(server_data)
    with _lock_add_node:
        db.session.add(s)
        db.session.commit()
        current_app.logger.debug(f"Server join acknowledge {s.name}")
    return {}, 204
コード例 #7
0
    def test_launch_orchestration_filter_by_orchestration_not_found(self):
        data = {'hosts': self.s1.id,
                'orchestration': 'invented',
                'params': {'folder': '/home/{{user}}',
                           'home': '{{folder}}',
                           'user': '******'},
                'skip_validation': True,
                'background': False}

        resp = self.client.post(url_for('api_1_0.launch_orchestration'),
                                json=data,
                                headers=self.auth.header)

        self.validate_error_response(resp, errors.EntityNotFound('Orchestration', ['invented'], ('orchestration',)))
コード例 #8
0
    def test_post(self):
        resp = self.client.post(url_for('api_1_0.vaultresource', name='foo'),
                                json={'value': ['list']},
                                headers=self.auth.header)

        self.assertEqual(204, resp.status_code)
        v = Vault.query.get((ROOT, 'global', 'foo'))
        self.assertListEqual(['list'], v.value)

        resp = self.client.post(url_for('api_1_0.vaultresource', name='fake'),
                                json={'value': ['list']},
                                headers=self.auth.header)
        self.validate_error_response(
            resp, errors.EntityNotFound("Vault", [ROOT, 'global', 'fake']))
コード例 #9
0
 def get(id_or_name, version=None) -> t.Union['Orchestration', str]:
     if is_valid_uuid(id_or_name):
         orch = Orchestration.query.get(id_or_name)
         if orch is None:
             return str(errors.EntityNotFound('Orchestration', id_or_name))
     else:
         if id_or_name:
             query = Orchestration.query.filter_by(
                 name=id_or_name).order_by(Orchestration.version.desc())
             if version:
                 query.filter_by(version=version)
             orch = query.first()
             if orch is None:
                 return f"No orchestration found for '{id_or_name}'" + (
                     f" version '{version}'" if version else None)
         else:
             return "No orchestration specified"
     return orch
コード例 #10
0
def file_sync(file_id):
    if get_jwt_identity() == '00000000-0000-0000-0000-000000000001':
        data = request.get_json()
        file = File.query.get(file_id)
        if file is None and not data.get('force', False):
            raise errors.EntityNotFound("File", file_id)

        file = data.get('file')
        content = zlib.decompress(base64.b64decode(data.get('data').encode('ascii')))

        _logger.debug(f"received file sync {file}.")
        try:
            if not os.path.exists(os.path.dirname(file)):
                os.makedirs(os.path.dirname(file))
            with open(file, 'wb') as fh:
                fh.write(content)
        except Exception as e:
            raise errors.GenericError(f"Error while trying to create/write file: {e}", 500)
        return {}, 204
    else:
        raise errors.UserForbiddenError
コード例 #11
0
    def test_get(self):
        resp = self.client.get(url_for('api_1_0.vaultresource', name='foo'),
                               headers=self.auth.header)
        self.assertDictEqual(self.vr1.to_json(no_delete=True), resp.get_json())

        resp = self.client.get(url_for('api_1_0.vaultresource',
                                       name='foo',
                                       scope='test'),
                               headers=self.auth.header)
        self.assertDictEqual(self.vr2.to_json(no_delete=True), resp.get_json())

        resp = self.client.get(url_for('api_1_0.vaultresource', name='foo') +
                               '?params=human',
                               headers=self.auth.header)
        self.assertDictEqual(self.vr1.to_json(no_delete=True, human=True),
                             resp.get_json())

        resp = self.client.get(url_for('api_1_0.vaultresource', name='fake'),
                               headers=self.auth.header)
        self.validate_error_response(
            resp, errors.EntityNotFound("Vault", [ROOT, 'global', 'fake']))
コード例 #12
0
ファイル: use_cases.py プロジェクト: dimensigon/dimensigon
def launch_command():
    data = request.get_json()

    server_list = []
    if 'target' in data:
        not_found = []
        servers = Server.query.all()
        if data['target'] == 'all':
            server_list = servers
        elif is_iterable_not_string(data['target']):
            for vv in data['target']:
                sl = search(vv, servers)
                if len(sl) == 0:
                    not_found.append(vv)
                else:
                    server_list.extend(sl)
        else:
            sl = search(data['target'], servers)
            if len(sl) == 0:
                not_found.append(data['target'])
            else:
                server_list.extend(sl)
        if not_found:
            return {
                'error':
                "Following granules or ids did not match to any server: " +
                ', '.join(not_found)
            }, 404
    else:
        server_list.append(g.server)

    if re.search(r'rm\s+((-\w+|--[-=\w]*)\s+)*(-\w*[rR]\w*|--recursive)',
                 data['command']):
        return {'error': 'rm with recursion is not allowed'}, 403
    data.pop('target', None)
    start = None

    username = getattr(User.query.get(get_jwt_identity()), 'name', None)
    if not username:
        raise errors.EntityNotFound('User', get_jwt_identity())
    cmd = wrap_sudo(username, data['command'])
    if g.server in server_list:
        start = time.time()
        server_list.pop(server_list.index(g.server))
        proc = subprocess.Popen(
            cmd,
            stdin=subprocess.PIPE if data.get('input', None) else None,
            stderr=subprocess.PIPE,
            stdout=subprocess.PIPE,
            shell=True,
            close_fds=True,
            encoding='utf-8')

    resp_data = {}
    if check_param_in_uri("human"):
        attr = 'name'
    else:
        attr = 'id'
    if server_list:
        resp: t.List[ntwrk.Response] = asyncio.run(
            ntwrk.parallel_requests(server_list,
                                    method='POST',
                                    view_or_url='api_1_0.launch_command',
                                    json=data))
        for s, r in zip(server_list, resp):
            key = getattr(s, attr, s.id)
            if r.ok:
                resp_data[key] = r.msg[s.id]
            else:
                if not r.exception:
                    resp_data[key] = {
                        'error': {
                            'status_code': r.code,
                            'response': r.msg
                        }
                    }
                else:
                    if isinstance(r.exception, errors.BaseError):
                        resp_data[key] = errors.format_error_content(
                            r.exception, current_app.config['DEBUG'])
                    else:
                        resp_data[key] = {
                            'error':
                            format_exception(r.exception) if
                            current_app.config['DEBUG'] else str(r.exception)
                            or str(r.exception.__class__.__name__)
                        }

    if start:
        key = getattr(g.server, attr, g.server.id)
        timeout = data.get('timeout', defaults.TIMEOUT_COMMAND)
        try:
            outs, errs = proc.communicate(input=(data.get('input', '') or ''),
                                          timeout=timeout)
        except (TimeoutError, subprocess.TimeoutExpired):
            proc.kill()
            try:
                outs, errs = proc.communicate(timeout=1)
            except:
                resp_data[key] = {
                    'error':
                    f"Command '{cmd}' timed out after {timeout} seconds. Unable to communicate with the process launched."
                }
            else:
                resp_data[key] = {
                    'error':
                    f"Command '{cmd}' timed out after {timeout} seconds",
                    'stdout': outs.split('\n'),
                    'stderr': errs.split('\n')
                }
        except Exception as e:
            current_app.logger.exception(
                "Exception raised while trying to run command")
            resp_data[key] = {
                'error':
                traceback.format_exc() if current_app.config['DEBUG'] else
                str(r.exception) or str(r.exception.__class__.__name__)
            }
        else:
            resp_data[key] = {
                'stdout': outs.split('\n'),
                'stderr': errs.split('\n'),
                'returncode': proc.returncode
            }
    resp_data['cmd'] = cmd
    resp_data['input'] = data.get('input', None)
    return resp_data, 200
コード例 #13
0
ファイル: use_cases.py プロジェクト: dimensigon/dimensigon
def launch_orchestration(orchestration_id):
    data = request.get_json()
    if orchestration_id:
        orchestration = Orchestration.query.get_or_raise(orchestration_id)
    else:
        iden = (data.get('orchestration'), )
        columns = ('orchestration', )
        query = Orchestration.query.filter_by(name=data.get('orchestration'))
        if 'version' in data:
            iden += (data.get('version'), )
            columns += ('version', )
            query = query.filter_by(version=data.get('version'))
        query = query.order_by(Orchestration.version.desc())
        if query.count() <= 1:
            orchestration = query.one_or_none()
        else:
            orchestration = query.first()
        if not orchestration:
            raise errors.EntityNotFound('Orchestration', iden, columns)

    if not orchestration.steps:
        return errors.GenericError(
            'orchestration does not have steps to execute',
            orchestration_id=orchestration_id)

    params = data.get('params') or {}
    hosts = data.get('hosts', Server.get_current().id)

    a = set(orchestration.target)
    if not isinstance(hosts, dict):
        hosts = dict(all=hosts)
    b = set(hosts.keys())
    c = a - b
    if len(c) > 0:
        raise errors.TargetUnspecified(c)
    c = b - a
    if len(c) > 0:
        raise errors.TargetNotNeeded(c)

    not_found = normalize_hosts(hosts)
    if not_found:
        raise errors.ServerNormalizationError(not_found)

    for target, target_hosts in hosts.items():
        if len(target_hosts) == 0:
            raise errors.EmptyTarget(target)
    # check param entries
    # rest = orchestration.user_parameters - set(params.keys())
    # if rest:
    #     rest = list(rest)
    #     rest.sort()
    #     return {'error': f"Parameter(s) not specified: {', '.join(rest)}"}, 404

    execution_id = str(uuid.uuid4())

    executor_id = get_jwt_identity()
    vc = Context(params,
                 dict(execution_id=None,
                      root_orch_execution_id=execution_id,
                      orch_execution_id=execution_id,
                      executor_id=executor_id),
                 vault=Vault.get_variables_from(executor_id,
                                                scope=data.get(
                                                    'scope', 'global')))

    if not data.get('skip_validation', False):
        validate_input_chain(
            orchestration, {
                'input': set(params.keys()),
                'env': set(vc.env.keys()),
                'vault': set(vc.vault.keys())
            })

    if request.get_json().get('background', True):
        future = executor.submit(deploy_orchestration,
                                 orchestration=orchestration.id,
                                 var_context=vc,
                                 hosts=hosts,
                                 timeout=data.get('timeout', None))
        try:
            future.result(5)
        except concurrent.futures.TimeoutError:
            return {'execution_id': execution_id}, 202
        except Exception as e:
            current_app.logger.exception(
                f"Exception got when executing orchestration {orchestration}")
            raise
    else:
        try:
            deploy_orchestration(orchestration=orchestration,
                                 var_context=vc,
                                 hosts=hosts,
                                 timeout=data.get('timeout', None))
        except Exception as e:
            current_app.logger.exception(
                f"Exception got when executing orchestration {orchestration}")
            raise
    return OrchExecution.query.get(execution_id).to_json(
        add_step_exec=True,
        human=check_param_in_uri('human'),
        split_lines=True), 200