Exemple #1
0
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    crd = yaml.load(Path('files/crd-v1beta1.yaml').read_text())

    port = hookenv.config('port')

    layer.caas_base.pod_spec_set({
        'service': {
            'annotations': {
                'getambassador.io/config':
                yaml.dump_all([{
                    'apiVersion': 'ambassador/v0',
                    'kind': 'Mapping',
                    'name': 'pipelines-viewer',
                    'prefix': '/data',
                    'rewrite': '/data',
                    'service': f'{service_name}:{port}',
                    'use_websocket': True,
                    'timeout_ms': 30000,
                }])
            }
        },
        'containers': [{
            'name': 'pipelines-viewer',
            'imageDetails': {
                'imagePath': image_info.registry_path,
                'username': image_info.username,
                'password': image_info.password,
            },
            'ports': [{
                'name': 'ui',
                'containerPort': port
            }],
        }],
        'customResourceDefinitions': {
            crd['metadata']['name']: crd['spec']
        },
    })

    layer.status.maintenance('creating container')
    set_flag('charm.started')
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    port = hookenv.config('port')

    layer.caas_base.pod_spec_set(
        {
            'service': {
                'annotations': {
                    'getambassador.io/config': yaml.dump_all(
                        [
                            {
                                'apiVersion': 'ambassador/v0',
                                'kind': 'Mapping',
                                'name': 'dashboard-mapping',
                                'prefix': '/',
                                'rewrite': '/',
                                'service': f'{service_name}:{port}',
                                'timeout_ms': 30000,
                            }
                        ]
                    )
                }
            },
            'containers': [
                {
                    'name': 'pipelines-dashboard',
                    'imageDetails': {
                        'imagePath': image_info.registry_path,
                        'username': image_info.username,
                        'password': image_info.password,
                    },
                    'ports': [{'name': 'ui', 'containerPort': port}],
                }
            ],
        }
    )

    layer.status.maintenance('creating container')
    set_flag('charm.started')
