Beispiel #1
0
    async def test_tune_everything_in_multiple_apps(self):
        interface = AsgardInterface()
        app1 = ScalableApp("test1")
        app2 = ScalableApp("test2")
        app3 = ScalableApp("test3")

        decisions = [
            Decision(app1.id, cpu=0.2, mem=10),
            Decision(app2.id, cpu=0.4, mem=20),
            Decision(app3.id, cpu=0.1, mem=9),
        ]

        with aioresponses() as rsps:
            rsps.put(
                f"{settings.ASGARD_API_ADDRESS}/v2/apps",
                status=200,
                payload={
                    "deploymentId": "test2",
                    "version": "1.0"
                },
            )
            applied_decisions = await interface.apply_decisions(decisions)

        self.assertEqual(len(applied_decisions), 3)
        for i in range(len(decisions)):
            self.assertEqual(applied_decisions[i]["id"], decisions[i].id)
            self.assertEqual(applied_decisions[i]["cpus"], decisions[i].cpu)
            self.assertEqual(applied_decisions[i]["mem"], decisions[i].mem)
Beispiel #2
0
    async def test_cpu_decision_is_rounded_to_3_decimal_places(self):
        interface = AsgardInterface()

        decisions = [Decision("test", cpu=0.436_721_072_367)]

        body_fixture = [{"id": "test", "cpus": 0.437}]
        headers_fixture = {
            "Content-Type": "application/json",
            "Authorization": f"Token {settings.AUTOSCALER_AUTH_TOKEN}",
        }

        with aioresponses() as rsps:
            rsps.put(
                f"{settings.ASGARD_API_ADDRESS}/v2/apps",
                status=200,
                payload={
                    "deploymentId": "test",
                    "version": "1.0"
                },
            )

            await interface.apply_decisions(decisions)
            calls = rsps.requests.get(
                ("put", URL(f"{settings.ASGARD_API_ADDRESS}/v2/apps")))

            self.assertIsNotNone(calls)
            self.assertEqual(body_fixture, calls[0].kwargs.get("json"))
            self.assertEqual(
                headers_fixture,
                interface._asgard_client._http_client.default_headers,
            )
Beispiel #3
0
    def decide_scaling_actions(self,
                               apps: List[ScalableApp]) -> List[Decision]:
        decisions = []
        for app in apps:
            if app.app_stats:
                decision = Decision(app.id)
                deploy_decision = False

                cpu_usage = app.app_stats.cpu_usage / 100
                mem_usage = app.app_stats.mem_usage / 100

                if app.is_set_to_scale_cpu():

                    if (cpu_usage > app.cpu_threshold +
                            settings.AUTOSCALER_MARGIN_THRESHOLD
                            or cpu_usage < app.cpu_threshold -
                            settings.AUTOSCALER_MARGIN_THRESHOLD):
                        new_cpu = (cpu_usage *
                                   app.cpu_allocated) / app.cpu_threshold

                        decision.cpu = (app.min_cpu_scale_limit
                                        if new_cpu < app.min_cpu_scale_limit
                                        else app.max_cpu_scale_limit if new_cpu
                                        > app.max_cpu_scale_limit else new_cpu)

                        deploy_decision = True
                if app.is_set_to_scale_mem():
                    if (mem_usage > app.mem_threshold +
                            settings.AUTOSCALER_MARGIN_THRESHOLD
                            or mem_usage < app.mem_threshold -
                            settings.AUTOSCALER_MARGIN_THRESHOLD):
                        new_mem = (mem_usage *
                                   app.mem_allocated) / app.mem_threshold

                        decision.mem = (app.min_mem_scale_limit
                                        if new_mem < app.min_mem_scale_limit
                                        else app.max_mem_scale_limit if new_mem
                                        > app.max_mem_scale_limit else new_mem)

                        deploy_decision = True

                if deploy_decision:
                    decisions.append(decision)

        return decisions
