def test_createService(self, client_mock):
        service = KubernetesService()
        client_mock.reset_mock()
        client_mock.CoreV1Api.return_value.create_namespaced_service.return_value = V1Service(
            kind="unit")

        expected_body = V1Service(metadata=self._createMeta(self.name),
                                  spec=V1ServiceSpec(
                                      cluster_ip="None",
                                      ports=[
                                          V1ServicePort(name="mongod",
                                                        port=27017,
                                                        protocol="TCP")
                                      ],
                                      selector={
                                          "heritage": "mongos",
                                          "name": self.name,
                                          "operated-by":
                                          "operators.ultimaker.com"
                                      },
                                  ))
        expected_calls = [
            call.CoreV1Api().create_namespaced_service(self.namespace,
                                                       expected_body)
        ]

        result = service.createService(self.cluster_object)
        self.assertEqual(expected_calls, client_mock.mock_calls)
        self.assertEqual(V1Service(kind="unit"), result)
Example #2
0
 def create_service(
     self,
     service_name: str,
     namespace: str,
     port: int = 80,
     protocol: str = 'TCP',
     service_type: str = 'LoadBalancer',
     target_port: int = 8080,
 ):
     self.core_api.create_namespaced_service(
         namespace=namespace,
         body=V1Service(
             kind='Service',
             metadata=V1ObjectMeta(name=service_name, ),
             spec=V1ServiceSpec(
                 type=service_type,
                 ports=[
                     V1ServicePort(protocol=protocol,
                                   port=port,
                                   target_port=target_port),
                 ],
                 selector={'app': service_name},
                 session_affinity='None',
             ),
         ))
Example #3
0
 def get_reference_object(self) -> V1Service:
     """Get deployment object for outpost"""
     meta = self.get_object_meta(name=self.name)
     ports = []
     for port in self.controller.deployment_ports:
         ports.append(
             V1ServicePort(
                 name=port.name,
                 port=port.port,
                 protocol=port.protocol.upper(),
                 target_port=port.inner_port or port.port,
             ))
     if self.is_embedded:
         selector_labels = {
             "app.kubernetes.io/name": "authentik",
             "app.kubernetes.io/component": "server",
         }
     else:
         selector_labels = DeploymentReconciler(
             self.controller).get_pod_meta()
     return V1Service(
         metadata=meta,
         spec=V1ServiceSpec(
             ports=ports,
             selector=selector_labels,
             type=self.controller.outpost.config.kubernetes_service_type,
         ),
     )
Example #4
0
 def deploy(self):
     spec = V1ServiceSpec(selector=self.selector,
                          type=self.service_type,
                          ports=self.ports)
     body = V1Service(metadata=self.meta, spec=spec)
     return k8sclient.apiV1.create_namespaced_service(
         self.meta.namespace, body)
def hub_pod_ssl(kube_client, kube_ns, ssl_app):
    """Start a hub pod with internal_ssl enabled"""
    # load ssl dir to tarfile
    buf = io.BytesIO()
    tf = tarfile.TarFile(fileobj=buf, mode="w")
    tf.add(ssl_app.internal_certs_location, arcname="internal-ssl", recursive=True)

    # store tarfile in a secret
    b64_certs = base64.b64encode(buf.getvalue()).decode("ascii")
    secret_name = "hub-ssl-secret"
    secret_manifest = V1Secret(
        metadata={"name": secret_name}, data={"internal-ssl.tar": b64_certs}
    )
    create_resource(kube_client, kube_ns, "secret", secret_manifest)

    name = "hub-ssl"

    service_manifest = V1Service(
        metadata=dict(name=name),
        spec=V1ServiceSpec(
            type="ClusterIP",
            ports=[V1ServicePort(port=8081, target_port=8081)],
            selector={"hub-name": name},
        ),
    )

    create_resource(kube_client, kube_ns, "service", service_manifest)

    return create_hub_pod(
        kube_client,
        kube_ns,
        pod_name=name,
        ssl=True,
    )
Example #6
0
    def test_updateService(self, client_mock):
        service = KubernetesService()
        client_mock.reset_mock()

        expected_body = V1Service(metadata=self._createMeta(self.name),
                                  spec=V1ServiceSpec(
                                      cluster_ip="None",
                                      ports=[
                                          V1ServicePort(name="mongod",
                                                        port=27017,
                                                        protocol="TCP")
                                      ],
                                      selector={
                                          "heritage": "mongos",
                                          "name": self.name,
                                          "operated-by":
                                          "operators.javamachr.cz"
                                      },
                                  ))
        result = service.updateService(self.cluster_object)
        expected_calls = [
            call.CoreV1Api().patch_namespaced_service(self.name,
                                                      self.namespace,
                                                      expected_body)
        ]
        self.assertEqual(expected_calls, client_mock.mock_calls)
        self.assertEqual(
            client_mock.CoreV1Api().patch_namespaced_service.return_value,
            result)