Exemple #3
0
def start_charm():
    layer.status.maintenance("configuring container")

    image_info = layer.docker_resource.get_info("oci-image")
    namespace = os.environ["JUJU_MODEL_NAME"]

    try:
        pilot = endpoint_from_name("istio-pilot").services()[0]
    except IndexError:
        hookenv.log("Got istio-pilot endpoint without any services")
        layer.status.maintenance("Waiting for istio-pilot relation")
        return False

    pilot_service = pilot['hosts'][0]['hostname']
    pilot_port = pilot['hosts'][0]['port']
    cfg = dict(hookenv.config())

    # Talk to the K8s API to read the auto-generated root certificate secret.
    # Borrow the env vars from the root process that let the Kubernetes
    # client automatically look up connection info, since `load_incluster_config`
    # for whatever reason doesn't support loading the serviceaccount token from disk.
    os.environ.update(
        dict(
            e.split("=")
            for e in Path("/proc/1/environ").read_text().split("\x00")
            if "KUBERNETES_SERVICE" in e))

    config.load_incluster_config()
    v1 = client.CoreV1Api()
    layer.status.maintenance(
        "Waiting for configmap/istio-ca-root-cert to be created")
    try:
        config_map = v1.read_namespaced_config_map(name="istio-ca-root-cert",
                                                   namespace=namespace)
        if not config_map.data.get("root-cert.pem"):
            hookenv.log("Got empty certificate, waiting for real one")
            return False
    except client.rest.ApiException as err:
        hookenv.log(err)
        hookenv.log(err.status)
        hookenv.log(err.reason)
        hookenv.log(err.body)
        hookenv.log(err.headers)
        layer.status.blocked("istio-ca-root-cert certificate not found.")
        return False

    layer.caas_base.pod_spec_set({
        "version":
        3,
        "serviceAccount": {
            "roles": [{
                "global":
                True,
                "rules": [
                    {
                        "apiGroups": ["*"],
                        "resources": ["*"],
                        "verbs": ["*"]
                    },
                    {
                        "nonResourceURLs": ["*"],
                        "verbs": ["*"]
                    },
                ],
            }]
        },
        "containers": [{
            "name":
            "istio-proxy",
            "args": [
                "proxy",
                "router",
                "--domain",
                f"{namespace}.svc.cluster.local",
                "--proxyLogLevel=warning",
                "--proxyComponentLogLevel=misc:error",
                f"--log_output_level={cfg['log-level']}",
                "--drainDuration",
                "45s",
                "--parentShutdownDuration",
                "1m0s",
                "--connectTimeout",
                "10s",
                "--serviceCluster",
                hookenv.service_name(),
                "--proxyAdminPort",
                cfg['proxy-admin-port'],
                "--statusPort",
                str(cfg['status-port']),
                "--controlPlaneAuthPolicy",
                "NONE",
                "--discoveryAddress",
                f"{pilot_service}:{pilot_port}",
                "--trust-domain=cluster.local",
            ],
            "imageDetails": {
                "imagePath": image_info.registry_path,
                "username": image_info.username,
                "password": image_info.password,
            },
            "envConfig": {
                "JWT_POLICY": "first-party-jwt",
                "PILOT_CERT_PROVIDER": "istiod",
                "ISTIO_META_USER_SDS": "true",
                "CA_ADDR": f"{pilot_service}:{pilot_port}",
                "NODE_NAME": {
                    "field": {
                        "path": "spec.nodeName",
                        "api-version": "v1"
                    }
                },
                "POD_NAME": {
                    "field": {
                        "path": "metadata.name",
                        "api-version": "v1"
                    }
                },
                "POD_NAMESPACE": namespace,
                "INSTANCE_IP": {
                    "field": {
                        "path": "status.podIP",
                        "api-version": "v1"
                    }
                },
                "HOST_IP": {
                    "field": {
                        "path": "status.hostIP",
                        "api-version": "v1"
                    }
                },
                "SERVICE_ACCOUNT": {
                    "field": {
                        "path": "spec.serviceAccountName",
                        "api-version": "v1"
                    }
                },
                "ISTIO_META_WORKLOAD_NAME": hookenv.service_name(),
                "ISTIO_META_OWNER":
                f"kubernetes://api/apps/v1/namespaces/{namespace}/deployments/{hookenv.service_name()}",
                "ISTIO_META_MESH_ID": "cluster.local",
                "ISTIO_AUTO_MTLS_ENABLED": "true",
                "ISTIO_META_POD_NAME": {
                    "field": {
                        "path": "metadata.name",
                        "api-version": "v1"
                    }
                },
                "ISTIO_META_CONFIG_NAMESPACE": namespace,
                "ISTIO_META_ROUTER_MODE": "sni-dnat",
                "ISTIO_META_CLUSTER_ID": "Kubernetes",
            },
            "ports": [
                {
                    "name": "status-port",
                    "containerPort": cfg['status-port']
                },
                {
                    "name": "http2",
                    "containerPort": cfg['http-port']
                },
                {
                    "name": "https",
                    "containerPort": cfg['https-port']
                },
                {
                    "name": "kiali",
                    "containerPort": cfg['kiali-port']
                },
                {
                    "name": "prometheus",
                    "containerPort": cfg['prometheus-port']
                },
                {
                    "name": "grafana",
                    "containerPort": cfg['grafana-port']
                },
                {
                    "name": "tracing",
                    "containerPort": cfg['tracing-port']
                },
                {
                    "name": "tls",
                    "containerPort": cfg['tls-port']
                },
                {
                    "name": "pilot",
                    "containerPort": cfg['xds-ca-port-legacy']
                },
                {
                    "name": "citadel",
                    "containerPort": cfg['citadel-grpc-port']
                },
                {
                    "name": "dns-tls",
                    "containerPort": cfg['dns-tls-port']
                },
            ],
            "kubernetes": {
                "readinessProbe": {
                    "failureThreshold": 30,
                    "httpGet": {
                        "path": "/healthz/ready",
                        "port": cfg['status-port'],
                        "scheme": "HTTP",
                    },
                    "initialDelaySeconds": 1,
                    "periodSeconds": 2,
                    "successThreshold": 1,
                    "timeoutSeconds": 1,
                },
            },
            "volumeConfig": [
                {
                    "name":
                    "istiod-ca-cert",
                    "mountPath":
                    "/var/run/secrets/istio",
                    "files": [{
                        "path": "root-cert.pem",
                        "content": config_map.data["root-cert.pem"],
                    }],
                },
                {
                    "name": "ingressgatewaysdsudspath",
                    "mountPath": "/var/run/ingress_gateway",
                    "emptyDir": {
                        "medium": "Memory"
                    },
                },
                {
                    "name":
                    "podinfo",
                    "mountPath":
                    "/etc/istio/pod",
                    "files": [
                        {
                            "path": "annotations",
                            "content": 'sidecar.istio.io/inject="false"',
                        },
                        {
                            "path":
                            "labels",
                            "content":
                            'app="istio-ingressgateway"\nistio="ingressgateway"',
                        },
                    ],
                },
            ],
        }],
    })

    layer.status.maintenance("creating container")
    set_flag("charm.started")
