constellation/.github/actions/constellation_create/action.yml
Moritz Sanft af05e17f49
ci: keep embedded measurements if stable image is used (#2109)
Co-authored-by: Moritz Sanft <58110325+msanft@users.noreply.github.com>
Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com>
Co-authored-by: Malte Poll <mp@edgeless.systems>
2023-08-04 09:43:32 +02:00

269 lines
11 KiB
YAML

name: Constellation create
description: Create a new Constellation cluster using latest OS image.
inputs:
workerNodesCount:
description: "Number of worker nodes to spawn."
required: true
controlNodesCount:
description: "Number of control-plane nodes to spawn."
required: true
cloudProvider:
description: "Either 'gcp' or 'azure'."
required: true
machineType:
description: "Machine type of VM to spawn."
required: false
osImage:
description: "OS image to use."
required: true
isDebugImage:
description: "Is OS img a debug img?"
required: true
kubernetesVersion:
description: "Kubernetes version to create the cluster from."
required: false
artifactNameSuffix:
description: "Suffix for artifact naming."
required: true
existingConfig:
default: "false"
description: "Use existing config file."
fetchMeasurements:
default: "false"
description: "Update measurements via the 'constellation config fetch-measurements' command."
#
# GCP specific inputs
#
gcpProject:
description: "The GCP project to deploy Constellation in."
required: false
gcpInClusterServiceAccountKey:
description: "The GCP Service account to use inside the created Constellation cluster."
required: false
#
# Azure specific inputs
#
azureSubscription:
description: "The Azure subscription ID to deploy Constellation in."
required: false
azureTenant:
description: "The Azure tenant ID to deploy Constellation in."
required: false
azureClientID:
description: "The Azure client ID of the application registration created for Constellation."
required: false
azureClientSecret:
description: "The Azure client secret value of the used secret."
required: false
azureUserAssignedIdentity:
description: "The Azure user assigned identity to use for Constellation."
required: false
azureResourceGroup:
description: "The Azure resource group to use for Constellation cluster"
required: false
outputs:
kubeconfig:
description: "The kubeconfig for the cluster."
value: ${{ steps.constellation-init.outputs.KUBECONFIG }}
masterSecret:
description: "The master-secret for the cluster."
value: ${{ steps.constellation-init.outputs.MASTERSECRET }}
osImageUsed:
description: "The OS image used in the cluster."
value: ${{ steps.setImage.outputs.image }}
runs:
using: "composite"
steps:
- name: Constellation config generate
shell: bash
if: inputs.existingConfig != 'true'
run: |
if [[ -n "${{ inputs.kubernetesVersion }}" ]]; then
constellation config generate ${{ inputs.cloudProvider }} --kubernetes="${{ inputs.kubernetesVersion }}" --debug
else
constellation config generate ${{ inputs.cloudProvider }} --debug
fi
yq eval -i "(.name) = \"e2e-test\"" constellation-conf.yaml
yq eval -i \
"(.provider | select(. | has(\"azure\")).azure.subscription) = \"${{ inputs.azureSubscription }}\" |
(.provider | select(. | has(\"azure\")).azure.tenant) = \"${{ inputs.azureTenant }}\" |
(.provider | select(. | has(\"azure\")).azure.location) = \"West US\" |
(.provider | select(. | has(\"azure\")).azure.userAssignedIdentity) = \"${{ inputs.azureUserAssignedIdentity }}\" |
(.provider | select(. | has(\"azure\")).azure.resourceGroup) = \"${{ inputs.azureResourceGroup }}\" |
constellation-conf.yaml
yq eval -i \
"(.provider | select(. | has(\"gcp\")).gcp.project) = \"${{ inputs.gcpProject }}\" |
(.provider | select(. | has(\"gcp\")).gcp.region) = \"europe-west3\" |
(.provider | select(. | has(\"gcp\")).gcp.zone) = \"europe-west3-b\" |
(.provider | select(. | has(\"gcp\")).gcp.serviceAccountKeyPath) = \"serviceAccountKey.json\"" \
constellation-conf.yaml
yq eval -i \
"(.provider | select(. | has(\"aws\")).aws.region) = \"us-east-2\" |
(.provider | select(. | has(\"aws\")).aws.zone) = \"us-east-2c\" |
(.provider | select(. | has(\"aws\")).aws.iamProfileControlPlane) = \"e2e_test_control_plane_instance_profile\" |
(.provider | select(. | has(\"aws\")).aws.iamProfileWorkerNodes) = \"e2e_test_worker_node_instance_profile\"" \
constellation-conf.yaml
if [[ -n "${{ inputs.kubernetesVersion }}" ]]; then
yq eval -i "(.kubernetesVersion) = \"${{ inputs.kubernetesVersion }}\"" constellation-conf.yaml
fi
- name: Set image
id: setImage
shell: bash
env:
imageInput: ${{ inputs.osImage }}
run: |
if [[ -z "${imageInput}" ]]; then
echo "No image specified. Using default image from config."
image=$(yq eval ".image" constellation-conf.yaml)
echo "image=${image}" | tee -a "$GITHUB_OUTPUT"
exit 0
fi
yq eval -i "(.image) = \"${imageInput}\"" constellation-conf.yaml
echo "image=${imageInput}" | tee -a "$GITHUB_OUTPUT"
- name: Update measurements for non-stable images
if: inputs.fetchMeasurements
shell: bash
run: |
constellation config fetch-measurements --debug --insecure
- name: Set instanceType
if: inputs.machineType && inputs.machineType != 'default'
shell: bash
run: |
yq eval -i "(.provider | select(. | has(\"azure\")).azure.instanceType) = \"${{ inputs.machineType }}\"" constellation-conf.yaml
yq eval -i "(.provider | select(. | has(\"gcp\")).gcp.instanceType) = \"${{ inputs.machineType }}\"" constellation-conf.yaml
yq eval -i "(.provider | select(. | has(\"aws\")).aws.instanceType) = \"${{ inputs.machineType }}\"" constellation-conf.yaml
- name: Create serviceAccountKey.json
if: inputs.cloudProvider == 'gcp' && !inputs.existingConfig # Skip if using existing config. serviceAccountKey.json is already present in that case.
shell: bash
env:
GCP_CLUSTER_SERVICE_ACCOUNT_KEY: ${{ inputs.gcpInClusterServiceAccountKey }}
run: |
echo "$GCP_CLUSTER_SERVICE_ACCOUNT_KEY" > serviceAccountKey.json
- name: Enable debugCluster flag
if: inputs.isDebugImage == 'true'
shell: bash
run: |
yq eval -i '(.debugCluster) = true' constellation-conf.yaml
# Uses --force flag since the CLI currently does not have a pre-release version and is always on the latest released version.
# However, many of our pipelines work on prerelease images. Thus the used images are newer than the CLI's version.
# This makes the version validation in the CLI fail.
- name: Constellation create
shell: bash
run: |
echo "Creating cluster using config:"
cat constellation-conf.yaml
sudo sh -c 'echo "127.0.0.1 license.confidential.cloud" >> /etc/hosts' || true
output=$(constellation --help)
if [[ $output == *"tf-log"* ]]; then
TFFLAG="--tf-log=DEBUG"
fi
constellation create -c ${{ inputs.controlNodesCount }} -w ${{ inputs.workerNodesCount }} -y --force --debug ${TFFLAG:-}
- name: Cdbg deploy
if: inputs.isDebugImage == 'true'
shell: bash
run: |
echo "::group::cdbg deploy"
chmod +x $GITHUB_WORKSPACE/build/cdbg
cdbg deploy \
--bootstrapper "${{ github.workspace }}/build/bootstrapper" \
--upgrade-agent "${{ github.workspace }}/build/upgrade-agent" \
--info logcollect=true \
--info logcollect.github.actor="${{ github.triggering_actor }}" \
--info logcollect.github.workflow="${{ github.workflow }}" \
--info logcollect.github.run-id="${{ github.run_id }}" \
--info logcollect.github.run-attempt="${{ github.run_attempt }}" \
--info logcollect.github.ref-name="${{ github.ref_name }}" \
--info logcollect.github.sha="${{ github.sha }}" \
--info logcollect.github.runner-os="${{ runner.os }}" \
--verbosity=-1 \
--force
echo "::endgroup::"
- name: Constellation init
id: constellation-init
shell: bash
run: |
constellation init --force --debug
echo "KUBECONFIG=$(pwd)/constellation-admin.conf" >> $GITHUB_OUTPUT
echo "MASTERSECRET=$(pwd)/constellation-mastersecret.json" >> $GITHUB_OUTPUT
- name: Wait for nodes to join and become ready
shell: bash
env:
KUBECONFIG: "${{ steps.constellation-init.outputs.KUBECONFIG }}"
JOINTIMEOUT: "1200" # 20 minutes timeout for all nodes to join
run: |
echo "::group::Wait for nodes"
NODES_COUNT=$((${{ inputs.controlNodesCount }} + ${{ inputs.workerNodesCount }}))
JOINWAIT=0
until [[ "$(kubectl get nodes -o json | jq '.items | length')" == "${NODES_COUNT}" ]] || [[ $JOINWAIT -gt $JOINTIMEOUT ]];
do
echo "$(kubectl get nodes -o json | jq '.items | length')/"${NODES_COUNT}" nodes have joined.. waiting.."
JOINWAIT=$((JOINWAIT+30))
sleep 30
done
if [[ $JOINWAIT -gt $JOINTIMEOUT ]]; then
echo "Timed out waiting for nodes to join"
exit 1
fi
echo "$(kubectl get nodes -o json | jq '.items | length')/"${NODES_COUNT}" nodes have joined"
if ! kubectl wait --for=condition=ready --all nodes --timeout=20m; then
kubectl get pods -n kube-system
kubectl get events -n kube-system
echo "::error::kubectl wait timed out before all nodes became ready"
echo "::endgroup::"
exit 1
fi
echo "::endgroup::"
- name: Download boot logs
if: always()
continue-on-error: true
shell: bash
env:
CSP: ${{ inputs.cloudProvider }}
run: |
echo "::group::Download boot logs"
CONSTELL_UID=$(yq '.uid' constellation-id.json)
case $CSP in
azure)
AZURE_RESOURCE_GROUP=$(yq eval ".provider.azure.resourceGroup" constellation-conf.yaml)
./.github/actions/constellation_create/az-logs.sh ${AZURE_RESOURCE_GROUP}
;;
gcp)
GCP_ZONE=$(yq eval ".provider.gcp.zone" constellation-conf.yaml)
./.github/actions/constellation_create/gcp-logs.sh ${GCP_ZONE} ${CONSTELL_UID}
;;
aws)
./.github/actions/constellation_create/aws-logs.sh us-east-2 ${CONSTELL_UID}
;;
esac
echo "::endgroup::"
- name: Upload boot logs
if: always() && !env.ACT
continue-on-error: true
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: serial-logs-${{ inputs.artifactNameSuffix }}
path: |
*.log
!terraform.log