Example #7
0
    def test_updateService(self, client_mock):
        service = KubernetesService()
        client_mock.reset_mock()

        expected_body = V1Service(metadata=self._createMeta(self.name),
                                  spec=V1ServiceSpec(
                                      cluster_ip="None",
                                      ports=[
                                          V1ServicePort(name='mongod',
                                                        port=27017,
                                                        protocol='TCP')
                                      ],
                                      selector={
                                          'heritage': 'mongos',
                                          'name': self.name,
                                          'operated-by':
                                          'operators.ultimaker.com'
                                      },
                                  ))
        result = service.updateService(self.cluster_object)
        expected_calls = [
            call.CoreV1Api().patch_namespaced_service(self.name,
                                                      self.namespace,
                                                      expected_body)
        ]
        self.assertEqual(expected_calls, client_mock.mock_calls)
        self.assertEqual(
            client_mock.CoreV1Api().patch_namespaced_service.return_value,
            result)
    def _create(self, namespace, name, app_name, labels, ports, spec_type):
        """Create service.

        :param str namespace:
        :param str name:
        :param str app_name:
        :param dict labels:
        :param List[int] ports:
        :param str spec_type:
        :rtype: V1Service
        """
        core_v1_api = self._clients.core_api
        annotations = {}  # todo add annotations to services

        meta = V1ObjectMeta(name=name, labels=labels, annotations=annotations)
        service_ports = []

        for port in ports:
            service_ports.append(
                V1ServicePort(
                    name="port" + str(port), port=port, target_port=port, protocol="TCP"
                )
            )

        selector_tag = {TagsService.get_default_selector(app_name): app_name}

        if spec_type == "LoadBalancer":
            allowed_ips = None  # todo - alexaz - add option to restrict source ips
            specs = V1ServiceSpec(
                ports=service_ports,
                selector=selector_tag,
                type=spec_type,
                load_balancer_source_ranges=allowed_ips,
            )
        else:
            specs = V1ServiceSpec(
                ports=service_ports, selector=selector_tag, type=spec_type
            )

        service = V1Service(metadata=meta, spec=specs)
        return core_v1_api.create_namespaced_service(
            namespace=namespace, body=service, pretty="true"
        )
Example #9
0
 def service_definition(self):
     return V1Service(metadata=V1ObjectMeta(name=self.name,
                                            namespace=self.namespace),
                      spec=V1ServiceSpec(
                          ports=self.ports_to_expose,
                          publish_not_ready_addresses=True,
                          session_affinity=None,
                          type='LoadBalancer',
                          selector={self.selector_key:
                                    self.selector_value}))
Example #10
0
    def __init__(self) -> None:
        service_port = V1ServicePort(name="sql", port=5432)

        self.service = V1Service(
            api_version="v1",
            kind="Service",
            metadata=V1ObjectMeta(name="postgres", labels={"app": "postgres"}),
            spec=V1ServiceSpec(
                type="NodePort", ports=[service_port], selector={"app": "postgres"}
            ),
        )
Example #11
0
    def __init__(self) -> None:
        ports = [
            V1ServicePort(name="kafka", port=9092),
            V1ServicePort(name="schema-registry", port=8081),
        ]

        self.service = V1Service(
            metadata=V1ObjectMeta(name="redpanda", labels={"app": "redpanda"}),
            spec=V1ServiceSpec(
                type="NodePort", ports=ports, selector={"app": "redpanda"}
            ),
        )
Example #12
0
def ensure_ingress_routed_svc(api_core_v1: client.CoreV1Api,
                              api_custom: client.CustomObjectsApi, domain,
                              hostname, name, target_name, namespace,
                              port_name, svc_port, target_port):
    ensure_service(api=api_core_v1,
                   service=V1Service(api_version="v1",
                                     metadata=V1ObjectMeta(name=name),
                                     spec=V1ServiceSpec(
                                         type='ClusterIP',
                                         ports=[
                                             V1ServicePort(
                                                 protocol='TCP',
                                                 port=svc_port,
                                                 name=port_name,
                                                 target_port=target_port),
                                         ],
                                         selector={'app': target_name})),
                   name=name,
                   namespace=namespace)
    ensure_custom_object(api=api_custom,
                         custom_object={
                             'apiVersion': 'traefik.containo.us/v1alpha1',
                             'kind': 'IngressRoute',
                             'metadata': {
                                 'name': name,
                             },
                             'spec': {
                                 'entryPoints': ['websecure'],
                                 'routes': [{
                                     'match':
                                     f'Host(`{hostname}.{domain}`)',
                                     'kind':
                                     'Rule',
                                     'services': [{
                                         'name': name,
                                         'port': svc_port
                                     }],
                                     'middlewares': [{
                                         'name': 'traefik-forward-auth',
                                         'namespace': 'default'
                                     }]
                                 }],
                                 'tls': {
                                     'certResolver': 'default'
                                 }
                             }
                         },
                         group='traefik.containo.us',
                         plural='ingressroutes',
                         version='v1alpha1',
                         name=hostname,
                         namespace=namespace)
