Exemplo n.º 1
0
    def split(self) -> Apps:

        if self.is_read_request():
            if self.is_list_apps_request():
                apps = self.marathon_client.list_apps()
                for app in apps:
                    yield self.merge_marathon_apps(MarathonApp(), app), app
            elif self.is_app_request():
                app = self._get_original_app(self.request.user, self.object_id)
                yield self.merge_marathon_apps(MarathonApp(), app), app
            elif self.is_group_request():
                self.group = self._get_original_group(self.request.user,
                                                      self.object_id)
                for app in self.group.iterate_apps():
                    yield self.merge_marathon_apps(MarathonApp(), app), app

            return

        # Request is a WRITE
        if self.is_app_request():
            for app in self.get_request_data():
                request_app = MarathonApp.from_json(app)
                app = self._get_original_app(self.request.user, self.object_id
                                             or request_app.id)

                yield self.merge_marathon_apps(request_app, app), app
        elif self.is_tasks_request():
            request_data = self.request.get_json()
            for task_id in request_data['ids']:
                request_task = MarathonTask.from_json({"id": task_id})
                yield request_task, request_task
            return
Exemplo n.º 2
0
    def test_split_groups_read_on_specific_group(self, group_b_fixture):

        with application.test_request_context('/v2/groups/group-b',
                                              method='GET') as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with RequestsMock() as rsps:
                rsps.add(method='GET',
                         url=conf.MARATHON_ADDRESSES[0] +
                         '/v2/groups//dev/group-b',
                         body=json.dumps(group_b_fixture),
                         status=200)

                apps = list(request_parser.split())
                self.assertEqual(2, len(apps))

                original_app_one = MarathonApp.from_json(
                    {"id": "/dev/group-b/appb0"})
                original_app_two = MarathonApp.from_json(
                    {"id": "/dev/group-b/group-b0/app0"})
                expected_apps = [
                    (request_parser.merge_marathon_apps(
                        MarathonApp(), original_app_one), original_app_one),
                    (request_parser.merge_marathon_apps(
                        MarathonApp(), original_app_two), original_app_two),
                ]
                self.assertEqual(expected_apps, apps)
Exemplo n.º 3
0
    def test_can_read_app_if_already_migrated(self, single_full_app_fixture):
        """
        Conferimos que é possível fazer um GET em
        /v2/apps/<app-id> para uma app que já está migrada.
        O <app-id> usado é sempre *sem* namespace
        """
        request_data = deepcopy(single_full_app_fixture)
        single_full_app_fixture["id"] = "/dev/foo"
        with application.test_request_context("/v2/apps/foo",
                                              method="GET") as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with RequestsMock() as rsps:
                rsps.add(
                    method="GET",
                    url=conf.MARATHON_ADDRESSES[0] + "/v2/apps//dev/foo",
                    body=json.dumps({"app": single_full_app_fixture}),
                    status=200,
                )

                apps = list(request_parser.split())

                original_app = MarathonApp.from_json(single_full_app_fixture)
                expected_app = (
                    request_parser.merge_marathon_apps(MarathonApp(),
                                                       original_app),
                    original_app,
                )
                self.assertEqual(apps, [expected_app])
Exemplo n.º 4
0
    def test_change_request_path_if_is_read_single_app(
            self, single_full_app_fixture):
        with application.test_request_context('/v2/apps/foo',
                                              method='GET') as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            single_full_app_fixture['id'] = "/dev/foo"
            apps = [(MarathonApp.from_json(single_full_app_fixture),
                     MarathonApp.from_json(single_full_app_fixture))]

            request = request_parser.join(apps)
            self.assertIsInstance(request, HollowmanRequest)
            self.assertEqual("/v2/apps/dev/foo", request.path)
