def test_deployment_reconciler(self): """test that deployment requires update""" controller = ProxyKubernetesController(self.outpost, self.service_connection) deployment_reconciler = DeploymentReconciler(controller) self.assertIsNotNone(deployment_reconciler.retrieve()) config = self.outpost.config config.kubernetes_replicas = 3 self.outpost.config = config with self.assertRaises(NeedsUpdate): deployment_reconciler.reconcile( deployment_reconciler.retrieve(), deployment_reconciler.get_reference_object(), ) with CONFIG.patch("outposts.container_image_base", "test"): with self.assertRaises(NeedsUpdate): deployment_reconciler.reconcile( deployment_reconciler.retrieve(), deployment_reconciler.get_reference_object(), ) deployment_reconciler.delete( deployment_reconciler.get_reference_object())
def outpost_controller(self: MonitoredTask, outpost_pk: str): """Create/update/monitor the deployment of an Outpost""" logs = [] outpost: Outpost = Outpost.objects.get(pk=outpost_pk) self.set_uid(slugify(outpost.name)) try: if not outpost.service_connection: return if outpost.type == OutpostType.PROXY: service_connection = outpost.service_connection if isinstance(service_connection, DockerServiceConnection): logs = ProxyDockerController( outpost, service_connection).up_with_logs() if isinstance(service_connection, KubernetesServiceConnection): logs = ProxyKubernetesController( outpost, service_connection).up_with_logs() LOGGER.debug( "---------------Outpost Controller logs starting----------------") for log in logs: LOGGER.debug(log) LOGGER.debug( "-----------------Outpost Controller logs end-------------------") except ControllerException as exc: self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc)) else: self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, logs))
def outpost_pre_delete(outpost_pk: str): """Delete outpost objects before deleting the DB Object""" outpost = Outpost.objects.get(pk=outpost_pk) if outpost.type == OutpostType.PROXY: service_connection = outpost.service_connection if isinstance(service_connection, DockerServiceConnection): ProxyDockerController(outpost, service_connection).down() if isinstance(service_connection, KubernetesServiceConnection): ProxyKubernetesController(outpost, service_connection).down()
def test_kubernetes_controller_static(self): """Test Kubernetes Controller""" provider: ProxyProvider = ProxyProvider.objects.create( name="test", internal_host="http://localhost", external_host="http://localhost", authorization_flow=Flow.objects.first(), ) service_connection = KubernetesServiceConnection.objects.first() outpost: Outpost = Outpost.objects.create( name="test", type=OutpostType.PROXY, service_connection=service_connection, ) outpost.providers.add(provider) outpost.save() controller = ProxyKubernetesController(outpost, service_connection) manifest = controller.get_static_deployment() self.assertEqual(len(list(yaml.load_all(manifest, Loader=yaml.SafeLoader))), 4)
def test_kubernetes_controller_ingress(self): """Test Kubernetes Controller's Ingress""" provider: ProxyProvider = ProxyProvider.objects.create( name="test", internal_host="http://localhost", external_host="https://localhost", authorization_flow=create_test_flow(), ) provider2: ProxyProvider = ProxyProvider.objects.create( name="test2", internal_host="http://otherhost", external_host="https://otherhost", mode=ProxyMode.FORWARD_SINGLE, authorization_flow=create_test_flow(), ) service_connection = KubernetesServiceConnection.objects.first() outpost: Outpost = Outpost.objects.create( name="test", type=OutpostType.PROXY, service_connection=service_connection, ) outpost.providers.add(provider) self.controller = ProxyKubernetesController(outpost, service_connection) ingress_rec = IngressReconciler(self.controller) ingress = ingress_rec.retrieve() self.assertEqual(len(ingress.spec.rules), 1) self.assertEqual(ingress.spec.rules[0].host, "localhost") # add provider, check again outpost.providers.add(provider2) ingress = ingress_rec.retrieve() self.assertEqual(len(ingress.spec.rules), 2) self.assertEqual(ingress.spec.rules[0].host, "localhost") self.assertEqual(ingress.spec.rules[1].host, "otherhost")
def controller_for_outpost(outpost: Outpost) -> Optional[BaseController]: """Get a controller for the outpost, when a service connection is defined""" if not outpost.service_connection: return None service_connection = outpost.service_connection if outpost.type == OutpostType.PROXY: if isinstance(service_connection, DockerServiceConnection): return ProxyDockerController(outpost, service_connection) if isinstance(service_connection, KubernetesServiceConnection): return ProxyKubernetesController(outpost, service_connection) if outpost.type == OutpostType.LDAP: if isinstance(service_connection, DockerServiceConnection): return LDAPDockerController(outpost, service_connection) if isinstance(service_connection, KubernetesServiceConnection): return LDAPKubernetesController(outpost, service_connection) return None
def test_controller_rename(self): """test that objects get deleted and re-created with new names""" controller = ProxyKubernetesController(self.outpost, self.service_connection) self.assertIsNone(controller.up()) self.outpost.name = "foo" self.assertIsNone(controller.up()) apps = AppsV1Api(controller.client) with self.assertRaises(OpenApiException): apps.read_namespaced_deployment( "test", self.outpost.config.kubernetes_namespace) controller.down()
def test_controller_full_update(self): """Test an update that triggers all objects""" controller = ProxyKubernetesController(self.outpost, self.service_connection) self.assertIsNone(controller.up()) with patch("authentik.outposts.controllers.k8s.base.get_version", MagicMock(return_value="1234")): self.assertIsNone(controller.up()) deployment_reconciler = DeploymentReconciler(controller) deployment = deployment_reconciler.retrieve() self.assertEqual( deployment.metadata.labels["app.kubernetes.io/version"], "1234") controller.down()
def test_kubernetes_controller_deploy(self): """Test Kubernetes Controller""" provider: ProxyProvider = ProxyProvider.objects.create( name="test", internal_host="http://localhost", external_host="http://localhost", authorization_flow=Flow.objects.first(), ) service_connection = KubernetesServiceConnection.objects.first() outpost: Outpost = Outpost.objects.create( name="test", type=OutpostType.PROXY, service_connection=service_connection, ) outpost.providers.add(provider) outpost.save() controller = ProxyKubernetesController(outpost, service_connection) controller.up() controller.down()
class TestProxyKubernetes(TestCase): """Test Controllers""" controller: Optional[KubernetesController] def setUp(self): # Ensure that local connection have been created outpost_local_connection() self.controller = None def tearDown(self) -> None: if self.controller: for log in self.controller.down_with_logs(): LOGGER.info(log) return super().tearDown() def test_kubernetes_controller_static(self): """Test Kubernetes Controller""" provider: ProxyProvider = ProxyProvider.objects.create( name="test", internal_host="http://localhost", external_host="http://localhost", authorization_flow=create_test_flow(), ) service_connection = KubernetesServiceConnection.objects.first() outpost: Outpost = Outpost.objects.create( name="test", type=OutpostType.PROXY, service_connection=service_connection, ) outpost.providers.add(provider) outpost.save() self.controller = ProxyKubernetesController(outpost, service_connection) manifest = self.controller.get_static_deployment() self.assertEqual( len(list(yaml.load_all(manifest, Loader=yaml.SafeLoader))), 4) def test_kubernetes_controller_ingress(self): """Test Kubernetes Controller's Ingress""" provider: ProxyProvider = ProxyProvider.objects.create( name="test", internal_host="http://localhost", external_host="https://localhost", authorization_flow=create_test_flow(), ) provider2: ProxyProvider = ProxyProvider.objects.create( name="test2", internal_host="http://otherhost", external_host="https://otherhost", mode=ProxyMode.FORWARD_SINGLE, authorization_flow=create_test_flow(), ) service_connection = KubernetesServiceConnection.objects.first() outpost: Outpost = Outpost.objects.create( name="test", type=OutpostType.PROXY, service_connection=service_connection, ) outpost.providers.add(provider) self.controller = ProxyKubernetesController(outpost, service_connection) ingress_rec = IngressReconciler(self.controller) ingress = ingress_rec.retrieve() self.assertEqual(len(ingress.spec.rules), 1) self.assertEqual(ingress.spec.rules[0].host, "localhost") # add provider, check again outpost.providers.add(provider2) ingress = ingress_rec.retrieve() self.assertEqual(len(ingress.spec.rules), 2) self.assertEqual(ingress.spec.rules[0].host, "localhost") self.assertEqual(ingress.spec.rules[1].host, "otherhost")