Exemple #1
0
    def setUp(self):
        """Create and configure a new app instance for each test."""
        # create the app with common test config
        self.app = create_app('test')
        self.app_context = self.app.app_context()
        self.app_context.push()
        self.client = self.app.test_client()
        self.headers = {
            "Authorization":
            f"Bearer {create_access_token('00000000-0000-0000-0000-000000000001')}"
        }

        db.create_all()
        set_initial()

        self.soft = Software(id='aaaaaaaa-1234-5678-1234-56781234aaa1',
                             name='test',
                             version='1',
                             filename='file')
        self.soft2 = Software(id='aaaaaaaa-1234-5678-1234-56781234aaa2',
                              name='test',
                              version='2',
                              filename='file')
        self.ssa = SoftwareServerAssociation(software=self.soft,
                                             server=Server.get_current(),
                                             path='/root')
        db.session.add_all([self.soft, self.soft2, self.ssa])
        db.session.commit()
Exemple #2
0
    def test_get_servers_from_scope_less_than_min_quorum(
            self, mock_get_now, mock_app):
        mock_get_now.return_value = dt.datetime(2019,
                                                4,
                                                1,
                                                tzinfo=dt.timezone.utc)
        me = Server(id='00000000-0000-0000-0000-000000000000',
                    name='node0',
                    port=5000,
                    me=True,
                    created_on=now)
        db.session.add(me)
        servers = []
        for i in range(1, 4):
            s = Server(f'node{i}', port=5000, created_on=old_age)
            r = Route(s, cost=0)

            db.session.add_all([s, r])

            servers.append(s)

        mock_app.dm.cluster_manager.get_alive.return_value = [
            s.id for s in servers
        ]

        quorum = get_servers_from_scope(scope=Scope.CATALOG)

        self.assertEqual(4, len(quorum))
        self.assertIn(Server.get_current(), quorum)
Exemple #3
0
 def _notify_cluster_out(self):
     with self.dm.flask_app.app_context():
         servers = Server.get_neighbours()
         if servers:
             self.logger.debug(
                 f"Sending shutdown to {', '.join([s.name for s in servers])}"
             )
         else:
             self.logger.debug("No server to send shutdown information")
         if servers:
             responses = asyncio.run(
                 ntwrk.parallel_requests(
                     servers,
                     'post',
                     view_or_url='api_1_0.cluster_out',
                     view_data=dict(server_id=str(Server.get_current().id)),
                     json={
                         'death':
                         get_now().strftime(defaults.DATEMARK_FORMAT)
                     },
                     timeout=2,
                     auth=get_root_auth()))
             if self.logger.level <= logging.DEBUG:
                 for r in responses:
                     if not r.ok:
                         self.logger.warning(
                             f"Unable to send data to {r.server}: {r}")
Exemple #4
0
    def setUp(self, mocked_now):
        self.initials = dict(self.initials)
        self.initials.update(action_template=False)
        mocked_now.return_value = now1
        super().setUp()
        with self.app2_context:
            mocked_now.return_value = now2
            soft = Software(id='aaaaaaaa-1234-5678-1234-56781234aaa1', name='test', version='1', filename='file')
            at = ActionTemplate(id='aaaaaaaa-1234-5678-1234-56781234aaa2', name='mkdir', version=1,
                                action_type=ActionType.SHELL, code='mkdir {dir}')
            db.session.add_all([soft, at])
            db.session.commit()
            mocked_now.return_value = now3
            ssa = SoftwareServerAssociation(software=soft, server=Server.get_current(), path='/root')
            db.session.add(ssa)
            db.session.commit()
            self.soft_json = soft.to_json()
            self.at_json = at.to_json()
            self.catalog = fetch_catalog(now1)

        self.mock_queue = mock.Mock()
        self.mock_dm = mock.Mock()
        self.mock_dm.flask_app = self.app
        self.mock_dm.engine = db.engine
        self.mock_dm.manager.dict.return_value = dict()
        self.mock_dm.server_id = self.s1.id

        self.cm = CatalogManager("Catalog", startup_event=threading.Event(), shutdown_event=threading.Event(),
                                 publish_q=self.mock_queue, event_q=None, dimensigon=self.mock_dm)
        db.session.commit()