Exemplo n.º 5
0
    def test_split_groups_write_PUT_on_group(self):
        """
        Atualmente, o único body que chega em um PUT em /v2/groups é:
            {"scaleBy": <N>}
        onde `<N>` é o fator que será multiplicado pelo atual número de TASK_RUNNING de cada app.

        O problema é que o Request.split() retorna uma lista de apps, e o Request.join() potencialmente
        vai reconstruir um body com essa lista de apps. O problema é que isso gera um request body *diferente* do orignal,
        já que agora temos um body contendo um APP_GROUP com todas suas apps (e sub apps).

        E se fazemos apenas isso, a informação do "scaleBy" se perdeu, pois se mandamos um request com o TASK_GROUP inteiro para o
        upstream, nada vai mudar já que as apps não foram modificadas.

        Uma ideia é o Core do hollowman decobrir essa ação de scaleBy e chamar o métoro "scale_by" dos filtros, já com a request_app tendo seu
        atributo "instances" multiplicado pelo fator. Opcionalmente o fator poderia ser passado como parametro para o filtro.

        Isso nos daria a possibilidade de "corrigir" um problema atual do scaleby que é:
            Quando damos scale_by = 2 em um app que está suspended, ela continua suspended já que 2 * 0 = 0. A ideia é que suspended apps também sejam
            ligadas considerando esse fator. O que faríamos no filtro seria, para toda app que instances = 0, consideramos instances = 1 e multiplicamos pelo fator.

        Enfim, apenas uma ideia. Temos que ver o que fazemos com esse teste aqui.
        """

        with application.test_request_context("/v2/groups/group-b",
                                              method="PUT") as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with RequestsMock() as rsps:
                rsps.add(
                    method="GET",
                    url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/group-b",
                    body=json.dumps(group_b_fixture),
                    status=200,
                )

                apps = list(request_parser.split())
                self.assertEqual(2, len(apps))

                expected_apps = [
                    (
                        MarathonApp(),
                        MarathonApp.from_json({"id": "/dev/group-b/appb0"}),
                    ),
                    (
                        MarathonApp(),
                        MarathonApp.from_json(
                            {"id": "/dev/group-b/group-b0/app0"}),
                    ),
                ]
                self.assertEqual(expected_apps, apps)
Exemplo n.º 6
0
    def setUp(self, single_full_app_fixture):

        self.request_apps = [
            (MarathonApp(id='/xablau'), MarathonApp(id='/xena')),
            (MarathonApp(id='/foo'), MarathonApp(id='/bar')),
        ]

        rebuild_schema()
        self.session = HollowmanSession()
        self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0")
        self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company")
        self.user.accounts = [self.account_dev]
        self.session.add(self.user)
        self.session.add(self.account_dev)
        self.session.commit()
Exemplo n.º 7
0
    def test_a_read_single_app_request_returns_a_single_marathonapp_if_app_exists(
            self, fixture):
        with application.test_request_context('/v2/apps//foo',
                                              method='GET',
                                              data=b'') as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)

            with patch.object(request_parser, 'marathon_client') as client:
                original_app = MarathonApp.from_json(fixture)
                client.get_app.return_value = original_app
                apps = list(request_parser.split())

            self.assertEqual(apps, [(request_parser.merge_marathon_apps(
                MarathonApp(), original_app), client.get_app.return_value)])
Exemplo n.º 8
0
    def test_multiapp_response_returns_multiple_marathonapp_instances(self, fixture):
        modified_app = fixture.copy()
        modified_app['id'] = '/xablau'

        apps = [fixture, modified_app]
        with application.test_request_context('/v2/apps/',
                                              method='GET', data=b'') as ctx:
            response = FlaskResponse(response=json.dumps({"apps": apps}),
                                     status=HTTPStatus.OK,
                                     headers={})
            response = Response(ctx.request, response)

        with patch.object(response, 'marathon_client') as client:
            original_apps = [MarathonApp.from_json(app) for app in apps]
            client.get_app.side_effect = original_apps
            apps = list(response.split())
            self.assertEqual([call("/foo"), call("/xablau")], client.get_app.call_args_list)

        self.assertEqual(
            apps,
            [
                (AsgardApp.from_json(fixture), original_apps[0]),
                (AsgardApp.from_json(modified_app), original_apps[1])
            ]
        )
Exemplo n.º 9
0
def run_paasta_metastatus_high_cpu(context, app_id):
    context.marathon_client.create_app(
        app_id,
        MarathonApp(cmd='/bin/sleep 1000',
                    cpus=9,
                    instances=3,
                    container=CONTAINER))
Exemplo n.º 10
0
def run_paasta_metastatus_high_cpu(context, app_id):
    context.marathon_clients.current[0].create_app(
        app_id,
        MarathonApp(
            cmd="/bin/sleep 100000", cpus=9.1, instances=3, container=CONTAINER
        ),
    )