Exemple #4
0
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    crd = yaml.load(Path('files/crd-v1beta1.yaml').read_text())

    port = hookenv.config('port')

    layer.caas_base.pod_spec_set(
        {
            'version':
            2,
            'serviceAccount': {
                'global':
                True,
                'rules': [
                    {
                        'apiGroups': ['*'],
                        'resources': ['deployments', 'services'],
                        'verbs': [
                            'create', 'get', 'list', 'watch', 'update',
                            'patch', 'delete'
                        ],
                    },
                    {
                        'apiGroups': ['kubeflow.org'],
                        'resources': ['viewers'],
                        'verbs': [
                            'create', 'get', 'list', 'watch', 'update',
                            'patch', 'delete'
                        ],
                    },
                ],
            },
            'service': {
                'annotations': {
                    'getambassador.io/config':
                    yaml.dump_all([{
                        'apiVersion': 'ambassador/v0',
                        'kind': 'Mapping',
                        'name': 'pipelines-viewer',
                        'prefix': '/data',
                        'rewrite': '/data',
                        'service': f'{service_name}:{port}',
                        'use_websocket': True,
                        'timeout_ms': 30000,
                    }])
                }
            },
            'containers': [{
                'name': 'pipelines-viewer',
                'imageDetails': {
                    'imagePath': image_info.registry_path,
                    'username': image_info.username,
                    'password': image_info.password,
                },
                'config': {
                    'POD_NAMESPACE': os.environ['JUJU_MODEL_NAME']
                },
            }],
        },
        {
            'kubernetesResources': {
                'customResourceDefinitions': {
                    crd['metadata']['name']: crd['spec']
                }
            }
        },
    )

    layer.status.maintenance('creating container')
    set_flag('charm.started')
Exemple #5
0
def configure_mesh():
    endpoint_from_name('service-mesh').add_route(
        prefix='/',
        service=hookenv.service_name(),
        port=hookenv.config('port'))
