# Dev full Session Tiltfile example. # # cp9 owns only session/substrate lifecycle and exposes read-only facts through # CP9_SESSION_CONTEXT. This file owns the Dev full runtime graph. ctx_path = os.getenv("CP9_SESSION_CONTEXT", "") if ctx_path == "": fail("CP9_SESSION_CONTEXT is required") ctx = read_json(ctx_path) runtime_id = ctx.get("runtime_id", "primary") if runtime_id != "primary" and runtime_id != "gcp-regional": fail("CP9_SESSION_CONTEXT.runtime_id is unsupported: " + runtime_id) session_name = ctx.get("session_name", "") namespace = ctx.get("namespace", session_name) evidence_dir = ctx.get("evidence_dir", "") kube_context = ctx.get("kube_context", "") kubeconfig = ctx.get("kubeconfig_path", "") source_build_parallelism = ctx.get("source_build_parallelism", 1) source_build_supported = ctx.get("source_build_supported", True) target = ctx.get("target", {}) host = ctx.get("host", {}) controller = host.get("controller", "local") ui = ctx.get("ui", {}) cluster_name = host.get("cluster_name", "") dedicated_api = host.get("dedicated_api", {}) dedicated_api_admin_kubeconfig = dedicated_api.get("admin_kubeconfig_path", "") dedicated_api_host_manifest = dedicated_api.get("host_manifest_path", "") dedicated_api_bootstrap_manifest = dedicated_api.get("bootstrap_manifest_path", "") terraform_info = ctx.get("terraform", {}) remote_ec2_runtime = terraform_info.get("remote_ec2_runtime", {}) remote_aws_runtime_identity = host.get("mode", "") == "remote-ec2-k3d" and remote_ec2_runtime.get("enabled", False) remote_o11y_ingress = host.get("mode", "") == "remote-ec2-k3d" and host.get("remote", {}).get("o11y_load_balancer_dns", "") != "" terraform_outputs_path = terraform_info.get("outputs_path", "") terraform_outputs = {} if terraform_outputs_path != "": terraform_outputs = read_json(terraform_outputs_path) owner_artifacts = ctx.get("artifacts", {}) owner_artifact_snapshot_path = owner_artifacts.get("snapshot_path", "") if owner_artifact_snapshot_path == "": fail("resolved owner artifact snapshot is missing") owner_artifact_snapshot = read_json(owner_artifact_snapshot_path) owner_artifact_snapshot_dir = "/".join(owner_artifact_snapshot_path.split("/")[:-1]) owner_artifact_images = {} owner_artifact_trigger_paths = {} owner_artifact_crds = {} for artifact in owner_artifact_snapshot.get("artifacts", []): name = artifact.get("name", "") kind = artifact.get("kind", "") if name == "": fail("resolved owner artifact has no name") if kind == "service": trigger_path = owner_artifact_snapshot_dir + "/triggers/" + name + ".json" trigger = read_json(trigger_path) if trigger.get("name", "") != name: fail("resolved owner artifact trigger name mismatch for " + name) if trigger.get("state", "") != "ready": fail("resolved owner artifact trigger is not ready for " + name) image = artifact.get("image", "") if image == "": fail("resolved owner artifact image is missing for " + name) owner_artifact_images[name] = image owner_artifact_trigger_paths[name] = trigger_path elif kind == "crd": local_path = artifact.get("local_path", "") if local_path == "": fail("resolved owner CRD artifact path is missing for " + name) owner_artifact_crds[name] = { "path": owner_artifact_snapshot_dir + "/" + local_path, "digest": artifact.get("digest", ""), "names": artifact.get("crd_names", []), } else: fail("resolved owner artifact kind is invalid for " + name) def _owner_artifact_image_if_present(name): if name not in owner_artifact_images: return "" image = owner_artifact_images.get(name, "") if image == "": fail("resolved owner artifact image is empty for " + name) return image def _owner_artifact_image(name): image = _owner_artifact_image_if_present(name) if image == "": fail("resolved owner artifact image is missing for " + name) return image def _owner_artifact_trigger_path(name): path = owner_artifact_trigger_paths.get(name, "") if path == "": fail("resolved owner artifact trigger is missing for " + name) return path source_backed_contract_registry = read_json("../../../internal/sourcebacked/contracts.json") source_backed_service_contracts = {} for contract in source_backed_contract_registry.get("contracts", []): contract_name = contract.get("name", "") if contract_name == "": fail("source-backed service contract missing name") if contract_name in source_backed_service_contracts: fail("duplicate source-backed service contract " + contract_name) source_backed_service_contracts[contract_name] = contract def _source_backed_contract(service): contract = source_backed_service_contracts.get(service, None) if contract == None: fail("source-backed service contract missing " + service) return contract def _source_backed_staging_image(service): image = _owner_artifact_image_if_present(service) if image != "": return image image = _source_backed_contract(service).get("stagingImage", "") if image == "": fail("source-backed service contract missing staging image for " + service) return image def _owner_crd_path(name): crd = owner_artifact_crds.get(name, {}) path = crd.get("path", "") if path == "": fail("resolved owner CRD artifact is missing " + name) return path def _source_backed_source(service): source = _source_backed_contract(service).get("source", {}) if source.get("repo", "") == "": fail("source-backed service contract missing source.repo for " + service) if source.get("main", "") == "": fail("source-backed service contract missing source.main for " + service) return source def _source_backed_source_repo(service): return _source_backed_source(service).get("repo", "") def _source_backed_source_main(service): return _source_backed_source(service).get("main", "") def _source_backed_source_mode(service): mode = _source_backed_source(service).get("mode", "") if mode == "": return "generic" return mode source_build_services = [ # Jianyuan dataflow/cdc/dataplane remote source-build profile: # check out the desired product branches in the sibling repos first. # "dataflow", # "ticdc-service", # "dataplane-manager", # The same regional entries also build and live-update their cp-byoc # workloads after BYOC activation; there is no second BYOC source list. # # "nextgen-global-service", # "tidb-mgmt-service", # "tempo-proxy", # "tempo-wrapper", # "account-provider", # "account-acl", # "account-central", # "account-openapi", # "dedicated-dataflow-svc", # # Starter k3d + remote-EKS source-build profile: # "serverless-service", # "cluster-proxy", # "gateway-controller", # "manager", # "ops-service", # "serverless-meta-service", # "serverless-meta-store", # "serverless-regional-service", # "tidb-gateway-inner", # "tidb-http-gateway", # "tidb-worker-scaler", # "vpa-agent", ] if not source_build_supported: source_build_services = [] live_update_services = [ # DEPRECATED compatibility knob (PRD #664): live-update now derives from # source_build_services plus the CP9 source-backed contract registry and # the shipped k3d live-update wiring. Entries here are validated for # compatibility but are no longer required and grant nothing extra. ] live_update_entrypoints = { # Source repo evidence: # dataflow-service-ng/Dockerfile copies dist/dataflow to /dataflow. # internal/ticdc-service/Dockerfile copies bin/manager to /manager. # internal/dataplane-manager/Dockerfile builds regional-server. cp9 keeps # those canonical image paths, but live-update entrypoints use /workspace # so the non-root runtime user can replace the binary. "dataflow": "/workspace/service", "dedicated-dataflow-svc": "/workspace/service", "ticdc-service": "/workspace/service", "dataplane-manager": "/workspace/service", "account-provider": "/workspace/service", "account-acl": "/workspace/service", "account-central": "/workspace/service", "serverless-service": "/workspace/service", "serverless-global-service": "/workspace/service", "cluster-controller": "/workspace/service", "cluster-control-server": "/workspace/service", "regional-server": "/workspace/service", "regional-tcidm-service": "/workspace/service", "dedicated-ticdc-service": "/workspace/service", "config-center": "/workspace/service", "dedicated-global-service": "/workspace/service", "tidb-mgmt-portal": "/workspace/service", "tidb-mgmt-service": "/workspace/service", "nextgen-global-service": "/workspace/service", "cluster-ng-server": "/workspace/service", "cluster-ng-executor": "/workspace/service", "config-center-regional": "/workspace/service", } live_update_repos = {} live_update_mains = {} for service in live_update_entrypoints: live_update_repos[service] = _source_backed_source_repo(service) live_update_mains[service] = _source_backed_source_main(service) live_update_fallback_paths = { "dataflow": ["Dockerfile", "go.mod", "go.sum"], "dedicated-dataflow-svc": ["deployments/docker/Dockerfile.service", "go.mod", "go.sum"], "ticdc-service": ["Dockerfile", "go.mod", "go.sum", "config"], "dataplane-manager": ["Dockerfile", "go.mod", "go.sum", "helm"], "account-provider": ["Dockerfile", "go.mod", "go.sum", "idl"], "account-acl": ["Dockerfile", "go.mod", "go.sum", "idl"], "account-central": ["Dockerfile", "go.mod", "go.sum", "idl"], "serverless-service": ["go.mod", "go.sum"], "serverless-global-service": ["go.mod", "go.sum"], "cluster-controller": ["Dockerfile", "go.mod", "go.sum", "helm-charts"], "cluster-control-server": ["Dockerfile", "go.mod", "go.sum"], "regional-server": ["Dockerfile", "go.mod", "go.sum", "helm-charts"], "regional-tcidm-service": ["Dockerfile", "go.mod", "go.sum"], "dedicated-ticdc-service": ["Dockerfile", "go.mod", "go.sum"], "config-center": ["Dockerfile", "go.mod", "go.sum", "migration"], "dedicated-global-service": ["Dockerfile", "go.mod", "go.sum"], "tidb-mgmt-portal": ["Dockerfile", "go.mod", "go.sum"], "tidb-mgmt-service": ["Dockerfile", "go.mod", "go.sum"], "nextgen-global-service": ["Dockerfile", "go.mod", "go.sum"], "cluster-ng-server": ["Dockerfile", "go.mod", "go.sum", "deployments"], "cluster-ng-executor": ["Dockerfile", "go.mod", "go.sum", "deployments"], "config-center-regional": ["Dockerfile", "go.mod", "go.sum", "migration"], } live_update_extra_pod_selectors = { "dataflow": [ {"app": "dataflow-ng-grpc"}, {"app": "dataflow-ng-http"}, {"app": "dataflow-ng-worker"}, {"app": "dataflow-ng-ops"}, {"app": "dataflow-ng-workflow"}, ], "dedicated-dataflow-svc": [ {"app.kubernetes.io/name": "dataflow-grpc"}, {"app.kubernetes.io/name": "dataflow-http"}, {"app.kubernetes.io/name": "dataflow-worker"}, {"app.kubernetes.io/name": "dataflow-workflow"}, ], "ticdc-service": [ {"app": "ticdc-service-controller"}, {"app": "ticdc-service-server"}, {"app": "ticdc-service-controller", "cp9.tidbcloud.com/persona": "byoc"}, {"app": "ticdc-service-server", "cp9.tidbcloud.com/persona": "byoc"}, ], "config-center-regional": [ {"app.kubernetes.io/name": "config-center-regional", "cp9.tidbcloud.com/persona": "byoc"}, ], "cluster-ng-server": [ {"app": "cluster-ng-server", "cp9.tidbcloud.com/persona": "byoc"}, ], "cluster-ng-executor": [ {"app": "cluster-ng-executor", "cp9.tidbcloud.com/persona": "byoc"}, ], "serverless-service": [ {"app.kubernetes.io/name": "serverless-svc-grpc-server"}, {"app.kubernetes.io/name": "serverless-service-worker"}, {"app.kubernetes.io/name": "serverless-svc-br-worker"}, ], } dataplane_manager_pod_selectors = [ {"app": "dataplane-controller"}, {"app": "dataplane-server"}, {"app": "dataplane-controller", "cp9.tidbcloud.com/persona": "byoc"}, {"app": "dataplane-server", "cp9.tidbcloud.com/persona": "byoc"}, ] byoc_source_rollout_deployments = { "config-center-regional": ["byoc-config-center-regional"], "cluster-ng-server": ["byoc-cluster-ng-server"], "cluster-ng-executor": ["byoc-cluster-ng-executor"], "dataplane-manager": ["byoc-dataplane-controller", "byoc-dataplane-server"], "ticdc-service": ["byoc-ticdc-service-controller", "byoc-ticdc-service-server"], } shared_base_services = [ "dedicated-global-service", "config-center", ] premium_product_services = [ "tidb-mgmt-portal", "tidb-mgmt-service", "tempo-proxy", "tempo-wrapper", "nextgen-global-service", "account-provider", "account-acl", "account-central", "account-openapi", "dataflow", "ticdc-service", "cluster-ng-server", "cluster-ng-executor", "config-center-regional", "dataplane-manager", ] account_workload_services = [ "account-provider", "account-acl", "account-central", "account-openapi", ] dedicated_product_services = [ "regional-server", "cluster-control-server", "cluster-controller", "dedicated-webhook-server", "regional-tcidm-service", "dedicated-dataflow-svc", "dedicated-ticdc-service", "dedicated-infra-api-crds", "dedicated-aws-provider", ] starter_k3d_product_services = [ "serverless-service", "serverless-global-service", ] starter_remote_product_services = [ "cluster-proxy", "gateway-controller", "manager", "ops-service", "serverless-meta-service", "serverless-meta-store", "serverless-regional-service", "tidb-gateway-inner", "tidb-http-gateway", "tidb-worker-scaler", "vpa-agent", ] starter_product_services = starter_k3d_product_services + starter_remote_product_services starter_product_source_repos = {} starter_product_source_mains = {} starter_product_source_modes = {} for service in starter_product_services: starter_product_source_repos[service] = _source_backed_source_repo(service) starter_product_source_mains[service] = _source_backed_source_main(service) starter_product_source_modes[service] = _source_backed_source_mode(service) dedicated_gated_services = [] always_local_stub_services = ["billing-svc", "o11y-stub"] staging_image_pull_secret = "cp9-staging-ecr-pull" staging_image_pins = { "serverless-service": _source_backed_staging_image("serverless-service"), "serverless-global-service": _source_backed_staging_image("serverless-global-service"), } starter_remote_staging_image_pins = { "cluster-proxy": _source_backed_staging_image("cluster-proxy"), "gateway-controller": _source_backed_staging_image("gateway-controller"), "manager": _source_backed_staging_image("manager"), "ops-service": _source_backed_staging_image("ops-service"), "serverless-meta-service": _source_backed_staging_image("serverless-meta-service"), "serverless-meta-store": _source_backed_staging_image("serverless-meta-store"), "serverless-regional-service": _source_backed_staging_image("serverless-regional-service"), "tidb-gateway-inner": _source_backed_staging_image("tidb-gateway-inner"), "tidb-http-gateway": _source_backed_staging_image("tidb-http-gateway"), "tidb-worker-scaler": _source_backed_staging_image("tidb-worker-scaler"), "vpa-agent": _source_backed_staging_image("vpa-agent"), } shared_base_staging_image_pins = { "dedicated-global-service": _source_backed_staging_image("dedicated-global-service"), "config-center": _source_backed_staging_image("config-center"), } dedicated_staging_image_pins = { "regional-server": _source_backed_staging_image("regional-server"), "cluster-control-server": _source_backed_staging_image("cluster-control-server"), "cluster-controller": _source_backed_staging_image("cluster-controller"), "dedicated-webhook-server": _source_backed_staging_image("dedicated-webhook-server"), "regional-tcidm-service": _source_backed_staging_image("regional-tcidm-service"), "dedicated-dataflow-svc": _source_backed_staging_image("dedicated-dataflow-svc"), "dedicated-ticdc-service": _source_backed_staging_image("dedicated-ticdc-service"), "dedicated-aws-provider": _source_backed_staging_image("dedicated-aws-provider"), } shared_base_service_classifications = { "shared-regional-kong-gateway": { "class": "manifest", "evidence": "staging-seed-us-west-2 namespace kong plus HTTPRoutes beside Regional service backends", "reason": "one shared Regional Gateway preserves product-owned same-namespace routes", }, "dedicated-global-service": { "class": "staging-image", "evidence": "staging-base-us-west-2 StatefulSet tidb-management-service/dedicated-global-service", "reason": "shared base global service used by Dedicated OpenAPI; do not isolate into the Dedicated seed namespace", }, "config-center": { "class": "staging-image", "evidence": "staging-base-us-west-2 Deployment devops/config-center", "reason": "shared base config-center; Premium seed has its own config-center-regional instance", }, } dedicated_service_classifications = { "regional-server": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment regional-server-system/regional-server", "reason": "regional Dedicated runtime service image observed in staging", }, "cluster-control-server": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment cluster-service/cluster-control-server", "reason": "Dedicated cluster control image observed in staging", }, "cluster-controller": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment cluster-service/cluster-controller", "reason": "Dedicated controller reconciles cloud.pingcap.com Cluster CRs into data-plane TiDB resources", }, "dedicated-webhook-server": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment cluster-service/webhook-server", "reason": "Dedicated admission defaulting and validation for cloud.pingcap.com resources", }, "regional-tcidm-service": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment tcidm/regional-tcidm-service", "reason": "Dedicated regional TCIDM image observed in staging", }, "dedicated-dataflow-svc": { "class": "staging-image", "evidence": "staging-base-us-west-2/staging-ms dataflow-grpc/http/worker/workflow use the shared dataflow-service image; cp9 imports the same one-image/four-deployment shape", "reason": "Dedicated dataflow runs as the shared dataflow-service binary with dedicated runtime config", }, "dedicated-ticdc-service": { "class": "staging-image", "evidence": "staging-seed-us-west-2 Deployment ticdc-service/ticdc-service-server", "reason": "Dedicated TiCDC service image observed in staging", }, "dedicated-infra-api-crds": { "class": "manifest", "evidence": "staging-seed-us-west-2 CRD surface plus checked-in selected Dedicated CRD mirror", "reason": "cluster-scoped API surface, no container image", }, "dedicated-aws-provider": { "class": "staging-image", "evidence": "app-delivery dedicated-regional-server/crossplane-aws-provider variants/aws/version.yaml; owner snapshot resolves the public forked provider image", "reason": "isolated legacy aws.crossplane.io controllers are required for Dedicated regional-server CRs; public GCR needs no ECR pull secret; Premium Upbound remains the aws.upbound.io provider family", }, } starter_service_classifications = { "serverless-service": { "class": "staging-image", "evidence": "staging-base-us-west-2 deployments staging-ms/serverless-svc-http-server, serverless-svc-grpc-server, serverless-svc-worker, and serverless-svc-br-worker", "reason": "Starter /~/v1beta1 branch, SQL-user, and changefeed routes use the serverless-service HTTP backend; imported Starter defaults to the staging image", }, "serverless-global-service": { "class": "staging-image", "evidence": "staging-base-us-west-2 deployment/statefulset tidb-management-service/serverless-global-service", "reason": "shared tidb-management-service config points serverless.url to kubernetes:///serverless-global-service:10000 in real staging", }, "cluster-proxy": { "class": "staging-image", "evidence": "staging-us-east-1-f01 deployment tidb-admin/dbaas-proxy", "reason": "Starter cluster proxy defaults to the staging image; selecting source-build compiles clusterproxy/cmd/proxy from infra-provider", }, "gateway-controller": { "class": "staging-image", "evidence": "staging-us-east-1-f01 deployment tidb-admin/gateway-controller", "reason": "Starter gateway reconciliation uses the real aws-shared-provider controller binary, RBAC, config, probes, and session-scoped source image path", }, "manager": { "class": "staging-image", "evidence": "Starter regional runtime deployment tidb-admin/manager on the session-owned remote EKS substrate", "reason": "Starter data-plane service defaults to staging image; selecting source-build pushes a session-scoped ECR image through the Session Tiltfile", }, "ops-service": { "class": "staging-image", "evidence": "staging-us-east-1-f01 deployment tidb-admin/ops-service", "reason": "Starter regional operations default to the staging image; selecting source-build compiles cmd/ops-service from aws-shared-provider", }, "serverless-meta-service": { "class": "staging-image", "evidence": "staging-us-east-1-f01 deployment tidb-admin/serverless-meta-server", "reason": "Starter uses the real serverless-metering metadata API with the staging protocol and session-owned DynamoDB/S3 inputs", }, "serverless-meta-store": { "class": "staging-image", "evidence": "staging-us-east-1-f01 deployment tidb-admin/meta-store", "reason": "Starter uses the real aws-shared-provider PD metadata store and TLS client path without the staging RDS dependency", }, "serverless-regional-service": { "class": "staging-image", "evidence": "Starter regional runtime deployment tidb-admin/serverless-regional-service on the session-owned remote EKS substrate", "reason": "Starter data-plane service defaults to staging image; selecting source-build pushes a session-scoped ECR image through the Session Tiltfile", }, "tidb-gateway-inner": { "class": "staging-image", "evidence": "Starter regional runtime deployment tidb-admin/tidb-gateway-inner on the session-owned remote EKS substrate", "reason": "Starter data-plane service defaults to staging image; selecting source-build pushes a session-scoped ECR image through the Session Tiltfile", }, "tidb-http-gateway": { "class": "staging-image", "evidence": "staging-us-east-1-f01 statefulset tidb-admin/tidb-http-gateway", "reason": "Starter HTTP SQL gateway uses the real aws-shared-provider binary, TLS, health contract, LoadBalancer service, and session-scoped source image path", }, "tidb-worker-scaler": { "class": "staging-image", "evidence": "Starter regional runtime deployment tidb-worker/tidb-worker-scaler on the session-owned remote EKS substrate", "reason": "Starter data-plane service defaults to staging image; selecting source-build pushes a session-scoped ECR image through the Session Tiltfile", }, "vpa-agent": { "class": "staging-image", "evidence": "staging-us-east-1-f01 daemonset tidb-vpa/vpa-agent", "reason": "Starter uses the real VPA node agent binary, host /proc path, RBAC, probes, and source-image rollout path", }, "starter-openapi-route-layer": { "class": "manifest", "evidence": "staging-base-us-west-2 ingress tidb-management-service/serverlessapi-serverless-tidb-mgmt-portal-80-ingress-0 and shared us-west-2.staging.shared.aws.tidbcloud.com ingress", "reason": "Starter routes are added to the single Dev full gateway route layer instead of a second gateway/host", }, } source_build_parallelism_int = int(source_build_parallelism) if source_build_supported and source_build_parallelism_int < 1: fail("services.source_build_parallelism must be a positive integer") def _graph_parallelism(): # Tilt's max_parallel_updates governs the WHOLE graph -- namespaces, CRDs, # kustomize applies, stubs -- roughly 116 resources, nearly all of them # kubectl round-trips that wait on the API server rather than on CPU. # Throttling those to protect the host was the old behaviour and it was the # wrong lever: source_build_services is empty by default, so it slowed down # every session that compiles nothing at all. Compilation is now bounded on # its own (see _source_build_chain_deps), which frees this to track the host. probe = str(local("nproc 2>/dev/null || sysctl -n hw.ncpu", quiet=True, echo_off=True)).strip() if probe == "": return 4 cores = int(probe) if cores < 4: return 4 return cores update_settings( max_parallel_updates=_graph_parallelism(), k8s_upsert_timeout_secs=120, ) _source_build_chain_tails = {} _source_build_chain_counts = {} def _source_build_chain_deps(kind, resource): # Bound concurrent auto-init compiles without touching graph parallelism: # hand each build a slot, and make it wait on the previous build in that # slot. With the default of one slot this is a straight serial chain; with # N slots at most N compiles overlap. Ordering within a slot is arbitrary # but stable, which is all the bound requires. # # Chains are per kind, and that is load-bearing rather than tidiness. The # Manual -live-binary resources use Tilt's serial execution instead. A # resource_deps chain would wait forever when a targeted deploy does not # trigger the previous service in the slot. slot = _source_build_chain_counts.get(kind, 0) % source_build_parallelism_int _source_build_chain_counts[kind] = _source_build_chain_counts.get(kind, 0) + 1 previous = _source_build_chain_tails.get(kind + "/" + str(slot), "") _source_build_chain_tails[kind + "/" + str(slot)] = resource if previous == "": return [] return [previous] if namespace == "": fail("CP9_SESSION_CONTEXT.namespace or session_name is required") if evidence_dir == "": fail("CP9_SESSION_CONTEXT.evidence_dir is required") if kubeconfig == "": fail("CP9_SESSION_CONTEXT.kubeconfig_path is required") if kube_context == "": fail("CP9_SESSION_CONTEXT.kube_context is required") if dedicated_api_admin_kubeconfig == "" or dedicated_api_host_manifest == "" or dedicated_api_bootstrap_manifest == "": fail("CP9_SESSION_CONTEXT.host.dedicated_api paths are required for dev-full") allow_k8s_contexts(kube_context) def _quote(value): return "'" + str(value).replace("'", "'\"'\"'") + "'" def _aws_runtime_identity_env(): if remote_aws_runtime_identity: return "CP9_AWS_RUNTIME_IDENTITY=ec2-instance-profile " return "" def _tf_value(name, default = ""): item = terraform_outputs.get(name, {}) if item == None: return default value = item.get("value", default) if value == None: return default return value runtime_patch_inputs = _tf_value("runtime_patch_inputs", {}) runtime_aws = runtime_patch_inputs.get("aws", {}) aws_profile = runtime_aws.get("profile", "cp9") target_region = runtime_aws.get("region", target.get("region", "")) if not target_region: fail("CP9_SESSION_CONTEXT target.region is required") starter_source_image_repositories = _tf_value("starter_source_image_repositories", {}) remote_eks = _tf_value("remote_eks", {}) o11y_aws_profile = os.getenv("CP9_O11Y_AWS_PROFILE", "cp9-developer") if remote_aws_runtime_identity: o11y_aws_profile = "-" o11y_platform_enabled = remote_aws_runtime_identity o11y_auth0_secret_id = "cp9/dev/auth0/o11y-m2m" o11y_image_registry = "385595570414.dkr.ecr.us-west-2.amazonaws.com" gcp_runtime_values = {} gcp_regional_endpoint_url = host.get("regional", {}).get("gcp", {}).get("regional_endpoint_url", "") if runtime_id == "gcp-regional": gcp_host = host.get("gcp", {}) gcp_remote = host.get("remote", {}) primary_host = host.get("primary", {}) primary_remote = primary_host.get("remote", {}) session_product_pca = terraform_info.get("session_product_pca", {}) dedicated_public_dns = terraform_info.get("dedicated_public_dns", {}) gcp_role_parts = gcp_host.get("aws_role_arn", "").split("/") gcp_service_account_parts = gcp_host.get("service_account_email", "").split("@") gcp_aws_token_file = gcp_host.get("aws_web_identity_token_file", "") gcp_remote_state_dir = gcp_remote.get("remote_state_dir", "") if gcp_remote_state_dir == "": fail("GCP runtime context is missing host.remote.remote_state_dir") gcp_aws_host_token_file = gcp_remote_state_dir + "/identity/token" primary_public_https_url = primary_remote.get("public_https_url", "") if primary_public_https_url == "": fail("GCP runtime context is missing primary host public_https_url") primary_public_host_parts = primary_public_https_url.split("://") if len(primary_public_host_parts) != 2 or primary_public_host_parts[0] != "https" or primary_public_host_parts[1] == "": fail("GCP runtime primary host public_https_url must be one HTTPS origin") gcp_runtime_values = { "__CP9_SESSION_NAME__": session_name, "__CP9_OWNER__": (ctx.get("session_tags") or {}).get("cp9-owner", ""), "__CP9_TTL_EXPIRES_AT__": ctx.get("ttl_expires_at", "").replace(":", "-").lower(), "__CP9_GCP_PROJECT_ID__": gcp_host.get("project_id", ""), "__CP9_GCP_DATAPLANE_PROJECT_ID__": gcp_host.get("dataplane_project_id", ""), "__CP9_GCP_SERVICE_ACCOUNT_EMAIL__": gcp_host.get("service_account_email", ""), "__CP9_GCP_SERVICE_ACCOUNT_NAME__": gcp_service_account_parts[0] if len(gcp_service_account_parts) == 2 else "", "__CP9_GCP_O11Y_SERVICE_ATTACHMENT__": gcp_host.get("o11y_service_attachment", ""), "__CP9_GCP_O11Y_BUCKET_NAME__": gcp_host.get("o11y_bucket", ""), "__CP9_GCP_AWS_ROLE_ARN__": gcp_host.get("aws_role_arn", ""), "__CP9_GCP_AWS_ROLE_NAME__": gcp_role_parts[len(gcp_role_parts) - 1] if len(gcp_role_parts) > 1 else "", "__CP9_GCP_AWS_IDENTITY_DIR__": "/".join(gcp_aws_token_file.split("/")[:-1]), "__CP9_GCP_REGIONAL_ENDPOINT_HOST__": gcp_host.get("regional_endpoint_host", ""), "__CP9_PRIMARY_AWS_REGION__": primary_remote.get("region", ""), "__CP9_PRIMARY_PUBLIC_HOST__": primary_public_host_parts[1], "__CP9_PRIMARY_AWS_CIDR__": primary_remote.get("public_ip", "") + "/32", "__CP9_PRIMARY_CONFIG_CENTER_URL__": primary_public_https_url + "/config-center", "__CP9_PRIMARY_O11Y_CONTROL_URL__": primary_public_https_url + "/o11y/control", "__CP9_GCP_RUNTIME_CIDR__": gcp_remote.get("public_ip", "") + "/32", "__CP9_SESSION_PRODUCT_PCA_ARN__": session_product_pca.get("arn", ""), "__CP9_DEDICATED_PUBLIC_DNS_ZONE_ID__": dedicated_public_dns.get("zone_id", ""), "__CP9_DEDICATED_PUBLIC_DNS_DOMAIN__": dedicated_public_dns.get("domain", ""), } for placeholder in gcp_runtime_values: value = gcp_runtime_values[placeholder] if value == "" or value == "/32": fail("GCP runtime context is missing " + placeholder) def _gcp_replacements(placeholders): replacements = [] for placeholder in placeholders: if placeholder not in gcp_runtime_values: fail("unknown GCP runtime placeholder " + placeholder) replacements.append(placeholder + "=" + gcp_runtime_values[placeholder]) return replacements def _dataplane_manager_public_access_env(): if host.get("mode", "") != "remote-ec2-k3d": return "" return "CP9_LOCAL_EKS_PUBLIC_ACCESS_CIDR=" + _quote("0.0.0.0/0") + " " def _json_status(status, detail): return "{\"status\":\"" + status + "\",\"detail\":\"" + detail + "\"}" def _write_evidence_command(name, status, detail): output = evidence_dir + "/" + name + ".json" return "mkdir -p " + _quote(evidence_dir) + " && printf '%s\\n' " + _quote(_json_status(status, detail)) + " > " + _quote(output) def _kubectl_base(target_namespace = ""): args = ["KUBECONFIG=" + _quote(kubeconfig), "kubectl", "--context", _quote(kube_context)] if target_namespace != "": args += ["--namespace", _quote(target_namespace)] return " ".join(args) def _ensure_namespace_command(target_namespace): return ( "KUBECONFIG=" + _quote(kubeconfig) + " kubectl --context " + _quote(kube_context) + " create namespace " + _quote(target_namespace) + " --dry-run=client -o yaml | KUBECONFIG=" + _quote(kubeconfig) + " kubectl --context " + _quote(kube_context) + " apply -f -" ) def _apply_kustomize_command(path, target_namespace): return ( _kubectl_base(target_namespace) + " apply --server-side --force-conflicts -k " + _quote(path) ) def _apply_dbaas_ui_command(path, target_namespace, runtime_config_path): return ( _apply_kustomize_command(path, target_namespace) + " && " + _kubectl_base(target_namespace) + " create configmap dbaas-ui-runtime --from-file=config.js=" + _quote(runtime_config_path) + " --dry-run=client -o yaml | " + _kubectl_base(target_namespace) + " apply --server-side --force-conflicts --field-manager=cp9-ui-runtime -f -" + " && stamp=$(python3 -c " + _quote("import hashlib, sys; print(hashlib.sha256(open(sys.argv[1], 'rb').read()).hexdigest())") + " " + _quote(runtime_config_path) + ")" + " && " + _kubectl_base(target_namespace) + " patch deployment/dbaas-ui --type=merge -p " + "\"{\\\"spec\\\":{\\\"template\\\":{\\\"metadata\\\":{\\\"annotations\\\":{\\\"cp9.tidbcloud.com/runtime-config-sha256\\\":\\\"$stamp\\\"}}}}}\"" ) def _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret = ""): namespace_arg = target_namespace if namespace_arg == "": namespace_arg = "-" cmd = [ _quote("./scripts/apply-kustomize-images.sh"), _quote(path), _quote(namespace_arg), _quote(kubeconfig), _quote(kube_context), ] for image in images: cmd.append(_quote(image)) command = _aws_runtime_identity_env() + " ".join(cmd) if image_pull_secret != "": command = "CP9_IMAGE_PULL_SECRET=" + _quote(image_pull_secret) + " " + command return command def _print_applied_kustomize_images_command(path, target_namespace, images, image_pull_secret = ""): return "CP9_PRINT_APPLIED_YAML=true " + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) def _render_kustomize_images_command(path, target_namespace, images, image_pull_secret = ""): return "CP9_RENDER_ONLY=true " + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) def _apply_kustomize_images_with_rollout_stamp_command(service, path, target_namespace, images, image_pull_secret = ""): return _image_rollout_stamp_env(service) + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) def _print_applied_kustomize_images_with_rollout_stamp_command(service, path, target_namespace, images, image_pull_secret = ""): return "CP9_PRINT_APPLIED_YAML=true " + _apply_kustomize_images_with_rollout_stamp_command(service, path, target_namespace, images, image_pull_secret) def _delete_kustomize_images_command(path, target_namespace, images, image_pull_secret = ""): namespace_arg = target_namespace if namespace_arg == "": return _render_kustomize_images_command(path, target_namespace, images, image_pull_secret) + " | " + _kubectl_base() + " delete --ignore-not-found=true -f -" return _render_kustomize_images_command(path, target_namespace, images, image_pull_secret) + " | " + _kubectl_base(namespace_arg) + " delete --ignore-not-found=true -f -" def _apply_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret = ""): cmd = [ _quote("./scripts/apply-dataplane-manager-runtime.sh"), _quote(path), _quote(target_namespace), _quote(kubeconfig), _quote(kube_context), _quote(ctx_path), ] for image in images: cmd.append(_quote(image)) env = _aws_runtime_identity_env() + _dataplane_manager_public_access_env() if image_pull_secret != "": env += "CP9_IMAGE_PULL_SECRET=" + _quote(image_pull_secret) + " " return env + " ".join(cmd) def _print_applied_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret = ""): return "CP9_PRINT_APPLIED_YAML=true " + _apply_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret) def _render_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret = ""): return "CP9_RENDER_ONLY=true " + _apply_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret) def _apply_dataplane_manager_runtime_with_rollout_stamp_command(path, target_namespace, images, image_pull_secret = ""): return _image_rollout_stamp_env("dataplane-manager") + _apply_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret) def _print_applied_dataplane_manager_runtime_with_rollout_stamp_command(path, target_namespace, images, image_pull_secret = ""): return "CP9_PRINT_APPLIED_YAML=true " + _apply_dataplane_manager_runtime_with_rollout_stamp_command(path, target_namespace, images, image_pull_secret) def _delete_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret = ""): return _render_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret) + " | " + _kubectl_base(target_namespace) + " delete --ignore-not-found=true -f -" def _apply_aws_creds_secret_command(target_namespace): return " ".join([ _quote("./scripts/apply-aws-creds-secret.sh"), _quote(target_namespace), _quote(kubeconfig), _quote(kube_context), _quote(ctx_path), ]) def _apply_staging_image_pull_secret_command(target_namespace): profile = "-" if not remote_aws_runtime_identity: profile = host.get("remote", {}).get("profile", os.getenv("AWS_PROFILE", "")) if profile == "": profile = "-" return " ".join([ _quote("./scripts/apply-staging-image-pull-secret.sh"), _quote(target_namespace), _quote(kubeconfig), _quote(kube_context), _quote(profile), _quote(staging_image_pull_secret), _quote(staging_image_registry), ]) def _apply_o11y_image_pull_secret_command(): return " ".join([ _quote("./scripts/apply-staging-image-pull-secret.sh"), _quote("observability"), _quote(kubeconfig), _quote(kube_context), _quote(o11y_aws_profile), _quote(staging_image_pull_secret), _quote(o11y_image_registry), ]) def _apply_o11y_runtime_secrets_command(): return " ".join([ _quote("./scripts/apply-o11y-runtime-secrets.sh"), _quote(kubeconfig), _quote(kube_context), _quote(o11y_aws_profile), _quote(target_region), _quote(o11y_auth0_secret_id), ]) def _apply_file_command(path, target_namespace = ""): return _kubectl_base(target_namespace) + " apply -f " + _quote(path) def _apply_crossplane_provider_package_command(path, package_image): return " ".join([ _quote("./scripts/apply-crossplane-provider-package.sh"), _quote(path), _quote(kubeconfig), _quote(kube_context), _quote(package_image), ]) def _create_missing_resources_from_file_command(path, target_namespace): return ( "(" + _kubectl_base(target_namespace) + " create -f " + _quote(path) + " || " + _kubectl_base(target_namespace) + " get -f " + _quote(path) + " >/dev/null)" ) def _print_applied_file_command(path, target_namespace = ""): return ( _apply_file_command(path, target_namespace) + " >&2 && " + _kubectl_base(target_namespace) + " get -f " + _quote(path) + " -o yaml" ) def _delete_file_command(path, target_namespace = ""): return _kubectl_base(target_namespace) + " delete --ignore-not-found=true -f " + _quote(path) def _apply_helm_command(name, chart, target_namespace, values, artifact_image = "", ready_command = ""): args = [ "./scripts/apply-helm-release.sh", name, chart, target_namespace, kubeconfig, kube_context, artifact_image, ] for value_file in values: args.append(value_file) cmd = " ".join([_quote(arg) for arg in args]) if ready_command != "": cmd += " && " + ready_command return cmd def _kong_plugin_configmap_command(plugin_name, target_namespace = "kong-system"): plugin_dir = "../../app-delivery/base/api-gateway-local/plugins/" + plugin_name return ( _kubectl_base(target_namespace) + " create configmap " + _quote("kong-plugin-" + plugin_name) + " --from-file=handler.lua=" + _quote(plugin_dir + "/handler.lua") + " --from-file=schema.lua=" + _quote(plugin_dir + "/schema.lua") + " --dry-run=client -o yaml | " + _kubectl_base(target_namespace) + " apply -f -" ) def _runtime_resource(runtime, name, cmd, deps = [], labels = [], resource_deps = [], allow_parallel = True, trigger_mode = TRIGGER_MODE_AUTO): if runtime_id != runtime: return if allow_parallel: local_resource( name, cmd, deps=deps, labels=labels, resource_deps=resource_deps, allow_parallel=True, trigger_mode=trigger_mode, ) else: local_resource( name, cmd, deps=deps, labels=labels, resource_deps=resource_deps, trigger_mode=trigger_mode, ) def _resource(name, cmd, deps = [], labels = [], resource_deps = [], allow_parallel = True, trigger_mode = TRIGGER_MODE_AUTO): _runtime_resource("primary", name, cmd, deps, labels, resource_deps, allow_parallel, trigger_mode) def _namespace_resource(target_namespace, runtime = "primary"): name = "ns-" + target_namespace _runtime_resource( runtime, name, _ensure_namespace_command(target_namespace), labels=["dev-full", "namespace"], ) return name def _kustomize_resource(name, path, target_namespace, resource_deps = [], extra_env = "", runtime = "primary"): deps = [path] if extra_env != "": deps.append(ctx_path) _runtime_resource( runtime, name, extra_env + _apply_kustomize_command(path, target_namespace), deps=deps, labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _crd_directory_resource(name, path, target_namespace, resource_deps = [], runtime = "primary"): command = ( "set -eu" + " && " + _kubectl_base(target_namespace) + " apply --server-side --force-conflicts --recursive -f " + _quote(path) + " && " + _wait_for_conditions_command([{ "wait_for": "condition=Established", "resource_args": "--recursive -f " + _quote(path), "transient_pattern": _crd_established_transient_pattern, }]) ) _runtime_resource( runtime, name, command, deps=[path], labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _kustomize_image_resource(name, path, target_namespace, images, resource_deps = [], image_pull_secret = "", extra_env = "", extra_deps = [], ready_command = "", runtime = "primary"): deps = [path, "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py"] + extra_deps if extra_env != "": deps.append(ctx_path) apply_command = extra_env + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) if ready_command != "": apply_command += " && " + ready_command if _live_update_enabled(name): image_selector = _local_image(name) live_apply_command = extra_env + _print_applied_kustomize_images_with_rollout_stamp_command(name, path, target_namespace, images, image_pull_secret) if ready_command != "": live_apply_command += " && " + ready_command k8s_custom_deploy( name, live_apply_command, extra_env + _delete_kustomize_images_command(path, target_namespace, images, image_pull_secret), deps=deps + _live_update_deps(name) + _source_image_rollout_deps(name), image_selector=image_selector, live_update=_live_update_steps(name, live_update_repos[name]), ) k8s_resource( name, extra_pod_selectors=live_update_extra_pod_selectors.get(name, []), labels=["dev-full", "app-delivery", "live-update"], resource_deps=resource_deps, ) return _runtime_resource( runtime, name, apply_command, deps=deps, labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _custom_deploy_resource(name, apply_cmd, delete_cmd, deps, resource_deps = []): if runtime_id != "primary": return k8s_custom_deploy( name, apply_cmd, delete_cmd, deps=deps, ) k8s_resource( name, labels=["dev-full", "app-delivery"], resource_deps=resource_deps, pod_readiness="ignore", ) def _file_custom_deploy_resource(name, path, target_namespace, resource_deps = []): _custom_deploy_resource( name, _print_applied_file_command(path, target_namespace), _delete_file_command(path, target_namespace), [path], resource_deps=resource_deps, ) def _starter_local_global_service_resource(name, path, target_namespace, images, resource_deps = [], image_pull_secret = ""): _kustomize_image_resource( name, path, target_namespace, images, resource_deps=resource_deps, image_pull_secret=image_pull_secret, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) def _regional_server_resource(path, target_namespace, images, resource_deps = [], image_pull_secret = ""): command = ( "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) ) _resource( "regional-server", command, deps=[path, "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _dedicated_global_service_resource(path, target_namespace, images, resource_deps = [], image_pull_secret = ""): command = ( "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) ) _resource( "dedicated-global-service", command, deps=[path, "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _dedicated_cluster_controller_resource(name, path, target_namespace, images, resource_deps = [], image_pull_secret = ""): command = ( "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + _apply_kustomize_images_command(path, target_namespace, images, image_pull_secret) ) _resource( name, command, deps=[path, "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _dedicated_webhook_server_resource(host_path, api_path, target_namespace, image, resource_deps = [], image_pull_secret = "", runtime = "primary"): command = " ".join([ "CP9_SESSION_CONTEXT=" + _quote(ctx_path), _quote("./scripts/apply-dedicated-webhook-server.sh"), _quote(host_path), _quote(api_path), _quote(target_namespace), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(image), _quote(image_pull_secret), ]) _runtime_resource( runtime, "dedicated-webhook-server", command, deps=[ host_path, api_path, "./scripts/apply-dedicated-webhook-server.sh", "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path, ], labels=["dev-full", "app-delivery", "dedicated-api"], resource_deps=resource_deps, ) def _dataplane_manager_resource(path, target_namespace, images, resource_deps = [], image_pull_secret = ""): if _live_update_enabled("dataplane-manager"): k8s_custom_deploy( "dataplane-manager", _print_applied_dataplane_manager_runtime_with_rollout_stamp_command(path, target_namespace, images, image_pull_secret), _delete_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret), deps=[path, "./scripts/apply-dataplane-manager-runtime.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path] + _live_update_deps("dataplane-manager") + _source_image_rollout_deps("dataplane-manager"), image_selector=_local_image("dataplane-manager"), live_update=_live_update_steps("dataplane-manager", live_update_repos["dataplane-manager"]), ) k8s_resource( "dataplane-manager", extra_pod_selectors=dataplane_manager_pod_selectors, labels=["dev-full", "app-delivery", "live-update"], resource_deps=resource_deps, ) return _resource( "dataplane-manager", _apply_dataplane_manager_runtime_command(path, target_namespace, images, image_pull_secret), deps=[path, "./scripts/apply-dataplane-manager-runtime.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _helm_resource(name, chart, target_namespace, values, resource_deps = [], artifact_image = "", artifact_name = "", ready_command = "", runtime = "primary"): deps = [chart, "./scripts/apply-helm-release.sh"] + values if artifact_image != "": deps.append(_owner_artifact_trigger_path(artifact_name or name)) _runtime_resource( runtime, name, _apply_helm_command(name, chart, target_namespace, values, artifact_image, ready_command), deps=deps, labels=["dev-full", "app-delivery"], resource_deps=resource_deps, ) def _gcp_import_owner_image_command(image): local_image = _gcp_local_owner_image(image) registry_login = ( "docker_config=$(mktemp -d)" + " && trap 'rm -rf -- \"$docker_config\"' EXIT" + " && token=$(curl --connect-timeout 5 --max-time 20 --fail --silent --show-error " + "--header 'Metadata-Flavor: Google' " + "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token " + "| python3 -c 'import json,sys; print(json.load(sys.stdin)[\"access_token\"])')" + " && test -n \"$token\"" + " && printf '%s' \"$token\" | DOCKER_CONFIG=\"$docker_config\" docker login --username oauth2accesstoken --password-stdin https://gcr.io >/dev/null" + " && unset token" ) return _join_commands([ registry_login, "DOCKER_CONFIG=\"$docker_config\" ./scripts/import-gcp-owner-amd64.sh " + _quote(image) + " " + _quote(cluster_name) + " " + _quote(local_image), "rm -rf -- \"$docker_config\" && trap - EXIT", ]) def _gcp_local_owner_image(image): parts = image.split("@") if len(parts) != 2 or parts[0] == "" or not parts[1].startswith("sha256:"): fail("GCP owner image must be digest pinned: " + image) return "cp9.local/gcp-owner:" + parts[1].replace(":", "-") def _gcp_owner_kustomize_resource(name, applications, resource_deps = [], ready_commands = []): image = _owner_artifact_image(name) local_image = _gcp_local_owner_image(image) commands = [_gcp_import_owner_image_command(image)] deps = [ "./scripts/import-gcp-owner-amd64.sh", "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", _owner_artifact_trigger_path(name), ctx_path, ] for application in applications: replacements = [application["image"] + "=" + local_image] replacements += _gcp_replacements(application.get("placeholders", [])) commands.append( "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + _apply_kustomize_images_command(application["path"], application["namespace"], replacements) ) deps.append(application["path"]) _runtime_resource( "gcp-regional", name, _join_commands(commands + ready_commands), deps=deps, labels=["dev-full", "app-delivery", "gcp-owner-artifact"], resource_deps=resource_deps, ) def _join_commands(commands): return " && ".join(commands) def _sanitize(value): return str(value).lower().replace("_", "-").replace(".", "-").replace("/", "-").replace(":", "-") def _local_image(service): return "cp9.local/" + _sanitize(session_name) + "-" + _sanitize(service) + ":local" def _live_update_supported(service): # CP9-owned capability gate (ADR 0011 amendment, PRD #664): live-update is # derived, not a second user opt-in. A service is live-update capable when # its source-backed contract supports source-build, its backend is the k3d # control plane (real EKS data-plane services use the image-level backend # instead), and the shipped k3d live-update wiring exists for it. contract = source_backed_service_contracts.get(service, None) if contract == None: return False if not contract.get("sourceBuildSupported", False): return False if contract.get("backend", {}).get("kind", "") != "k3d-control-plane": return False return service in live_update_repos def _live_update_enabled(service): return _contains(source_build_services, service) and _live_update_supported(service) def _live_update_binary_path(service): return ".cp9-build/" + service + "/live/service" def _ensure_live_update_binary_path(service): binary_path = _live_update_binary_path(service) binary_dir = ".cp9-build/" + service + "/live" local("mkdir -p " + _quote(binary_dir) + " && [ -e " + _quote(binary_path) + " ] || : > " + _quote(binary_path), quiet=True) return binary_path def _live_update_deps(service): return [_ensure_live_update_binary_path(service)] def _source_image_stamp_path(service): return ".cp9-build/" + service + "/image.stamp" def _ensure_source_image_stamp_path(service): stamp_path = _source_image_stamp_path(service) stamp_dir = ".cp9-build/" + service local("mkdir -p " + _quote(stamp_dir) + " && [ -e " + _quote(stamp_path) + " ] || : > " + _quote(stamp_path), quiet=True) return stamp_path def _source_image_rollout_deps(service): return [_ensure_source_image_stamp_path(service)] def _publish_source_image_stamp_command(service): stamp_path = _ensure_source_image_stamp_path(service) return ( "stamp=$(base64 < " + _quote(stamp_path) + " | tr -d '\\n')" + " && test -n \"$stamp\"" + " && tilt patch uiresource " + _quote(service + "-image") + " --type=merge -p " + "\"{\\\"metadata\\\":{\\\"annotations\\\":{\\\"cp9.tidbcloud.com/image-stamp\\\":\\\"$stamp\\\"}}}\"" ) def _image_rollout_stamp_env(service): stamp_path = _ensure_source_image_stamp_path(service) return "CP9_IMAGE_ROLLOUT_STAMP=$(cat " + _quote(stamp_path) + " 2>/dev/null || true) " def _byoc_source_rollout_command(service): deployments = byoc_source_rollout_deployments[service] kubectl = _kubectl_base("cp-byoc") activation_checks = [] patch_images = [] patch_stamps = [] rollout_status = [] image = _local_image(service) stamp_path = _ensure_source_image_stamp_path(service) for deployment in deployments: ref = "deployment/" + deployment activation_checks.append(kubectl + " get " + _quote(ref) + " >/dev/null 2>&1") patch = '[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"' + image + '"},{"op":"add","path":"/spec/template/spec/containers/0/imagePullPolicy","value":"IfNotPresent"}]' patch_images.append(kubectl + " patch " + _quote(ref) + " --type=json -p " + _quote(patch)) patch_stamps.append( kubectl + " patch " + _quote(ref) + " --type=merge -p " + "\"{\\\"spec\\\":{\\\"template\\\":{\\\"metadata\\\":{\\\"annotations\\\":{\\\"cp9.tidbcloud.com/source-image-stamp\\\":\\\"$stamp\\\"}}}}}\"", ) rollout_status.append(kubectl + " rollout status " + _quote(ref) + " --timeout=20m") return ( "if ! " + " || ! ".join(activation_checks) + "; then " + "printf '%s\\n' " + _quote("[cp9 byoc source rollout] " + service + ": BYOC runtime not activated; skipped") + "; else stamp=$(cat " + _quote(stamp_path) + " 2>/dev/null || true)" + " && " + " && ".join(patch_images + patch_stamps) + " && " + " && ".join(rollout_status) + "; fi" ) def _live_update_fallback_deps(service, repo): deps = [] for fallback in live_update_fallback_paths.get(service, []): deps.append(repo + "/" + fallback) return deps def _source_image_build_deps(service, repo, base_deps): if _live_update_enabled(service): return _live_update_fallback_deps(service, repo) + base_deps return [repo] + base_deps def _live_update_steps(service, repo): if service not in live_update_entrypoints: fail("live_update_entrypoints missing " + service) binary_path = _live_update_binary_path(service) fallback_steps = [] for fallback in _live_update_fallback_deps(service, repo): fallback_steps.append(fall_back_on(fallback)) return fallback_steps + [ sync(binary_path, live_update_entrypoints[service]), run("touch /tmp/cp9-live-update.restart", trigger=[binary_path]), ] def _live_update_binary_resource(name, repo, main): arch = _container_arch() build_script = "../build/build-live-binary.sh" local_resource( name + "-live-binary", " ".join([ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(arch), _quote(_live_update_binary_path(name)), ]), deps=[repo, build_script], labels=["dev-full", "live-update"], resource_deps=["premium-session-context"], allow_parallel=False, auto_init=False, trigger_mode=TRIGGER_MODE_MANUAL if host.get("mode", "") == "remote-ec2-k3d" and controller == "remote" else TRIGGER_MODE_AUTO, ) def _container_arch(): if host.get("mode", "") == "remote-ec2-k3d": remote_arch = host.get("remote", {}).get("architecture", "") if remote_arch == "arm64" or remote_arch == "amd64": return remote_arch fail("CP9_SESSION_CONTEXT.host.remote.architecture must be arm64 or amd64 for remote Dev full image builds") return "arm64" def _local_image_resource(name, repo, main, mode = "generic"): image = _local_image(name) if runtime_id != "primary": return image arch = _container_arch() build_script = "../build/build-local-image.sh" build_deps = _source_image_build_deps(name, repo, [build_script]) remote_direct_live_update = host.get("mode", "") == "remote-ec2-k3d" and controller == "remote" and _live_update_enabled(name) build_args = [ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(image), _quote(cluster_name), _quote(arch), _quote(".cp9-build/" + name), _quote(mode), ] if remote_direct_live_update: build_deps.append("../build/account-gateway-sources.sh") build_args.append(_quote(",".join(live_update_fallback_paths.get(name, [])))) if host.get("mode", "") == "remote-ec2-k3d" and controller != "remote": build_script = "../build/remote/build-remote-image.sh" build_deps = _source_image_build_deps(name, repo, [build_script, "../build/build-local-image.sh", "../build/remote/github-app-user-token.sh", "../build/remote/github-user-module-download.sh", "../build/remote/source-manifest.py", "../build/remote/remote-source-lock.sh", "../build/remote/remote-build-driver.sh", "../build/remote/remote-build-diagnostics.sh", ctx_path]) build_args = [ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(image), _quote(cluster_name), _quote(arch), _quote(".cp9-build/" + name), _quote(mode), _quote(ctx_path), ] command = " ".join(build_args) if remote_direct_live_update: command = command + " && " + _publish_source_image_stamp_command(name) _resource( name + "-image", command, deps=build_deps, labels=["dev-full", "image"], resource_deps=["premium-session-context"] + _source_build_chain_deps("image", name + "-image"), allow_parallel=True, trigger_mode=TRIGGER_MODE_MANUAL if remote_direct_live_update else TRIGGER_MODE_AUTO, ) return image def _starter_source_image_build_deps(service, repo, build_script, mode): deps = [repo, build_script] if build_script == "../starter/build-remote-image.sh": deps.append("../starter/build-local-image.sh") deps.append("../build/remote/source-manifest.py") deps.append("../build/remote/remote-source-lock.sh") deps.append("../build/remote/remote-build-driver.sh") deps.append("../build/remote/remote-build-diagnostics.sh") deps.append("../build/remote/github-app-user-token.sh") deps.append("../build/remote/github-user-module-download.sh") deps.append(ctx_path) return deps def _starter_live_update_binary_resource(name, repo, main, mode): arch = _container_arch() build_script = "../starter/build-local-image.sh" local_resource( name + "-live-binary", "CP9_LIVE_BINARY_OUTPUT=" + _quote(_live_update_binary_path(name)) + " " + " ".join([ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(_local_image(name)), _quote(""), _quote(arch), _quote(".cp9-build/" + name + "/live-build"), _quote(mode), ]), deps=_starter_source_image_build_deps(name, repo, build_script, mode), labels=["dev-full", "live-update"], resource_deps=["premium-session-context"], allow_parallel=False, auto_init=False, trigger_mode=TRIGGER_MODE_MANUAL if host.get("mode", "") == "remote-ec2-k3d" and controller == "remote" else TRIGGER_MODE_AUTO, ) def _starter_local_image_resource(name, repo, main, mode): image = _local_image(name) arch = _container_arch() build_script = "../starter/build-local-image.sh" build_args = [ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(image), _quote(cluster_name), _quote(arch), _quote(".cp9-build/" + name), _quote(mode), ] if host.get("mode", "") == "remote-ec2-k3d" and controller != "remote": build_script = "../starter/build-remote-image.sh" build_args = [ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(image), _quote(cluster_name), _quote(arch), _quote(".cp9-build/" + name), _quote(mode), _quote(ctx_path), ] command = " ".join(build_args) if _live_update_enabled(name): command = "CP9_ENABLE_LIVE_UPDATE=1 " + command _resource( name + "-image", command, deps=_starter_source_image_build_deps(name, repo, build_script, mode), labels=["dev-full", "image"], resource_deps=["premium-session-context"] + _source_build_chain_deps("image", name + "-image"), allow_parallel=True, ) return image def _starter_remote_source_image(service): repo = starter_source_image_repositories.get(service, "") if repo == "": fail("terraform output starter_source_image_repositories." + service + " is required for Starter remote-EKS source-build images") return repo + ":local" def _starter_remote_image_resource(name, repo, main, mode): image = _starter_remote_source_image(name) build_script = "../starter/build-local-image.sh" _resource( name + "-image", " ".join([ _quote(build_script), _quote(name), _quote(repo), _quote(main), _quote(image), _quote(""), _quote("amd64"), _quote(".cp9-build/" + name), _quote(mode), _quote(aws_profile), _quote(target_region), ]), deps=_starter_source_image_build_deps(name, repo, build_script, mode), labels=["dev-full", "image"], resource_deps=["premium-session-context"], allow_parallel=True, ) return image def _starter_remote_eks_cluster_name(): return remote_eks.get("cluster_name", "") def _starter_remote_eks_region(): return remote_eks.get("region", target_region) def _starter_remote_eks_context(): context = remote_eks.get("kubeconfig_context", "") if context != "": return context return _starter_remote_eks_cluster_name() def _starter_remote_eks_kubeconfig(): return ".cp9-build/starter-remote-eks/kubeconfig.yaml" starter_remote_owner_artifact_rollout_targets = { "starter-o11y-agent-control-server": { "kind": "kubernetes-deployment", "namespace": "observability", "name": "o11y-agent-control-server", "container": "agent-control-server", }, } def _starter_remote_rollout_target(service): target = starter_remote_owner_artifact_rollout_targets.get(service, None) if target == None: target = _source_backed_contract(service).get("rolloutTarget", {}) if target.get("kind", "") not in ["kubernetes-deployment", "kubernetes-statefulset", "kubernetes-daemonset"]: fail("Starter remote source-backed service must use a supported Kubernetes rollout target: " + service) for field in ["namespace", "name", "container"]: if target.get(field, "") == "": fail("Starter remote source-backed service missing rolloutTarget." + field + ": " + service) return target def _starter_remote_image_rollout_command(name, image): target = _starter_remote_rollout_target(name) profile = "-" if remote_aws_runtime_identity else aws_profile return _image_rollout_stamp_env(name) + " ".join([ _quote("../starter/rollout-starter-remote-image.sh"), _quote(name), _quote(image), _quote(target.get("kind", "")), _quote(target.get("namespace", "")), _quote(target.get("name", "")), _quote(target.get("container", "")), _quote(profile), _quote(_starter_remote_eks_region()), _quote(_starter_remote_eks_cluster_name()), _quote(_starter_remote_eks_kubeconfig()), _quote(_starter_remote_eks_context()), ]) def _starter_remote_image_rollout_resource(name, image): deps = ["../starter/rollout-starter-remote-image.sh", ctx_path] resource_name = name + "-remote-rollout" ownership_label = "source-backed" if terraform_outputs_path != "": deps.append(terraform_outputs_path) if _source_build_enabled(name): deps = deps + _source_image_rollout_deps(name) if name in starter_remote_owner_artifact_rollout_targets: deps.append(_owner_artifact_trigger_path(name)) resource_name = name ownership_label = "owner-artifact" _resource( resource_name, _starter_remote_image_rollout_command(name, image), deps=deps, labels=["dev-full", "starter", ownership_label], resource_deps=["premium-image-source-summary"] + _image_resource_deps(name), allow_parallel=True, ) def _contains(values, needle): for value in values: if value == needle: return True return False def _image_source_services(): return shared_base_services + premium_product_services + starter_product_services + dedicated_product_services def _source_backed_contract_source_build_supported(service): return _source_backed_contract(service).get("sourceBuildSupported", False) def _source_backed_contract_support_status(service): status = _source_backed_contract(service).get("supportStatus", "") if status == "": return "unsupported" return status def _validate_source_backed_contract(service): contract = _source_backed_contract(service) if not contract.get("sourceBuildSupported", False): fail("source_build_services selected unsupported source-backed service " + service + ": " + _source_backed_contract_support_status(service)) source = contract.get("source", {}) if source.get("repo", "") == "": fail("source-backed service contract missing source.repo for " + service) if source.get("main", "") == "": fail("source-backed service contract missing source.main for " + service) image_writer = contract.get("imageWriter", {}) if image_writer.get("kind", "") == "" or image_writer.get("kind", "") == "unsupported": fail("source-backed service contract missing supported image writer for " + service) rollout_target = contract.get("rolloutTarget", {}) if rollout_target.get("kind", "") == "": fail("source-backed service contract missing rollout target for " + service) readiness_check = contract.get("readinessCheck", {}) if readiness_check.get("kind", "") == "": fail("source-backed service contract missing readiness check for " + service) evidence_target = contract.get("evidenceTarget", {}) if evidence_target.get("kind", "") == "": fail("source-backed service contract missing evidence target for " + service) def _validate_premium_source_backed_contract(service): _validate_source_backed_contract(service) contract = _source_backed_contract(service) if contract.get("backend", {}).get("kind", "") != "k3d-control-plane": fail("Premium product service contract must use k3d-control-plane backend: " + service) image_writer = contract.get("imageWriter", {}) if image_writer.get("kind", "") != "tilt-local-image": fail("Premium product service contract must use tilt-local-image writer: " + service) if image_writer.get("resource", "") == "": fail("Premium product service contract missing image writer resource: " + service) def _service_classifications(): return _merge_string_maps(_merge_string_maps(shared_base_service_classifications, starter_service_classifications), dedicated_service_classifications) def _dedicated_gated(service): return _contains(dedicated_gated_services, service) def _dedicated_manifest(service): return dedicated_service_classifications.get(service, {}).get("class", "") == "manifest" def _validate_image_source_config(): seen = {} for service in source_build_services: if not _contains(_image_source_services(), service): fail("source_build_services contains unknown image source service " + service) if service in seen: fail("source_build_services contains duplicate service " + service) seen[service] = True _validate_source_backed_contract(service) # live_update_services is compatibility-only (PRD #664): live-update # derives from source_build_services plus the CP9 capability gate. Entries # are still validated so stale configs fail loudly instead of silently # meaning something different. if len(live_update_services) > 0: print("DEPRECATED: live_update_services is compatibility-only; live-update now derives from source_build_services plus the CP9 source-backed contract registry (PRD #664). Remove the list entries.") live_seen = {} for service in live_update_services: if not _contains(_image_source_services(), service): fail("live_update_services contains unknown image source service " + service) if service in live_seen: fail("live_update_services contains duplicate service " + service) if _contains(starter_remote_product_services, service): fail("live_update_services for Starter remote-EKS service awaits a proven remote restart backend: " + service) live_seen[service] = True if service not in live_update_entrypoints: fail("live_update_entrypoints missing " + service) if service not in live_update_repos: fail("live_update_repos missing " + service) if service not in live_update_mains: fail("live_update_mains missing " + service) if service not in live_update_fallback_paths: fail("live_update_fallback_paths missing " + service) if not _live_update_supported(service): fail("live_update_services contains service without CP9 live-update capability (see the source-backed contract registry): " + service) # The shipped k3d live-update wiring must stay internally consistent now # that no user list forces these lookups: live_update_repos anchors the # wiring, and every wired service needs its entrypoint/main/fallback data. for service in live_update_repos: if not _contains(_image_source_services(), service): fail("live_update_repos contains unknown image source service " + service) if service not in live_update_entrypoints: fail("live_update_entrypoints missing " + service) if service not in live_update_mains: fail("live_update_mains missing " + service) if service not in live_update_fallback_paths: fail("live_update_fallback_paths missing " + service) for service in premium_product_services: _validate_premium_source_backed_contract(service) for service in starter_product_services: if service not in starter_service_classifications: fail("starter_service_classifications missing Starter service " + service) if starter_service_classifications[service].get("class", "") == "": fail("starter_service_classifications[" + service + "].class must not be empty") if _contains(starter_remote_product_services, service): if service not in starter_remote_staging_image_pins: fail("starter_remote_staging_image_pins missing Starter remote service " + service) if starter_remote_staging_image_pins[service] == "": fail("starter_remote_staging_image_pins[" + service + "] must not be empty") else: if service not in staging_image_pins: fail("staging_image_pins missing Starter service " + service) if staging_image_pins[service] == "": fail("staging_image_pins[" + service + "] must not be empty") for service in shared_base_services: if service not in shared_base_service_classifications: fail("shared_base_service_classifications missing shared base service " + service) if shared_base_service_classifications[service].get("class", "") == "": fail("shared_base_service_classifications[" + service + "].class must not be empty") if service not in shared_base_staging_image_pins: fail("shared_base_staging_image_pins missing shared base service " + service) if shared_base_staging_image_pins[service] == "": fail("shared_base_staging_image_pins[" + service + "] must not be empty") gated_seen = {} for service in dedicated_gated_services: if not _contains(dedicated_product_services, service): fail("dedicated_gated_services contains unknown Dedicated service " + service) if service in gated_seen: fail("dedicated_gated_services contains duplicate service " + service) gated_seen[service] = True for service in dedicated_product_services: if service not in dedicated_service_classifications: fail("dedicated_service_classifications missing Dedicated service " + service) if dedicated_service_classifications[service].get("class", "") == "": fail("dedicated_service_classifications[" + service + "].class must not be empty") if _dedicated_manifest(service): continue if _dedicated_gated(service): continue if service not in dedicated_staging_image_pins: fail("dedicated_staging_image_pins missing Dedicated service " + service) if dedicated_staging_image_pins[service] == "": fail("dedicated_staging_image_pins[" + service + "] must not be empty") def _source_build_enabled(service): return _contains(source_build_services, service) def _image_source_mode(): if len(source_build_services) == len(premium_product_services): return "all-source" return "fast-start" def _product_image(service): _validate_premium_source_backed_contract(service) repo = _source_backed_source_repo(service) main = _source_backed_source_main(service) mode = _source_backed_source_mode(service) if _source_build_enabled(service): if _live_update_supported(service): if live_update_repos[service] != repo: fail("live_update_repos[" + service + "] does not match product image repo") if live_update_mains[service] != main: fail("live_update_mains[" + service + "] does not match product image main") _live_update_binary_resource(service, repo, main) return _local_image_resource(service, repo, main, mode) return _source_backed_staging_image(service) def _shared_base_product_image(service): if _source_build_enabled(service): repo = _source_backed_source_repo(service) main = _source_backed_source_main(service) mode = _source_backed_source_mode(service) if repo == "" or main == "": fail("source-backed shared base service missing source repo/main: " + service) if _live_update_supported(service): if live_update_repos[service] != repo: fail("live_update_repos[" + service + "] does not match shared base source repo") if live_update_mains[service] != main: fail("live_update_mains[" + service + "] does not match shared base source main") _live_update_binary_resource(service, repo, main) return _local_image_resource(service, repo, main, mode) return shared_base_staging_image_pins[service] def _dedicated_product_image(service): if _source_build_enabled(service): repo = _source_backed_source_repo(service) main = _source_backed_source_main(service) mode = _source_backed_source_mode(service) if repo == "" or main == "": fail("source-backed Dedicated service missing source repo/main: " + service) if _live_update_supported(service): if live_update_repos[service] != repo: fail("live_update_repos[" + service + "] does not match Dedicated source repo") if live_update_mains[service] != main: fail("live_update_mains[" + service + "] does not match Dedicated source main") _live_update_binary_resource(service, repo, main) return _local_image_resource(service, repo, main, mode) if _dedicated_manifest(service): fail("manifest Dedicated service has no image: " + service) if _dedicated_gated(service): fail("gated Dedicated service has no image: " + service) return dedicated_staging_image_pins[service] def _starter_product_image(service): if _source_build_enabled(service): if service not in starter_product_source_repos: fail("starter_product_source_repos missing Starter service " + service) if service not in starter_product_source_mains: fail("starter_product_source_mains missing Starter service " + service) if service not in starter_product_source_modes: fail("starter_product_source_modes missing Starter service " + service) if _contains(starter_remote_product_services, service): return _starter_remote_image_resource( service, starter_product_source_repos[service], starter_product_source_mains[service], starter_product_source_modes[service], ) if _live_update_supported(service): if live_update_repos[service] != starter_product_source_repos[service]: fail("live_update_repos[" + service + "] does not match Starter product image repo") if live_update_mains[service] != starter_product_source_mains[service]: fail("live_update_mains[" + service + "] does not match Starter product image main") _starter_live_update_binary_resource( service, starter_product_source_repos[service], starter_product_source_mains[service], starter_product_source_modes[service], ) return _starter_local_image_resource( service, starter_product_source_repos[service], starter_product_source_mains[service], starter_product_source_modes[service], ) if _contains(starter_remote_product_services, service): return starter_remote_staging_image_pins[service] return staging_image_pins[service] def _stub_image(service, repo, main, mode = "generic"): if not _contains(always_local_stub_services, service): fail("stub image service is not listed in always_local_stub_services: " + service) return _local_image_resource(service, repo, main, mode) def _image_resource_deps(service): if _source_build_enabled(service): return [service + "-image"] return [] def _image_source_summary_resource_deps(): deps = ["premium-session-context"] for service in _image_source_services(): deps = deps + _image_resource_deps(service) return deps def _image_registry(image): parts = str(image).split("/") if len(parts) < 2 or parts[0] == "": fail("staging image pin must include a registry host: " + image) return parts[0] def _staging_image_pull_secret_required(service): return source_backed_service_contracts.get(service, {}).get("stagingImagePullSecretRequired", True) def _uses_staging_pull_secret(service): return not _source_build_enabled(service) and _staging_image_pull_secret_required(service) def _staging_image_registry(): registry = "" for service in shared_base_staging_image_pins: service_registry = _image_registry(shared_base_staging_image_pins[service]) if registry == "": registry = service_registry elif registry != service_registry: fail("shared base staging image pins must use one ECR registry; got both " + registry + " and " + service_registry) for service in premium_product_services: service_registry = _image_registry(_source_backed_staging_image(service)) if registry == "": registry = service_registry elif registry != service_registry: fail("staging_image_pins must use one ECR registry; got both " + registry + " and " + service_registry) for service in starter_k3d_product_services: service_registry = _image_registry(staging_image_pins[service]) if registry == "": registry = service_registry elif registry != service_registry: fail("staging_image_pins must use one ECR registry; got both " + registry + " and " + service_registry) for service in dedicated_staging_image_pins: if not _staging_image_pull_secret_required(service): continue service_registry = _image_registry(dedicated_staging_image_pins[service]) if registry == "": registry = service_registry elif registry != service_registry: fail("staging image pins must use one ECR registry; got both " + registry + " and " + service_registry) if registry == "": fail("staging_image_pins must include at least one registry") return registry def _needs_staging_image_pull_secret(services): for service in services: if _uses_staging_pull_secret(service): return True return False def _staging_image_pull_secret_resource(target_namespace, namespace_dep): name = "premium-staging-ecr-pull-secret-" + target_namespace _resource( name, _apply_staging_image_pull_secret_command(target_namespace), deps=["./scripts/apply-staging-image-pull-secret.sh"], labels=["dev-full", "image-pull-secret"], resource_deps=[namespace_dep], allow_parallel=True, ) return name def _json_string(value): return "\"" + str(value).replace("\\", "\\\\").replace("\"", "\\\"") + "\"" def _json_string_array(values): parts = [] for value in values: parts.append(_json_string(value)) return "[" + ",".join(parts) + "]" def _json_image_map(services, images): parts = [] for service in services: if service in images: parts.append(_json_string(service) + ":" + _json_string(images[service])) return "{" + ",".join(parts) + "}" def _merge_string_maps(left, right): merged = {} for key in left: merged[key] = left[key] for key in right: merged[key] = right[key] return merged def _json_classification_map(services, classifications): service_parts = [] for service in services: if service not in classifications: continue classification = classifications[service] field_parts = [] for field in ["class", "mode", "selected_image", "staging_image", "source_repo", "source_main", "source_mode", "backend_kind", "backend_scope", "support_status", "evidence", "reason"]: value = classification.get(field, "") if value != "": field_parts.append(_json_string(field) + ":" + _json_string(value)) service_parts.append(_json_string(service) + ":{" + ",".join(field_parts) + "}") return "{" + ",".join(service_parts) + "}" def _staging_image_for_service(service): contract = source_backed_service_contracts.get(service, {}) contract_staging_image = contract.get("stagingImage", "") if contract_staging_image != "": return contract_staging_image if service in shared_base_staging_image_pins: return shared_base_staging_image_pins[service] if service in staging_image_pins: return staging_image_pins[service] if service in starter_remote_staging_image_pins: return starter_remote_staging_image_pins[service] if service in dedicated_staging_image_pins: return dedicated_staging_image_pins[service] return "" def _image_source_summary_services(): return _image_source_services() + always_local_stub_services + ["shared-regional-kong-gateway", "starter-openapi-route-layer"] def _image_source_service_mode(service, base_class): if _contains(always_local_stub_services, service): return "always-local-stub" if _source_build_enabled(service): return "source-backed" if base_class == "gated" or base_class == "manifest": return "gated" if _contains(dedicated_product_services, service) and (_dedicated_gated(service) or _dedicated_manifest(service)): return "gated" return "staging-image" def _put_if_non_empty(values, key, value): if value != "": values[key] = value def _image_source_service_classifications(images): static_classifications = _service_classifications() classifications = {} for service in _image_source_summary_services(): contract = source_backed_service_contracts.get(service, {}) static = static_classifications.get(service, {}) base_class = static.get("class", "") service_mode = _image_source_service_mode(service, base_class) service_class = base_class if service_class == "" or service_mode == "source-backed" or service_mode == "always-local-stub": service_class = service_mode values = { "class": service_class, "mode": service_mode, } _put_if_non_empty(values, "selected_image", images.get(service, "")) _put_if_non_empty(values, "staging_image", _staging_image_for_service(service)) source = contract.get("source", {}) _put_if_non_empty(values, "source_repo", source.get("repo", "")) _put_if_non_empty(values, "source_main", source.get("main", "")) _put_if_non_empty(values, "source_mode", source.get("mode", "")) backend = contract.get("backend", {}) _put_if_non_empty(values, "backend_kind", backend.get("kind", "")) _put_if_non_empty(values, "backend_scope", backend.get("scope", "")) _put_if_non_empty(values, "support_status", contract.get("supportStatus", "")) _put_if_non_empty(values, "evidence", static.get("evidence", "")) reason = static.get("reason", "") if reason == "" and service_mode == "gated": reason = contract.get("supportStatus", "") _put_if_non_empty(values, "reason", reason) classifications[service] = values return classifications def _staging_image_services(): services = [] for service in shared_base_services: if not _source_build_enabled(service): services.append(service) for service in premium_product_services: if not _source_build_enabled(service): services.append(service) for service in starter_product_services: if not _source_build_enabled(service): services.append(service) for service in dedicated_product_services: if _dedicated_gated(service): continue if _dedicated_manifest(service): continue if not _source_build_enabled(service): services.append(service) return services def _dedicated_staging_image_services(): services = [] for service in dedicated_product_services: if _dedicated_gated(service): continue if _dedicated_manifest(service): continue if not _source_build_enabled(service): services.append(service) if o11y_platform_enabled: services.append("dedicated-o11y-agent-control-server") return services def _image_source_summary_json(images): staging_services = _staging_image_services() service_classifications = _image_source_service_classifications(images) return "{" + ",".join([ _json_string("apiVersion") + ":" + _json_string("cp9.premium.image-source/v1alpha1"), _json_string("kind") + ":" + _json_string("PremiumImageSourceSummary"), _json_string("mode") + ":" + _json_string(_image_source_mode()), _json_string("sharedBaseServices") + ":" + _json_string_array(shared_base_services), _json_string("premiumServices") + ":" + _json_string_array(premium_product_services), _json_string("starterServices") + ":" + _json_string_array(starter_product_services), _json_string("dedicatedServices") + ":" + _json_string_array(dedicated_product_services), _json_string("sourceBuildServices") + ":" + _json_string_array(source_build_services), _json_string("stagingImageServices") + ":" + _json_string_array(staging_services), _json_string("alwaysLocalStubServices") + ":" + _json_string_array(always_local_stub_services), _json_string("gatedServices") + ":" + _json_string_array(dedicated_gated_services), _json_string("serviceClassifications") + ":" + _json_classification_map(_image_source_summary_services(), service_classifications), _json_string("images") + ":" + _json_image_map(_image_source_summary_services(), images), ]) + "}" def _write_image_source_summary_command(images): output = evidence_dir + "/premium-image-source-summary.json" return "mkdir -p " + _quote(evidence_dir) + " && printf '%s\\n' " + _quote(_image_source_summary_json(images)) + " > " + _quote(output) crd_wait_default_timeout_seconds = 120 crd_wait_extended_timeout_seconds = 180 _crd_wait_timeout_pattern = "^error: timed out waiting for the condition( on [^[:space:]]+)?$" _crd_established_timeout_pattern = "^(error: )?timed out waiting for the condition( on [^[:space:]]+)?$" _crd_resource_not_found_pattern = "^Error from server \\(NotFound\\): [[:alnum:]./-]+ \"[^\"]+\" not found$" _crd_create_transient_pattern = _crd_wait_timeout_pattern + "|" + _crd_resource_not_found_pattern _crd_established_transient_pattern = _crd_established_timeout_pattern + "|^(error: )?\\.status\\.conditions accessor error: ( is of the type , expected \\[\\]interface\\{\\})?$" def _wait_for_conditions_command(conditions, total_timeout_seconds = crd_wait_default_timeout_seconds): wait_steps = [] for condition in conditions: wait_steps.append( "wait_for_condition " + _quote(condition["wait_for"]) + " " + _quote(condition["transient_pattern"]) + " " + condition["resource_args"] ) return ( "deadline=$(($(date +%s) + " + str(total_timeout_seconds) + "))" + " && wait_for_condition() {" + " wait_for=\"$1\"; shift; transient_pattern=\"$1\"; shift;" + " while :; do" + " now=$(date +%s); remaining=$((deadline - now)); test \"$remaining\" -gt 0 || return 1;" + " if wait_output=$(" + _kubectl_base() + " wait --for=\"$wait_for\" \"$@\" --timeout=\"${remaining}s\" 2>&1 > /dev/null); then" + " return 0;" + " else wait_rc=$?; fi;" + " if [ -n \"$wait_output\" ] && printf '%s\\n' \"$wait_output\" | grep -Eiq \"$transient_pattern\" && ! printf '%s\\n' \"$wait_output\" | grep -Eivq \"$transient_pattern\"; then" + " now=$(date +%s); if [ \"$now\" -ge \"$deadline\" ]; then printf '%s\\n' \"$wait_output\" >&2; return \"$wait_rc\"; fi; sleep 1;" + " else printf '%s\\n' \"$wait_output\" >&2; return \"$wait_rc\";" + " fi;" + " done;" + "}" + " && " + " && ".join(wait_steps) ) def _wait_for_crd_command(name, total_timeout_seconds = crd_wait_default_timeout_seconds): crd_ref = _quote("crd/" + name) return ( "set -eu && " + _wait_for_conditions_command([ { "wait_for": "create", "resource_args": crd_ref, "transient_pattern": _crd_create_transient_pattern, }, { "wait_for": "condition=Established", "resource_args": crd_ref, "transient_pattern": _crd_established_transient_pattern, }, ], total_timeout_seconds) ) _validate_image_source_config() staging_image_registry = _staging_image_registry() session_ns = _namespace_resource(namespace) global_ns = _namespace_resource("cp9-global") premium_ns = _namespace_resource("cp9-premium") metering_ns = _namespace_resource("metering") byoc_runtime_namespace_path = "./cp-byoc-namespace.yaml" byoc_runtime_ns = "ns-cp-byoc" _resource( byoc_runtime_ns, _create_missing_resources_from_file_command(byoc_runtime_namespace_path, ""), deps=[byoc_runtime_namespace_path], labels=["dev-full", "namespace"], ) cp9_system_ns = _namespace_resource("cp9-system") crossplane_system_ns = _namespace_resource("crossplane-system") kong_system_ns = _namespace_resource("kong-system") shared_regional_kong_system_ns = _namespace_resource("shared-regional-kong-system") dataplane_manager_ns = premium_ns dataplane_metadata_ns = _namespace_resource("dataplane-metadata") dedicated_ns = _namespace_resource("cp9-dedicated") dedicated_system_ns = dedicated_ns observability_ns = _namespace_resource("observability") o11y_platform_ns = observability_ns global_staging_image_services = [ "dedicated-global-service", "config-center", "tidb-mgmt-portal", "tidb-mgmt-service", "nextgen-global-service", "account-provider", "account-acl", "account-central", "account-openapi", "dedicated-dataflow-svc", "dataflow", "serverless-service", "serverless-global-service", "tempo-proxy", "tempo-wrapper", ] premium_staging_image_services = [ "ticdc-service", "cluster-ng-server", "cluster-ng-executor", "config-center-regional", "dataplane-manager", ] premium_o11y_resource_deps = [] if o11y_platform_enabled: premium_staging_image_services.append("premium-o11y-agent-control-server") global_staging_pull_secret = "" if _needs_staging_image_pull_secret(global_staging_image_services): global_staging_pull_secret = _staging_image_pull_secret_resource("cp9-global", global_ns) premium_staging_pull_secret = _staging_image_pull_secret_resource("cp9-premium", premium_ns) metering_staging_pull_secret = _staging_image_pull_secret_resource("metering", metering_ns) dedicated_staging_pull_secret = "" if _needs_staging_image_pull_secret(_dedicated_staging_image_services()): dedicated_staging_pull_secret = _staging_image_pull_secret_resource("cp9-dedicated", dedicated_ns) o11y_staging_pull_secret = "" if o11y_platform_enabled: o11y_staging_pull_secret = "o11y-platform-image-pull-secret" _resource( o11y_staging_pull_secret, _apply_o11y_image_pull_secret_command(), deps=["./scripts/apply-staging-image-pull-secret.sh"], labels=["dev-full", "o11y", "image-pull-secret"], resource_deps=[o11y_platform_ns], allow_parallel=True, ) _resource( "o11y-platform-runtime-secrets", _apply_o11y_runtime_secrets_command(), deps=["./scripts/apply-o11y-runtime-secrets.sh"], labels=["dev-full", "o11y", "runtime-secret"], resource_deps=[o11y_platform_ns, premium_ns, dedicated_ns], ) def _staging_image_pull_secret_dep(service): if service == "ticdc-service": return [premium_staging_pull_secret] if _source_build_enabled(service): return [] if service in premium_staging_image_services: return [premium_staging_pull_secret] return [global_staging_pull_secret] def _staging_image_pull_secret_name(service): if not _uses_staging_pull_secret(service): return "" return staging_image_pull_secret def _staging_image_pull_secret_name_for_any(services): for service in services: if _uses_staging_pull_secret(service): return staging_image_pull_secret return "" def _dedicated_staging_image_pull_secret_dep(service): if not _uses_staging_pull_secret(service) or _dedicated_gated(service) or _dedicated_manifest(service): return [] return [dedicated_staging_pull_secret] _resource( "premium-session-context", "mkdir -p " + _quote(evidence_dir) + " && cp " + _quote(ctx_path) + " " + _quote(evidence_dir + "/premium-session-context.json"), deps=[ctx_path], labels=["dev-full", "session-context"], ) # Stub/local dependency resources from the generated Premium graph. _resource("metrics-service", _write_evidence_command("metrics-service", "ready", "session Tiltfile stub"), resource_deps=[session_ns]) tidb_mgmt_portal_image = _product_image("tidb-mgmt-portal") tidb_mgmt_service_image = _product_image("tidb-mgmt-service") nextgen_global_service_image = _product_image("nextgen-global-service") billing_svc_image = _stub_image( "billing-svc", "./billing-plan-stub", "main.go", ) o11y_stub_image = _stub_image( "o11y-stub", "./o11y-stub", "main.go", ) dataflow_image = _product_image("dataflow") ticdc_service_image = _product_image("ticdc-service") cluster_ng_server_image = _product_image("cluster-ng-server") cluster_ng_executor_image = _product_image("cluster-ng-executor") nextgen_metering_server_image = _owner_artifact_image("nextgen-metering-server") config_center_regional_image = _product_image("config-center-regional") dataplane_manager_image = _product_image("dataplane-manager") account_provider_image = _product_image("account-provider") account_acl_image = _product_image("account-acl") account_central_image = _product_image("account-central") account_openapi_image = _product_image("account-openapi") serverless_service_image = _starter_product_image("serverless-service") serverless_global_service_image = _starter_product_image("serverless-global-service") dedicated_global_service_image = _shared_base_product_image("dedicated-global-service") tempo_proxy_image = _product_image("tempo-proxy") tempo_wrapper_image = _product_image("tempo-wrapper") config_center_image = _shared_base_product_image("config-center") regional_server_image = _dedicated_product_image("regional-server") cluster_control_server_image = _dedicated_product_image("cluster-control-server") cluster_controller_image = _dedicated_product_image("cluster-controller") dedicated_webhook_server_image = _dedicated_product_image("dedicated-webhook-server") regional_tcidm_service_image = _dedicated_product_image("regional-tcidm-service") dedicated_dataflow_svc_image = _dedicated_product_image("dedicated-dataflow-svc") dedicated_ticdc_service_image = _dedicated_product_image("dedicated-ticdc-service") dedicated_aws_provider_image = _dedicated_product_image("dedicated-aws-provider") premium_product_images = { "tidb-mgmt-portal": tidb_mgmt_portal_image, "tidb-mgmt-service": tidb_mgmt_service_image, "tempo-proxy": tempo_proxy_image, "tempo-wrapper": tempo_wrapper_image, "nextgen-global-service": nextgen_global_service_image, "account-provider": account_provider_image, "account-acl": account_acl_image, "account-central": account_central_image, "account-openapi": account_openapi_image, "dataflow": dataflow_image, "ticdc-service": ticdc_service_image, "cluster-ng-server": cluster_ng_server_image, "cluster-ng-executor": cluster_ng_executor_image, "config-center-regional": config_center_regional_image, "dataplane-manager": dataplane_manager_image, } starter_product_images = { "serverless-service": serverless_service_image, "serverless-global-service": serverless_global_service_image, } starter_remote_product_images = { service: _starter_product_image(service) for service in starter_remote_product_services } shared_base_product_images = { "dedicated-global-service": dedicated_global_service_image, "config-center": config_center_image, } dedicated_product_images = { "regional-server": regional_server_image, "cluster-control-server": cluster_control_server_image, "cluster-controller": cluster_controller_image, "dedicated-webhook-server": dedicated_webhook_server_image, "regional-tcidm-service": regional_tcidm_service_image, "dedicated-dataflow-svc": dedicated_dataflow_svc_image, "dedicated-ticdc-service": dedicated_ticdc_service_image, "dedicated-aws-provider": dedicated_aws_provider_image, } always_local_stub_images = { "billing-svc": billing_svc_image, "o11y-stub": o11y_stub_image, } image_source_product_images = _merge_string_maps(_merge_string_maps(_merge_string_maps(_merge_string_maps(_merge_string_maps(shared_base_product_images, premium_product_images), starter_product_images), starter_remote_product_images), dedicated_product_images), always_local_stub_images) _resource( "premium-image-source-summary", _write_image_source_summary_command(image_source_product_images), labels=["dev-full", "proof"], resource_deps=_image_source_summary_resource_deps(), ) for service in byoc_source_rollout_deployments: if _source_build_enabled(service): _resource( service + "-byoc-source-rollout", _byoc_source_rollout_command(service), deps=_source_image_rollout_deps(service), labels=["dev-full", "byoc", "source-backed"], resource_deps=[service + "-image"], allow_parallel=True, ) for service in starter_remote_product_services: _starter_remote_image_rollout_resource(service, starter_remote_product_images[service]) starter_o11y_agent_control_server_artifact = "starter-o11y-agent-control-server" _starter_remote_image_rollout_resource( starter_o11y_agent_control_server_artifact, _owner_artifact_image(starter_o11y_agent_control_server_artifact), ) # Live control-plane foundations. _kustomize_image_resource( "premium-metadb", "../../app-delivery/envs/dev-full/premium-metadb", "cp9-system", images=[], resource_deps=[cp9_system_ns], extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _kustomize_resource( "eventbus", "../../app-delivery/envs/dev-full/eventbus", "cp9-global", resource_deps=[global_ns], ) _kustomize_resource( "account-local-dependencies", "../../app-delivery/envs/dev-full/account-local-dependencies", "cp9-global", resource_deps=[global_ns], ) _kustomize_image_resource( "account-svc-config", "../../app-delivery/envs/dev-full/account-svc-config", "cp9-global", # premium-source-aws-credentials mints the aws-creds secret the account # deployments mount; materialize the session-scoped server.secret before # the account workloads start so first rollout sees the patched config. images=[], resource_deps=[global_ns, "premium-metadb", "account-local-dependencies", "premium-source-aws-credentials"], # The apply script patches server.secret (shared Auth0 Management M2M # Secrets Manager key + KMS region) into account-central-conf from the # session context (PRD #571 account unification). extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) def _account_workload_resource(service, path, image): _kustomize_image_resource( service, path, "cp9-global", [ "cp9.local/" + service + ":placeholder=" + image, ], resource_deps=["account-svc-config"] + _staging_image_pull_secret_dep(service) + _image_resource_deps(service), image_pull_secret=_staging_image_pull_secret_name(service), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _account_workload_resource( "account-provider", "../../app-delivery/envs/dev-full/account-provider", account_provider_image, ) _account_workload_resource( "account-acl", "../../app-delivery/envs/dev-full/account-acl", account_acl_image, ) _account_workload_resource( "account-central", "../../app-delivery/envs/dev-full/account-central", account_central_image, ) _account_workload_resource( "account-openapi", "../../app-delivery/envs/dev-full/account-openapi", account_openapi_image, ) _resource( "account-svc", "true", labels=["dev-full", "app-delivery"], resource_deps=account_workload_services, ) _kustomize_image_resource( "billing-svc", "./billing-plan-stub", "cp9-global", [ "cp9.local/billing-plan-stub:placeholder=" + billing_svc_image, ], resource_deps=[global_ns, "billing-svc-image"], ) _kustomize_image_resource( "o11y-stub", "./o11y-stub", "cp9-global", [ "cp9.local/o11y-stub:placeholder=" + o11y_stub_image, ], resource_deps=[global_ns, "o11y-stub-image"], ) _crd_directory_resource( "cluster-ng-service-crds", _owner_crd_path("cluster-ng-service-crds"), "cp9-system", resource_deps=[cp9_system_ns], ) _crd_directory_resource( "ticdc-service-crds", _owner_crd_path("ticdc-service-crds"), "cp9-system", resource_deps=[cp9_system_ns], ) _kustomize_image_resource( "config-center-regional", "../../app-delivery/envs/dev-full/config-center-regional", "cp9-premium", [ "385595570414.dkr.ecr.us-west-2.amazonaws.com/dbaas/nightly/config-center:044bbf126f08579c07f98060ac09b6c44e9c15bd=" + config_center_regional_image, ], resource_deps=[premium_ns, "premium-metadb"] + _staging_image_pull_secret_dep("config-center-regional") + _image_resource_deps("config-center-regional"), image_pull_secret=_staging_image_pull_secret_name("config-center-regional"), ) _crd_directory_resource( "dataplane-manager-crds", _owner_crd_path("dataplane-manager-crds"), "cp9-system", resource_deps=[cp9_system_ns], ) _crd_directory_resource( "o11y-agent-control-server-crds", _owner_crd_path("o11y-agent-control-server-crds"), "cp9-system", resource_deps=[cp9_system_ns], ) _crd_directory_resource( "gateway-api-crds", _owner_crd_path("gateway-api-crds"), "cp9-system", resource_deps=[cp9_system_ns], ) if o11y_platform_enabled: _kustomize_resource( "o11y-platform-crds", "../../app-delivery/envs/dev-full/o11y-platform-crds", "", resource_deps=[o11y_platform_ns], ) _resource( "o11y-platform-crds-ready", _join_commands([ _wait_for_crd_command("vmclusters.operator.victoriametrics.com"), _wait_for_crd_command("vmservicescrapes.operator.victoriametrics.com"), _wait_for_crd_command("clusters.observability.pingcap.com"), _wait_for_crd_command("endpointservices.observability.pingcap.com"), _wait_for_crd_command("iams.observability.pingcap.com"), _wait_for_crd_command("integrationtasks.observability.pingcap.com"), _wait_for_crd_command("kubernetesagents.agent.observability.pingcap.com"), _wait_for_crd_command("o11yk8sagents.agent.observability.pingcap.com"), _wait_for_crd_command("o11ytidbagents.agent.observability.pingcap.com"), _wait_for_crd_command("privateendpoints.observability.pingcap.com"), _wait_for_crd_command("s3s.observability.pingcap.com"), _wait_for_crd_command("sharedpoolagents.agent.observability.pingcap.com"), _wait_for_crd_command("subscriptions.observability.pingcap.com"), _wait_for_crd_command("tidbgroupagents.agent.observability.pingcap.com"), ]), labels=["dev-full", "o11y", "crd"], resource_deps=["o11y-agent-control-server-crds", "o11y-platform-crds"], ) _kustomize_image_resource( "o11y-platform", "../../app-delivery/envs/dev-full/o11y-platform", "observability", [], resource_deps=[ o11y_platform_ns, "o11y-platform-crds-ready", "o11y-platform-runtime-secrets", o11y_staging_pull_secret, ], extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _kustomize_resource( "gateway-crds", "../../app-delivery/envs/dev-full/gateway-crds", "", resource_deps=[kong_system_ns, "gateway-api-crds"], ) _kustomize_resource( "shared-regional-gateway-crds", "../../app-delivery/envs/dev-full/shared-regional-gateway-crds", "", resource_deps=[premium_ns, dedicated_ns, shared_regional_kong_system_ns, "gateway-api-crds"], ) shared_regional_kong_plugin = "o11y-dedicated-route" shared_regional_kong_plugin_dir = "../../app-delivery/base/api-gateway-local/plugins/" + shared_regional_kong_plugin shared_regional_kong_plugin_files = [ shared_regional_kong_plugin_dir + "/handler.lua", shared_regional_kong_plugin_dir + "/schema.lua", ] _resource( "shared-regional-kong-plugin-" + shared_regional_kong_plugin, _kong_plugin_configmap_command(shared_regional_kong_plugin, "shared-regional-kong-system"), deps=shared_regional_kong_plugin_files, labels=["dev-full", "kong-plugin"], resource_deps=[shared_regional_kong_system_ns], ) _helm_resource( "shared-regional-kong-ingress-controller", "../../app-delivery/charts/kong-ingress-controller", "shared-regional-kong-system", ["./shared-regional-kong-ingress-controller/local-values.yaml"], resource_deps=[ kong_system_ns, shared_regional_kong_system_ns, byoc_runtime_ns, observability_ns, "gateway-api-crds", "shared-regional-gateway-crds", "shared-regional-kong-plugin-" + shared_regional_kong_plugin, ], ) _resource( "shared-regional-kong-plugin-rollout", _join_commands([ _kubectl_base("shared-regional-kong-system") + " rollout restart deployment/shared-regional-kong-ingress-controller-kong", _kubectl_base("shared-regional-kong-system") + " rollout status deployment/shared-regional-kong-ingress-controller-kong --timeout=180s", ]), deps=shared_regional_kong_plugin_files, labels=["dev-full", "kong-plugin"], resource_deps=["shared-regional-kong-ingress-controller"], ) shared_regional_kong_proxy_deps = ["shared-regional-kong-plugin-rollout"] if remote_o11y_ingress: _resource( "shared-regional-kong-ingress-controller-remote-proxy", _print_applied_file_command("./shared-regional-kong-ingress-controller/remote-proxy.yaml"), deps=["./shared-regional-kong-ingress-controller/remote-proxy.yaml"], labels=["dev-full", "app-delivery"], resource_deps=["shared-regional-kong-ingress-controller"], ) shared_regional_kong_proxy_deps.append("shared-regional-kong-ingress-controller-remote-proxy") _helm_resource( "nextgen-crossplane", "../../app-delivery/charts/crossplane", "crossplane-system", ["../../app-delivery/envs/dev-full/crossplane/values.yaml"], resource_deps=[crossplane_system_ns], artifact_image=_owner_artifact_image("nextgen-crossplane"), ready_command=_join_commands([ _kubectl_base("crossplane-system") + " rollout status deployment/nextgen-crossplane --timeout=180s", _kubectl_base("crossplane-system") + " rollout status deployment/nextgen-crossplane-rbac-manager --timeout=180s", ]), ) _resource( "nextgen-crossplane-ready", _join_commands([ _wait_for_crd_command("providers.pkg.crossplane.io"), _wait_for_crd_command("deploymentruntimeconfigs.pkg.crossplane.io"), ]), labels=["dev-full", "app-delivery"], resource_deps=["nextgen-crossplane"], allow_parallel=True, ) upbound_provider_base = "../../app-delivery/base/upbound-aws-provider" upbound_provider_runtime_config = upbound_provider_base + "/deploymentruntimeconfig-aws-family.yaml" upbound_provider_default_config = upbound_provider_base + "/providerconfig-default.yaml" upbound_provider_aws_config = upbound_provider_base + "/providerconfig-provider-aws.yaml" if remote_aws_runtime_identity: upbound_provider_runtime_config = upbound_provider_base + "/deploymentruntimeconfig-aws-family-instance-profile.yaml" upbound_provider_default_config = upbound_provider_base + "/providerconfig-default-instance-profile.yaml" upbound_provider_aws_config = upbound_provider_base + "/providerconfig-provider-aws-instance-profile.yaml" _resource( "upbound-aws-provider-credentials", _apply_aws_creds_secret_command("crossplane-system"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[crossplane_system_ns], allow_parallel=True, ) _resource( "dataplane-manager-aws-credentials", _apply_aws_creds_secret_command("cp9-premium"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[dataplane_manager_ns], allow_parallel=True, ) _resource( "metering-aws-credentials", _apply_aws_creds_secret_command("metering"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[metering_ns], allow_parallel=True, ) _resource( "premium-source-aws-credentials", _apply_aws_creds_secret_command("cp9-global"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[global_ns], allow_parallel=True, ) _resource( "dedicated-regional-server-aws-credentials", _apply_aws_creds_secret_command("cp9-dedicated"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[dedicated_ns], allow_parallel=True, ) _resource( "dedicated-aws-provider-credentials", _apply_aws_creds_secret_command("cp9-dedicated"), deps=["./scripts/apply-aws-creds-secret.sh", ctx_path], labels=["dev-full", "app-delivery"], resource_deps=[dedicated_system_ns, "dedicated-regional-server-aws-credentials"], allow_parallel=True, ) _resource( "upbound-aws-provider", _join_commands([ _apply_file_command(upbound_provider_base + "/serviceaccount.yaml", "crossplane-system"), _apply_file_command(upbound_provider_runtime_config), ]), deps=[ upbound_provider_base + "/serviceaccount.yaml", upbound_provider_runtime_config, ], labels=["dev-full", "app-delivery"], resource_deps=[crossplane_system_ns, "nextgen-crossplane-ready"], allow_parallel=True, ) premium_upbound_provider_specs = [ {"artifact": "premium-upbound-provider-family-aws", "manifest": upbound_provider_base + "/provider-family-aws.yaml"}, {"artifact": "premium-upbound-provider-aws-iam", "manifest": upbound_provider_base + "/upbound-provider-aws-iam.yaml"}, {"artifact": "premium-upbound-provider-aws-route53", "manifest": upbound_provider_base + "/upbound-provider-aws-route53.yaml"}, {"artifact": "premium-upbound-provider-aws-ec2", "manifest": upbound_provider_base + "/upbound-provider-aws-ec2.yaml"}, {"artifact": "premium-upbound-provider-aws-eks", "manifest": upbound_provider_base + "/upbound-provider-aws-eks.yaml"}, {"artifact": "premium-upbound-provider-aws-s3", "manifest": upbound_provider_base + "/upbound-provider-aws-s3.yaml"}, {"artifact": "premium-upbound-provider-aws-kms", "manifest": upbound_provider_base + "/upbound-provider-aws-kms.yaml"}, ] premium_upbound_provider_resources = [] for provider_spec in premium_upbound_provider_specs: artifact_name = provider_spec["artifact"] provider_manifest = provider_spec["manifest"] _resource( artifact_name, _apply_crossplane_provider_package_command(provider_manifest, _owner_artifact_image(artifact_name)), deps=[provider_manifest, "./scripts/apply-crossplane-provider-package.sh", _owner_artifact_trigger_path(artifact_name)], labels=["dev-full", "app-delivery", "crossplane"], resource_deps=[crossplane_system_ns, "nextgen-crossplane-ready", "upbound-aws-provider"], allow_parallel=True, ) premium_upbound_provider_resources.append(artifact_name) _resource( "upbound-aws-provider-providerconfigs", _join_commands([ _wait_for_crd_command("providerconfigs.aws.upbound.io", crd_wait_extended_timeout_seconds), _apply_file_command(upbound_provider_default_config), _apply_file_command(upbound_provider_aws_config), ]), deps=[ upbound_provider_default_config, upbound_provider_aws_config, ], labels=["dev-full", "app-delivery"], resource_deps=["upbound-aws-provider", "upbound-aws-provider-credentials"] + premium_upbound_provider_resources, allow_parallel=True, ) # Imported Dedicated runtime surface. These services run inside the Premium # persona so Dedicated OpenAPI can be proved without reintroducing a # standalone Dedicated persona target. _resource( "dedicated-api-host-ready", " ".join([ _quote("./scripts/ensure-dedicated-api-host.sh"), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(dedicated_api_host_manifest), ]), deps=[ "./scripts/ensure-dedicated-api-host.sh", dedicated_api_admin_kubeconfig, dedicated_api_host_manifest, ], labels=["dev-full", "app-delivery", "dedicated-api"], resource_deps=[cp9_system_ns, dedicated_ns], ) dedicated_crossplane_crds = [ _owner_crd_path("dedicated-crossplane-aws-crds"), "../../app-delivery/envs/dev-full/dedicated-ticdc-api-crds/provider-aws-eks-v1.21.1-crds.json", ] _resource( "dedicated-crossplane-aws-crds", _join_commands([ " ".join([ _quote("./scripts/apply-crd-artifact.sh"), _quote(crds), _quote(dedicated_api_admin_kubeconfig), _quote("cp9-dedicated"), _quote("180s"), ]) for crds in dedicated_crossplane_crds ]), deps=["./scripts/apply-crd-artifact.sh", dedicated_api_admin_kubeconfig] + dedicated_crossplane_crds, labels=["dev-full", "app-delivery", "dedicated-api", "crd"], resource_deps=["dedicated-api-host-ready"], ) _resource( "dedicated-infra-api-crds", "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + " ".join([ _quote("./scripts/bootstrap-dedicated-api.sh"), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(dedicated_api_bootstrap_manifest), _quote(_owner_crd_path("dedicated-regional-api-crds")), _quote(_owner_crd_path("dedicated-infra-api-crds")), _quote(_owner_crd_path("dedicated-dm-api-crds")), _quote(_owner_crd_path("dedicated-ticdc-api-crds")), _quote(_owner_crd_path("o11y-agent-control-server-crds")), _quote("../../app-delivery/envs/dev-full/dedicated-cluster-control-server-support"), _quote("../../app-delivery/envs/dev-full/regional-server/account-list.yaml"), _quote("../../app-delivery/envs/dev-full/dedicated-infra-api-crds/dm-provider.yaml"), _quote(evidence_dir + "/dedicated-api-bootstrap.json"), ]), deps=[ "./scripts/bootstrap-dedicated-api.sh", "./scripts/render-dedicated-account-contract.py", dedicated_api_admin_kubeconfig, dedicated_api_bootstrap_manifest, ctx_path, _owner_crd_path("dedicated-regional-api-crds"), _owner_crd_path("dedicated-infra-api-crds"), _owner_crd_path("dedicated-dm-api-crds"), _owner_crd_path("dedicated-ticdc-api-crds"), _owner_crd_path("o11y-agent-control-server-crds"), "../../app-delivery/envs/dev-full/dedicated-cluster-control-server-support", "../../app-delivery/envs/dev-full/regional-server/account-list.yaml", "../../app-delivery/envs/dev-full/dedicated-infra-api-crds/dm-provider.yaml", ], labels=["dev-full", "app-delivery", "dedicated-api"], resource_deps=["dedicated-crossplane-aws-crds"], ) _kustomize_image_resource( "dedicated-aws-provider", "../../app-delivery/envs/dev-full/dedicated-aws-provider", "cp9-dedicated", images=[ "cp9.local/dedicated-aws-provider:placeholder=" + dedicated_aws_provider_image, ], resource_deps=[dedicated_ns, "dedicated-infra-api-crds", "dedicated-aws-provider-credentials"] + _dedicated_staging_image_pull_secret_dep("dedicated-aws-provider"), image_pull_secret=_staging_image_pull_secret_name("dedicated-aws-provider"), extra_deps=[_owner_artifact_trigger_path("dedicated-aws-provider")], ready_command=_kubectl_base("cp9-dedicated") + " rollout status deployment/aws-provider-upstream --timeout=180s", ) _kustomize_image_resource( "config-center", "../../app-delivery/envs/dev-full/config-center", "cp9-global", [ "cp9.local/config-center:placeholder=" + config_center_image, ], resource_deps=[ global_ns, "premium-metadb", ] + _staging_image_pull_secret_dep("config-center"), image_pull_secret=staging_image_pull_secret, ) _kustomize_image_resource( "dedicated-dataflow-svc", "../../app-delivery/envs/dev-full/dedicated-dataflow-svc", "cp9-global", [ "cp9.local/dataflow-svc:placeholder=" + dedicated_dataflow_svc_image, ], resource_deps=[ global_ns, "eventbus", "premium-metadb", "account-svc", "billing-svc", "config-center", ] + _staging_image_pull_secret_dep("dedicated-dataflow-svc") + _image_resource_deps("dedicated-dataflow-svc"), image_pull_secret=_staging_image_pull_secret_name("dedicated-dataflow-svc"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _resource( "dedicated-global-service-seed", "./scripts/apply-dedicated-global-service-seed.sh " + _quote(kubeconfig) + " " + _quote(kube_context) + " " + _quote("../../app-delivery/envs/premium/premium-metadb/64-dedicated-global-service-local-seed-20260625.sql"), deps=[ "./scripts/apply-dedicated-global-service-seed.sh", "../../app-delivery/envs/premium/premium-metadb/64-dedicated-global-service-local-seed-20260625.sql", ], labels=["dev-full", "app-delivery"], resource_deps=["premium-metadb"], ) dedicated_global_service_gcp_seed_deps = [] if gcp_regional_endpoint_url != "": _resource( "dedicated-global-service-gcp-seed", "CP9_GCP_REGIONAL_ENDPOINT_URL=" + _quote(gcp_regional_endpoint_url) + " " + "./scripts/apply-dedicated-global-service-seed.sh " + _quote(kubeconfig) + " " + _quote(kube_context) + " " + _quote("../../app-delivery/envs/premium/premium-metadb/69-dedicated-gcp-catalog-cp9-20260831.sql"), deps=[ "./scripts/apply-dedicated-global-service-seed.sh", "../../app-delivery/envs/premium/premium-metadb/69-dedicated-gcp-catalog-cp9-20260831.sql", ctx_path, ], labels=["dev-full", "app-delivery", "gcp-catalog"], resource_deps=["dedicated-global-service-seed"], ) dedicated_global_service_gcp_seed_deps.append("dedicated-global-service-gcp-seed") _dedicated_global_service_resource( "../../app-delivery/envs/dev-full/dedicated-global-service", "cp9-global", [ "cp9.local/dedicated-global-service:placeholder=" + dedicated_global_service_image, ], resource_deps=[ global_ns, "eventbus", "premium-metadb", "account-svc", "billing-svc", "config-center", "dedicated-dataflow-svc", "dedicated-global-service-seed", ] + dedicated_global_service_gcp_seed_deps + _staging_image_pull_secret_dep("dedicated-global-service"), image_pull_secret=staging_image_pull_secret, ) _kustomize_image_resource( "tempo-proxy", "../../app-delivery/envs/dev-full/tempo-proxy", "cp9-global", [ "cp9.local/tempo-proxy:placeholder=" + tempo_proxy_image, ], resource_deps=[ global_ns, "account-provider", "tidb-mgmt-service", "serverless-global-service", "dedicated-global-service", ] + _staging_image_pull_secret_dep("tempo-proxy") + _image_resource_deps("tempo-proxy"), image_pull_secret=_staging_image_pull_secret_name("tempo-proxy"), ) _kustomize_image_resource( "tempo-wrapper", "../../app-delivery/envs/dev-full/tempo-wrapper", "cp9-global", [ "cp9.local/tempo-wrapper:placeholder=" + tempo_wrapper_image, ], resource_deps=[ global_ns, "account-provider", "account-acl", "tidb-mgmt-service", "dedicated-global-service", ] + _staging_image_pull_secret_dep("tempo-wrapper") + _image_resource_deps("tempo-wrapper"), image_pull_secret=_staging_image_pull_secret_name("tempo-wrapper"), ) _regional_server_resource( "../../app-delivery/envs/dev-full/regional-server", "cp9-dedicated", [ "cp9.local/regional-server:placeholder=" + regional_server_image, ], resource_deps=[ dedicated_ns, observability_ns, "dedicated-infra-api-crds", "dedicated-regional-server-aws-credentials", "dedicated-aws-provider", ] + _dedicated_staging_image_pull_secret_dep("regional-server"), image_pull_secret=staging_image_pull_secret, ) if o11y_platform_enabled: _kustomize_image_resource( "dedicated-o11y-agent-control-server", "../../app-delivery/envs/dev-full/dedicated-o11y-agent-control-server", "cp9-dedicated", [ "cp9.local/dedicated-o11y-agent-control-server:placeholder=" + _owner_artifact_image("dedicated-o11y-agent-control-server"), ], resource_deps=[ "regional-server", "o11y-platform", "o11y-platform-crds-ready", "o11y-platform-gateway", "o11y-platform-runtime-secrets", dedicated_staging_pull_secret, ], image_pull_secret=staging_image_pull_secret, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", extra_deps=[_owner_artifact_trigger_path("dedicated-o11y-agent-control-server")], ready_command=_kubectl_base("cp9-dedicated") + " rollout status deployment/o11y-agent-control-server --timeout=180s", ) _resource( "cluster-control-server-support", "true", labels=["dev-full", "app-delivery", "dedicated-api"], resource_deps=["dedicated-infra-api-crds"], ) _dedicated_webhook_server_resource( "../../app-delivery/envs/dev-full/dedicated-webhook-server", "../../app-delivery/envs/dev-full/dedicated-webhook-server-api", "cp9-dedicated", dedicated_webhook_server_image, resource_deps=[ dedicated_ns, "dedicated-infra-api-crds", ] + _dedicated_staging_image_pull_secret_dep("dedicated-webhook-server"), image_pull_secret=staging_image_pull_secret, ) if o11y_platform_enabled: _kustomize_resource( "dedicated-webhook-server-metrics", "../../app-delivery/envs/dev-full/dedicated-webhook-server-metrics", "cp9-dedicated", resource_deps=[ dedicated_ns, "dedicated-webhook-server", "o11y-platform-crds-ready", ], ) _kustomize_image_resource( "cluster-control-server", "../../app-delivery/envs/dev-full/dedicated-cluster-control-server", "cp9-dedicated", [ "cp9.local/cluster-control-server:placeholder=" + cluster_control_server_image, ], resource_deps=[ dedicated_ns, "dedicated-infra-api-crds", "cluster-control-server-support", "dedicated-webhook-server", "account-svc-config", ] + _dedicated_staging_image_pull_secret_dep("cluster-control-server"), image_pull_secret=staging_image_pull_secret, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _dedicated_cluster_controller_resource( "cluster-controller", "../../app-delivery/envs/dev-full/dedicated-cluster-controller", "cp9-dedicated", [ "cp9.local/cluster-controller:placeholder=" + cluster_controller_image, ], resource_deps=[ dedicated_ns, "dedicated-infra-api-crds", "dedicated-aws-provider", "cluster-control-server", "dedicated-webhook-server", ] + _dedicated_staging_image_pull_secret_dep("cluster-controller"), image_pull_secret=staging_image_pull_secret, ) _kustomize_image_resource( "regional-tcidm-service", "../../app-delivery/envs/dev-full/regional-tcidm-service", "cp9-dedicated", [ "cp9.local/regional-tcidm-service:placeholder=" + regional_tcidm_service_image, ], resource_deps=[ dedicated_ns, "regional-server", ] + _dedicated_staging_image_pull_secret_dep("regional-tcidm-service"), image_pull_secret=staging_image_pull_secret, ) _kustomize_image_resource( "dedicated-upbound-family", "../../app-delivery/envs/dev-full/dedicated-upbound-family", "cp9-dedicated", [ "cp9.local/dedicated-upbound-family:placeholder=" + _owner_artifact_image("dedicated-upbound-family"), ], resource_deps=[dedicated_ns, "dedicated-infra-api-crds", "dedicated-aws-provider-credentials"], image_pull_secret=staging_image_pull_secret, extra_deps=[_owner_artifact_trigger_path("dedicated-upbound-family")], ready_command=_kubectl_base("cp9-dedicated") + " rollout status deployment/dedicated-upbound-family --timeout=180s", ) _kustomize_image_resource( "dedicated-upbound-eks", "../../app-delivery/envs/dev-full/dedicated-upbound-eks", "cp9-dedicated", [ "cp9.local/dedicated-upbound-eks:placeholder=" + _owner_artifact_image("dedicated-upbound-eks"), ], resource_deps=[dedicated_ns, "dedicated-infra-api-crds", "dedicated-aws-provider-credentials"], image_pull_secret=staging_image_pull_secret, extra_deps=[_owner_artifact_trigger_path("dedicated-upbound-eks")], ready_command=_kubectl_base("cp9-dedicated") + " rollout status deployment/dedicated-upbound-eks --timeout=180s", ) _kustomize_image_resource( "dedicated-ticdc-service", "../../app-delivery/envs/dev-full/dedicated-ticdc-service", "cp9-dedicated", [ "cp9.local/dedicated-ticdc-service:placeholder=" + dedicated_ticdc_service_image, ], resource_deps=[ dedicated_ns, "dedicated-infra-api-crds", "dedicated-aws-provider-credentials", "dedicated-upbound-family", "dedicated-upbound-eks", "regional-server", ] + _dedicated_staging_image_pull_secret_dep("dedicated-ticdc-service"), image_pull_secret=staging_image_pull_secret, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) console_auth_plugin_names = [ "cookie-filter", "bearer-token-fallback", "cookie-auth", "console-header-management", ] kong_plugin_names = ["force-https", "digest-auth", "rate-limit", "o11y-dedicated-route"] + console_auth_plugin_names kong_plugin_files = [] for plugin_name in kong_plugin_names: plugin_dir = "../../app-delivery/base/api-gateway-local/plugins/" + plugin_name plugin_files = [plugin_dir + "/handler.lua", plugin_dir + "/schema.lua"] kong_plugin_files += plugin_files _resource( "kong-plugin-" + plugin_name, _kong_plugin_configmap_command(plugin_name), deps=plugin_files, labels=["dev-full", "kong-plugin"], resource_deps=[kong_system_ns], ) _helm_resource( "kong-ingress-controller", "../../app-delivery/charts/kong-ingress-controller", "kong-system", ["./kong-ingress-controller/local-values.yaml"], resource_deps=[ kong_system_ns, shared_regional_kong_system_ns, observability_ns, "gateway-api-crds", "gateway-crds", ] + ["kong-plugin-" + plugin_name for plugin_name in kong_plugin_names], ) _resource( "kong-plugin-rollout", _join_commands([ _kubectl_base("kong-system") + " rollout restart deployment/kong-ingress-controller-kong", _kubectl_base("kong-system") + " rollout status deployment/kong-ingress-controller-kong --timeout=180s", ]), deps=kong_plugin_files, labels=["dev-full", "kong-plugin"], resource_deps=["kong-ingress-controller"], ) if o11y_platform_enabled: _kustomize_image_resource( "o11y-platform-gateway", "../../app-delivery/envs/dev-full/o11y-platform/gateway", "", [], resource_deps=[ "o11y-platform", "gateway-crds", "kong-plugin-rollout", ] + shared_regional_kong_proxy_deps, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _kustomize_image_resource( "premium-o11y-agent-control-server", "../../app-delivery/envs/dev-full/premium-o11y-agent-control-server", "cp9-premium", [ "cp9.local/premium-o11y-agent-control-server:placeholder=" + _owner_artifact_image("premium-o11y-agent-control-server"), ], resource_deps=[ premium_ns, "o11y-platform", "o11y-platform-crds-ready", "o11y-platform-gateway", "o11y-platform-runtime-secrets", ] + _staging_image_pull_secret_dep("premium-o11y-agent-control-server"), image_pull_secret=_staging_image_pull_secret_name("premium-o11y-agent-control-server"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", extra_deps=[_owner_artifact_trigger_path("premium-o11y-agent-control-server")], ready_command=_kubectl_base("cp9-premium") + " rollout status deployment/o11y-agent-control-server --timeout=180s", ) premium_o11y_resource_deps = ["premium-o11y-agent-control-server"] kong_openapi_plugins = "../../app-delivery/base/api-gateway-local-premium/kong-plugins.yaml" kong_console_auth_plugins = "../../app-delivery/base/api-gateway-local-premium/console-auth-plugins.yaml" _resource( "kong-openapi-plugins", _join_commands([ _wait_for_crd_command("kongclusterplugins.configuration.konghq.com", crd_wait_extended_timeout_seconds), _apply_file_command(kong_openapi_plugins), _apply_file_command(kong_console_auth_plugins), ]), deps=[kong_openapi_plugins, kong_console_auth_plugins], labels=["dev-full", "kong-plugin"], resource_deps=["kong-plugin-rollout"], ) # Premium source/live application graph. These are direct Session Tiltfile # resources now; cp9 no longer generates service scripts or app-delivery inputs. _kustomize_image_resource( "nextgen-global-service", "../../app-delivery/envs/dev-full/nextgen-global-service", "cp9-global", [ "cp9.local/nextgen-global-service:placeholder=" + nextgen_global_service_image, ], resource_deps=[global_ns, "eventbus", "premium-metadb", "account-svc", "cluster-ng-server", "kong-ingress-controller"] + _staging_image_pull_secret_dep("nextgen-global-service") + _image_resource_deps("nextgen-global-service"), image_pull_secret=_staging_image_pull_secret_name("nextgen-global-service"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _dataplane_manager_resource( "../../app-delivery/envs/dev-full/dataplane-manager", "cp9-premium", [ "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/dataplane-manager:17c3c9bc2bcfda9c67b9d77d2395ec9f4d373384@sha256:dbd2ce62e131a43442e1a0dfb83a83356f9d94a5c7ab95d85cda0134bda3a89a=" + dataplane_manager_image, ], resource_deps=[ dataplane_manager_ns, dataplane_metadata_ns, "config-center-regional", "nextgen-crossplane", "dataplane-manager-crds", "upbound-aws-provider", "upbound-aws-provider-credentials", "upbound-aws-provider-providerconfigs", "dataplane-manager-aws-credentials", "premium-session-context", ] + premium_o11y_resource_deps + _staging_image_pull_secret_dep("dataplane-manager") + _image_resource_deps("dataplane-manager"), image_pull_secret=_staging_image_pull_secret_name("dataplane-manager"), ) _kustomize_image_resource( "metering", "../../app-delivery/envs/dev-full/nextgen-metering-server", "metering", [ "cp9.local/nextgen-metering-server:placeholder=" + nextgen_metering_server_image, ], resource_deps=[ metering_ns, "metering-aws-credentials", metering_staging_pull_secret, "premium-session-context", ], image_pull_secret=staging_image_pull_secret, extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", extra_deps=[_owner_artifact_trigger_path("nextgen-metering-server")], ready_command=_kubectl_base("metering") + " rollout status statefulset/nextgen-metering-server --timeout=180s", ) _kustomize_image_resource( "cluster-ng-server", "../../app-delivery/envs/dev-full/cluster-ng-server", "cp9-premium", [ "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/cluster-service-ng:main-17c3c9bc2bcfda9c67b9d77d2395ec9f4d373384@sha256:c9808e7f060795f276bdbe66190757abbf5887ad7f4ba0e8a08f1c933cb8ef0e=" + cluster_ng_server_image, ], resource_deps=[ premium_ns, "cluster-ng-service-crds", "config-center-regional", "dataplane-manager", "o11y-agent-control-server-crds", "premium-metadb", "dataplane-manager-aws-credentials", "shared-regional-gateway-crds", ] + _staging_image_pull_secret_dep("cluster-ng-server") + _image_resource_deps("cluster-ng-server"), image_pull_secret=_staging_image_pull_secret_name("cluster-ng-server"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _kustomize_image_resource( "cluster-ng-executor", "../../app-delivery/envs/dev-full/cluster-ng-executor", "cp9-premium", [ "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/ng-executor:release-v0.31-5506a950e74516c28b915fa22c8f4bd54c984a88=" + cluster_ng_executor_image, ], resource_deps=[premium_ns, "billing-svc", "cluster-ng-server", "dataplane-manager-aws-credentials"] + _staging_image_pull_secret_dep("cluster-ng-executor") + _image_resource_deps("cluster-ng-executor"), image_pull_secret=_staging_image_pull_secret_name("cluster-ng-executor"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _file_custom_deploy_resource( "serverless-service-leader-election-rbac", "../../app-delivery/envs/dev-full/serverless-service/leader-election-rbac.yaml", "default", resource_deps=[global_ns], ) _starter_local_global_service_resource( "serverless-service", "../../app-delivery/envs/dev-full/serverless-service", "cp9-global", [ "public.ecr.aws/docker/library/nginx:1.27-alpine=" + serverless_service_image, ], resource_deps=[ global_ns, "eventbus", "account-svc", "billing-svc", "o11y-stub", "premium-metadb", "config-center", ] + _staging_image_pull_secret_dep("serverless-service") + _image_resource_deps("serverless-service"), image_pull_secret=_staging_image_pull_secret_name("serverless-service"), ) _starter_local_global_service_resource( "serverless-global-service", "../../app-delivery/envs/dev-full/serverless-global-service", "cp9-global", [ "public.ecr.aws/docker/library/nginx:1.27-alpine=" + serverless_global_service_image, ], resource_deps=[ global_ns, "eventbus", "account-svc", "billing-svc", "premium-metadb", "premium-source-aws-credentials", "serverless-service", ] + _staging_image_pull_secret_dep("serverless-global-service") + _image_resource_deps("serverless-global-service"), image_pull_secret=_staging_image_pull_secret_name("serverless-global-service"), ) _kustomize_image_resource( "tidb-mgmt-service", "../../app-delivery/envs/dev-full/tidb-mgmt-service", "cp9-global", [ "cp9.local/tidb-mgmt-service:placeholder=" + tidb_mgmt_service_image, ], resource_deps=[global_ns, "eventbus", "nextgen-global-service", "serverless-global-service", "serverless-service", "premium-metadb", "account-svc"] + _staging_image_pull_secret_dep("tidb-mgmt-service") + _image_resource_deps("tidb-mgmt-service"), image_pull_secret=_staging_image_pull_secret_name("tidb-mgmt-service"), ) _kustomize_image_resource( "dataflow", "../../app-delivery/envs/dev-full/dataflow", "cp9-global", [ "cp9.local/dataflow:placeholder=" + dataflow_image, ], resource_deps=[ global_ns, "eventbus", "config-center-regional", "nextgen-global-service", "premium-metadb", "account-svc", "tidb-mgmt-service", "ticdc-service", ] + _staging_image_pull_secret_dep("dataflow") + _image_resource_deps("dataflow"), image_pull_secret=_staging_image_pull_secret_name("dataflow"), extra_env="CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " ", ) _kustomize_image_resource( "ticdc-service", "../../app-delivery/envs/dev-full/ticdc-service", "cp9-premium", [ "cp9.local/ticdc-service:placeholder=" + ticdc_service_image, ], resource_deps=[ premium_ns, "ticdc-service-crds", "cluster-ng-server", "dataplane-manager", "dataplane-manager-aws-credentials", ] + _staging_image_pull_secret_dep("ticdc-service") + _image_resource_deps("ticdc-service"), image_pull_secret=_staging_image_pull_secret_name("ticdc-service"), ) _kustomize_image_resource( "tidb-mgmt-portal", "../../app-delivery/envs/dev-full/tidb-mgmt-portal", "cp9-global", [ "cp9.local/tidb-mgmt-portal:placeholder=" + tidb_mgmt_portal_image, ], resource_deps=[global_ns, "nextgen-global-service", "serverless-global-service", "tidb-mgmt-service", "account-svc"] + _staging_image_pull_secret_dep("tidb-mgmt-portal") + _image_resource_deps("tidb-mgmt-portal"), image_pull_secret=_staging_image_pull_secret_name("tidb-mgmt-portal"), ) _kustomize_resource( "api-gateway-local", "../../app-delivery/envs/dev-full/api-gateway-local-premium", "cp9-global", resource_deps=[global_ns, "kong-openapi-plugins", "account-local-dependencies", "tidb-mgmt-portal", "tidb-mgmt-service", "tempo-wrapper", "serverless-service", "dataflow"], ) # The built-in browser UI is a mandatory Remote Dev full slice. Local sessions # omit the `ui` context entirely, so they materialize no workload, route, # runtime configuration, URL, or implicit port-forward contract. if ui: if host.get("mode", "") != "remote-ec2-k3d": fail("dbaas-ui is supported only on remote-ec2-k3d") ui_path = "../../app-delivery/envs/dev-full/dbaas-ui" ui_namespace = "cp9-global" ui_runtime_config_path = ui.get("runtime_config_path", "") ui_placeholder_path = "../../app-delivery/base/dbaas-ui-route-parity/routing-placeholders.yaml" if ui_runtime_config_path == "": fail("dbaas-ui requires a generated per-session runtime config") ui_resource_deps = [ global_ns, "kong-ingress-controller", "kong-openapi-plugins", "dataflow", "dedicated-dataflow-svc", ] if global_staging_pull_secret != "": ui_resource_deps.append(global_staging_pull_secret) _resource( "dbaas-ui", _join_commands([ _apply_dbaas_ui_command(ui_path, ui_namespace, ui_runtime_config_path), _create_missing_resources_from_file_command(ui_placeholder_path, ui_namespace), ]), deps=[ui_path, ui_runtime_config_path, ui_placeholder_path], labels=["dev-full", "app-delivery", "browser-ui"], resource_deps=ui_resource_deps, allow_parallel=True, ) def _premium_openapi_probe_command(): ingress_output = evidence_dir + "/premium-openapi-tidbs-ingress.json" backend_output = evidence_dir + "/tidb-mgmt-portal-rollout.json" return ( _kubectl_base("cp9-global") + " get ingress premium-openapi-tidbs -o json > " + _quote(ingress_output) + " && " + _kubectl_base("cp9-global") + " rollout status deployment/tidb-mgmt-portal --timeout=120s" + " && printf '%s\\n' " + _quote(_json_status("ready", "tidb-mgmt-portal rollout complete")) + " > " + _quote(backend_output) ) def _starter_openapi_surfaces_probe_command(): output = evidence_dir + "/starter-openapi-surfaces.json" return ( _kubectl_base("cp9-global") + " get service tidb-mgmt-portal serverless-svc-http serverless-svc-grpc serverless-global-service tidb-mgmt-service -o json > " + _quote(output) ) def _starter_openapi_route_inventory_command(): return _join_commands([ "mkdir -p " + _quote(evidence_dir), _kubectl_base("cp9-global") + " get ingress premium-openapi-tidbs starter-openapi-serverless -o json > " + _quote(evidence_dir + "/starter-openapi-route-ingresses.json"), _kubectl_base() + " get kongclusterplugins.configuration.konghq.com openapi-plugin-force-https openapi-plugin-digest-auth openapi-plugin-rate-limit -o json > " + _quote(evidence_dir + "/starter-openapi-kong-plugins.json"), _kubectl_base("kong-system") + " get service/kong-ingress-controller-kong-proxy deployment/kong-ingress-controller-kong -o json > " + _quote(evidence_dir + "/starter-openapi-kong-runtime.json"), _kubectl_base("cp9-global") + " get service tidb-mgmt-portal serverless-svc-http -o json > " + _quote(evidence_dir + "/starter-openapi-backend-services.json"), _kubectl_base("cp9-global") + " get endpoints tidb-mgmt-portal serverless-svc-http -o json > " + _quote(evidence_dir + "/starter-openapi-backend-endpoints.json"), "printf '%s\\n' " + _quote(_json_status("ready", "Starter OpenAPI route inventory captured inside the Dev full gateway layer")) + " > " + _quote(evidence_dir + "/starter-openapi-route-inventory.json"), ]) def _starter_openapi_route_probe_command(name, surface, path, backend_ready_command): output = evidence_dir + "/" + name + ".txt" logs_output = evidence_dir + "/" + name + "-kong.log" request_id = session_name + "-" + name probe_name = _sanitize(name) url = "http://kong-ingress-controller-kong-proxy.kong-system.svc.cluster.local" + path curl_command = ( _kubectl_base("cp9-global") + " delete pod " + _quote(probe_name) + " --ignore-not-found" + " && " + _kubectl_base("cp9-global") + " run " + _quote(probe_name) + " --restart=Never --rm -i --attach=true --image=curlimages/curl:8.11.1 --command -- curl -sS --max-time 20" + " -H " + _quote("X-Request-Id: " + request_id) + " -H " + _quote("X-Forwarded-Proto: https") + " -o /tmp/response-body -w " + _quote("HTTP_STATUS=%{http_code}\\n") + " " + _quote(url) ) return _join_commands([ "mkdir -p " + _quote(evidence_dir), _kubectl_base("kong-system") + " rollout status deployment/kong-ingress-controller-kong --timeout=120s", backend_ready_command, "printf '%s\\n' " + _quote("surface=" + surface + " path=" + path + " request_id=" + request_id) + " > " + _quote(output), "( (" + curl_command + ") >> " + _quote(output) + " || true )", "( " + _kubectl_base("kong-system") + " logs deployment/kong-ingress-controller-kong --all-containers=true --tail=200 > " + _quote(logs_output) + " || true )", "grep -Eq " + _quote("HTTP_STATUS=(200|201|202|204|400|401|403|409|500|502|503)") + " " + _quote(output), "! grep -Eq " + _quote("HTTP_STATUS=(000|404)") + " " + _quote(output), ]) _resource( "premium-openapi-tidbs-ingress", _premium_openapi_probe_command(), labels=["dev-full", "ingress", "proof"], resource_deps=["api-gateway-local"], ) _resource( "starter-openapi-surfaces", _starter_openapi_surfaces_probe_command(), labels=["dev-full", "starter-openapi", "proof"], resource_deps=["tidb-mgmt-portal", "serverless-service", "serverless-global-service", "tidb-mgmt-service"], ) _resource( "starter-openapi-route-inventory", _starter_openapi_route_inventory_command(), labels=["dev-full", "starter-openapi", "ingress", "proof"], resource_deps=["api-gateway-local", "starter-openapi-surfaces"], ) _resource( "starter-openapi-management-route-probe", _starter_openapi_route_probe_command( "starter-openapi-management-route-probe", "tidb-mgmt-portal", "/v1beta1/clusters", _kubectl_base("cp9-global") + " rollout status deployment/tidb-mgmt-portal --timeout=180s", ), labels=["dev-full", "starter-openapi", "ingress", "proof"], resource_deps=["starter-openapi-route-inventory"], ) _resource( "starter-openapi-serverless-route-probe", _starter_openapi_route_probe_command( "starter-openapi-serverless-route-probe", "serverless-service", "/v1beta1/clusters/cp9-route-probe/privateLinkConnections:getAvailabilityZones", _kubectl_base("cp9-global") + " rollout status deployment/serverless-service --timeout=180s", ), labels=["dev-full", "starter-openapi", "ingress", "proof"], resource_deps=["starter-openapi-route-inventory"], ) _resource( "starter-local-train-baseline", _write_evidence_command( "starter-local-train-baseline", "ready", "Starter Train A operations preserved for the Dev full proof: cluster create/get/password, branch list, SQL-user update, returned endpoint SQL, OpenAPI delete; final cp9 destroy belongs to the Dev full cleanup stage", ), labels=["dev-full", "starter-openapi", "proof"], resource_deps=["starter-openapi-management-route-probe", "starter-openapi-serverless-route-probe"], ) if remote_aws_runtime_identity: _resource( "remote-aws-runtime-identity-proof", " ".join([ _quote("../proof/capture-remote-aws-runtime-identity.sh"), _quote(kubeconfig), _quote(kube_context), _quote(ctx_path), ]), deps=["../proof/capture-remote-aws-runtime-identity.sh", ctx_path], labels=["dev-full", "aws-identity", "proof"], resource_deps=[ "account-svc", "cluster-ng-server", "dataplane-manager", "upbound-aws-provider-providerconfigs", "regional-server", "serverless-global-service", "serverless-service", "dedicated-aws-provider", "cluster-controller", ], ) # The GCP evaluation is the secondary Regional runtime only. Global, Premium, # Starter, and Essential resources above are all primary-scoped through # _resource; this branch owns the live-active west1 Dedicated graph. if runtime_id == "gcp-regional": gcp_cp9_system_ns = _namespace_resource("cp9-system", runtime="gcp-regional") gcp_dedicated_ns = _namespace_resource("cp9-dedicated", runtime="gcp-regional") gcp_crossplane_system_ns = _namespace_resource("crossplane-system", runtime="gcp-regional") gcp_kong_system_ns = _namespace_resource("kong-system", runtime="gcp-regional") gcp_observability_ns = _namespace_resource("observability", runtime="gcp-regional") gcp_aws_runtime_env = " ".join([ "AWS_ROLE_ARN=" + _quote(gcp_host.get("aws_role_arn", "")), "AWS_WEB_IDENTITY_TOKEN_FILE=" + _quote(gcp_aws_host_token_file), "AWS_ROLE_SESSION_NAME=cp9-gcp-regional", "AWS_REGION=" + _quote(primary_remote.get("region", "")), "AWS_DEFAULT_REGION=" + _quote(primary_remote.get("region", "")), "AWS_EC2_METADATA_DISABLED=true", ]) _runtime_resource( "gcp-regional", "dedicated-api-host-ready", " ".join([ _quote("./scripts/ensure-dedicated-api-host.sh"), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(dedicated_api_host_manifest), ]), deps=[ "./scripts/ensure-dedicated-api-host.sh", dedicated_api_admin_kubeconfig, dedicated_api_host_manifest, ], labels=["dev-full", "gcp-regional", "dedicated-api"], resource_deps=[gcp_cp9_system_ns, gcp_dedicated_ns], ) gcp_crossplane_crds = _owner_crd_path("dedicated-crossplane-gcp-crds") aws_crossplane_crds = _owner_crd_path("dedicated-crossplane-aws-crds") for crd_artifact in [ {"name": "dedicated-crossplane-gcp-crds", "path": gcp_crossplane_crds}, {"name": "dedicated-crossplane-aws-crds", "path": aws_crossplane_crds}, ]: _runtime_resource( "gcp-regional", crd_artifact["name"], " ".join([ _quote("./scripts/apply-crd-artifact.sh"), _quote(crd_artifact["path"]), _quote(dedicated_api_admin_kubeconfig), _quote("cp9-dedicated"), _quote("180s"), ]), deps=[ "./scripts/apply-crd-artifact.sh", dedicated_api_admin_kubeconfig, crd_artifact["path"], ], labels=["dev-full", "gcp-regional", "dedicated-api", "crd", "owner-artifact"], resource_deps=["dedicated-api-host-ready"], ) _runtime_resource( "gcp-regional", "dedicated-infra-api-crds", "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " " + " ".join([ _quote("./scripts/bootstrap-dedicated-api.sh"), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(dedicated_api_bootstrap_manifest), _quote(_owner_crd_path("dedicated-regional-api-crds")), _quote(_owner_crd_path("dedicated-infra-api-crds")), _quote(_owner_crd_path("dedicated-dm-api-crds")), _quote(_owner_crd_path("dedicated-ticdc-api-crds")), _quote(_owner_crd_path("o11y-agent-control-server-crds")), _quote("../../app-delivery/envs/dev-full/dedicated-cluster-control-server-support"), _quote("../../app-delivery/envs/dev-full/gcp-regional-server/account-list.yaml"), _quote("../../app-delivery/envs/dev-full/gcp-dedicated-api/dm-provider.yaml"), _quote(evidence_dir + "/dedicated-api-bootstrap.json"), ]), deps=[ "./scripts/bootstrap-dedicated-api.sh", "./scripts/render-dedicated-account-contract.py", dedicated_api_admin_kubeconfig, dedicated_api_bootstrap_manifest, ctx_path, _owner_crd_path("dedicated-regional-api-crds"), _owner_crd_path("dedicated-infra-api-crds"), _owner_crd_path("dedicated-dm-api-crds"), _owner_crd_path("dedicated-ticdc-api-crds"), _owner_crd_path("o11y-agent-control-server-crds"), "../../app-delivery/envs/dev-full/dedicated-cluster-control-server-support", "../../app-delivery/envs/dev-full/gcp-regional-server/account-list.yaml", "../../app-delivery/envs/dev-full/gcp-dedicated-api/dm-provider.yaml", ], labels=["dev-full", "gcp-regional", "dedicated-api"], resource_deps=["dedicated-crossplane-gcp-crds", "dedicated-crossplane-aws-crds"], ) _gcp_owner_kustomize_resource( "gcp-classic-provider", [{ "path": "../../app-delivery/envs/dev-full/gcp-classic-provider", "namespace": "cp9-dedicated", "image": "cp9.local/gcp-classic-provider:placeholder", }], resource_deps=["dedicated-infra-api-crds"], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/gcp-provider --timeout=180s"], ) _gcp_owner_kustomize_resource( "gcp-upstream-provider", [{ "path": "../../app-delivery/envs/dev-full/gcp-upstream-provider", "namespace": "cp9-dedicated", "image": "cp9.local/gcp-upstream-provider:placeholder", }], resource_deps=["dedicated-infra-api-crds"], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/gcp-provider-upstream --timeout=180s"], ) _gcp_owner_kustomize_resource( "dedicated-aws-provider", [{ "path": "../../app-delivery/envs/dev-full/gcp-classic-aws-provider", "namespace": "cp9-dedicated", "image": "cp9.local/dedicated-aws-provider:placeholder", "placeholders": [ "__CP9_PRIMARY_AWS_REGION__", "__CP9_GCP_AWS_ROLE_ARN__", "__CP9_GCP_AWS_IDENTITY_DIR__", ], }], resource_deps=["dedicated-infra-api-crds"], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/aws-provider-upstream --timeout=180s"], ) gcp_crossplane_image = _owner_artifact_image("gcp-crossplane") gcp_crossplane_local_image = _gcp_local_owner_image(gcp_crossplane_image) _runtime_resource( "gcp-regional", "gcp-crossplane", _join_commands([ _gcp_import_owner_image_command(gcp_crossplane_image), _apply_helm_command( "gcp-crossplane", "../../app-delivery/charts/crossplane", "crossplane-system", ["../../app-delivery/envs/dev-full/gcp-crossplane/values.yaml"], gcp_crossplane_local_image, ), _kubectl_base("crossplane-system") + " rollout status deployment/gcp-crossplane --timeout=180s", _kubectl_base("crossplane-system") + " rollout status deployment/gcp-crossplane-rbac-manager --timeout=180s", ]), deps=[ "../../app-delivery/charts/crossplane", "../../app-delivery/envs/dev-full/gcp-crossplane/values.yaml", "./scripts/import-gcp-owner-amd64.sh", "./scripts/apply-helm-release.sh", _owner_artifact_trigger_path("gcp-crossplane"), ], labels=["dev-full", "gcp-regional", "crossplane", "owner-artifact"], resource_deps=[gcp_crossplane_system_ns], ) _runtime_resource( "gcp-regional", "gcp-crossplane-ready", _join_commands([ _wait_for_crd_command("providers.pkg.crossplane.io"), _wait_for_crd_command("deploymentruntimeconfigs.pkg.crossplane.io"), ]), labels=["dev-full", "gcp-regional", "crossplane"], resource_deps=["gcp-crossplane"], ) gcp_upbound_base = "../../app-delivery/base/upbound-gcp-provider" _runtime_resource( "gcp-regional", "gcp-upbound-provider-runtime", _join_commands([ _apply_file_command(gcp_upbound_base + "/serviceaccount.yaml", "crossplane-system"), _apply_file_command(gcp_upbound_base + "/deploymentruntimeconfig-gcp-family.yaml"), ]), deps=[ gcp_upbound_base + "/serviceaccount.yaml", gcp_upbound_base + "/deploymentruntimeconfig-gcp-family.yaml", ], labels=["dev-full", "gcp-regional", "crossplane"], resource_deps=["gcp-crossplane-ready"], ) gcp_upbound_provider_specs = [ {"artifact": "gcp-upbound-provider-family", "manifest": gcp_upbound_base + "/provider-family-gcp.yaml"}, {"artifact": "gcp-upbound-provider-compute", "manifest": gcp_upbound_base + "/provider-gcp-compute.yaml"}, {"artifact": "gcp-upbound-provider-container", "manifest": gcp_upbound_base + "/provider-gcp-container.yaml"}, {"artifact": "gcp-upbound-provider-dns", "manifest": gcp_upbound_base + "/provider-gcp-dns.yaml"}, {"artifact": "gcp-upbound-provider-iam", "manifest": gcp_upbound_base + "/provider-gcp-iam.yaml"}, {"artifact": "gcp-upbound-provider-storage", "manifest": gcp_upbound_base + "/provider-gcp-storage.yaml"}, ] gcp_upbound_provider_resources = [] for provider_spec in gcp_upbound_provider_specs: artifact_name = provider_spec["artifact"] provider_manifest = provider_spec["manifest"] _runtime_resource( "gcp-regional", artifact_name, _apply_crossplane_provider_package_command(provider_manifest, _owner_artifact_image(artifact_name)), deps=[provider_manifest, "./scripts/apply-crossplane-provider-package.sh", _owner_artifact_trigger_path(artifact_name)], labels=["dev-full", "gcp-regional", "crossplane", "owner-artifact"], resource_deps=["gcp-upbound-provider-runtime"], ) gcp_upbound_provider_resources.append(artifact_name) _runtime_resource( "gcp-regional", "gcp-upbound-provider-config", _join_commands([ _wait_for_crd_command("providerconfigs.gcp.upbound.io", crd_wait_extended_timeout_seconds), _apply_kustomize_images_command( "../../app-delivery/envs/dev-full/gcp-upbound-provider-config", "", _gcp_replacements(["__CP9_GCP_DATAPLANE_PROJECT_ID__"]), ), ]), deps=[ "../../app-delivery/envs/dev-full/gcp-upbound-provider-config", "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path, ], labels=["dev-full", "gcp-regional", "crossplane"], resource_deps=gcp_upbound_provider_resources, ) _runtime_resource( "gcp-regional", "gcp-gateway-api-crds", _join_commands([ _apply_kustomize_command("../../app-delivery/base/gateway-api-crds", ""), _wait_for_crd_command("gatewayclasses.gateway.networking.k8s.io"), _wait_for_crd_command("gateways.gateway.networking.k8s.io"), _wait_for_crd_command("httproutes.gateway.networking.k8s.io"), ]), deps=["../../app-delivery/base/gateway-api-crds"], labels=["dev-full", "gcp-regional", "gateway"], resource_deps=[gcp_kong_system_ns], ) _runtime_resource( "gcp-regional", "gcp-o11y-kong-plugin", _kong_plugin_configmap_command("o11y-dedicated-route"), deps=[ "../../app-delivery/base/api-gateway-local/plugins/o11y-dedicated-route/handler.lua", "../../app-delivery/base/api-gateway-local/plugins/o11y-dedicated-route/schema.lua", ], labels=["dev-full", "gcp-regional", "o11y", "kong-plugin"], resource_deps=[gcp_kong_system_ns], ) _helm_resource( "gcp-regional-kong-controller", "../../app-delivery/charts/kong-ingress-controller", "kong-system", ["../../app-delivery/envs/dev-full/gcp-regional-kong/values.yaml"], resource_deps=["gcp-gateway-api-crds", "gcp-o11y-kong-plugin", gcp_observability_ns], ready_command=_kubectl_base("kong-system") + " rollout status deployment/gcp-regional-kong-controller-kong --timeout=180s", runtime="gcp-regional", ) _runtime_resource( "gcp-regional", "gcp-o11y-runtime-secret", " ".join([ gcp_aws_runtime_env, _quote("./scripts/apply-o11y-runtime-secrets.sh"), _quote(kubeconfig), _quote(kube_context), _quote("-"), _quote(primary_remote.get("region", "")), _quote(o11y_auth0_secret_id), _quote("cp9-dedicated"), ]), deps=["./scripts/apply-o11y-runtime-secrets.sh", ctx_path], labels=["dev-full", "gcp-regional", "o11y", "runtime-secret"], resource_deps=[gcp_dedicated_ns], ) _runtime_resource( "gcp-regional", "gcp-o11y-platform-crds", _join_commands([ _apply_kustomize_command("../../app-delivery/envs/dev-full/o11y-platform-crds", ""), _wait_for_crd_command("vmclusters.operator.victoriametrics.com"), _wait_for_crd_command("clusters.observability.pingcap.com"), _wait_for_crd_command("endpointservices.observability.pingcap.com"), _wait_for_crd_command("iams.observability.pingcap.com"), _wait_for_crd_command("s3s.observability.pingcap.com"), ]), deps=["../../app-delivery/envs/dev-full/o11y-platform-crds"], labels=["dev-full", "gcp-regional", "o11y", "crd"], resource_deps=[gcp_observability_ns], ) _runtime_resource( "gcp-regional", "gcp-o11y-platform-image-pull-secret", gcp_aws_runtime_env + " " + _apply_staging_image_pull_secret_command("observability"), deps=["./scripts/apply-staging-image-pull-secret.sh"], labels=["dev-full", "gcp-regional", "o11y", "image-pull-secret"], resource_deps=[gcp_observability_ns], ) _runtime_resource( "gcp-regional", "gcp-o11y-platform", "CP9_SESSION_CONTEXT=" + _quote(ctx_path) + " CP9_IMAGE_PULL_SECRET=" + _quote(staging_image_pull_secret) + " " + _apply_kustomize_images_command( "../../app-delivery/envs/dev-full/gcp-o11y-platform", "observability", _gcp_replacements([ "__CP9_GCP_PROJECT_ID__", "__CP9_GCP_O11Y_SERVICE_ATTACHMENT__", "__CP9_GCP_O11Y_BUCKET_NAME__", "__CP9_GCP_REGIONAL_ENDPOINT_HOST__", "__CP9_PRIMARY_AWS_REGION__", "__CP9_PRIMARY_PUBLIC_HOST__", ]), ), deps=["../../app-delivery/envs/dev-full/gcp-o11y-platform", ctx_path], labels=["dev-full", "gcp-regional", "o11y", "app-delivery"], resource_deps=[ "gcp-o11y-platform-crds", "gcp-o11y-platform-image-pull-secret", ], ) _gcp_owner_kustomize_resource( "gcp-o11y-agent-control-server", [{ "path": "../../app-delivery/envs/dev-full/gcp-dedicated-o11y-agent-control-server", "namespace": "cp9-dedicated", "image": "cp9.local/dedicated-o11y-agent-control-server:placeholder", "placeholders": ["__CP9_SESSION_NAME__", "__CP9_PRIMARY_O11Y_CONTROL_URL__"], }], resource_deps=[ "dedicated-infra-api-crds", "gcp-regional-server", "gcp-o11y-runtime-secret", "gcp-o11y-platform", "gcp-regional-kong", ], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/o11y-agent-control-server --timeout=180s"], ) gcp_webhook_image = _owner_artifact_image("gcp-webhook-server") gcp_webhook_local_image = _gcp_local_owner_image(gcp_webhook_image) _runtime_resource( "gcp-regional", "gcp-webhook-server", _join_commands([ _gcp_import_owner_image_command(gcp_webhook_image), " ".join([ "CP9_SESSION_CONTEXT=" + _quote(ctx_path), _quote("./scripts/apply-dedicated-webhook-server.sh"), _quote("../../app-delivery/envs/dev-full/dedicated-webhook-server"), _quote("../../app-delivery/envs/dev-full/dedicated-webhook-server-api"), _quote("cp9-dedicated"), _quote(kubeconfig), _quote(kube_context), _quote(dedicated_api_admin_kubeconfig), _quote(gcp_webhook_local_image), _quote(""), ]), ]), deps=[ "../../app-delivery/envs/dev-full/dedicated-webhook-server", "../../app-delivery/envs/dev-full/dedicated-webhook-server-api", "./scripts/import-gcp-owner-amd64.sh", "./scripts/apply-dedicated-webhook-server.sh", "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", _owner_artifact_trigger_path("gcp-webhook-server"), ctx_path, ], labels=["dev-full", "gcp-regional", "owner-artifact"], resource_deps=["dedicated-infra-api-crds"], ) _gcp_owner_kustomize_resource( "gcp-cluster-control-server", [{ "path": "../../app-delivery/envs/dev-full/gcp-dedicated-cluster-control-server", "namespace": "cp9-dedicated", "image": "cp9.local/cluster-control-server:placeholder", "placeholders": ["__CP9_SESSION_NAME__"], }], resource_deps=["dedicated-infra-api-crds", "gcp-webhook-server"], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/cluster-control-server --timeout=180s"], ) regional_server_placeholders = [ "__CP9_SESSION_NAME__", "__CP9_OWNER__", "__CP9_TTL_EXPIRES_AT__", "__CP9_GCP_PROJECT_ID__", "__CP9_GCP_DATAPLANE_PROJECT_ID__", "__CP9_GCP_SERVICE_ACCOUNT_EMAIL__", "__CP9_GCP_AWS_ROLE_ARN__", "__CP9_GCP_AWS_IDENTITY_DIR__", "__CP9_PRIMARY_AWS_REGION__", "__CP9_PRIMARY_AWS_CIDR__", "__CP9_GCP_RUNTIME_CIDR__", "__CP9_SESSION_PRODUCT_PCA_ARN__", "__CP9_DEDICATED_PUBLIC_DNS_ZONE_ID__", "__CP9_DEDICATED_PUBLIC_DNS_DOMAIN__", ] _gcp_owner_kustomize_resource( "gcp-regional-server", [{ "path": "../../app-delivery/envs/dev-full/gcp-regional-server", "namespace": "cp9-dedicated", "image": "cp9.local/regional-server:placeholder", "placeholders": regional_server_placeholders, }], resource_deps=[ "dedicated-infra-api-crds", "gcp-classic-provider", "gcp-upstream-provider", "dedicated-aws-provider", "gcp-upbound-provider-config", "gcp-cluster-control-server", ], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/regional-server --timeout=180s"], ) cluster_controller_placeholders = [ "__CP9_SESSION_NAME__", "__CP9_GCP_PROJECT_ID__", "__CP9_GCP_DATAPLANE_PROJECT_ID__", "__CP9_GCP_SERVICE_ACCOUNT_EMAIL__", "__CP9_GCP_SERVICE_ACCOUNT_NAME__", "__CP9_GCP_AWS_ROLE_ARN__", "__CP9_GCP_AWS_ROLE_NAME__", "__CP9_GCP_AWS_IDENTITY_DIR__", "__CP9_PRIMARY_AWS_REGION__", "__CP9_PRIMARY_CONFIG_CENTER_URL__", "__CP9_SESSION_PRODUCT_PCA_ARN__", "__CP9_DEDICATED_PUBLIC_DNS_ZONE_ID__", "__CP9_DEDICATED_PUBLIC_DNS_DOMAIN__", ] gke_controller_identity_placeholders = [ "__CP9_GCP_AWS_ROLE_ARN__", "__CP9_GCP_AWS_IDENTITY_DIR__", "__CP9_PRIMARY_AWS_REGION__", ] _gcp_owner_kustomize_resource( "gcp-gke-provider", [ { "path": "../../app-delivery/envs/dev-full/gcp-dedicated-cluster-controller", "namespace": "cp9-dedicated", "image": "cp9.local/cluster-controller:placeholder", "placeholders": cluster_controller_placeholders, }, { "path": "../../app-delivery/envs/dev-full/gcp-dm-controller", "namespace": "cp9-dedicated", "image": "cp9.local/gcp-gke-provider:placeholder", "placeholders": gke_controller_identity_placeholders, }, { "path": "../../app-delivery/envs/dev-full/gcp-import-controller", "namespace": "cp9-dedicated", "image": "cp9.local/gcp-gke-provider:placeholder", "placeholders": gke_controller_identity_placeholders, }, ], resource_deps=[ "dedicated-infra-api-crds", "gcp-classic-provider", "gcp-upstream-provider", "dedicated-aws-provider", "gcp-upbound-provider-config", "gcp-o11y-agent-control-server", "gcp-webhook-server", "gcp-cluster-control-server", ], ready_commands=[ _kubectl_base("cp9-dedicated") + " rollout status deployment/cluster-controller --timeout=180s", _kubectl_base("cp9-dedicated") + " rollout status deployment/dm-controller --timeout=180s", _kubectl_base("cp9-dedicated") + " rollout status deployment/import-controller --timeout=180s", ], ) _gcp_owner_kustomize_resource( "gcp-regional-tcidm-service", [{ "path": "../../app-delivery/envs/dev-full/gcp-regional-tcidm-service", "namespace": "cp9-dedicated", "image": "cp9.local/regional-tcidm-service:placeholder", "placeholders": ["__CP9_SESSION_NAME__"], }], resource_deps=["gcp-regional-server", "gcp-gke-provider"], ready_commands=[_kubectl_base("cp9-dedicated") + " rollout status deployment/regional-tcidm-service --timeout=180s"], ) _gcp_owner_kustomize_resource( "gcp-dedicated-ticdc-service", [{ "path": "../../app-delivery/envs/dev-full/gcp-dedicated-ticdc-service", "namespace": "cp9-dedicated", "image": "cp9.local/dedicated-ticdc-service:placeholder", "placeholders": ["__CP9_SESSION_NAME__"], }], resource_deps=["gcp-regional-server", "gcp-gke-provider"], ready_commands=[ _kubectl_base("cp9-dedicated") + " rollout status deployment/dedicated-ticdc-controller --timeout=180s", _kubectl_base("cp9-dedicated") + " rollout status deployment/dedicated-ticdc-service --timeout=180s", ], ) _runtime_resource( "gcp-regional", "gcp-regional-kong", _join_commands([ _apply_kustomize_images_command( "../../app-delivery/envs/dev-full/gcp-regional-kong", "", _gcp_replacements(["__CP9_GCP_REGIONAL_ENDPOINT_HOST__"]), ), _kubectl_base("kong-system") + " wait --for=condition=Programmed gateway/gcp-regional --timeout=180s", _kubectl_base("cp9-dedicated") + " wait --for=jsonpath='{.status.parents[0].conditions[?(@.type==\"Accepted\")].status}'=True httproute/gcp-regional-product --timeout=180s", _kubectl_base("observability") + " wait --for=jsonpath='{.status.parents[0].conditions[?(@.type==\"Accepted\")].status}'=True httproute/gcp-o11y-regional --timeout=180s", _kubectl_base("observability") + " wait --for=jsonpath='{.status.parents[0].conditions[?(@.type==\"Accepted\")].status}'=True httproute/gcp-o11y-data --timeout=180s", _kubectl_base("observability") + " wait --for=jsonpath='{.status.parents[0].conditions[?(@.type==\"Accepted\")].status}'=True httproute/gcp-o11y-private-write --timeout=180s", ]), deps=[ "../../app-delivery/envs/dev-full/gcp-regional-kong", "./scripts/apply-kustomize-images.sh", "./scripts/patch-local-manifests.py", "./scripts/strip-human-aws-credentials.py", ctx_path, ], labels=["dev-full", "gcp-regional", "gateway"], resource_deps=["gcp-regional-kong-controller", "gcp-regional-server", "gcp-o11y-platform"], )