Exemplo n.º 11
0
    def test_join_one_app_should_produce_one_app_not_a_list(self, fixture):
        """
        Um POST em /v2/apps, apesar de receber no body apens uma app ({...}),
        após o request.join(), restá produzindo um request com uma lista de apps:
            [{...}], e a API do marathon não aceita lista no POST apenas no PUT.

            O problema parece ser no request.join():89, onde fazemos if self.is_list_app_request().
            Precisamos olhar se é PUT ou POST e gerar list() ou dict() apropriadamente.
        """
        with application.test_request_context("/v2/apps/",
                                              method="POST",
                                              data=json.dumps(fixture)) as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            mock_app = get_fixture("single_full_app.json")
            mock_apps = [(MarathonApp.from_json(mock_app), Mock())]

            joined_request = request_parser.join(mock_apps)
            self.assertIsInstance(joined_request, HollowmanRequest)
            joined_request_data = json.loads(joined_request.data)
            self.assertFalse(
                isinstance(joined_request_data, list),
                "Body não deveria ser uma lista",
            )
            self.assertEqual("/foo", joined_request_data["id"])
Exemplo n.º 12
0
def deploy_marathon_app(client, marathon_json, sleep_secs=10, retries=3):
    app_id = marathon_json['id']

    CONFIG_URI = os.getenv('CONFIG_URI')
    if CONFIG_URI:
        marathon_json['uris'].append(CONFIG_URI)

    print("Attempting deploy Marathon app with id: %s" % app_id)
    print(marathon_json, file=sys.stderr)
    marathon_app = MarathonApp.from_json(marathon_json)

    # We are going to retry, in the case of blocked deployments
    attempt = 0
    while attempt < retries:
        try:
            try:
                client.get_app(app_id)
                response = client.update_app(app_id, marathon_app)
            except NotFoundError:
                response = client.create_app(app_id, marathon_app)
            print(response, file=sys.stderr)
            print('Deployment succeeded.')
            break
        except Exception, ex:
            attempt += 1
            print(ex.message)
            print('Failure attempting to deploy app. Retrying...')
            time.sleep(sleep_secs)
Exemplo n.º 13
0
 def _get_original_app(self, user, app_id):
     app_id_with_namespace = "/{}/{}".format(user.current_account.namespace,
                                             app_id.strip("/"))
     try:
         return self.marathon_client.get_app(app_id_with_namespace)
     except NotFoundError as e:
         return MarathonApp.from_json({"id": app_id_with_namespace})
Exemplo n.º 14
0
    def test_multiapp_response_returns_multiple_marathonapp_instances(
            self, fixture):
        modified_app = fixture.copy()
        modified_app["id"] = "/xablau"

        apps = [fixture, modified_app]
        with application.test_request_context("/v2/apps/",
                                              method="GET",
                                              data=b"") as ctx:
            response = FlaskResponse(
                response=json.dumps({"apps": apps}),
                status=HTTPStatus.OK,
                headers={},
            )
            response = Response(ctx.request, response)

        with patch.object(response, "marathon_client") as client:
            original_apps = [MarathonApp.from_json(app) for app in apps]
            client.get_app.side_effect = original_apps
            apps = list(response.split())

        self.assertEqual(
            apps,
            [
                (AsgardApp.from_json(fixture), original_apps[0]),
                (AsgardApp.from_json(modified_app), original_apps[1]),
            ],
        )
Exemplo n.º 15
0
    def test_empty_labels(self):
        app_dict = {"labels": {}}
        request_app = MarathonApp.from_json(app_dict)
        filtered_app = self.filter.write(Mock(), request_app, Mock())
        filtered_app = filtered_app.json_repr()

        self.assertDictEqual(filtered_app["labels"], {})
Exemplo n.º 16
0
    async def setUp(self):
        await super(RequestHandlersTests, self).setUp()
        self.request_apps = [
            (MarathonApp(id="/xablau"), MarathonApp(id="/xena")),
            (MarathonApp(id="/foo"), MarathonApp(id="/bar")),
        ]

        self.user = UserDB(
            tx_email="*****@*****.**",
            tx_name="John Doe",
            tx_authkey="69ed620926be4067a36402c3f7e9ddf0",
        )
        self.account_dev = AccountDB(id=4,
                                     name="Dev Team",
                                     namespace="dev",
                                     owner="company")
        self.user.accounts = [self.account_dev]
Exemplo n.º 17
0
 def test_adjust_apps_request_path_repeating_non_final_path(self):
     with application.test_request_context('/v2/apps/app0/app0/app1',
                                           method='GET') as ctx:
         request_wrapper = Request(ctx.request)
         original_app = MarathonApp(id="/dev/app0/app0/app1")
         request_wrapper._adjust_request_path_if_needed(
             request_wrapper.request, original_app)
         self.assertEqual("/v2/apps/dev/app0/app0/app1",
                          request_wrapper.request.path)
