diff --git a/readme.md b/readme.md index ec73075..f0a5c2a 100644 --- a/readme.md +++ b/readme.md @@ -90,6 +90,69 @@ The following inputs can be used as `step.with` keys: | `timeout` | `5m` | The timeout for the Helm command | | `working-directory` | `.` | The working directory where the action commands will operate | +### Setup S3 Preview + +Creates an S3 preview prefix by copying from the main prefix. + +#### Example + +```yaml + - uses: aboutbits/github-actions-kubernetes/setup-s3-preview@v3 + with: + configmap-name: my-app-environments + namespace: my-namespace + preview-number: ${{ github.event.number }} +``` + +#### Inputs + +The following inputs can be used as `step.with` keys: + +| Name | Required/Default | Description | +|-----------------------------|-----------------------------|-----------------------------------------------------| +| `configmap-name` | `app-spring-deployment-environments` | Name of the ConfigMap | +| `namespace` | required | Kubernetes namespace | +| `preview-number` | required | Preview number (PR number) | +| `secret-name` | `app-secrets` | Name of the secret containing credentials | +| `s3-bucket-key` | `S3_BUCKET` | Key for S3_BUCKET in ConfigMap | +| `s3-endpoint-key` | `S3_ENDPOINT` | Key for S3_ENDPOINT in ConfigMap | +| `s3-region-key` | `S3_REGION` | Key for S3_REGION in ConfigMap | +| `s3-root-folder-key` | `S3_ROOT_FOLDER` | Key for S3_ROOT_FOLDER in ConfigMap | +| `s3-force-path-style-access-key` | `S3_FORCE_PATH_STYLE_ACCESS` | Key for S3_FORCE_PATH_STYLE_ACCESS in ConfigMap | +| `s3-access-key-key` | `S3_ACCESS_KEY` | Key for S3_ACCESS_KEY in Secret | +| `s3-secret-key-key` | `S3_SECRET_KEY` | Key for S3_SECRET_KEY in Secret | + +### Teardown S3 Preview + +Deletes the S3 preview prefix. + +#### Example + +```yaml + - uses: aboutbits/github-actions-kubernetes/teardown-s3-preview@v3 + with: + configmap-name: my-app-environments + namespace: my-namespace + preview-number: ${{ github.event.number }} +``` + +#### Inputs + +The following inputs can be used as `step.with` keys: + +| Name | Required/Default | Description | +|-----------------------------|-----------------------------|-----------------------------------------------------| +| `configmap-name` | `app-spring-deployment-environments` | Name of the ConfigMap | +| `namespace` | required | Kubernetes namespace | +| `preview-number` | required | Preview number (PR number) | +| `secret-name` | `app-secrets` | Name of the secret containing credentials | +| `s3-bucket-key` | `S3_BUCKET` | Key for S3_BUCKET in ConfigMap | +| `s3-endpoint-key` | `S3_ENDPOINT` | Key for S3_ENDPOINT in ConfigMap | +| `s3-region-key` | `S3_REGION` | Key for S3_REGION in ConfigMap | +| `s3-force-path-style-access-key` | `S3_FORCE_PATH_STYLE_ACCESS` | Key for S3_FORCE_PATH_STYLE_ACCESS in ConfigMap | +| `s3-access-key-key` | `S3_ACCESS_KEY` | Key for S3_ACCESS_KEY in Secret | +| `s3-secret-key-key` | `S3_SECRET_KEY` | Key for S3_SECRET_KEY in Secret | + ### Setup PostgreSQL Preview Schema Sets up a PostgreSQL preview schema by cloning a base schema. diff --git a/setup-s3-preview/action.yml b/setup-s3-preview/action.yml new file mode 100644 index 0000000..f49def2 --- /dev/null +++ b/setup-s3-preview/action.yml @@ -0,0 +1,105 @@ +name: 'Setup S3 Preview' +description: 'Creates an S3 preview prefix by copying from the main prefix' +inputs: + configmap-name: + description: 'Name of the ConfigMap' + required: false + default: 'app-spring-deployment-environments' + namespace: + description: 'Kubernetes namespace' + required: true + preview-number: + description: 'Preview number (PR number)' + required: true + secret-name: + description: 'Name of the secret containing credentials' + required: false + default: 'app-secrets' + s3-bucket-key: + description: 'Key for S3_BUCKET in ConfigMap' + required: false + default: 'S3_BUCKET' + s3-endpoint-key: + description: 'Key for S3_ENDPOINT in ConfigMap' + required: false + default: 'S3_ENDPOINT' + s3-region-key: + description: 'Key for S3_REGION in ConfigMap' + required: false + default: 'S3_REGION' + s3-root-folder-key: + description: 'Key for S3_ROOT_FOLDER in ConfigMap' + required: false + default: 'S3_ROOT_FOLDER' + s3-force-path-style-access-key: + description: 'Key for S3_FORCE_PATH_STYLE_ACCESS in ConfigMap' + required: false + default: 'S3_FORCE_PATH_STYLE_ACCESS' + s3-access-key-key: + description: 'Key for S3_ACCESS_KEY in Secret' + required: false + default: 'S3_ACCESS_KEY' + s3-secret-key-key: + description: 'Key for S3_SECRET_KEY in Secret' + required: false + default: 'S3_SECRET_KEY' + +runs: + using: "composite" + steps: + - name: Prepare setup-s3 job + env: + JOB_NAME: "prepare-s3-preview-${{ inputs.preview-number }}" + CONFIGMAP_NAME: "${{ inputs.configmap-name }}" + SECRET_NAME: "${{ inputs.secret-name }}" + S3_BUCKET_KEY: "${{ inputs.s3-bucket-key }}" + S3_ENDPOINT_KEY: "${{ inputs.s3-endpoint-key }}" + S3_REGION_KEY: "${{ inputs.s3-region-key }}" + S3_ROOT_FOLDER_KEY: "${{ inputs.s3-root-folder-key }}" + S3_FORCE_PATH_STYLE_ACCESS_KEY: "${{ inputs.s3-force-path-style-access-key }}" + S3_ACCESS_KEY_KEY: "${{ inputs.s3-access-key-key }}" + S3_SECRET_KEY_KEY: "${{ inputs.s3-secret-key-key }}" + PREVIEW_NUMBER: "${{ inputs.preview-number }}" + run: | + envsubst ' + $JOB_NAME + $CONFIGMAP_NAME + $SECRET_NAME + $S3_BUCKET_KEY + $S3_ENDPOINT_KEY + $S3_REGION_KEY + $S3_ROOT_FOLDER_KEY + $S3_FORCE_PATH_STYLE_ACCESS_KEY + $S3_ACCESS_KEY_KEY + $S3_SECRET_KEY_KEY + $PREVIEW_NUMBER + ' < ${{ github.action_path }}/job-template.yml > job-setup-s3.yml + + echo "Prepared job manifest: job-setup-s3.yml" + shell: bash + + - name: Create setup-s3 job + run: | + kubectl apply --namespace ${{ inputs.namespace }} -f job-setup-s3.yml + shell: bash + + - name: Wait for setup-s3 job to complete + env: + JOB_NAME: "prepare-s3-preview-${{ inputs.preview-number }}" + NAMESPACE: "${{ inputs.namespace }}" + run: | + echo "Waiting for job $JOB_NAME in namespace $NAMESPACE..." + + if kubectl wait --namespace $NAMESPACE --for=condition=complete --timeout=10m job/$JOB_NAME; then + echo "Job finished with status: Complete" + kubectl logs job/$JOB_NAME --namespace $NAMESPACE + elif kubectl wait --namespace $NAMESPACE --for=condition=failed --timeout=1s job/$JOB_NAME; then + echo "Job finished with status: Failed" + kubectl logs job/$JOB_NAME --namespace $NAMESPACE + exit 1 + else + echo "Timeout waiting for job to complete." + kubectl logs job/$JOB_NAME --namespace $NAMESPACE || true + exit 1 + fi + shell: bash diff --git a/setup-s3-preview/job-template.yml b/setup-s3-preview/job-template.yml new file mode 100644 index 0000000..8bd5cab --- /dev/null +++ b/setup-s3-preview/job-template.yml @@ -0,0 +1,94 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: ${JOB_NAME} + labels: + app.kubernetes.io/managed-by: github-actions + app.kubernetes.io/component: s3-preview-setup +spec: + ttlSecondsAfterFinished: 60 + template: + spec: + restartPolicy: Never + containers: + - name: prepare-s3-preview + image: amazon/aws-cli:2 + command: [ "bash", "-c" ] + args: + - | + set -e + + echo "### START $(date --iso-8601=seconds) ###" + + if [ "$S3_FORCE_PATH_STYLE_ACCESS" = "true" ]; then + aws configure set default.s3.addressing_style path + fi + + S3_ARGS="" + if [ -n "$S3_ENDPOINT" ]; then + S3_ARGS="--endpoint-url $S3_ENDPOINT" + fi + + S3_SOURCE_PREFIX="" + if [ -n "$S3_ROOT_FOLDER" ]; then + S3_SOURCE_PREFIX="s3://$S3_BUCKET/${S3_ROOT_FOLDER%/}/" + else + S3_SOURCE_PREFIX="s3://$S3_BUCKET/" + fi + + S3_PREVIEW_PREFIX="s3://$S3_BUCKET/preview-${PREVIEW_NUMBER}/" + + echo "Checking if $S3_PREVIEW_PREFIX already exists..." + if [ "$(aws s3 $S3_ARGS ls "$S3_PREVIEW_PREFIX" | wc -l)" -gt 0 ]; then + echo "$S3_PREVIEW_PREFIX already exists. Skipping setup." + echo "Script finished successfully!" + echo "### END $(date --iso-8601=seconds) ###" + exit 0 + fi + + echo "Syncing from $S3_SOURCE_PREFIX to $S3_PREVIEW_PREFIX ..." + aws s3 $S3_ARGS sync "$S3_SOURCE_PREFIX" "$S3_PREVIEW_PREFIX" + + echo "Script finished successfully!" + echo "### END $(date --iso-8601=seconds) ###" + env: + - name: S3_BUCKET + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_BUCKET_KEY} + - name: S3_ENDPOINT + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_ENDPOINT_KEY} + optional: true + - name: AWS_DEFAULT_REGION + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_REGION_KEY} + - name: S3_ROOT_FOLDER + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_ROOT_FOLDER_KEY} + optional: true + - name: S3_FORCE_PATH_STYLE_ACCESS + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_FORCE_PATH_STYLE_ACCESS_KEY} + optional: true + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: ${SECRET_NAME} + key: ${S3_ACCESS_KEY_KEY} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: ${SECRET_NAME} + key: ${S3_SECRET_KEY_KEY} + - name: PREVIEW_NUMBER + value: "${PREVIEW_NUMBER}" diff --git a/teardown-s3-preview/action.yml b/teardown-s3-preview/action.yml new file mode 100644 index 0000000..f1292a2 --- /dev/null +++ b/teardown-s3-preview/action.yml @@ -0,0 +1,99 @@ +name: 'Teardown S3 Preview' +description: 'Deletes the S3 preview prefix' +inputs: + configmap-name: + description: 'Name of the ConfigMap' + required: false + default: 'app-spring-deployment-environments' + namespace: + description: 'Kubernetes namespace' + required: true + preview-number: + description: 'Preview number (PR number)' + required: true + secret-name: + description: 'Name of the secret containing credentials' + required: false + default: 'app-secrets' + s3-bucket-key: + description: 'Key for S3_BUCKET in ConfigMap' + required: false + default: 'S3_BUCKET' + s3-endpoint-key: + description: 'Key for S3_ENDPOINT in ConfigMap' + required: false + default: 'S3_ENDPOINT' + s3-region-key: + description: 'Key for S3_REGION in ConfigMap' + required: false + default: 'S3_REGION' + s3-force-path-style-access-key: + description: 'Key for S3_FORCE_PATH_STYLE_ACCESS in ConfigMap' + required: false + default: 'S3_FORCE_PATH_STYLE_ACCESS' + s3-access-key-key: + description: 'Key for S3_ACCESS_KEY in Secret' + required: false + default: 'S3_ACCESS_KEY' + s3-secret-key-key: + description: 'Key for S3_SECRET_KEY in Secret' + required: false + default: 'S3_SECRET_KEY' + +runs: + using: "composite" + steps: + - name: Prepare teardown-s3 job + env: + JOB_NAME: "teardown-s3-preview-${{ inputs.preview-number }}" + CONFIGMAP_NAME: "${{ inputs.configmap-name }}" + SECRET_NAME: "${{ inputs.secret-name }}" + S3_BUCKET_KEY: "${{ inputs.s3-bucket-key }}" + S3_ENDPOINT_KEY: "${{ inputs.s3-endpoint-key }}" + S3_REGION_KEY: "${{ inputs.s3-region-key }}" + S3_FORCE_PATH_STYLE_ACCESS_KEY: "${{ inputs.s3-force-path-style-access-key }}" + S3_ACCESS_KEY_KEY: "${{ inputs.s3-access-key-key }}" + S3_SECRET_KEY_KEY: "${{ inputs.s3-secret-key-key }}" + PREVIEW_NUMBER: "${{ inputs.preview-number }}" + run: | + envsubst ' + $JOB_NAME + $CONFIGMAP_NAME + $SECRET_NAME + $S3_BUCKET_KEY + $S3_ENDPOINT_KEY + $S3_REGION_KEY + $S3_FORCE_PATH_STYLE_ACCESS_KEY + $S3_ACCESS_KEY_KEY + $S3_SECRET_KEY_KEY + $PREVIEW_NUMBER + ' < ${{ github.action_path }}/job-template.yml > job-teardown-s3.yml + + echo "Prepared job manifest: job-teardown-s3.yml" + shell: bash + + - name: Create teardown-s3 job + run: | + kubectl apply --namespace ${{ inputs.namespace }} -f job-teardown-s3.yml + shell: bash + + - name: Wait for teardown-s3 job to complete + env: + JOB_NAME: "teardown-s3-preview-${{ inputs.preview-number }}" + NAMESPACE: "${{ inputs.namespace }}" + run: | + echo "Waiting for job $JOB_NAME in namespace $NAMESPACE..." + + if kubectl wait --namespace $NAMESPACE --for=condition=complete --timeout=5m job/$JOB_NAME; then + echo "Job finished with status: Complete" + kubectl logs job/$JOB_NAME --namespace $NAMESPACE + elif kubectl wait --namespace $NAMESPACE --for=condition=failed --timeout=1s job/$JOB_NAME; then + echo "Job finished with status: Failed" + kubectl logs job/$JOB_NAME --namespace $NAMESPACE + exit 1 + else + echo "Timeout waiting for job to complete." + kubectl logs job/$JOB_NAME --namespace $NAMESPACE || true + exit 1 + fi + shell: bash diff --git a/teardown-s3-preview/job-template.yml b/teardown-s3-preview/job-template.yml new file mode 100644 index 0000000..5fcb37b --- /dev/null +++ b/teardown-s3-preview/job-template.yml @@ -0,0 +1,81 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: ${JOB_NAME} + labels: + app.kubernetes.io/managed-by: github-actions + app.kubernetes.io/component: s3-preview-teardown +spec: + ttlSecondsAfterFinished: 60 + template: + spec: + restartPolicy: Never + containers: + - name: teardown-s3-preview + image: amazon/aws-cli:2 + command: [ "bash", "-c" ] + args: + - | + set -e + + echo "### START $(date --iso-8601=seconds) ###" + + if [ "$S3_FORCE_PATH_STYLE_ACCESS" = "true" ]; then + aws configure set default.s3.addressing_style path + fi + + S3_ARGS="" + if [ -n "$S3_ENDPOINT" ]; then + S3_ARGS="--endpoint-url $S3_ENDPOINT" + fi + + S3_PREVIEW_PREFIX="s3://$S3_BUCKET/preview-${PREVIEW_NUMBER}/" + + echo "Checking if $S3_PREVIEW_PREFIX exists..." + if [ "$(aws s3 $S3_ARGS ls "$S3_PREVIEW_PREFIX" | wc -l)" -eq 0 ]; then + echo "$S3_PREVIEW_PREFIX does not exist or is empty. Skipping teardown." + echo "Script finished successfully!" + echo "### END $(date --iso-8601=seconds) ###" + exit 0 + fi + + echo "Removing $S3_PREVIEW_PREFIX recursively..." + aws s3 $S3_ARGS rm "$S3_PREVIEW_PREFIX" --recursive + + echo "Script finished successfully!" + echo "### END $(date --iso-8601=seconds) ###" + env: + - name: S3_BUCKET + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_BUCKET_KEY} + - name: S3_ENDPOINT + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_ENDPOINT_KEY} + optional: true + - name: AWS_DEFAULT_REGION + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_REGION_KEY} + - name: S3_FORCE_PATH_STYLE_ACCESS + valueFrom: + configMapKeyRef: + name: ${CONFIGMAP_NAME} + key: ${S3_FORCE_PATH_STYLE_ACCESS_KEY} + optional: true + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: ${SECRET_NAME} + key: ${S3_ACCESS_KEY_KEY} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: ${SECRET_NAME} + key: ${S3_SECRET_KEY_KEY} + - name: PREVIEW_NUMBER + value: "${PREVIEW_NUMBER}"