Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared crossplane action refactor #137

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
85 changes: 85 additions & 0 deletions .github/workflows/crossplane.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
on:
workflow_call:
inputs:
environment:
required: true
type: string
service_name:
required: true
type: string

permissions:
id-token: write
contents: read
pull-requests: write
statuses: write

jobs:
crossplane-terraform:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
-
name: Checkout shared-actions
uses: actions/checkout@v4
with:
repository: vimeda/shared-actions
path: ./scripts
ref: feature/shared-crossplane
-
name: Checkout service
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
path: ./scripts/${{ inputs.service_name }}
-
name: Install yq
uses: chrisdickinson/[email protected]
with:
yq-version: v4.25.3
-
name: Install 1Password CLI
uses: 1password/install-cli-action@v1
-
name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-${{ inputs.service_name }}-role
role-session-name: ga-${{ inputs.service_name }}
aws-region: eu-central-1
-
name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ~1.9

-
name: Terraform Init
working-directory: ./scripts/crossplane
run: |
terraform init \
-backend-config="region=eu-central-1" \
-backend-config="bucket=terraform-eks" \
-backend-config="key=crossplane/${{ inputs.service_name }}"

-
name: Terraform Validate
working-directory: ./scripts/crossplane
run: |
terraform validate -no-color
-
name: Terraform
working-directory: ./scripts/crossplane
run: |
echo "${{ secrets.STAGING_KUBECONFIG }}" > ${{ github.workspace }}/kubeconfig.yaml
export KUBECONFIG=${{ github.workspace }}/kubeconfig.yaml
terraform apply -auto-approve -no-color \
-var-file=${{ inputs.environment }}.tfvars \
-var="commit_hash=${{ github.sha }}" \
-var="service_name=${{ inputs.service_name }}"
env:
TF_WORKSPACE: ${{ inputs.environment }}
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.STAGING_ONEPASSWORD_SERVICEACCOUNT_TOKEN }}


25 changes: 5 additions & 20 deletions .github/workflows/pr-crossplane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ jobs:
path: ${{ github.workspace }}/dist
zip_lambda_workflow_step: ${{ inputs.zip_lambda_workflow_step }}

- name: Display structure of downloaded files
run: ls -R
working-directory: ${{ steps.download.outputs.download-path }}


- uses: hashicorp/setup-terraform@v1
with:
terraform_version: ~1.4
Expand All @@ -89,26 +84,16 @@ jobs:
id: downloadscripts
with:
name: scripts
path: ./scripts

- name: copy scripts to scripts folder in working directory
run: |
mkdir ./scripts && ls
cp -r ${{ github.workspace }}/scripts/.github/workflows ./scripts
shell: sh
path: /tmp/scripts

- name: Install 1Password Cli, patch claim
run: |
curl https://cache.agilebits.com/dist/1P/op2/pkg/v2.18.0/op_linux_amd64_v2.18.0.zip > op.zip
unzip op.zip
sudo mv op /usr/local/bin
rm op.zip
ls
curl https://cache.agilebits.com/dist/1P/op2/pkg/v2.18.0/op_linux_amd64_v2.23.0.zip > op.zip
sudo unzip op.zip -d /usr/local/bin && rm op.zip
python -m pip install "ruamel.yaml<0.18.0"

python scripts/workflows/scripts/patch.py


python /tmp/scripts/.github/workflows/scripts/patch.py

for file in *claims.yaml; do
if [ -f "$file" ]; then
cat $file
Expand Down
2 changes: 2 additions & 0 deletions crossplane/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.terraform/
.terraform.lock.hcl
3 changes: 3 additions & 0 deletions crossplane/backend-config.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
region = "eu-central-1"
bucket = "terraform-eks"
key = "crossplane/${service_name}/state.tf"
58 changes: 58 additions & 0 deletions crossplane/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
data "template_file" "claims" {
for_each = fileset("../${var.service_name}/configs/crossplane/${terraform.workspace}", "*.yaml")
template = file("../${var.service_name}/configs/crossplane/${terraform.workspace}/${each.value}")

vars = {
commit_hash = var.commit_hash
}
}

#
# Use external data source to run the bash script to modify the claims
data "external" "modified_yaml" {
for_each = data.template_file.claims
program = ["bash", "${path.module}/modify-claims.sh"]

query = {
vault_id = var.vault_id
claim_yaml = each.value.rendered
env = terraform.workspace
}
}

output "modified_yaml" {
value = data.external.modified_yaml
}

# Locals for decoding the updated YAML from the external script output
locals {
# Define the path to the directory containing YAML files
yaml_dir = "${path.module}/tmp" # Adjust this to your module's relative path
yaml_files = fileset(local.yaml_dir, "*.yaml") # Get all YAML files in the specified directory
}

# Parse the YAML content into Kubernetes documents using kubectl provider
data "kubectl_file_documents" "claims" {
depends_on = [data.external.modified_yaml] # Ensure this runs after the external data source
for_each = data.external.modified_yaml
content = yamlencode(jsondecode(each.value.result.manifest))
}

output "kubectl_manifest" {
value = data.kubectl_file_documents.claims
}

locals {
# Collect all manifests into a flat list
manifests_array = flatten([
for doc in data.kubectl_file_documents.claims : [
for _, manifest in doc.manifests : manifest
]
])
}