Exemplo n.º 18
0
 def test_adjust_apps_request_path_no_aaditional_paths(self):
     with application.test_request_context('/v2/apps/my-app',
                                           method='GET') as ctx:
         request_wrapper = Request(ctx.request)
         original_app = MarathonApp(id="/dev/my-app")
         request_wrapper._adjust_request_path_if_needed(
             request_wrapper.request, original_app)
         self.assertEqual("/v2/apps/dev/my-app",
                          request_wrapper.request.path)
Exemplo n.º 19
0
 def test_adjust_apps_tasks_task_id_DELETE_request_path(self):
     with application.test_request_context('/v2/apps/my-app/tasks/task_id',
                                           method='DELETE') as ctx:
         request_wrapper = Request(ctx.request)
         original_app = MarathonApp(id="/dev/my-app")
         request_wrapper._adjust_request_path_if_needed(
             request_wrapper.request, original_app)
         self.assertEqual("/v2/apps/dev/my-app/tasks/task_id",
                          request_wrapper.request.path)
Exemplo n.º 20
0
 def test_adjust_apps_versions_request_path(self):
     with application.test_request_context("/v2/apps/my-app/versions",
                                           method="GET") as ctx:
         request_wrapper = Request(ctx.request)
         original_app = MarathonApp(id="/dev/my-app")
         request_wrapper._adjust_request_path_if_needed(
             request_wrapper.request, original_app)
         self.assertEqual("/v2/apps/dev/my-app/versions",
                          request_wrapper.request.path)
Exemplo n.º 21
0
    def test_a_request_for_restart_operation_with_appid_in_url_path_returns_a_tuple_of_marathonapp(
            self, fixture):
        with application.test_request_context('/v2/apps/xablau/restart',
                                              method='PUT',
                                              data=b'{"force": true}') as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with RequestsMock() as rsps:
                rsps.add(method='GET',
                         url=conf.MARATHON_ADDRESSES[0] +
                         '/v2/apps//dev/xablau',
                         body=json.dumps({'app': fixture}),
                         status=200)
                apps = list(request_parser.split())

                original_app = MarathonApp.from_json(fixture)
                expected_app = (request_parser.merge_marathon_apps(
                    MarathonApp(), original_app), original_app)
                self.assertEqual(apps, [expected_app])
Exemplo n.º 22
0
def run_paasta_metastatus_high_disk(context, app_id):
    context.marathon_clients.current[0].create_app(
        app_id,
        MarathonApp(
            cmd='/bin/sleep 100000',
            disk=95,
            instances=3,
            container=CONTAINER,
        ),
    )
Exemplo n.º 23
0
 def test_a_request_for_write_operation_with_appid_in_url_path_returns_a_tuple_of_marathonapp(
         self, fixture):
     scale_up = {'instances': 10}
     with application.test_request_context(
             '/v2/apps/foo', method='PUT',
             data=json.dumps(scale_up)) as ctx:
         ctx.request.user = self.user
         request_parser = Request(ctx.request)
         with RequestsMock() as rsps:
             rsps.add(method='GET',
                      url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo',
                      body=json.dumps({'app': fixture}),
                      status=200)
             apps = list(request_parser.split())
             original_app = MarathonApp.from_json(fixture)
             expected_apps = (request_parser.merge_marathon_apps(
                 MarathonApp.from_json(scale_up),
                 original_app), original_app)
             self.assertEqual(apps, [expected_apps])
Exemplo n.º 24
0
    def test_split_does_not_break_when_removing_force_parameter_if_request_is_a_list(
            self, fixture):
        request_data = {"id": "/foo", "instances": 2}
        with application.test_request_context(
                '/v2/apps/', method='PUT',
                data=json.dumps(request_data)) as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with RequestsMock() as rsps:
                rsps.add(method='GET',
                         url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo',
                         body=json.dumps({'app': fixture}),
                         status=200)
                apps = list(request_parser.split())

                original_app = MarathonApp.from_json(fixture)
                expected_app = (request_parser.merge_marathon_apps(
                    MarathonApp.from_json(request_data),
                    original_app), original_app)
                self.assertEqual(apps, [expected_app])