def start_charm():
    if not hookenv.is_leader():
        hookenv.log("This unit is not a leader.")
        return False

    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    api = endpoint_from_name('pipelines-api').services()[0]
    minio = endpoint_from_name('minio').services()[0]['hosts'][0]

    port = hookenv.config('port')

    layer.caas_base.pod_spec_set({
        'version':
        2,
        'serviceAccount': {
            'rules': [
                {
                    'apiGroups': [''],
                    'resources': ['pods', 'pods/log'],
                    'verbs': ['create', 'get', 'list'],
                },
                {
                    'apiGroups': ['kubeflow.org'],
                    'resources': ['viewers'],
                    'verbs': ['create', 'get', 'list', 'watch', 'delete'],
                },
            ]
        },
        'service': {
            'annotations': {
                'getambassador.io/config':
                yaml.dump_all([{
                    'apiVersion': 'ambassador/v0',
                    'kind': 'Mapping',
                    'name': 'pipeline-ui',
                    'prefix': '/pipeline',
                    'rewrite': '/pipeline',
                    'service': f'{service_name}:{port}',
                    'use_websocket': True,
                    'timeout_ms': 30000,
                }])
            }
        },
        'containers': [{
            'name': 'pipelines-ui',
            'imageDetails': {
                'imagePath': image_info.registry_path,
                'username': image_info.username,
                'password': image_info.password,
            },
            'config': {
                'ML_PIPELINE_SERVICE_HOST': api['service_name'],
                'ML_PIPELINE_SERVICE_PORT': api['hosts'][0]['port'],
                'MINIO_HOST': minio['hostname'],
                'MINIO_PORT': minio['port'],
                'MINIO_NAMESPACE': os.environ['JUJU_MODEL_NAME'],
                'ALLOW_CUSTOM_VISUALIZATIONS': True,
            },
            'ports': [{
                'name': 'ui',
                'containerPort': port
            }],
        }],
    })

    layer.status.maintenance('creating container')
    set_flag('charm.started')
Exemple #7
0
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()
    model = os.environ['JUJU_MODEL_NAME']

    profiles = endpoint_from_name('kubeflow-profiles').services()[0]
    profiles_service = profiles['service_name']

    port = hookenv.config('port')
    profile = hookenv.config('profile')

    layer.caas_base.pod_spec_set(
        {
            'version':
            2,
            'serviceAccount': {
                'global':
                True,
                'rules': [{
                    'apiGroups': [''],
                    'resources': ['events', 'namespaces', 'nodes'],
                    'verbs': ['get', 'list', 'watch'],
                }],
            },
            'service': {
                'annotations': {
                    'getambassador.io/config':
                    yaml.dump_all([{
                        'apiVersion': 'ambassador/v0',
                        'kind': 'Mapping',
                        'name': 'dashboard-mapping',
                        'prefix': '/',
                        'rewrite': '/',
                        'service': f'{service_name}:{port}',
                        'timeout_ms': 30000,
                    }])
                }
            },
            'containers': [{
                'name': 'kubeflow-dashboard',
                'imageDetails': {
                    'imagePath': image_info.registry_path,
                    'username': image_info.username,
                    'password': image_info.password,
                },
                'config': {
                    'USERID_HEADER': 'kubeflow-userid',
                    'USERID_PREFIX': '',
                    'PROFILES_KFAM_SERVICE_HOST':
                    f'{profiles_service}.{model}',
                },
                'ports': [{
                    'name': 'ui',
                    'containerPort': port
                }],
                'kubernetes': {
                    'livenessProbe': {
                        'httpGet': {
                            'path': '/healthz',
                            'port': 8082
                        },
                        'initialDelaySeconds': 30,
                        'periodSeconds': 30,
                    }
                },
            }],
        },
        {
            'kubernetesResources': {
                'customResourceDefinitions': {
                    crd['metadata']['name']: crd['spec']
                    for crd in yaml.safe_load_all(
                        Path("files/crds.yaml").read_text())
                },
                'customResources': {
                    'profiles.kubeflow.org': [{
                        'apiVersion': 'kubeflow.org/v1beta1',
                        'kind': 'Profile',
                        'metadata': {
                            'name': profile
                        },
                        'spec': {
                            'owner': {
                                'kind': 'User',
                                'name': profile
                            }
                        },
                    }]
                },
            }
        },
    )

    layer.status.maintenance('creating container')
    set_flag('charm.started')