resource "kubectl_manifest" "apply" {
depends_on = [data.kubectl_file_documents.claims]
for_each = toset(local.manifests_array)
yaml_body = each.value # Apply each manifest from the array
}
80 changes: 80 additions & 0 deletions crossplane/modify-claims.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash

set -euov pipefail

# Ensure the tmp/ folder exists in the current working directory
mkdir -p tmp/

# Extract variables using jq
eval "$(jq -r '@sh "ENV=\(.env) VAULT_ID=\(.vault_id) CLAIM_YAML=\(.claim_yaml)"')"

# Generate a SHA256 hash from CLAIM_YAML and use part of it for the file name
hash=$(echo -n "$CLAIM_YAML" | sha256sum | cut -d' ' -f1)

# Create a temporary file in the tmp/ folder, prefixed with 'tmpfile_' and suffixed with the hash
temp_yaml_file="tmp/tmpfile_${hash}.yaml"

# Write the input YAML to the temporary file for processing
echo "$CLAIM_YAML" > "$temp_yaml_file"

# Predefined arrays of claim types to process
CLAIM_TYPES_LAMBDA=("XLykonLambda" "XLykonLambdaDockerImage")
CLAIM_TYPES_GOAPP=("XLykonGoApp")

# Check the kind of the YAML
kind=$(yq eval '.kind' "$temp_yaml_file")

# Function to add VPC configuration based on environment
add_vpc_config() {
local env="$1"
local config

if [[ "$env" == "staging" ]]; then
config='{"vpcConfig":[{"securityGroupIds":["sg-03c24245575c1ebc0"],"subnetIds":["subnet-011cb6fe763310759","subnet-08deca209f9e46ebb","subnet-06e62ab1abfd70465"]}]}'
elif [[ "$env" == "prod" ]]; then
config='{"vpcConfig":[{"securityGroupIds":["sg-03c24245575c1ebc0"],"subnetIds":["subnet-011cb6fe763310759","subnet-08deca20d9f9e46ebb","subnet-06e62ab1abfd70465"]}]}'
else
echo "Error: Unsupported environment $env"
exit 1
fi

yq eval ".spec.parameters += $config" -i "$temp_yaml_file"
}

if [[ " ${CLAIM_TYPES_LAMBDA[@]} " =~ " ${kind} " ]]; then
# Handle XLykonLambda and XLykonLambdaDockerImage
service_name=$(yq eval '.spec.parameters.service_name' "$temp_yaml_file")

if [[ -z "$service_name" ]]; then
echo "Warning: service_name is not defined, skipping secret fetching."
else
secrets=$(op items get "$service_name" --vault="$VAULT_ID" --format=json | jq '.fields | map({(.label): .value}) | add')

if [[ -z "$secrets" ]]; then
echo "Warning: Failed to fetch secrets for $service_name, skipping secret addition."
else
# Wrap secrets in an array with 'variables'
secrets_with_variables=$(jq -n --argjson secrets "$secrets" '[{"variables": $secrets}]')

# Update the YAML file with the secrets under 'secrets' field
yq eval ".spec.parameters.secrets = $secrets_with_variables" -i "$temp_yaml_file"
fi
fi
add_vpc_config "$ENV" # Add VPC config only for Lambda types
elif [[ " ${CLAIM_TYPES_GOAPP[@]} " =~ " ${kind} " ]]; then
# Handle XLykonGoApp
if [[ "$ENV" == "staging" ]]; then
vault_id="errsir3kqd4gdjgaxliofyskey"
elif [[ "$ENV" == "prod" ]]; then
vault_id="37y43e5v2qd3iptgt7wgyk34ga"
else
echo "Error: Unsupported environment $ENV"
exit 1
fi

yq eval ".spec.parameters.vault_id = \"$vault_id\"" -i "$temp_yaml_file"
fi

# Convert the final YAML to JSON for Terraform
manifest=$(yq eval -o=json "$temp_yaml_file")
jq -n --arg manifest "$manifest" '{ manifest: $manifest }'
2 changes: 2 additions & 0 deletions crossplane/prod.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cluster_name = "prod-eks-v2"
vault_id = "37y43e5v2qd3iptgt7wgyk34ga"
2 changes: 2 additions & 0 deletions crossplane/staging.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cluster_name = "staging-eks-v2"
vault_id = "errsir3kqd4gdjgaxliofyskey"
19 changes: 19 additions & 0 deletions crossplane/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
variable "commit_hash" {
description = "git commit hash, which will be used to tag the docker image"
type = string
}

variable "cluster_name" {
description = "name of the eks cluster"
type = string
}

variable "service_name" {
description = "name of the service to deploy"
type = string
}

variable "vault_id" {
description = "1password vault id"
type = string
}
25 changes: 25 additions & 0 deletions crossplane/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
terraform {
required_version = ">= 1.0.0"

required_providers {
kubectl = {
source = "alekc/kubectl"
version = ">= 2.0.0"
}
local = {
source = "hashicorp/local"
version = "2.5.2"
}
aws = {
source = "hashicorp/aws"
version = "4.64.0"
}
template = {
source = "hashicorp/template"
version = "2.2.0"
}
}
backend "s3" {
}
}

6 changes: 0 additions & 6 deletions renovate.json

This file was deleted.