diff --git a/.werft/build.ts b/.werft/build.ts index bfd7cbe38f9089..b34656afdb15bc 100644 --- a/.werft/build.ts +++ b/.werft/build.ts @@ -139,7 +139,7 @@ export async function build(context, version) { const retag = ("with-retag" in buildConfig) ? "" : "--dont-retag"; const cleanSlateDeployment = mainBuild || ("with-clean-slate-deployment" in buildConfig); const installEELicense = !("without-ee-license" in buildConfig); - const withPayment= "with-payment" in buildConfig; + const withPayment = "with-payment" in buildConfig; const withObservability = "with-observability" in buildConfig; const withHelm = "with-helm" in buildConfig; @@ -238,7 +238,7 @@ export async function build(context, version) { continue } let flag = file.substring(0, file.length - "-coverage.out".length); - exec(`codecov -N "${parent_commit}" --flags=${flag} --file "${coverageOutput}/${file}"`, {slice: "coverage"}); + exec(`codecov -N "${parent_commit}" --flags=${flag} --file "${coverageOutput}/${file}"`, { slice: "coverage" }); } werft.done('coverage'); @@ -285,8 +285,8 @@ export async function build(context, version) { werft.phase(phases.PREDEPLOY, "Checking for existing installations..."); // the context namespace is not set at this point - const hasGitpodHelmInstall = exec(`helm status ${helmInstallName} -n ${deploymentConfig.namespace}`, {slice: "check for Helm install", dontCheckRc: true}).code === 0; - const hasGitpodInstallerInstall = exec(`kubectl get configmap gitpod-app -n ${deploymentConfig.namespace}`, {slice: "check for Installer install", dontCheckRc: true}).code === 0; + const hasGitpodHelmInstall = exec(`helm status ${helmInstallName} -n ${deploymentConfig.namespace}`, { slice: "check for Helm install", dontCheckRc: true }).code === 0; + const hasGitpodInstallerInstall = exec(`kubectl get configmap gitpod-app -n ${deploymentConfig.namespace}`, { slice: "check for Installer install", dontCheckRc: true }).code === 0; werft.log("result of installation checks", `has Helm install: ${hasGitpodHelmInstall}, has Installer install: ${hasGitpodInstallerInstall}`); if (withHelm) { @@ -386,7 +386,7 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi } // add the image pull secret to the namespcae if it doesn't exist - const hasPullSecret = (exec(`kubectl get secret ${IMAGE_PULL_SECRET_NAME} -n ${namespace}`, {slice: installerSlices.IMAGE_PULL_SECRET, dontCheckRc: true, silent: true })).code === 0; + const hasPullSecret = (exec(`kubectl get secret ${IMAGE_PULL_SECRET_NAME} -n ${namespace}`, { slice: installerSlices.IMAGE_PULL_SECRET, dontCheckRc: true, silent: true })).code === 0; if (!hasPullSecret) { try { werft.log(installerSlices.IMAGE_PULL_SECRET, "Adding the image pull secret to the namespace"); @@ -406,9 +406,9 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi // download and init with the installer try { werft.log(installerSlices.INSTALLER_INIT, "Downloading installer and initializing config file"); - exec(`docker run --entrypoint sh --rm eu.gcr.io/gitpod-core-dev/build/installer:${version} -c "cat /app/installer" > /tmp/installer`, {slice: installerSlices.INSTALLER_INIT}); - exec(`chmod +x /tmp/installer`, {slice: installerSlices.INSTALLER_INIT}); - exec(`/tmp/installer init > config.yaml`, {slice: installerSlices.INSTALLER_INIT}); + exec(`docker run --entrypoint sh --rm eu.gcr.io/gitpod-core-dev/build/installer:${version} -c "cat /app/installer" > /tmp/installer`, { slice: installerSlices.INSTALLER_INIT }); + exec(`chmod +x /tmp/installer`, { slice: installerSlices.INSTALLER_INIT }); + exec(`/tmp/installer init > config.yaml`, { slice: installerSlices.INSTALLER_INIT }); werft.done(installerSlices.INSTALLER_INIT); } catch (err) { werft.fail(installerSlices.INSTALLER_INIT, err) @@ -417,8 +417,8 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi // prepare a proper config file try { werft.log(installerSlices.INSTALLER_RENDER, "Post process the base installer config file and render k8s manifests"); - const PROJECT_NAME="gitpod-core-dev"; - const CONTAINER_REGISTRY_URL=`eu.gcr.io/${PROJECT_NAME}/build/`; + const PROJECT_NAME = "gitpod-core-dev"; + const CONTAINER_REGISTRY_URL = `eu.gcr.io/${PROJECT_NAME}/build/`; const CONTAINERD_RUNTIME_DIR = "/var/lib/containerd/io.containerd.runtime.v2.task/k8s.io"; // get some values we need to customize the config and write them to file @@ -431,47 +431,59 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi exec(`yq m -i config.yaml ./workspaceSizing`, { slice: installerSlices.INSTALLER_RENDER }); // write some values inline - exec(`yq w -i config.yaml certificate.name ${PROXY_SECRET_NAME}`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml containerRegistry.inCluster false`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml containerRegistry.external.url ${CONTAINER_REGISTRY_URL}`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml containerRegistry.external.certificate.kind secret`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml containerRegistry.external.certificate.name ${IMAGE_PULL_SECRET_NAME}`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml domain ${deploymentConfig.domain}`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml jaegerOperator.inCluster false`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml workspace.runtime.containerdRuntimeDir ${CONTAINERD_RUNTIME_DIR}`, {slice: installerSlices.INSTALLER_RENDER}); + exec(`yq w -i config.yaml certificate.name ${PROXY_SECRET_NAME}`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml containerRegistry.inCluster false`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml containerRegistry.external.url ${CONTAINER_REGISTRY_URL}`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml containerRegistry.external.certificate.kind secret`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml containerRegistry.external.certificate.name ${IMAGE_PULL_SECRET_NAME}`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml domain ${deploymentConfig.domain}`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml jaegerOperator.inCluster false`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml workspace.runtime.containerdRuntimeDir ${CONTAINERD_RUNTIME_DIR}`, { slice: installerSlices.INSTALLER_RENDER }); if ((deploymentConfig.analytics || "").startsWith("segment|")) { - exec(`yq w -i config.yaml analytics.writer segment`, {slice: installerSlices.INSTALLER_RENDER}); - exec(`yq w -i config.yaml analytics.segmentKey ${deploymentConfig.analytics!.substring("segment|".length)}`, {slice: installerSlices.INSTALLER_RENDER}); + exec(`yq w -i config.yaml analytics.writer segment`, { slice: installerSlices.INSTALLER_RENDER }); + exec(`yq w -i config.yaml analytics.segmentKey ${deploymentConfig.analytics!.substring("segment|".length)}`, { slice: installerSlices.INSTALLER_RENDER }); } else if (!!deploymentConfig.analytics) { - exec(`yq w -i config.yaml analytics.writer ${deploymentConfig.analytics!}`, {slice: installerSlices.INSTALLER_RENDER}); + exec(`yq w -i config.yaml analytics.writer ${deploymentConfig.analytics!}`, { slice: installerSlices.INSTALLER_RENDER }); } if (withObservability) { // TODO: there's likely more to do... - const tracingEndpoint = exec(`yq r ./.werft/values.tracing.yaml tracing.endpoint`,{slice: installerSlices.INSTALLER_RENDER}).stdout.trim(); - exec(`yq w -i config.yaml observability.tracing.endpoint ${tracingEndpoint}`, {slice: installerSlices.INSTALLER_RENDER}); + const tracingEndpoint = exec(`yq r ./.werft/values.tracing.yaml tracing.endpoint`, { slice: installerSlices.INSTALLER_RENDER }).stdout.trim(); + exec(`yq w -i config.yaml observability.tracing.endpoint ${tracingEndpoint}`, { slice: installerSlices.INSTALLER_RENDER }); } - // TODO: Remove this after #6867 is done - werft.log("authProviders", "copy authProviders") + werft.log("authProviders", "copy authProviders from secret") try { - exec(`kubectl get secret preview-envs-authproviders --namespace=keys -o yaml \ - | yq r - data.authProviders \ + exec(`for row in $(kubectl get secret preview-envs-authproviders --namespace=keys -o jsonpath="{.data.authProviders}" \ | base64 -d -w 0 \ - > ./authProviders`, { silent: true }); - exec(`yq merge --inplace config.yaml ./authProviders`, { silent: true }) + | yq r - authProviders -j \ + | jq -r 'to_entries | .[] | @base64'); do + key=$(echo $row | base64 -d | jq -r '.key') + providerId=$(echo $row | base64 -d | jq -r '.value.id') + data=$(echo $row | base64 -d | yq r - value --prettyPrint | ) + + yq w -i ./config.yaml authProviders[$key].kind "secret" + yq w -i ./config.yaml authProviders[$key].name "$providerId" + + kubectl create secret generic "$providerId" \ + --namespace ${namespace} \ + --from-literal=provider="$data" \ + --dry-run=client -o yaml | + kubectl replace --force -f - + done`, { silent: true }) + werft.done('authProviders'); } catch (err) { werft.fail('authProviders', err); } // validate the config and cluster - exec(`/tmp/installer validate config -c config.yaml`, {slice: installerSlices.INSTALLER_RENDER}); + exec(`/tmp/installer validate config -c config.yaml`, { slice: installerSlices.INSTALLER_RENDER }); // TODO: Ignore cluster validation errors (our k8s version is too old in core-dev) // consider removing '|| true' after we've left core-dev and are using K3s for preview envs - exec(`/tmp/installer validate cluster -c config.yaml || true`, {slice: installerSlices.INSTALLER_RENDER}); + exec(`/tmp/installer validate cluster -c config.yaml || true`, { slice: installerSlices.INSTALLER_RENDER }); // render the k8s manifest exec(`/tmp/installer render --namespace ${deploymentConfig.namespace} --config config.yaml > k8s.yaml`, { silent: true }); @@ -486,22 +498,22 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi if (deploymentConfig.installEELicense) { werft.log(installerSlices.INSTALLER_POST_PROCESSING, "Adding the EE License..."); - exec(`cp /mnt/secrets/gpsh-coredev/license /tmp/license`, {slice: installerSlices.INSTALLER_POST_PROCESSING}); + exec(`cp /mnt/secrets/gpsh-coredev/license /tmp/license`, { slice: installerSlices.INSTALLER_POST_PROCESSING }); // post-process.sh looks for /tmp/license, and if it exists, adds it to the configmap } else { - exec(`touch /tmp/license`, {slice: installerSlices.INSTALLER_POST_PROCESSING}); + exec(`touch /tmp/license`, { slice: installerSlices.INSTALLER_POST_PROCESSING }); } - exec(`touch /tmp/defaultFeatureFlags`, {slice: installerSlices.INSTALLER_POST_PROCESSING}); + exec(`touch /tmp/defaultFeatureFlags`, { slice: installerSlices.INSTALLER_POST_PROCESSING }); if (workspaceFeatureFlags && workspaceFeatureFlags.length > 0) { werft.log(installerSlices.INSTALLER_POST_PROCESSING, "Adding feature flags..."); workspaceFeatureFlags.forEach(featureFlag => { - exec(`echo \'"${featureFlag}"\' >> /tmp/defaultFeatureFlags`, {slice: installerSlices.INSTALLER_POST_PROCESSING}); + exec(`echo \'"${featureFlag}"\' >> /tmp/defaultFeatureFlags`, { slice: installerSlices.INSTALLER_POST_PROCESSING }); }) // post-process.sh looks for /tmp/defaultFeatureFlags // each "flag" string gets added to the configmap } - exec(`./.werft/post-process.sh ${registryNodePortMeta} ${wsdaemonPortMeta} ${nodepoolIndex} ${deploymentConfig.destname}`, {slice: installerSlices.INSTALLER_POST_PROCESSING}); + exec(`./.werft/post-process.sh ${registryNodePortMeta} ${wsdaemonPortMeta} ${nodepoolIndex} ${deploymentConfig.destname}`, { slice: installerSlices.INSTALLER_POST_PROCESSING }); werft.done(installerSlices.INSTALLER_POST_PROCESSING); } catch (err) { werft.fail(installerSlices.INSTALLER_POST_PROCESSING, err); @@ -510,7 +522,7 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi werft.log(installerSlices.APPLY_INSTALL_MANIFESTS, "Installing preview environment."); try { // errors could result in outputing a secret to the werft log when kubernetes patches existing objects... - exec(`kubectl apply -f k8s.yaml`,{ slice: installerSlices.APPLY_INSTALL_MANIFESTS, silent: true }); + exec(`kubectl apply -f k8s.yaml`, { slice: installerSlices.APPLY_INSTALL_MANIFESTS, silent: true }); werft.done(installerSlices.APPLY_INSTALL_MANIFESTS); } catch (err) { werft.fail(installerSlices.APPLY_INSTALL_MANIFESTS, err); @@ -521,7 +533,7 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi try { werft.log(installerSlices.DEPLOYMENT_WAITING, "Server not ready. Let the waiting...commence!"); - exec(`kubectl rollout status deployment/server --timeout=5m`,{ slice: installerSlices.DEPLOYMENT_WAITING }); + exec(`kubectl rollout status deployment/server --timeout=5m`, { slice: installerSlices.DEPLOYMENT_WAITING }); werft.done(installerSlices.DEPLOYMENT_WAITING); } catch (err) { werft.fail(installerSlices.DEPLOYMENT_WAITING, err); @@ -566,7 +578,7 @@ export async function deployToDevWithInstaller(deploymentConfig: DeploymentConfi // cleanup non-namespace objects werft.log(installerSlices.CLEAN_ENV_STATE, "removing old unnamespaced objects - this might take a while"); try { - await deleteNonNamespaceObjects(namespace, destname, { ...shellOpts, slice: installerSlices.CLEAN_ENV_STATE }); + await deleteNonNamespaceObjects(namespace, destname, { ...shellOpts, slice: installerSlices.CLEAN_ENV_STATE }); werft.done(installerSlices.CLEAN_ENV_STATE); } catch (err) { werft.fail(installerSlices.CLEAN_ENV_STATE, err); @@ -662,8 +674,8 @@ export async function deployToDevWithHelm(deploymentConfig: DeploymentConfig, wo exec(`werft log result -d "Monitoring Satellite - Grafana" -c github-check-Grafana url https://grafana-${monitoringDomain}/dashboards`); exec(`werft log result -d "Monitoring Satellite - Prometheus" -c github-check-Prometheus url https://prometheus-${monitoringDomain}/graph`); } else { - exec(`echo '"with-observability" annotation not set, skipping...'`, {slice: `observability`}) - exec(`echo 'To deploy monitoring-satellite, please add "/werft with-observability" to your PR description.'`, {slice: `observability`}) + exec(`echo '"with-observability" annotation not set, skipping...'`, { slice: `observability` }) + exec(`echo 'To deploy monitoring-satellite, please add "/werft with-observability" to your PR description.'`, { slice: `observability` }) } werft.done('observability'); @@ -902,7 +914,7 @@ async function publishHelmChart(imageRepoBase: string, version: string) { function getNodePoolIndex(namespace: string): number { const nodeAffinityValues = getNodeAffinities(); - return parseInt(createHash('sha256').update(namespace).digest('hex').substring(0,5),16) % nodeAffinityValues.length; + return parseInt(createHash('sha256').update(namespace).digest('hex').substring(0, 5), 16) % nodeAffinityValues.length; } function getNodeAffinities(): string[] {