Exemple #8
0
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    mysql = endpoint_from_name('mysql')
    minio = endpoint_from_name('minio').services()[0]['hosts'][0]

    grpc_port = hookenv.config('grpc-port')
    http_port = hookenv.config('http-port')

    layer.caas_base.pod_spec_set({
        'service': {
            'annotations': {
                'getambassador.io/config':
                yaml.dump_all([{
                    'apiVersion': 'ambassador/v0',
                    'kind': 'Mapping',
                    'name': 'pipeline-api',
                    'prefix': '/apis/v1beta1/pipelines',
                    'rewrite': '/apis/v1beta1/pipelines',
                    'service': f'{service_name}:{http_port}',
                    'use_websocket': True,
                    'timeout_ms': 30000,
                }])
            }
        },
        'containers': [{
            'name':
            'pipelines-api',
            'imageDetails': {
                'imagePath': image_info.registry_path,
                'username': image_info.username,
                'password': image_info.password,
            },
            'ports': [
                {
                    'name': 'grpc',
                    'containerPort': grpc_port
                },
                {
                    'name': 'http',
                    'containerPort': http_port
                },
            ],
            'config': {
                'MYSQL_SERVICE_HOST': mysql.host(),
                'MYSQL_SERVICE_PORT': mysql.port(),
                'MINIO_SERVICE_SERVICE_HOST': minio['hostname'],
                'MINIO_SERVICE_SERVICE_PORT': minio['port'],
                'POD_NAMESPACE': os.environ['JUJU_MODEL_NAME'],
            },
            'files': [{
                'name': 'config',
                'mountPath': '/config',
                'files': {
                    'config.json':
                    json.dumps({
                        'DBConfig': {
                            'DriverName': 'mysql',
                            'DataSourceName': mysql.database(),
                            'User': mysql.user(),
                            'Password': mysql.password(),
                        },
                        'ObjectStoreConfig': {
                            'AccessKey': hookenv.config('minio-access-key'),
                            'SecretAccessKey':
                            hookenv.config('minio-secret-key'),
                            'BucketName': hookenv.config('minio-bucket-name'),
                        },
                        'InitConnectionTimeout': '5s',
                    }),
                    'sample_config.json':
                    Path('files/sample_config.json').read_text(),
                },
            }],
        }],
    })

    layer.status.maintenance('creating container')
    set_flag('charm.started')