Example #13
0
 def create_gluster_service(self, v1_api, namespace_name):
     service = V1Service()
     service.api_version = "v1"
     service.kind = "Service"
     meta = V1ObjectMeta()
     meta.generate_name = "gluster-service"
     service.metadata = meta
     service_spec = V1ServiceSpec()
     service_port = V1ServicePort(port=5)
     service_spec.ports = [service_port]
     service.spec = service_spec
     api_response = v1_api.create_namespaced_service(
         namespace=namespace_name, body=service)
     return api_response.metadata.name
Example #14
0
 def deploy(self, force=False):
     spec = V1ServiceSpec(selector=self.selector,
                          type=self.service_type,
                          ports=self.ports)
     body = V1Service(metadata=self.meta, spec=spec)
     try:
         k8sclient.apiV1.create_namespaced_service(self.meta.namespace,
                                                   body)
     except ApiException as e:
         if e.status != 409 or not force:
             raise e
         k8sclient.remove_service(self.meta.namespace, self.meta.name)
         k8sclient.apiV1.create_namespaced_service(self.meta.namespace,
                                                   body)
Example #15
0
 def create_service(self,
                    namespace,
                    name,
                    selector,
                    port,
                    protocol="TCP",
                    service_type="ClusterIP"):
     metadata = V1ObjectMeta(name=name, namespace=namespace)
     port = V1ServicePort(name=name, port=port, protocol=protocol)
     spec = V1ServiceSpec(selector=selector,
                          type=service_type,
                          ports=[port])
     body = V1Service(metadata=metadata, spec=spec)
     return self.apiV1.create_namespaced_service(namespace, body)
Example #16
0
def generate_delaying_proxy_service():
    return V1Service(
        kind='Service',
        metadata=V1ObjectMeta(
            name='delaying-proxy-svc',
            labels={'app': 'delaying-proxy-svc'},
        ),
        spec=V1ServiceSpec(
            type='ClusterIP',
            ports=[
                V1ServicePort(name='default',
                              protocol='TCP',
                              port=80,
                              target_port=8080),
            ],
            selector={'app': 'delaying-proxy'},
            session_affinity='None',
        ),
    )
Example #17
0
def generate_secrets_server_service(
    secrets_server_config: SecretsServerConfig, ):
    # We need to ensure that the labels and selectors match between the deployment and the service,
    # therefore we base them on the configured service name.
    service_name = secrets_server_config.service_name()
    selector = {'app': service_name}

    return V1Service(
        kind='Service',
        metadata=V1ObjectMeta(name=service_name, ),
        spec=V1ServiceSpec(
            type='ClusterIP',
            ports=[
                V1ServicePort(protocol='TCP', port=80, target_port=8080),
            ],
            selector=selector,
            session_affinity='None',
        ),
    )
Example #18
0
 def get_reference_object(self) -> V1Service:
     """Get deployment object for outpost"""
     meta = self.get_object_meta(name=self.name)
     ports = []
     for port in self.controller.deployment_ports:
         ports.append(
             V1ServicePort(
                 name=port.name,
                 port=port.port,
                 protocol=port.protocol.upper(),
                 target_port=port.port,
             ))
     selector_labels = DeploymentReconciler(self.controller).get_pod_meta()
     return V1Service(
         metadata=meta,
         spec=V1ServiceSpec(ports=ports,
                            selector=selector_labels,
                            type="ClusterIP"),
     )
Example #19
0
 def _create_kube_service(self,
                          k8s_id,
                          ports,
                          namespace=KubernetesConfig.K8S_NAMESPACE):
     '''
     :param ports: List of [[int targetport, int port]] to expose thru the service
     :return: Service object
     '''
     name = k8s_id + "-service"
     serviceports = []
     for portname, targetport, portnumber in ports:
         serviceports.append(
             V1ServicePort(name=portname,
                           target_port=targetport,
                           port=portnumber))
     metadata = client.V1ObjectMeta(name=name, namespace=namespace)
     spec = V1ServiceSpec(
         selector={KubernetesConfig.K8S_LABELS_OPGUID: k8s_id},
         ports=serviceports)
     service = V1Service(metadata=metadata, spec=spec)
     return service
