def test_brutal_bounce(): # mock the new client used to brutal bounce in the background using threading. mock_cloned_client = mock.MagicMock() with mock.patch( "paasta_tools.kubernetes.application.controller_wrappers.KubeClient", return_value=mock_cloned_client, autospec=True, ): with mock.patch( "paasta_tools.kubernetes.application.controller_wrappers.threading.Thread", autospec=True, ) as mock_deep_delete_and_create: mock_client = mock.MagicMock() app = mock.MagicMock() app.item.metadata.name = "fake_name" app.item.metadata.namespace = "faasta" # we do NOT call deep_delete_and_create app = setup_app({}, True) DeploymentWrapper.update(self=app, kube_client=mock_client) assert mock_deep_delete_and_create.call_count == 0 # we call deep_delete_and_create: when bounce_method is brutal config_dict = {"instances": 1, "bounce_method": "brutal"} app = setup_app(config_dict, True) app.update(kube_client=mock_client) mock_deep_delete_and_create.assert_called_once_with( target=app.deep_delete_and_create, args=[mock_cloned_client])
def list_namespaced_deployments(kube_client: KubeClient, namespace: str, **kwargs) -> Sequence[DeploymentWrapper]: return [ DeploymentWrapper(deployment) for deployment in kube_client.deployments.list_namespaced_deployment( namespace, **kwargs).items if is_valid_application(deployment) ]
def setup_app(config_dict, exists_hpa): item = mock.MagicMock() item.metadata.name = "fake_name" item.metadata.namespace = "faasta" app = DeploymentWrapper(item=item) app.soa_config = KubernetesDeploymentConfig( service="service", cluster="cluster", instance="instance", config_dict=config_dict, branch_dict=None, ) app.exists_hpa = mock.Mock(return_value=exists_hpa) app.delete_horizontal_pod_autoscaler = mock.Mock(return_value=None) return app
def create_application_object( kube_client: KubeClient, service: str, instance: str, soa_dir: str ) -> Tuple[bool, Optional[Application]]: try: service_instance_config = load_kubernetes_service_config_no_cache( service, instance, load_system_paasta_config().get_cluster(), soa_dir=soa_dir, ) except NoDeploymentsAvailable: log.debug( "No deployments found for %s.%s in cluster %s. Skipping." % (service, instance, load_system_paasta_config().get_cluster()) ) return True, None except NoConfigurationForServiceError: error_msg = ( "Could not read kubernetes configuration file for %s.%s in cluster %s" % (service, instance, load_system_paasta_config().get_cluster()) ) log.error(error_msg) return False, None try: formatted_application = service_instance_config.format_kubernetes_app() except InvalidKubernetesConfig as e: log.error(str(e)) return False, None app = None if isinstance(formatted_application, V1Deployment): app = DeploymentWrapper(formatted_application) elif isinstance(formatted_application, V1StatefulSet): app = StatefulSetWrapper(formatted_application) else: raise Exception("Unknown kubernetes object to update") app.load_local_config(soa_dir, load_system_paasta_config()) return True, app
def test_cleanup_unused_apps(fake_deployment, fake_stateful_set, invalid_app): mock_kube_client = mock.MagicMock() with mock.patch( "paasta_tools.cleanup_kubernetes_jobs.KubeClient", return_value=mock_kube_client, autospec=True, ), mock.patch( "paasta_tools.cleanup_kubernetes_jobs.list_namespaced_applications", return_value=[DeploymentWrapper(fake_deployment)], autospec=True, ), mock.patch( "paasta_tools.cleanup_kubernetes_jobs.get_services_for_cluster", return_value={}, autospec=True, ), mock.patch("paasta_tools.cleanup_kubernetes_jobs.alert_state_change", autospec=True) as mock_alert_state_change: mock_alert_state_change.__enter__ = mock.Mock( return_value=(mock.Mock(), None)) mock_alert_state_change.__exit__ = mock.Mock(return_value=None) cleanup_unused_apps("soa_dir", kill_threshold=1, force=False) assert mock_kube_client.deployments.delete_namespaced_deployment.call_count == 1
def test_sync_horizontal_pod_autoscaler(): mock_client = mock.MagicMock() app = mock.MagicMock() app.item.metadata.name = "fake_name" app.item.metadata.namespace = "faasta" # helper Functions for mocking def setup_app(app, config_dict, exists_hpa): app.reset_mock() mock_client.reset_mock() app.get_soa_config.return_value = config_dict app.exists_hpa.return_value = exists_hpa # Do nothing config_dict = {"instances": 1} setup_app(app, config_dict, False) DeploymentWrapper.sync_horizontal_pod_autoscaler(self=app, kube_client=mock_client) assert (mock_client.autoscaling. create_namespaced_horizontal_pod_autoscaler.call_count == 0) assert (mock_client.autoscaling.patch_namespaced_horizontal_pod_autoscaler. call_count == 0) assert app.delete_horizontal_pod_autoscaler.call_count == 0 # old HPA got removed so delete config_dict = {"instances": 1} setup_app(app, config_dict, True) DeploymentWrapper.sync_horizontal_pod_autoscaler(self=app, kube_client=mock_client) assert (mock_client.autoscaling. create_namespaced_horizontal_pod_autoscaler.call_count == 0) assert (mock_client.autoscaling.patch_namespaced_horizontal_pod_autoscaler. call_count == 0) assert app.delete_horizontal_pod_autoscaler.call_count == 1 # Create config_dict = {} setup_app(app, config_dict, False) DeploymentWrapper.sync_horizontal_pod_autoscaler(self=app, kube_client=mock_client) assert (mock_client.autoscaling.patch_namespaced_horizontal_pod_autoscaler. call_count == 0) assert app.delete_horizontal_pod_autoscaler.call_count == 0 mock_client.autoscaling.create_namespaced_horizontal_pod_autoscaler.assert_called_once_with( namespace="faasta", body=app.soa_config.get_autoscaling_metric_spec.return_value, pretty=True, ) # Update config_dict = {} setup_app(app, config_dict, True) DeploymentWrapper.sync_horizontal_pod_autoscaler(self=app, kube_client=mock_client) assert (mock_client.autoscaling. create_namespaced_horizontal_pod_autoscaler.call_count == 0) assert app.delete_horizontal_pod_autoscaler.call_count == 0 mock_client.autoscaling.patch_namespaced_horizontal_pod_autoscaler.assert_called_once_with( namespace="faasta", name="fake_name", body=app.soa_config.get_autoscaling_metric_spec.return_value, pretty=True, )