Beispiel #4
0
    async def test_tune_multiple_apps_with_different_params(self):
        interface = AsgardInterface()
        app1 = ScalableApp("test1")
        app2 = ScalableApp("test2")
        app3 = ScalableApp("test3")

        decisions = [
            Decision(app1.id, mem=10),
            Decision(app2.id, cpu=0.4),
            Decision(app3.id, cpu=0.1, mem=9),
        ]

        with aioresponses() as rsps:
            rsps.put(
                f"{settings.ASGARD_API_ADDRESS}/v2/apps",
                status=200,
                payload={
                    "deploymentId": "test2",
                    "version": "1.0"
                },
            )
            applied_decisions = await interface.apply_decisions(decisions)

        self.assertEqual(len(applied_decisions), 3)

        self.assertEqual(applied_decisions[0]["id"], decisions[0].id)
        self.assertEqual(applied_decisions[0]["mem"], decisions[0].mem)
        self.assertEqual("cpus" in applied_decisions[0], False)

        self.assertEqual(applied_decisions[1]["id"], decisions[1].id)
        self.assertEqual(applied_decisions[1]["cpus"], decisions[1].cpu)
        self.assertEqual("mem" in applied_decisions[1], False)

        self.assertEqual(applied_decisions[2]["id"], decisions[2].id)
        self.assertEqual(applied_decisions[2]["mem"], decisions[2].mem)
        self.assertEqual(applied_decisions[2]["cpus"], decisions[2].cpu)