Example #20
0
 def manage_service(self, logger):
     create_service = False
     try:
         service = core_v1_api.read_namespaced_service(
             self.deployment_name, self.deployment_namespace)
     except ApiException as e:
         if e.status == 404:
             create_service = True
         else:
             raise
     if create_service:
         logger.info(
             f"Creating Service {self.deployment_name} in {self.deployment_namespace}"
         )
         service = core_v1_api.create_namespaced_service(
             self.deployment_namespace,
             V1Service(
                 metadata=V1ObjectMeta(
                     annotations={
                         owner_annotation: self.make_owner_annotation(),
                     },
                     labels={owner_uid_label: self.uid},
                     name=self.deployment_name,
                 ),
                 spec=V1ServiceSpec(
                     ports=[
                         V1ServicePort(
                             name="10080-tcp",
                             port=10080,
                             protocol="TCP",
                             target_port=10080,
                         )
                     ],
                     selector={"name": self.deployment_name},
                     type="ClusterIP",
                 ),
             ),
         )
     return service
Example #21
0
def create(ns, subs):
  svc = broker.client.V1Service(
    api_version='v1',
    metadata=V1ObjectMeta(
      namespace=ns,
      name=subs.get('name'),
      labels=subs.get('labels', {'app': subs.get('name')})
    ),
    spec=V1ServiceSpec(
      type=subs.get('type', 'ClusterIP'),
      selector=subs.get('labels', {'app': subs.get('name')}),
      ports=[
        V1ServicePort(
          port=subs.get('from_port', 80),
          target_port=subs.get('to_port', 80)
        )
      ]
    )
  )

  broker.coreV1.create_namespaced_service(
    body=svc,
    namespace=ns
  )