Exemple #9
0
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    minio = endpoint_from_name('minio').services()[0]['hosts'][0]
    mysql = endpoint_from_name('mysql')
    profiles = endpoint_from_name(
        'kubeflow-profiles').services()[0]['hosts'][0]
    viz = endpoint_from_name(
        'pipelines-visualization').services()[0]['hosts'][0]

    grpc_port = hookenv.config('grpc-port')
    http_port = hookenv.config('http-port')

    layer.caas_base.pod_spec_set(
        {
            'version':
            2,
            'serviceAccount': {
                'rules': [
                    {
                        'apiGroups': ['argoproj.io'],
                        'resources': ['workflows'],
                        'verbs': [
                            'create', 'get', 'list', 'watch', 'update',
                            'patch', 'delete'
                        ],
                    },
                    {
                        'apiGroups': ['kubeflow.org'],
                        'resources': ['scheduledworkflows'],
                        'verbs':
                        ['create', 'get', 'list', 'update', 'patch', 'delete'],
                    },
                    {
                        'apiGroups': [''],
                        'resources': ['pods'],
                        'verbs': ['delete']
                    },
                ]
            },
            'service': {
                'annotations': {
                    'getambassador.io/config':
                    yaml.dump_all([{
                        'apiVersion': 'ambassador/v0',
                        'kind': 'Mapping',
                        'name': 'pipeline-api',
                        'prefix': '/apis/v1beta1/pipelines',
                        'rewrite': '/apis/v1beta1/pipelines',
                        'service': f'{service_name}:{http_port}',
                        'use_websocket': True,
                        'timeout_ms': 30000,
                    }])
                }
            },
            'containers': [{
                'name':
                'pipelines-api',
                'imageDetails': {
                    'imagePath': image_info.registry_path,
                    'username': image_info.username,
                    'password': image_info.password,
                },
                'ports': [
                    {
                        'name': 'grpc',
                        'containerPort': grpc_port
                    },
                    {
                        'name': 'http',
                        'containerPort': http_port
                    },
                ],
                'command': [
                    'apiserver',
                    '--config=/config',
                    '--sampleconfig=/config/sample_config.json',
                    '-logtostderr=true',
                ],
                'config': {
                    'POD_NAMESPACE': os.environ['JUJU_MODEL_NAME']
                },
                'files': [
                    {
                        'name': 'config',
                        'mountPath': '/config',
                        'files': {
                            'config.json':
                            json.dumps({
                                'DBConfig': {
                                    'DriverName': 'mysql',
                                    'DataSourceName': mysql.database(),
                                    'Host': mysql.host(),
                                    'Port': mysql.port(),
                                    'User': '******',
                                    'Password': mysql.root_password(),
                                    'DBName': 'mlpipeline',
                                },
                                'ObjectStoreConfig': {
                                    'Host':
                                    minio['hostname'],
                                    'Port':
                                    minio['port'],
                                    'AccessKey':
                                    hookenv.config('minio-access-key'),
                                    'SecretAccessKey':
                                    hookenv.config('minio-secret-key'),
                                    'BucketName':
                                    hookenv.config('minio-bucket-name'),
                                },
                                'InitConnectionTimeout':
                                '5s',
                                "DefaultPipelineRunnerServiceAccount":
                                "pipeline-runner",
                                "ML_PIPELINE_VISUALIZATIONSERVER_SERVICE_HOST":
                                viz['hostname'],
                                "ML_PIPELINE_VISUALIZATIONSERVER_SERVICE_PORT":
                                viz['port'],
                                'PROFILES_KFAM_SERVICE_HOST':
                                profiles['hostname'],
                                'PROFILES_KFAM_SERVICE_PORT':
                                profiles['port'],
                            }),
                            'sample_config.json':
                            Path('files/sample_config.json').read_text(),
                        },
                    },
                    {
                        'name': 'samples',
                        'mountPath': '/samples',
                        'files': {
                            Path(sample).name: Path(sample).read_text()
                            for sample in glob('files/*.yaml')
                        },
                    },
                ],
            }],
        },
        k8s_resources={
            'kubernetesResources': {
                'serviceAccounts': [{
                    'name':
                    'pipeline-runner',
                    'rules': [
                        {
                            'apiGroups': [''],
                            'resources': ['secrets'],
                            'verbs': ['get']
                        },
                        {
                            'apiGroups': [''],
                            'resources': ['configmaps'],
                            'verbs': ['get', 'watch', 'list'],
                        },
                        {
                            'apiGroups': [''],
                            'resources': ['persistentvolumeclaims'],
                            'verbs': ['create', 'delete', 'get'],
                        },
                        {
                            'apiGroups': ['snapshot.storage.k8s.io'],
                            'resources': ['volumesnapshots'],
                            'verbs': ['create', 'delete', 'get'],
                        },
                        {
                            'apiGroups': ['argoproj.io'],
                            'resources': ['workflows'],
                            'verbs':
                            ['get', 'list', 'watch', 'update', 'patch'],
                        },
                        {
                            'apiGroups': [''],
                            'resources':
                            ['pods', 'pods/exec', 'pods/log', 'services'],
                            'verbs': ['*'],
                        },
                        {
                            'apiGroups': ['', 'apps', 'extensions'],
                            'resources': ['deployments', 'replicasets'],
                            'verbs': ['*'],
                        },
                        {
                            'apiGroups': ['kubeflow.org'],
                            'resources': ['*'],
                            'verbs': ['*']
                        },
                        {
                            'apiGroups': ['batch'],
                            'resources': ['jobs'],
                            'verbs': ['*']
                        },
                    ],
                }]
            }
        },
    )

    layer.status.maintenance('creating container')
    clear_flag('mysql.changed')
    set_flag('charm.started')