Beispiel #5
0
    async def test_tune_one_thing_in_one_app(self):
        interface = AsgardInterface()
        app = ScalableApp("test")
        decisions = [Decision(app.id, cpu=0.3)]

        with aioresponses() as rsps:
            rsps.put(
                f"{settings.ASGARD_API_ADDRESS}/v2/apps",
                status=200,
                payload={
                    "deploymentId": "test1",
                    "version": "1.0"
                },
            )
            applied_decisions = await interface.apply_decisions(decisions)

        self.assertEqual(len(applied_decisions), 1)
        self.assertEqual(applied_decisions[0]["id"], decisions[0].id)
        self.assertEqual(applied_decisions[0]["cpus"], decisions[0].cpu)
        self.assertEqual("mem" in applied_decisions[0], False)
    def decide_scaling_actions(self,
                               apps: List[ScalableApp]) -> List[Decision]:
        decisions = []
        for app in apps:
            if app.app_stats:
                decision = Decision(app.id)
                deploy_decision = False

                cpu_usage = app.app_stats.cpu_usage / 100
                mem_usage = app.app_stats.mem_usage / 100

                if app.is_set_to_scale_cpu():

                    if (abs(cpu_usage - app.cpu_threshold) >
                            settings.AUTOSCALER_MARGIN_THRESHOLD):
                        new_cpu = (cpu_usage *
                                   app.cpu_allocated) / app.cpu_threshold

                        decision.cpu = (app.min_cpu_scale_limit
                                        if new_cpu < app.min_cpu_scale_limit
                                        else app.max_cpu_scale_limit if new_cpu
                                        > app.max_cpu_scale_limit else new_cpu)

                        event = (DecisionEvents.CPU_SCALE_DOWN
                                 if app.cpu_allocated > decision.cpu else
                                 DecisionEvents.CPU_SCALE_UP)
                        self.logger.info({
                            "appname": app.id,
                            "event": event,
                            "previous_value": app.cpu_allocated,
                            "new_value": decision.cpu,
                        })

                        deploy_decision = True

                    else:
                        self.logger.debug({
                            "appname":
                            app.id,
                            "event":
                            DecisionEvents.CPU_SCALE_NONE,
                            "reason":
                            "usage within accepted margin",
                            "usage":
                            cpu_usage,
                            "threshold":
                            app.cpu_threshold,
                            "accepted_margin":
                            settings.AUTOSCALER_MARGIN_THRESHOLD,
                        })

                if app.is_set_to_scale_mem():
                    if (abs(mem_usage - app.mem_threshold) >
                            settings.AUTOSCALER_MARGIN_THRESHOLD):
                        new_mem = (mem_usage *
                                   app.mem_allocated) / app.mem_threshold

                        decision.mem = (app.min_mem_scale_limit
                                        if new_mem < app.min_mem_scale_limit
                                        else app.max_mem_scale_limit if new_mem
                                        > app.max_mem_scale_limit else new_mem)

                        event = (DecisionEvents.MEM_SCALE_DOWN
                                 if app.mem_allocated > decision.mem else
                                 DecisionEvents.MEM_SCALE_UP)
                        self.logger.info({
                            "appname": app.id,
                            "event": event,
                            "previous_value": app.mem_allocated,
                            "new_value": decision.mem,
                        })

                        deploy_decision = True

                    else:
                        self.logger.debug({
                            "appname":
                            app.id,
                            "event":
                            DecisionEvents.MEM_SCALE_NONE,
                            "reason":
                            "usage within accepted margin",
                            "usage":
                            mem_usage,
                            "threshold":
                            app.mem_threshold,
                            "accepted_margin":
                            settings.AUTOSCALER_MARGIN_THRESHOLD,
                        })

                if deploy_decision:
                    decisions.append(decision)

        return decisions
    def decide_scaling_actions(self,
                               apps: List[ScalableApp]) -> List[Decision]:
        decisions = []
        for app in apps:
            if app.app_stats:
                decision = Decision(app.id)

                if app.cpu_needs_scaling():
                    new_cpu = (app.get_cpu_usage() *
                               app.cpu_allocated) / app.cpu_threshold

                    new_cpu = _limit_number(
                        new_cpu,
                        app.min_cpu_scale_limit,
                        app.max_cpu_scale_limit,
                    )

                    if new_cpu != app.cpu_allocated:
                        decision.cpu = new_cpu
                        event = (DecisionEvents.CPU_SCALE_DOWN
                                 if app.cpu_allocated > decision.cpu else
                                 DecisionEvents.CPU_SCALE_UP)
                        self.logger.info({
                            "appname": app.id,
                            "event": event,
                            "previous_value": app.cpu_allocated,
                            "new_value": decision.cpu,
                        })

                if app.is_set_to_scale_cpu() and decision.cpu is None:
                    self.logger.debug({
                        "appname":
                        app.id,
                        "event":
                        DecisionEvents.CPU_SCALE_NONE,
                        "reason":
                        "usage within accepted margin",
                        "usage":
                        app.get_cpu_usage(),
                        "threshold":
                        app.cpu_threshold,
                        "accepted_margin":
                        settings.AUTOSCALER_MARGIN_THRESHOLD,
                    })

                if app.mem_needs_scaling():
                    new_mem = (app.get_mem_usage() *
                               app.mem_allocated) / app.mem_threshold

                    new_mem = _limit_number(
                        new_mem,
                        app.min_mem_scale_limit,
                        app.max_mem_scale_limit,
                    )

                    if new_mem != app.mem_allocated:
                        decision.mem = new_mem

                        event = (DecisionEvents.MEM_SCALE_DOWN
                                 if app.mem_allocated > decision.mem else
                                 DecisionEvents.MEM_SCALE_UP)
                        self.logger.info({
                            "appname": app.id,
                            "event": event,
                            "previous_value": app.mem_allocated,
                            "new_value": decision.mem,
                        })

                if app.is_set_to_scale_mem() and decision.mem is None:
                    self.logger.debug({
                        "appname":
                        app.id,
                        "event":
                        DecisionEvents.MEM_SCALE_NONE,
                        "reason":
                        "usage within accepted margin",
                        "usage":
                        app.get_mem_usage(),
                        "threshold":
                        app.mem_threshold,
                        "accepted_margin":
                        settings.AUTOSCALER_MARGIN_THRESHOLD,
                    })

                if decision.mem is not None or decision.cpu is not None:
                    decisions.append(decision)

        return decisions