Example #22
0
def create_nifi_instances(api_apps_v1, api_core_v1, api_custom, domain):
    for instance in NifiInstance.objects.filter(state='PENDING_CREATE'):
        instance.state = 'CREATING'
        instance.save()
        port_name = 'web'
        instance.state = 'CREATE_FAILED'
        try:
            namespace = 'default'

            if instance.namespace is not None and instance.namespace != 'default':
                namespace = instance.namespace
                ensure_namespace(api_core_v1, namespace)
            else:
                instance.namespace = 'default'

            # deploy nifi
            nifi_volume_paths = [
                ('db-repo', '/opt/nifi/nifi-current/database_repository',
                 '20Gi', 'standard'),
                ('flowfile-repo', '/opt/nifi/nifi-current/flowfile_repository',
                 '20Gi', 'standard'),
                ('provenance-repo',
                 '/opt/nifi/nifi-current/provenance_repository', '20Gi',
                 'standard'),
                ('content-repo', '/opt/nifi/nifi-current/content_repository',
                 '20Gi', 'standard'),
            ]
            ensure_statefulset_with_containers(
                api_apps_v1=api_apps_v1,
                name=instance.hostname,
                namespace=namespace,
                replicas=1,
                containers=[
                    V1Container(name='nifi',
                                image=instance.image,
                                env=[
                                    V1EnvVar(name='NIFI_WEB_HTTP_HOST',
                                             value='0.0.0.0')
                                ],
                                ports=[V1ContainerPort(container_port=8080)],
                                volume_mounts=[
                                    V1VolumeMount(name=path[0],
                                                  mount_path=path[1])
                                    for path in nifi_volume_paths
                                ])
                ],
                init_containers=[
                    V1Container(name='init-permissions',
                                image='busybox',
                                command=[
                                    'sh', '-c',
                                    'chown -R 1000:1000 /opt/nifi/nifi-current'
                                ],
                                volume_mounts=[
                                    V1VolumeMount(name=path[0],
                                                  mount_path=path[1])
                                    for path in nifi_volume_paths
                                ])
                ],
                volume_paths=nifi_volume_paths)
            ensure_ingress_routed_svc(api_core_v1=api_core_v1,
                                      api_custom=api_custom,
                                      domain=domain,
                                      hostname=instance.hostname,
                                      name=instance.hostname,
                                      target_name=instance.hostname,
                                      namespace=namespace,
                                      port_name=port_name,
                                      svc_port=80,
                                      target_port=8080)

            # deploy mongo
            if instance.deploy_mongo:
                mongo_volume_paths = [
                    ('db', '/data/db', '20Gi', 'standard'),
                ]
                ensure_statefulset_with_containers(
                    api_apps_v1=api_apps_v1,
                    name='mongo',
                    namespace=namespace,
                    replicas=1,
                    containers=[
                        V1Container(
                            name='mongo',
                            image='mongo',
                            env=[
                                V1EnvVar(name='MONGO_INITDB_ROOT_USERNAME',
                                         value='admin'),
                                V1EnvVar(name='MONGO_INITDB_ROOT_PASSWORD',
                                         value='admin')
                            ],
                            ports=[
                                V1ContainerPort(name='mongo',
                                                container_port=27017)
                            ],
                            volume_mounts=[
                                V1VolumeMount(name=path[0], mount_path=path[1])
                                for path in mongo_volume_paths
                            ])
                    ],
                    volume_paths=mongo_volume_paths)
                ensure_service(api=api_core_v1,
                               service=V1Service(
                                   api_version="v1",
                                   metadata=V1ObjectMeta(name='mongo'),
                                   spec=V1ServiceSpec(
                                       type='ClusterIP',
                                       ports=[
                                           V1ServicePort(protocol='TCP',
                                                         port=27017,
                                                         name='mongo',
                                                         target_port=27017),
                                       ],
                                       selector={'app': 'mongo'})),
                               name='mongo',
                               namespace=namespace)
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(
                        name='mongo-express',
                        image='mongo-express',
                        env=[
                            V1EnvVar(name='ME_CONFIG_MONGODB_ADMINUSERNAME',
                                     value='admin'),
                            V1EnvVar(name='ME_CONFIG_MONGODB_ADMINPASSWORD',
                                     value='admin')
                        ],
                        ports=[V1ContainerPort(container_port=8000)]),
                    'mongo-express', instance.namespace)
                ensure_ingress_routed_svc(api_core_v1=api_core_v1,
                                          api_custom=api_custom,
                                          domain=domain,
                                          hostname="mongo-" +
                                          instance.hostname,
                                          name="mongo-" + instance.hostname,
                                          target_name="mongo-express",
                                          namespace=namespace,
                                          port_name=port_name,
                                          svc_port=80,
                                          target_port=8081)

            if instance.deploy_kafka:
                # deploy zookeeper
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(name='zookeeper',
                                image='wurstmeister/zookeeper',
                                env=[],
                                ports=[V1ContainerPort(container_port=2181)]),
                    'zookeeper', instance.namespace)
                ensure_service(api=api_core_v1,
                               service=V1Service(
                                   api_version="v1",
                                   metadata=V1ObjectMeta(name='zookeeper'),
                                   spec=V1ServiceSpec(
                                       type='ClusterIP',
                                       ports=[
                                           V1ServicePort(protocol='TCP',
                                                         port=2181,
                                                         name='zookeeper',
                                                         target_port=2181),
                                       ],
                                       selector={'app': 'zookeeper'})),
                               name='zookeeper',
                               namespace=namespace)

                # deploy kafka
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(name='kafka',
                                image='wurstmeister/kafka',
                                env=[
                                    V1EnvVar(name='KAFKA_ADVERTISED_HOST_NAME',
                                             value='kafka'),
                                    V1EnvVar(name='KAFKA_ZOOKEEPER_CONNECT',
                                             value='zookeeper:2181'),
                                    V1EnvVar(name='KAFKA_PORT', value='9092')
                                ],
                                ports=[V1ContainerPort(container_port=9092)]),
                    'kafka', instance.namespace)
                ensure_service(api=api_core_v1,
                               service=V1Service(
                                   api_version="v1",
                                   metadata=V1ObjectMeta(name='kafka'),
                                   spec=V1ServiceSpec(
                                       type='ClusterIP',
                                       ports=[
                                           V1ServicePort(protocol='TCP',
                                                         port=9092,
                                                         name='kafka',
                                                         target_port=9092),
                                       ],
                                       selector={'app': 'kafka'})),
                               name='kafka',
                               namespace=namespace)

            if instance.deploy_prometheus:
                # deploy prometheus
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(name='prometheus',
                                image='prom/prometheus',
                                env=[],
                                ports=[V1ContainerPort(container_port=9090)]),
                    'prometheus', instance.namespace)
                ensure_ingress_routed_svc(api_core_v1=api_core_v1,
                                          api_custom=api_custom,
                                          domain=domain,
                                          hostname="prometheus-" +
                                          instance.hostname,
                                          name="prometheus",
                                          target_name="prometheus",
                                          namespace=namespace,
                                          port_name=port_name,
                                          svc_port=9090,
                                          target_port=9090)

            if instance.deploy_jupyter:
                # deploy jupyter
                instance.jupyter_token = str(uuid.uuid1())
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(
                        name='jupyter',
                        image='jupyter/datascience-notebook',
                        command=[
                            'start-notebook.sh',
                            '--NotebookApp.token=' + instance.jupyter_token
                        ],
                        env=[],
                        ports=[V1ContainerPort(container_port=8888)]),
                    'jupyter', instance.namespace)
                ensure_ingress_routed_svc(api_core_v1=api_core_v1,
                                          api_custom=api_custom,
                                          domain=domain,
                                          hostname="jupyter-" +
                                          instance.hostname,
                                          name="jupyter",
                                          target_name="jupyter",
                                          namespace=namespace,
                                          port_name=port_name,
                                          svc_port=8888,
                                          target_port=8888)

            # deploy custom instance types
            custom_instances = Instance.objects.filter(parent=instance)
            for ci in custom_instances:
                inst_type: InstanceType = ci.instance_type
                env_vars = [
                    V1EnvVar(name=e.name, value=e.default_value)
                    for e in InstanceTypeEnvVar.objects.filter(
                        instance_type=inst_type)
                ]
                ports = [
                    V1ContainerPort(container_port=p.internal)
                    for p in InstanceTypePort.objects.filter(
                        instance_type=inst_type)
                ]
                ensure_single_container_deployment(
                    api_apps_v1,
                    V1Container(name=inst_type.container_name,
                                image=inst_type.image,
                                env=env_vars,
                                ports=ports), inst_type.container_name,
                    instance.namespace)
                for svc in InstanceTypeIngressRoutedService.objects.filter(
                        instance_type=inst_type):
                    ensure_ingress_routed_svc(
                        api_core_v1=api_core_v1,
                        api_custom=api_custom,
                        domain=domain,
                        hostname=svc.service_name + '-' + instance.hostname,
                        name=svc.service_name + '-' + instance.hostname,
                        target_name=inst_type.container_name,
                        namespace=namespace,
                        port_name=port_name,
                        svc_port=svc.svc_port,
                        target_port=svc.target_port)

            instance.state = 'RUNNING'
        finally:
            instance.save()