Exemple #5
0
    def test_get_internal_error_server(self, m):
        msg = '<html>Iternal error server</html>'
        status = 500

        responses.add(responses.GET, self.url, status=status, body=msg)
        m.get(self.url, status=status, body=msg)

        resp = get(Server.get_current(), 'home')

        self.assertEqual(status, resp.code)
        self.assertEqual(msg, resp.msg)

        resp = run(async_get(Server.get_current(), 'home'))

        self.assertEqual(status, resp.code)
        self.assertEqual(msg, resp.msg)
Exemple #6
0
def load_global_data_into_context():
    from dimensigon.domain.entities import Server, Dimension
    from dimensigon.web.decorators import set_source
    global _dimension, _server
    set_source()
    g.server = Server.get_current()
    g.dimension = Dimension.get_current()
Exemple #7
0
    def test_from_json_new(self):
        ssa_json = dict(software_id='aaaaaaaa-1234-5678-1234-56781234aaa2',
                        server_id=str(Server.get_current().id),
                        path='/root',
                        last_modified_at=defaults.INITIAL_DATEMARK.strftime(
                            defaults.DATEMARK_FORMAT))

        smashed = SoftwareServerAssociation.from_json(ssa_json)

        self.assertEqual(defaults.INITIAL_DATEMARK, smashed.last_modified_at)
        self.assertIsNotNone(smashed.last_modified_at)
        self.assertEqual("/root", smashed.path)
        self.assertIsNotNone(smashed.path)
        self.assertEqual(Server.get_current(), smashed.server)
        self.assertIsNotNone(smashed.server)
        self.assertEqual(self.soft2, smashed.software)
        self.assertIsNotNone(smashed.software)
Exemple #8
0
 def callback_prevent(url, **kwargs):
     assert kwargs['json'] == {
         'scope': 'CATALOG',
         'datemark': self.datemark,
         'applicant': [Server.get_current().id, self.n1.id, self.n2.id]
     }
     return CallbackResult("{'message': 'Preventing lock acquired'}",
                           status=200)