Exemplo n.º 25
0
 def test_adjust_apps_request_path_keep_additional_paths_multiple_paths(
         self):
     with application.test_request_context(
             '/v2/apps/my-app/versions/2017-10-31T13:01:07.768Z',
             method='GET') as ctx:
         request_wrapper = Request(ctx.request)
         original_app = MarathonApp(id="/dev/my-app")
         request_wrapper._adjust_request_path_if_needed(
             request_wrapper.request, original_app)
         self.assertEqual(
             "/v2/apps/dev/my-app/versions/2017-10-31T13:01:07.768Z",
             request_wrapper.request.path)
Exemplo n.º 26
0
    def __init__(self,
                 scheduler,
                 executable='dask-worker',
                 docker_image='mrocklin/dask-distributed',
                 marathon_address='http://localhost:8080',
                 username=None,
                 password=None,
                 auth_token=None,
                 app_name=None,
                 **kwargs):
        self.scheduler = scheduler
        self.executor = ThreadPoolExecutor(1)

        # Create Marathon App to run dask-worker
        args = [
            executable,
            scheduler.address,
            '--name',
            '$MESOS_TASK_ID',  # use Mesos task ID as worker name
            '--worker-port',
            '$PORT_WORKER',
            '--nanny-port',
            '$PORT_NANNY',
            '--http-port',
            '$PORT_HTTP'
        ]

        ports = [{
            'port': 0,
            'protocol': 'tcp',
            'name': port_name
        } for port_name in ['worker', 'nanny', 'http']]

        if 'mem' in kwargs:
            args.extend(
                ['--memory-limit',
                 str(int(kwargs['mem'] * 0.6 * 1e6))])

        kwargs['cmd'] = ' '.join(args)
        container = MarathonContainer({'image': docker_image})

        app = MarathonApp(instances=0,
                          container=container,
                          port_definitions=ports,
                          **kwargs)

        # Connect and register app
        self.client = MarathonClient(servers=marathon_address,
                                     username=username,
                                     password=password,
                                     auth_token=auth_token)
        self.app = self.client.create_app(app_name or 'dask-%s' % uuid.uuid4(),
                                          app)
Exemplo n.º 27
0
def do_full_rollback(client: MarathonClient, rollback: list):
    print('------------------\nPerforming rollback in order:')
    print('\n'.join(rollback))
    print('------------------')
    for each in rollback:
        if os.path.isfile(each):
            with open(each) as json_file:
                app = MarathonApp.from_json(json.load(json_file))
            _update_application(client, app, each, False)
        else:
            deployment = client.delete_app(each, True)
            wait_for_deployment(client, deployment)
Exemplo n.º 28
0
    def test_it_recreates_a_post_request_for_a_single_app(self, fixture):
        with application.test_request_context('/v2/apps//foo',
                                              method='POST',
                                              data=json.dumps(fixture)) as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with patch.object(request_parser, 'marathon_client') as client:
                client.get_app.return_value = MarathonApp.from_json(fixture)
                apps = list(request_parser.split())

                request = request_parser.join(apps)
                self.assertIsInstance(request, HollowmanRequest)
                self.assertEqual(request.get_json()['id'], '/foo')
Exemplo n.º 29
0
    def test_it_recreates_a_get_request_for_a_single_app(self, fixture):
        with application.test_request_context("/v2/apps//foo",
                                              method="GET",
                                              data=b"") as ctx:
            ctx.request.user = self.user
            request_parser = Request(ctx.request)
            with patch.object(request_parser, "marathon_client") as client:
                client.get_app.return_value = MarathonApp.from_json(fixture)
                apps = list(request_parser.split())

                request = request_parser.join(apps)
                self.assertIsInstance(request, HollowmanRequest)
                self.assertEqual(request, ctx.request)
                self.assertEqual(request.data, b"")
Exemplo n.º 30
0
 def register_services(self, service_registry="conf/marathon"):
     for app_def in glob.glob(os.path.join(service_registry, "*json")):
         with open(app_def, "r") as stream:
             args = json.loads(stream.read())
             app_id = args['id']
             args = Names.snake_case(args)
             logger.debug("Creating service: %s", json.dumps(args,
                                                             indent=2))
             args['tasks'] = []
             app = MarathonApp(**args)
             try:
                 logging.info("Creating app [id=>{0}]".format(app_id))
                 self.marathon.create_app(app_id, app)
             except:
                 traceback.print_exc()
Exemplo n.º 31
0
 def create_app_from_json(self, json_data ):
   a = MarathonApp.from_json(json_data)
   return MarathonClient.create_app(self, a.id, a)
Exemplo n.º 32
0
 def update_app_from_json( self, json_data, force ):
   a = MarathonApp.from_json(json_data)
   return MarathonClient.update_app(self, a.id, a, force)