Example #23
0
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from pytest import raises, fixture
from kubernetes.client import V1ObjectMeta, V1ServiceList, V1Service, V1ServiceSpec, V1ServicePort
import util.k8s.kubectl as kubectl
from util.app_names import NAUTAAppNames
from util.exceptions import KubectlConnectionError, LocalPortOccupiedError, KubernetesError
from cli_text_consts import UtilKubectlTexts as Texts


SERVICES_LIST_MOCK = V1ServiceList(items=[
    V1Service(metadata=V1ObjectMeta(name="service", namespace="namespace"),
              spec=V1ServiceSpec(ports=[V1ServicePort(port=5000, node_port=33451)]))
]).items

TOP_RESULT_SUCCESS = "NAME CPU(cores) MEMORY(bytes)\nnauta-fluentd-hdr2p 9m 155Mi"
TOP_RESULT_FAILURE = "NAME CPU(cores) MEMORY(bytes)\nnauta-fluentd-hdr2p 9m"


@fixture
def mock_k8s_svc(mocker):
    svcs_list_mock = mocker.patch('util.k8s.kubectl.get_app_services')
    svcs_list_mock.return_value = SERVICES_LIST_MOCK


# noinspection PyUnusedLocal,PyShadowingNames
def test_start_port_forwarding_success(mock_k8s_svc, mocker):
    subprocess_command_mock = mocker.patch('util.system.execute_subprocess_command')