Exemple #9
0
    def test_lock_catalog_error_on_preventing(self, m):
        def callback_prevent(url, **kwargs):
            self.assertDictEqual(
                kwargs['json'], {
                    'scope':
                    'CATALOG',
                    'applicant': [
                        str(Server.get_current().id),
                        str(self.n1.id),
                        str(self.n2.id)
                    ]
                })
            return CallbackResult("{'message': 'Preventing lock acquired'}",
                                  status=200)

        def callback_unlock(url, **kwargs):
            self.assertDictEqual(
                kwargs['json'], {
                    'scope':
                    'CATALOG',
                    'action':
                    'UNLOCK',
                    'applicant': [
                        str(Server.get_current().id),
                        str(self.n1.id),
                        str(self.n2.id)
                    ]
                })
            return CallbackResult("{'message': 'UnLocked'}", status=200)

        m.post(Server.get_current().url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(self.n1.url('api_1_0.locker_prevent'),
               exception=ClientConnectionError())
        m.post(self.n2.url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(Server.get_current().url('api_1_0.locker_unlock'),
               callback=callback_unlock)
        m.post(self.n2.url('api_1_0.locker_unlock'), callback=callback_unlock)

        with self.assertRaises(errors.LockError):
            lock(Scope.CATALOG, [Server.get_current(), self.n1, self.n2],
                 identity=ROOT)

        c = Locker.query.get(Scope.CATALOG)
        self.assertEqual(State.UNLOCKED, c.state)
Exemple #10
0
    def __init__(self, server: 'Server', proxy: 'Server' = None):
        from dimensigon.domain.entities import Server
        try:
            p = proxy or Server.get_current()
        except NoResultFound:
            p = None

        self.destination = dict(name=server.name, id=server.id)
        self.proxy = dict(name=p.name, id=p.id) if p else None
Exemple #11
0
 def callback_lock(url, **kwargs):
     assert kwargs['json'] == {
         'scope':
         'CATALOG',
         'applicant': [
             str(Server.get_current().id),
             str(self.n1.id),
             str(self.n2.id)
         ]
     }
     return CallbackResult("{'message': 'Locked'}", status=200)
Exemple #12
0
def ping(dest: t.Union[Server, Gate],
         retries=3,
         timeout=30,
         verify=False,
         session=None):
    server = Server.get_current(session=session)
    return _ping(dest=dest,
                 source=server,
                 retries=retries,
                 timeout=timeout,
                 verify=verify)
Exemple #13
0
    def make_first_request(self):
        from dimensigon.domain.entities import Server
        import dimensigon.web.network as ntwrk

        with self.flask_app.app_context():
            start = time.time()
            while True:
                resp = ntwrk.get(Server.get_current(), 'root.home', timeout=1)
                if not resp.ok and time.time() - start < 30:
                    time.sleep(0.5)
                else:
                    break
            self._main_ctx.publish_q.safe_put(EventMessage("Listening", source="Dimensigon"))
Exemple #14
0
 def callback_prevent(url, **kwargs):
     self.assertDictEqual(
         kwargs['json'], {
             'scope':
             'CATALOG',
             'applicant': [
                 str(Server.get_current().id),
                 str(self.n1.id),
                 str(self.n2.id)
             ]
         })
     return CallbackResult("{'message': 'Preventing lock acquired'}",
                           status=200)
Exemple #15
0
    def test_lock_catalog(self, m):
        def callback_prevent(url, **kwargs):
            assert kwargs['json'] == {
                'scope': 'CATALOG',
                'datemark': self.datemark,
                'applicant': [Server.get_current().id, self.n1.id, self.n2.id]
            }
            return CallbackResult("{'message': 'Preventing lock acquired'}",
                                  status=200)

        def callback_lock(url, **kwargs):
            assert kwargs['json'] == {
                'scope':
                'CATALOG',
                'applicant': [
                    str(Server.get_current().id),
                    str(self.n1.id),
                    str(self.n2.id)
                ]
            }
            return CallbackResult("{'message': 'Locked'}", status=200)

        m.post(Server.get_current().url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(self.n1.url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(self.n2.url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(Server.get_current().url('api_1_0.locker_lock'),
               callback=callback_lock)
        m.post(self.n1.url('api_1_0.locker_lock'), callback=callback_lock)
        m.post(self.n2.url('api_1_0.locker_lock'), callback=callback_lock)

        applicant = lock(Scope.CATALOG,
                         [Server.get_current(), self.n1, self.n2],
                         identity=ROOT)

        self.assertEqual(applicant,
                         [Server.get_current().id, self.n1.id, self.n2.id])
Exemple #16
0
    def test_to_from_json(self):
        ssa_json = self.ssa.to_json()
        ssa_json['path'] = '/new_root'

        smashed = SoftwareServerAssociation.from_json(ssa_json)

        self.assertEqual("/new_root", smashed.path)
        self.assertIsNotNone(smashed.path)
        self.assertEqual(Server.get_current(), smashed.server)
        self.assertIsNotNone(smashed.server)
        self.assertEqual(self.soft, smashed.software)
        self.assertIsNotNone(smashed.software)
        self.assertEqual(self.ssa.last_modified_at, smashed.last_modified_at)
        self.assertIsNotNone(smashed.last_modified_at)

        db.session.commit()

        del smashed

        ssa = SoftwareServerAssociation.query.get(
            ('aaaaaaaa-1234-5678-1234-56781234aaa1', Server.get_current().id))
        self.assertEqual("/new_root", ssa.path)
Exemple #17
0
 def callback_unlock(url, **kwargs):
     self.assertDictEqual(
         kwargs['json'], {
             'scope':
             'CATALOG',
             'action':
             'UNLOCK',
             'applicant': [
                 str(Server.get_current().id),
                 str(self.n1.id),
                 str(self.n2.id)
             ]
         })
     return CallbackResult("{'message': 'UnLocked'}", status=200)
Exemple #18
0
    def test_get(self):
        resp = self.client.get(url_for('api_1_0.loglist'),
                               headers=self.auth.header)
        self.assertListEqual([self.log.to_json()], resp.get_json())

        log = Log(source_server=Server.get_current(),
                  target='/access.log',
                  destination_server=self.dest2)
        db.session.add(log)
        db.session.commit()

        # test with filter
        resp = self.client.get(url_for('api_1_0.loglist') +
                               "?filter[target]=/access.log",
                               headers=self.auth.header)
        self.assertListEqual([log.to_json()], resp.get_json())

        # test with filter on a server
        resp = self.client.get(url_for('api_1_0.loglist') +
                               f"?filter[dst_server_id]={self.dest1.id}",
                               headers=self.auth.header)
        self.assertListEqual([self.log.to_json()], resp.get_json())
Exemple #19
0
    def test_get_servers_from_scope_more_than_min_quorum(
            self, mock_get_now, mock_app):
        mock_get_now.return_value = dt.datetime(2019,
                                                4,
                                                1,
                                                tzinfo=dt.timezone.utc)
        Server.set_initial()
        servers = []
        for i in range(0, 7):

            s = Server(f'node{i}', port=5000, created_on=old_age)

            if i == 0:
                r = Route(s, cost=0)
            else:
                r = Route(s, random.choice(servers), cost=i)

            db.session.add_all([s, r])

            servers.append(s)

        mock_get_now.return_value = dt.datetime(2019,
                                                4,
                                                2,
                                                tzinfo=dt.timezone.utc)
        mock_app.dm.cluster_manager.get_alive.return_value = [
            s.id for s in servers
        ]
        s62 = Server(f'node72', port=5000)
        Route(s62, random.choice(servers), cost=6)
        db.session.add(s62)

        quorum = get_servers_from_scope(scope=Scope.CATALOG)

        self.assertEqual(8, len(quorum))
        self.assertNotIn(s62, quorum)
        self.assertIn(s, quorum)
        self.assertIn(Server.get_current(), quorum)
Exemple #20
0
def pack_msg(data, *args, **kwargs):
    if not __ca.config['SECURIZER']:
        return data
    else:
        # if not ('symmetric_key' in kwargs or 'cipher_key' in kwargs):
        #     try:
        #         kwargs['cipher_key'] = session.get('cipher_key')
        #     except RuntimeError:
        #         pass
        # if generate_key:
        #     kwargs.pop('symmetric_key', None)
        #     kwargs.pop('cipher_key', None)
        dim = None
        if dim is None:
            dim = Dimension.get_current()
            if dim is None:
                raise ValueError('No dimension found but SECURIZER set')
        return _pack_msg(data,
                         *args,
                         source=Server.get_current(),
                         pub_key=dim.public,
                         priv_key=dim.private,
                         **kwargs)
Exemple #21
0
def _prepare_headers(server: t.Union[Server, str], headers=None):
    headers = headers or {}
    if isinstance(server, Server):
        headers.update({'D-Destination': str(server.id)})
    headers.update({'D-Source': str(Server.get_current().id)})
    return headers
    def test_lock_scope_packing(self, mock_app, m):

        mock_app.dm.cluster_manager.get_alive.return_value = [
            self.s2.id, self.s3.id
        ]

        def callback_prevent(url, **kwargs):
            return CallbackResult("{'message': 'Preventing lock acquired'}",
                                  status=200)

        def callback_lock(url, **kwargs):
            return CallbackResult("{'message': 'Locked'}", status=200)

        def callback_unlock(url, **kwargs):
            return CallbackResult("{'message': 'UnLocked'}", status=200)

        def callback_client(url, **kwargs):
            kwargs.pop('allow_redirects')
            # workarround for https://github.com/pnuckowski/aioresponses/issues/111
            headers = {
                'Authorization':
                f"Bearer {create_access_token('00000000-0000-0000-0000-000000000001')}"
            }

            r = self.client.post(url.path,
                                 json=kwargs['json'],
                                 headers=headers)

            return CallbackResult(r.data, status=r.status_code)

        m.post(re.compile(Server.get_current().url() + '.*'),
               callback=callback_client)
        m.post(self.s2.url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(self.s3.url('api_1_0.locker_prevent'),
               callback=callback_prevent)
        m.post(re.compile(Server.get_current().url() + '.*'),
               callback=callback_client)
        m.post(self.s2.url('api_1_0.locker_lock'), callback=callback_lock)
        m.post(self.s3.url('api_1_0.locker_lock'), callback=callback_lock)
        m.post(re.compile(Server.get_current().url() + '.*'),
               callback=callback_client)
        m.post(self.s2.url('api_1_0.locker_unlock'), callback=callback_unlock)
        m.post(self.s3.url('api_1_0.locker_unlock'), callback=callback_unlock)

        l = Locker.query.get(Scope.CATALOG)
        self.assertEqual(State.UNLOCKED, l.state)
        self.assertEqual(None, l.applicant)

        with self.app.test_request_context('/api/v1.0/lock'):
            load_global_data_into_context()
            with lock_scope(Scope.CATALOG, identity=ROOT):
                l = Locker.query.get(Scope.CATALOG)
                self.assertEqual(State.LOCKED, l.state)
                self.assertEqual([
                    str(Server.get_current().id),
                    str(self.s2.id),
                    str(self.s3.id)
                ], l.applicant)

        l = Locker.query.get(Scope.CATALOG)
        self.assertEqual(State.UNLOCKED, l.state)
        self.assertEqual(None, l.applicant)
Exemple #23
0
    def bootstrap(self):
        """ bootstraps the application. Gunicorn is still not listening on sockets
        """
        with self.app_context():
            from dimensigon.domain.entities import Server, Parameter
            import dimensigon.web.network as ntwrk
            from dimensigon.domain.entities import Locker

            # reset scopes
            Locker.set_initial(unlock=True)

            # check gates
            me = Server.get_current()
            if me is None:
                raise RuntimeError("No server set as 'current'")

            input_gates = bind2gate(self.dm.config.http_conf.get('bind'))
            current_gates = [(gate.dns or str(gate.ip), gate.port)
                             for gate in me.gates]
            new_gates = set(input_gates).difference(set(current_gates))
            self.server_id_with_new_gates = None
            if new_gates:
                if Parameter.get('join_server'):
                    join_server = Server.query.get(
                        Parameter.get('join_server'))
                else:
                    join_server = None
                servers = Server.get_neighbours()
                if join_server in servers:
                    servers.pop(servers.index(join_server))
                    servers.append(join_server)
                else:
                    self.logger.warning(
                        f'Join server {join_server} is not a neighbour')
                start = time.time()
                resp = None
                server = True
                while len(servers) > 0 and server and (time.time() -
                                                       start) < 900:
                    server_retries = 0
                    server = servers[-1]
                    self.logger.debug(
                        f"Sending new gates {new_gates} to {server}...")
                    resp = ntwrk.patch(
                        server,
                        'api_1_0.serverresource',
                        view_data=dict(server_id=str(Server.get_current().id)),
                        json={
                            'gates': [{
                                'dns_or_ip': ip,
                                'port': port
                            } for ip, port in new_gates]
                        },
                        timeout=60,
                        auth=get_root_auth())
                    if not resp.ok:
                        self.logger.debug(
                            f"Unable to send new gates to {server}. Reason: {resp}"
                        )
                        self.logger.info(
                            f"Unable to create new gates. Trying to send again in 5 seconds..."
                        )
                        time.sleep(5)
                        if resp.code == 409:
                            # try with the same server
                            server_retries += 1
                        elif resp.code == 500:

                            # try with another server
                            i = servers.index(server) - 1
                            if i >= 0:
                                server = servers[i]
                                server_retries = 0
                            else:
                                server = None
                        if server_retries == 3:
                            # changing server
                            i = servers.index(server) - 1
                            if i >= 0:
                                server = servers[i]
                                server_retries = 0
                            else:
                                server = None
                    else:
                        self.logger.debug("New gates created succesfully")
                        Parameter.set('new_gates_server', server.id)
                        break

                if not servers:
                    if Server.query.count() == 1:
                        self.logger.info(
                            f"Creating new gates {new_gates} without performing a lock on catalog"
                        )
                        for gate in new_gates:
                            g = me.add_new_gate(gate[0], gate[1])
                            db.session.add(g)

                else:
                    if resp and not resp.ok:
                        self.logger.warning(
                            f"Remote servers may not connect with {me}. ")
                db.session.commit()
Exemple #24
0
def deploy_orchestration(orchestration: t.Union[Id, Orchestration],
                         hosts: t.Dict[str, t.Union[t.List[Id]]],
                         var_context: 'Context' = None,
                         execution: t.Union[Id, OrchExecution] = None,
                         executor: t.Union[Id, User] = None,
                         execution_server: t.Union[Id, Server] = None,
                         lock_retries=2,
                         lock_delay=3, timeout=None) -> Id:
    """deploy the orchestration

    Args:
        orchestration: id or orchestration to execute
        hosts: Mapping to all distributions
        var_context: Context configuration
        execution: id or execution to associate with the orchestration. If none, a new one is created
        executor: id or User who executes the orchestration
        execution_server: id or User who executes the orchestration
        lock_retries: tries to lock for orchestration N times
        lock_delay: delay between retries
    Returns:
        OrchExecution ID

    Raises:
        Exception: if anything goes wrong
    """
    execution = execution or var_context.env.get('orch_execution_id')
    executor = executor or var_context.env.get('executor_id')
    hosts = hosts or var_context.get('hosts')
    if not isinstance(orchestration, Orchestration):
        orchestration = db.session.query(Orchestration).get(orchestration)
    if not isinstance(execution, OrchExecution):
        exe = None
        if execution is not None:
            exe = db.session.query(OrchExecution).get(execution)
        if exe is None:
            if not isinstance(executor, User):
                executor = db.session.query(User).get(executor)
            if executor is None:
                raise ValueError('executor must be set')
            if not isinstance(execution_server, Server):
                if execution_server is None:
                    try:
                        execution_server = g.server
                    except AttributeError:
                        execution_server = Server.get_current()
                    if execution_server is None:
                        raise ValueError('execution server not found')
                else:
                    execution_server = db.session.query(Server).get(execution_server)
            exe = OrchExecution(id=execution, orchestration_id=orchestration.id, target=hosts,
                                params=dict(var_context),
                                executor_id=executor.id, server_id=execution_server.id)
            db.session.add(exe)
            db.session.commit()

    else:
        exe = execution
    current_app.logger.debug(
        f"Execution {exe.id}: Launching orchestration {orchestration} on {hosts} with {var_context}")

    return _deploy_orchestration(orchestration, var_context, hosts, exe, lock_retries, lock_delay, timeout)
Exemple #25
0
 def my_logs(self):
     return self.session.query(Log).filter_by(
         source_server=Server.get_current(session=self.session)).all()
Exemple #26
0
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
Exemple #27
0
def join():
    global fetched_catalog
    if get_jwt_identity() == '00000000-0000-0000-0000-000000000004':
        js = request.get_json()
        current_app.logger.debug(
            f"New server wanting to join: {json.dumps(js, indent=2)}")
        if db.session.query(Server).filter_by(
                id=js.get('id', None)).count() > 0:
            raise errors.DuplicatedId(js.get('id', None))
        if db.session.query(Server).filter_by(
                name=js.get('name', None)).count() > 0:
            raise errors.AlreadyExists('name', js.get('name', None))
        s = Server.from_json(js)
        s.created_on = get_now()
        external_ip = ipaddress.ip_address(request.remote_addr)
        if not external_ip.is_loopback and external_ip not in [
                gate.ip for gate in s.gates
        ]:
            for port in set([gate.port for gate in s.gates]):
                s.add_new_gate(external_ip, port, hidden=True)

        certfile = current_app.dm.config.http_conf.get('certfile', None)
        keyfile = current_app.dm.config.http_conf.get('keyfile', None)

        if keyfile and os.path.exists(keyfile):
            with open(keyfile, 'rb') as fh:
                keyfile_content = fh.read()
        else:
            raise errors.FileNotFound(keyfile)
        if certfile and os.path.exists(certfile):
            with open(certfile, 'rb') as fh:
                certfile_content = fh.read()
        else:
            raise errors.FileNotFound(certfile)

        data = {
            'keyfile': base64.b64encode(keyfile_content).decode(),
            'certfile': base64.b64encode(certfile_content).decode()
        }

        data.update(Dimension=g.dimension.to_json())
        data.update(me=str(Server.get_current().id))

        with _lock:
            if fetched_catalog[1] is None or fetched_catalog[0] < get_now(
            ) - dt.timedelta(minutes=1):
                c = fetch_catalog()
                fetched_catalog = (get_now(), c)
            else:
                c = fetched_catalog[1]
        data.update(catalog=c)

        if _lock_delete.acquire(False):
            try:
                delete_old_temp_servers()
            finally:
                _lock_delete.release()

        server_data = s.to_json(add_gates=True)
        servers_to_be_created.update({s.id: server_data})
        del s
        return data, 200
    else:
        raise errors.GenericError('Invalid token', status_code=400)
Exemple #28
0
    def _notify_cluster_in(self):
        from dimensigon.domain.entities import Server
        import dimensigon.web.network as ntwrk
        from dimensigon.domain.entities import Parameter

        try:
            signaled = self._route_initiated.wait(timeout=120)
        except Exception:
            return

        if not signaled:
            self.logger.warning("Route Event not fired.")

        self.logger.debug("Notify Cluster")
        with self.dm.flask_app.app_context():
            not_notify = set()
            me = Server.get_current()

            msg = [
                r.to_json() for r in Route.query.options(
                    orm.lazyload(Route.destination), orm.lazyload(Route.gate),
                    orm.lazyload(Route.proxy_server)).all()
            ]

            neighbours = Server.get_neighbours()

            if Parameter.get('join_server', None):
                join_server = Server.query.get(Parameter.get('join_server'))
            else:
                join_server = None

            now = get_now()
            msg = dict(keepalive=now.strftime(defaults.DATEMARK_FORMAT),
                       routes=msg)
            if neighbours:
                random.shuffle(neighbours)
                first = [
                    s for s in neighbours
                    if s.id == Parameter.get('new_gates_server', None)
                ]
                if first:
                    neighbours.pop(neighbours.index(first[0]))
                    neighbours = first + neighbours
                elif join_server in neighbours:
                    neighbours.pop(neighbours.index(join_server))
                    neighbours = [join_server] + neighbours
                for s in neighbours:
                    if s.id not in not_notify:
                        self.logger.debug(
                            f"Sending 'Cluster IN' message to {s}")
                        resp = ntwrk.post(s,
                                          'api_1_0.cluster_in',
                                          view_data=dict(server_id=str(me.id)),
                                          json=msg,
                                          timeout=10,
                                          auth=get_root_auth())
                        if resp.ok:
                            converted = []
                            for ident, str_keepalive, death in resp.msg[
                                    'cluster']:
                                try:
                                    keepalive = dt.datetime.strptime(
                                        str_keepalive,
                                        defaults.DATEMARK_FORMAT)
                                except ValueError:
                                    continue
                                converted.append((ident, keepalive, death))
                            self.put_many(converted)
                            not_notify.update(resp.msg.get('neighbours', []))
                        else:
                            self.logger.debug(
                                f"Unable to send 'Cluster IN' message to {s} . Response: {resp}"
                            )
                    else:
                        self.logger.debug(
                            f"Skiping server {s} from sending 'Cluster IN' message"
                        )
                # alive = [(getattr(Server.query.get(s_id), 'name', None) or s_id) for s_id in
                #          self.get_alive()]
                # self.logger.info(f"Alive servers: {', '.join(alive)}")
            else:
                self.logger.debug("No neighbour to send 'Cluster IN'")
        self.logger.debug("Notify Cluster ended")
Exemple #29
0
def create_cmd_from_orchestration(orchestration: Orchestration, var_context: Context,
                                  hosts: t.Dict[str, t.List[Id]],
                                  executor: concurrent.futures.Executor,
                                  register: 'RegisterStepExecution') -> CompositeCommand:
    current_server = Server.get_current()

    def create_do_cmd_from_step(_step: Step, _s2cc):
        d = {}
        if _step in _s2cc:
            cc = _s2cc[_step]
        else:
            activate_server_ctx = len([server_id for target in _step.target for server_id in hosts[target]]) > 1
            for target in _step.target:
                for server_id in hosts[target]:
                    if str(server_id) == str(current_server.id):
                        cls = Command
                    else:
                        cls = partial(ProxyCommand, server_id)

                    var_kwargs = dict()
                    if activate_server_ctx:
                        var_kwargs.update(key_server_ctx=server_id)
                    c = cls(create_operation(_step),
                            undo_command=_create_server_undo_command(executor, current_server, server_id,
                                                                     _step, var_context, register),
                            var_context=var_context.local_ctx({'server_id': server_id}, **var_kwargs),
                            stop_on_error=_step.stop_on_error,
                            stop_undo_on_error=None,
                            undo_on_error=_step.undo_on_error,
                            pre_process=_step.pre_process,
                            post_process=_step.post_process,
                            register=register,
                            id_=(str(server_id), str(_step.id)),
                            signature=_step.schema)

                    d[c] = []
            if len(d) == 1:
                cc = c
            elif len(d) > 1:
                cc = CompositeCommand(dict_tree=d,
                                      stop_on_error=False,
                                      stop_undo_on_error=False,
                                      id_=str(_step.id), executor=executor, register=register, var_context=var_context)
            else:
                cc = None
        return cc

    def iterate_tree(_step: Step, _d, _s2cc):
        if _step in s2cc_map:
            _c = _s2cc[_step]
        else:
            _c = create_do_cmd_from_step(_step, _s2cc)
            _s2cc[_step] = _c
            if _c not in _d:
                _d[_c] = []
            for child_step in _step.children_do_steps:
                _d[_c].append(iterate_tree(child_step, _d, _s2cc))
        return _c

    root_steps = orchestration.root
    tree = {}
    s2cc_map = {}
    for step in root_steps:
        iterate_tree(step, tree, s2cc_map)

    return CompositeCommand(dict_tree=tree,
                            stop_undo_on_error=orchestration.stop_undo_on_error,
                            stop_on_error=orchestration.stop_on_error,
                            id_=str(orchestration.id), executor=executor, register=register)