Exemple #10
0
def start_charm():
    if not hookenv.is_leader():
        hookenv.log("This unit is not a leader.")
        return False

    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    api = endpoint_from_name('metadata-api').services()[0]
    grpc = endpoint_from_name('metadata-grpc').services()[0]

    port = hookenv.config('port')

    layer.caas_base.pod_spec_set({
        'version':
        2,
        'serviceAccount': {
            'rules': [
                {
                    'apiGroups': [''],
                    'resources': ['pods', 'pods/log'],
                    'verbs': ['create', 'get', 'list'],
                },
                {
                    'apiGroups': ['kubeflow.org'],
                    'resources': ['viewers'],
                    'verbs': ['create', 'get', 'list', 'watch', 'delete'],
                },
            ]
        },
        'service': {
            'annotations': {
                'getambassador.io/config':
                yaml.dump_all([{
                    'apiVersion': 'ambassador/v0',
                    'kind': 'Mapping',
                    'name': 'metadata-ui',
                    'prefix': '/metadata',
                    'rewrite': '/metadata',
                    'service': f'{service_name}:{port}',
                    'use_websocket': True,
                    'timeout_ms': 30000,
                }])
            }
        },
        'containers': [{
            'name': 'metadata-ui',
            'imageDetails': {
                'imagePath': image_info.registry_path,
                'username': image_info.username,
                'password': image_info.password,
            },
            'ports': [{
                'name': 'http',
                'containerPort': port
            }],
            'config': {
                'METADATA_SERVICE_SERVICE_HOST': api['service_name'],
                'METADATA_SERVICE_SERVICE_PORT': api['hosts'][0]['port'],
                'METADATA_ENVOY_SERVICE_SERVICE_HOST': grpc['service_name'],
                'METADATA_ENVOY_SERVICE_SERVICE_PORT':
                grpc['hosts'][0]['port'],
            },
        }],
    })

    layer.status.maintenance('creating container')
    set_flag('charm.started')
def configure_mesh():
    endpoint_from_name('service-mesh').add_route(
        prefix='/apis/v1beta1/pipelines',
        service=hookenv.service_name(),
        port=hookenv.config('http-port'),
    )
def start_charm():
    layer.status.maintenance('configuring container')

    image_info = layer.docker_resource.get_info('oci-image')
    service_name = hookenv.service_name()

    api = endpoint_from_name('pipelines-api').services()[0]

    ui_port = hookenv.config('ui-port')
    proxy_port = hookenv.config('proxy-port')

    layer.caas_base.pod_spec_set({
        'service': {
            'annotations': {
                'getambassador.io/config':
                yaml.dump_all([
                    {
                        'apiVersion': 'ambassador/v0',
                        'kind': 'Mapping',
                        'name': 'pipeline-ui',
                        'prefix': '/pipeline',
                        'rewrite': '/pipeline',
                        'service': f'{service_name}:{ui_port}',
                        'use_websocket': True,
                        'timeout_ms': 30000,
                    },
                    {
                        'apiVersion': 'ambassador/v0',
                        'kind': 'Mapping',
                        'name': 'pipeline-ui-apis',
                        'prefix': '/apis',
                        'rewrite': '/apis',
                        'service': f'{service_name}:{proxy_port}',
                        'use_websocket': True,
                        'timeout_ms': 30000,
                    },
                ])
            }
        },
        'containers': [{
            'name':
            'pipelines-ui',
            'imageDetails': {
                'imagePath': image_info.registry_path,
                'username': image_info.username,
                'password': image_info.password,
            },
            'config': {
                'ML_PIPELINE_SERVICE_HOST': api['service_name'],
                'ML_PIPELINE_SERVICE_PORT': api['hosts'][0]['port'],
            },
            'ports': [
                {
                    'name': 'ui',
                    'containerPort': ui_port
                },
                {
                    'name': 'api-proxy',
                    'containerPort': proxy_port
                },
            ],
        }],
    })

    layer.status.maintenance('creating container')
    set_flag('charm.started')