Example #24
0
def ensure_traefik(api_core_v1, api_ext_v1_beta1, api_apps_v1, api_custom,
                   api_rbac_auth_v1_b1, admin_email, domain, static_ip,
                   oauth_client_id, oauth_client_secret, oauth_domain,
                   oauth_secret):
    ensure_crd(api=api_ext_v1_beta1,
               name='ingressroutes.traefik.containo.us',
               group='traefik.containo.us',
               kind='IngressRoute',
               plural='ingressroutes',
               singular='ingressroute',
               scope='Namespaced')
    ensure_crd(api=api_ext_v1_beta1,
               name='ingressroutetcps.traefik.containo.us',
               group='traefik.containo.us',
               kind='IngressRouteTCP',
               plural='ingressroutetcps',
               singular='ingressroutetcp',
               scope='Namespaced')
    ensure_crd(api=api_ext_v1_beta1,
               name='middlewares.traefik.containo.us',
               group='traefik.containo.us',
               kind='Middleware',
               plural='middlewares',
               singular='middleware',
               scope='Namespaced')
    ensure_crd(api=api_ext_v1_beta1,
               name='tlsoptions.traefik.containo.us',
               group='traefik.containo.us',
               kind='TLSOption',
               plural='tlsoptions',
               singular='tlsoption',
               scope='Namespaced')
    ensure_role(api=api_rbac_auth_v1_b1,
                role=V1ClusterRole(
                    api_version='rbac.authorization.k8s.io/v1beta1',
                    kind='ClusterRole',
                    metadata=V1ObjectMeta(name='traefik-ingress-controller'),
                    rules=[
                        V1PolicyRule(
                            api_groups=[''],
                            resources=['services', 'endpoints', 'secrets'],
                            verbs=['get', 'list', 'watch']),
                        V1PolicyRule(api_groups=['extensions'],
                                     resources=['ingresses'],
                                     verbs=['get', 'list', 'watch']),
                        V1PolicyRule(api_groups=['extensions'],
                                     resources=['ingresses/status'],
                                     verbs=['update']),
                        V1PolicyRule(api_groups=['traefik.containo.us'],
                                     resources=['middlewares'],
                                     verbs=['get', 'list', 'watch']),
                        V1PolicyRule(api_groups=['traefik.containo.us'],
                                     resources=['ingressroutes'],
                                     verbs=['get', 'list', 'watch']),
                        V1PolicyRule(api_groups=['traefik.containo.us'],
                                     resources=['ingressroutetcps'],
                                     verbs=['get', 'list', 'watch']),
                        V1PolicyRule(api_groups=['traefik.containo.us'],
                                     resources=['tlsoptions'],
                                     verbs=['get', 'list', 'watch'])
                    ]),
                name='traefik-ingress-controller')
    ensure_role_binding(
        api=api_rbac_auth_v1_b1,
        role_binding=V1ClusterRoleBinding(
            api_version='rbac.authorization.k8s.io/v1beta1',
            kind='ClusterRoleBinding',
            metadata=V1ObjectMeta(name='traefik-ingress-controller'),
            role_ref=V1RoleRef(api_group='rbac.authorization.k8s.io',
                               kind='ClusterRole',
                               name='traefik-ingress-controller'),
            subjects=[
                V1Subject(kind='ServiceAccount',
                          name='traefik-ingress-controller',
                          namespace='default')
            ]),
        name='traefik-ingress-controller')
    ensure_service(
        api=api_core_v1,
        service=V1Service(
            api_version="v1",
            metadata=V1ObjectMeta(name='traefik'),
            spec=V1ServiceSpec(
                type='LoadBalancer',
                load_balancer_ip=static_ip,
                ports=[
                    # V1ServicePort(
                    #     protocol='TCP',
                    #     port=80,
                    #     name='web'
                    # ),
                    V1ServicePort(protocol='TCP', port=443, name='websecure'),
                ],
                selector={'app': 'traefik'})),
        name='traefik',
        namespace='default')
    ensure_service_account(
        api=api_core_v1,
        account=V1ServiceAccount(
            api_version="v1",
            metadata=V1ObjectMeta(name='traefik-ingress-controller'),
        ),
        name='traefik-ingress-controller',
        namespace='default')
    ensure_deployment(
        api=api_apps_v1,
        deployment=V1Deployment(
            api_version="apps/v1",
            metadata=V1ObjectMeta(name='traefik', labels={'app': 'traefik'}),
            spec=V1DeploymentSpec(
                replicas=1,
                selector=V1LabelSelector(match_labels={'app': 'traefik'}),
                template=V1PodTemplateSpec(
                    metadata=V1ObjectMeta(name='traefik',
                                          labels={'app': 'traefik'}),
                    spec=V1PodSpec(
                        service_account_name='traefik-ingress-controller',
                        containers=[
                            V1Container(
                                name='traefik',
                                image='traefik:v2.0',
                                args=[
                                    '--api.insecure',
                                    '--accesslog',
                                    '--entrypoints.web.Address=:80',
                                    '--entrypoints.websecure.Address=:443',
                                    '--providers.kubernetescrd',
                                    '--certificatesresolvers.default.acme.tlschallenge',
                                    f'--certificatesresolvers.default.acme.email={admin_email}',
                                    '--certificatesresolvers.default.acme.storage=acme.json',
                                    # '--certificatesresolvers.default.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory',
                                ],
                                ports=[
                                    V1ContainerPort(name='web',
                                                    container_port=8000),
                                    V1ContainerPort(name='websecure',
                                                    container_port=4443),
                                    V1ContainerPort(name='admin',
                                                    container_port=8080),
                                ])
                        ])))),
        name='traefik',
        namespace='default')
    ensure_deployment(
        api=api_apps_v1,
        deployment=V1Deployment(
            api_version="apps/v1",
            metadata=V1ObjectMeta(name='traefik-forward-auth',
                                  labels={'app': 'traefik-forward-auth'}),
            spec=V1DeploymentSpec(
                replicas=1,
                selector=V1LabelSelector(
                    match_labels={'app': 'traefik-forward-auth'}),
                template=V1PodTemplateSpec(
                    metadata=V1ObjectMeta(
                        name='traefik-forward-auth',
                        labels={'app': 'traefik-forward-auth'}),
                    spec=V1PodSpec(containers=[
                        V1Container(
                            name='traefik-forward-auth',
                            image='thomseddon/traefik-forward-auth:2',
                            ports=[
                                V1ContainerPort(name='auth',
                                                container_port=4181),
                            ],
                            env=[
                                V1EnvVar(name='PROVIDERS_GOOGLE_CLIENT_ID',
                                         value=oauth_client_id),
                                # V1EnvVar(name='LOG_LEVEL', value='trace'),
                                V1EnvVar(name='PROVIDERS_GOOGLE_CLIENT_SECRET',
                                         value=oauth_client_secret),
                                V1EnvVar(name='SECRET', value=oauth_secret),
                                V1EnvVar(name='DOMAIN', value=oauth_domain),
                                V1EnvVar(name='COOKIE_DOMAIN', value=domain),
                                V1EnvVar(name='AUTH_HOST',
                                         value=f'auth.{domain}'),
                            ])
                    ])))),
        name='traefik-forward-auth',
        namespace='default')
    ensure_custom_object(api=api_custom,
                         custom_object={
                             'apiVersion': 'traefik.containo.us/v1alpha1',
                             'kind': 'IngressRoute',
                             'metadata': {
                                 'name': 'traefik-forward-auth',
                             },
                             'spec': {
                                 'entryPoints': ['websecure'],
                                 'routes': [{
                                     'match':
                                     f'Host(`auth.{domain}`)',
                                     'kind':
                                     'Rule',
                                     'services': [{
                                         'name': 'traefik-forward-auth',
                                         'port': 4181
                                     }],
                                     'middlewares': [{
                                         'name':
                                         'traefik-forward-auth'
                                     }]
                                 }],
                                 'tls': {
                                     'certResolver': 'default'
                                 }
                             }
                         },
                         group='traefik.containo.us',
                         plural='ingressroutes',
                         version='v1alpha1',
                         name='traefik-forward-auth',
                         namespace='default')
    ensure_custom_object(api=api_custom,
                         custom_object={
                             'apiVersion': 'traefik.containo.us/v1alpha1',
                             'kind': 'Middleware',
                             'metadata': {
                                 'name': 'traefik-forward-auth',
                             },
                             'spec': {
                                 'forwardAuth': {
                                     'address':
                                     'http://traefik-forward-auth:4181',
                                     'authResponseHeaders':
                                     ['X-Forwarded-User'],
                                 }
                             }
                         },
                         group='traefik.containo.us',
                         plural='middlewares',
                         version='v1alpha1',
                         name='traefik-forward-auth',
                         namespace='default')
    ensure_service(api=api_core_v1,
                   service=V1Service(
                       api_version="v1",
                       metadata=V1ObjectMeta(name='traefik-forward-auth'),
                       spec=V1ServiceSpec(
                           type='ClusterIP',
                           ports=[
                               V1ServicePort(protocol='TCP',
                                             port=4181,
                                             name='auth'),
                           ],
                           selector={'app': 'traefik-forward-auth'})),
                   name='traefik-forward-auth',
                   namespace='default')
    ensure_whoami(api_apps_v1, api_core_v1, api_custom, domain)
    def start_stateful_container(self, service_name: str, container_name: str,
                                 spec, labels: dict[str, str], change_key: str):
        # Setup PVC
        deployment_name = self._dependency_name(service_name, container_name)
        mounts, volumes = [], []
        for volume_name, volume_spec in spec.volumes.items():
            mount_name = f'{deployment_name}-{volume_name}'

            # Check if the PVC exists, create if not
            self._ensure_pvc(mount_name, volume_spec.storage_class, volume_spec.capacity, deployment_name)

            # Create the volume info
            volumes.append(V1Volume(
                name=mount_name,
                persistent_volume_claim=V1PersistentVolumeClaimVolumeSource(mount_name)
            ))
            mounts.append(V1VolumeMount(mount_path=volume_spec.mount_path, name=mount_name))

        # Read the key being used for the deployment instance or generate a new one
        instance_key = uuid.uuid4().hex
        try:
            old_deployment = self.apps_api.read_namespaced_deployment(deployment_name, self.namespace)
            for container in old_deployment.spec.template.spec.containers:
                for env in container.env:
                    if env.name == 'AL_INSTANCE_KEY':
                        instance_key = env.value
                        break
        except ApiException as error:
            if error.status != 404:
                raise

        # Setup the deployment itself
        labels['container'] = container_name
        spec.container.environment.append({'name': 'AL_INSTANCE_KEY', 'value': instance_key})
        self._create_deployment(service_name, deployment_name, spec.container,
                                30, 1, labels, volumes=volumes, mounts=mounts,
                                core_mounts=spec.run_as_core, change_key=change_key)

        # Setup a service to direct to the deployment
        try:
            service = self.api.read_namespaced_service(deployment_name, self.namespace)
            service.metadata.labels = labels
            service.spec.selector = labels
            service.spec.ports = [V1ServicePort(port=int(_p)) for _p in spec.container.ports]
            self.api.patch_namespaced_service(deployment_name, self.namespace, service)
        except ApiException as error:
            if error.status != 404:
                raise
            service = V1Service(
                metadata=V1ObjectMeta(name=deployment_name, labels=labels),
                spec=V1ServiceSpec(
                    cluster_ip='None',
                    selector=labels,
                    ports=[V1ServicePort(port=int(_p)) for _p in spec.container.ports]
                )
            )
            self.api.create_namespaced_service(self.namespace, service)

        # Add entries to the environment variable list to point to this container
        self._service_limited_env[service_name][f'{container_name}_host'] = deployment_name
        self._service_limited_env[service_name][f'{container_name}_key'] = instance_key
        if spec.container.ports:
            self._service_limited_env[service_name][f'{container_name}_port'] = spec.container.ports[0]