diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..e4c1a76 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,113 @@ +name: Deploy + +on: + pull_request: + types: ["opened", "edited", "reopened", "synchronize"] + push: + branches: + - main + workflow_call: + # Map the workflow outputs to job outputs + outputs: + container_id: + description: "ID of your container inside your namespace" + value: ${{ jobs.deploy.outputs.scw_container_id }} + namespace_id: + description: "ID of your container namespace" + value: ${{ jobs.deploy.outputs.scw_namespace_id }} + +jobs: + deploy: + runs-on: ubuntu-latest + name: deploy scaleway serverless container + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEPLOYMENT_NAME: "container" + SCW_DNS: ${{ github.ref_name == 'main' && 'containers.philibeaux.fr' || '' }} + steps: + - name: Start deployment + uses: bobheadxi/deployments@v1.5.0 + id: deployment + with: + step: start + token: ${{ env.GH_TOKEN }} + env: ${{ env.DEPLOYMENT_NAME }} + ref: ${{ github.head_ref }} + - uses: actions/checkout@v4 + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v4 + - name: Export custom variables + run: | + SAFE_GITHUB_HEAD_REF_SLUG_URL=$(echo $GITHUB_HEAD_REF_SLUG_URL-$DEPLOYMENT_NAME | rev | cut -c-37 | rev) + ([[ $GITHUB_REF == 'refs/heads/main' ]] && echo "BRANCH_SLUG=main" || echo "BRANCH_SLUG=$SAFE_GITHUB_HEAD_REF_SLUG_URL") >> $GITHUB_ENV + + - name: Set scw_max_concurrency + id: set-max-concurrency + run: | + if [[ "${{ env.BRANCH_SLUG }}" == "main" ]]; then + echo "SCW_MAX_CONCURRENCY=5" >> $GITHUB_ENV + else + echo "SCW_MAX_CONCURRENCY=1" >> $GITHUB_ENV + fi + + - name: Set scw_min_scale + id: set-min-scale + run: | + if [[ "${{ env.BRANCH_SLUG }}" == "main" ]]; then + echo "SCW_MIN_SCALE=1" >> $GITHUB_ENV + else + echo "SCW_MIN_SCALE=0" >> $GITHUB_ENV + fi + + - name: Set scw_limit + id: set-cpu-limit + run: | + if [[ "${{ env.BRANCH_SLUG }}" == "main" ]]; then + echo "SCW_CPU_LIMIT=1120" >> $GITHUB_ENV + echo "SCW_MEMORY_LIMIT=1024" >> $GITHUB_ENV + else + echo "SCW_CPU_LIMIT=140" >> $GITHUB_ENV + echo "SCW_MEMORY_LIMIT=256" >> $GITHUB_ENV + fi + + - name: Deploy Serverless Container Scaleway + uses: ./ + id: deploy + with: + type: "deploy" + scw_registry: rg.fr-par.scw.cloud/aphilibeaux/scaleway-form:latest + scw_dns: ${{ env.SCW_DNS }} + root_zone: ${{ env.BRANCH_SLUG == 'main' }} + scw_access_key: ${{ secrets.SCW_ACCESS_KEY }} + scw_secret_key: ${{ secrets.SCW_SECRET_KEY }} + scw_containers_namespace_id: ${{ secrets.SCW_CONTAINERS_NAMESPACE_ID }} + scw_environment_variables: "GITHUB=DEPLOY" + # scw_secrets: "GITHUB=DEPLOY" + scw_min_scale: ${{ env.SCW_MIN_SCALE }} + scw_cpu_limit: ${{ env.SCW_CPU_LIMIT }} + scw_max_concurrency: ${{ env.SCW_MAX_CONCURRENCY }} + scw_sandbox: "v2" + scw_memory_limit: ${{ env.SCW_MEMORY_LIMIT }} + + - name: check output + shell: bash + run: | + echo "${{ steps.deploy.outputs.url }}" + echo "${{ steps.deploy.outputs.container_url }}" + echo "${{ steps.deploy.outputs.scw_container_id }}" + echo "${{ steps.deploy.outputs.scw_namespace_id }}" + + - name: Update deployment status + uses: bobheadxi/deployments@v1.5.0 + if: always() + with: + step: finish + env: ${{ env.DEPLOYMENT_NAME }} + token: ${{ env.GH_TOKEN }} + auto_inactive: true + # This will now be automatically handled by github with the auto_inactive + override: false + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: ${{ steps.deploy.outputs.url }} + diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml deleted file mode 100644 index 8ae5472..0000000 --- a/.github/workflows/main.yaml +++ /dev/null @@ -1,121 +0,0 @@ -# only serve a purpose to live test -name: Deploy - -on: - pull_request: - types: ['opened', 'edited', 'reopened', 'synchronize'] - push: - branches: - - main - workflow_call: - # Map the workflow outputs to job outputs - outputs: - container_id: - description: "ID of your container inside your namespace" - value: ${{ jobs.deploy.outputs.scw_container_id }} - namespace_id: - description: "ID of your container namespace" - value: ${{ jobs.deploy.outputs.scw_namespace_id }} - -# jobs: -# deploy-scaleway-container: -# runs-on: ubuntu-latest -# name: deploy scaleway serverless container -# steps: -# # To use this repository's private action, -# # you must check out the repository -# - name: Checkout -# uses: actions/checkout@v2 - -# - name: Export custom variables -# run: | -# SAFE_GITHUB_HEAD_REF_SLUG_URL=$(echo $GITHUB_HEAD_REF | rev | cut -c-37 | rev) -# ([[ $GITHUB_REF == 'refs/heads/main' ]] && echo "BRANCH_SLUG=main" || echo "BRANCH_SLUG=$SAFE_GITHUB_HEAD_REF_SLUG_URL") >> $GITHUB_ENV -# - uses: hmarr/debug-action@v2 - -# - name: Start deployment -# uses: bobheadxi/deployments@v1.0.1 -# id: deployment -# with: -# step: start -# token: ${{ secrets.GH_TOKEN }} -# env: ${{ env.BRANCH_SLUG }} -# ref: ${{ github.head_ref }} -# debug: true - -# - name: Scaleway Container Deploy action -# id: deploy -# uses: ./ # Uses an action in the root directory -# with: -# type: deploy -# scw_access_key: ${{ secrets.ACCESS_KEY }} -# scw_secret_key: ${{ secrets.SECRET_KEY }} -# scw_containers_namespace_id: ae28eaf1-3b94-4660-bce0-9b0e0a5d1062 -# scw_registry: rg.fr-par.scw.cloud/aphilibeaux/scaleway-form:latest -# scw_dns: containers.philibeaux.fr -# root_zone: true - -# - name: check output -# shell: bash -# run: | -# echo "${{ steps.deploy.outputs.url }}" -# echo "${{ steps.deploy.outputs.container_url }}" -# echo "${{ steps.deploy.outputs.scw_container_id }}" -# echo "${{ steps.deploy.outputs.scw_namespace_id }}" - -# - name: Update deployment status -# uses: bobheadxi/deployments@v1.0.1 -# if: always() -# with: -# debug: true -# step: finish -# env: ${{ env.BRANCH_SLUG }} -# token: ${{ secrets.GH_TOKEN }} -# status: ${{ job.status }} -# deployment_id: ${{ steps.deployment.outputs.deployment_id }} -# env_url: ${{ steps.deploy.outputs.url }} - -# teardown-scaleway-container: -# name: teardown scaleway serverless container -# needs: deploy-scaleway-container -# runs-on: ubuntu-latest -# steps: -# # To use this repository's private action, -# # you must check out the repository -# - name: Checkout -# uses: actions/checkout@v2 - -# - name: Export custom variables -# run: | -# SAFE_GITHUB_HEAD_REF_SLUG_URL=$(echo $GITHUB_HEAD_REF | rev | cut -c-37 | rev) -# ([[ $GITHUB_REF == 'refs/heads/main' ]] && echo "BRANCH_SLUG=main" || echo "BRANCH_SLUG=$SAFE_GITHUB_HEAD_REF_SLUG_URL") >> $GITHUB_ENV -# - uses: hmarr/debug-action@v2 - -# - name: Scaleway Container Teardown action -# id: deploy -# uses: ./ # Uses an action in the root directory -# with: -# type: teardown -# scw_access_key: ${{ secrets.ACCESS_KEY }} -# scw_secret_key: ${{ secrets.SECRET_KEY }} -# scw_containers_namespace_id: ae28eaf1-3b94-4660-bce0-9b0e0a5d1062 -# scw_registry: rg.fr-par.scw.cloud/aphilibeaux/scaleway-form:latest -# scw_dns: containers.philibeaux.fr -# root_zone: true - -# - name: check output -# shell: bash -# run: | -# echo "${{ steps.deploy.outputs.url }}" -# echo "${{ steps.deploy.outputs.container_url }}" -# echo "${{ steps.deploy.outputs.scw_container_id }}" -# echo "${{ steps.deploy.outputs.scw_namespace_id }}" - -# - name: Update deployment status -# uses: bobheadxi/deployments@v1.0.1 -# if: always() -# with: -# debug: true -# step: delete-env -# token: ${{ secrets.GH_TOKEN }} -# env: ${{ env.BRANCH_SLUG }} \ No newline at end of file diff --git a/.github/workflows/teardown.yaml b/.github/workflows/teardown.yaml new file mode 100644 index 0000000..99c461d --- /dev/null +++ b/.github/workflows/teardown.yaml @@ -0,0 +1,53 @@ +# only serve a purpose to live test +name: Teardown + +on: + pull_request: + types: [closed] + workflow_call: + # Map the workflow outputs to job outputs + outputs: + container_id: + description: "ID of your container inside your namespace" + value: ${{ jobs.deploy.outputs.scw_container_id }} + namespace_id: + description: "ID of your container namespace" + value: ${{ jobs.deploy.outputs.scw_namespace_id }} + +jobs: + teardown: + runs-on: ubuntu-22.04 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + IMAGE_NAME: rg.fr-par.scw.cloud/aphilibeaux/scaleway-form + DEPLOYMENT_NAME: container + SCW_DNS: ${{ github.ref_name == 'main' && 'containers.philibeaux.fr'|| '' }} + + steps: + - uses: actions/checkout@v4 # v4.1.4 + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v4 + + - name: Export custom variables + run: | + SAFE_HEAD_REF=$(echo $GITHUB_HEAD_REF_DEPLOYMENT_NAME | rev | cut -c-37 | rev | sed 's/^-//g') + echo "BRANCH_SLUG=$SAFE_HEAD_REF" >> $GITHUB_ENV + + - name: Deploy Serverless Container Scaleway + uses: ./ + id: deploy + with: + type: "teardown" + scw_dns: ${{ env.SCW_DNS }} + root_zone: ${{ env.BRANCH_SLUG == 'main' }} + scw_access_key: ${{ secrets.SCW_ACCESS_KEY }} + scw_secret_key: ${{ secrets.SCW_SECRET_KEY }} + scw_containers_namespace_id: ae28eaf1-3b94-4660-bce0-9b0e0a5d1062 + scw_registry: rg.fr-par.scw.cloud/aphilibeaux/scaleway-form:latest + + - name: Remove deployment + uses: bobheadxi/deployments@v1.5.0 + with: + step: deactivate-env + token: ${{ env.GITHUB_TOKEN }} + env: ${{ env.BRANCH_SLUG }} \ No newline at end of file diff --git a/container.go b/container.go index dc84b70..7ae3606 100644 --- a/container.go +++ b/container.go @@ -9,6 +9,58 @@ import ( "github.com/scaleway/scaleway-sdk-go/scw" ) +func getSecrets() []*container.Secret { + SecretsMap := getKeyValue(EnvSecrets) + Secrets := make([]*container.Secret, 0) + + for key, value := range SecretsMap { + Secrets = append(Secrets, &container.Secret{ + Key: key, + Value: &value, + }) + } + + return Secrets +} + +func GetSandboxVersion() container.ContainerSandbox { + + sandbox := envOr(EnvSandbox, Sandbox.String()) + + if sandbox == "v1" { + return container.ContainerSandboxV1 + } + + if sandbox == "v2" { + return container.ContainerSandboxV2 + } + + return container.ContainerSandboxUnknownSandbox +} + + +func getContainerEnvVariables() *container.Container { + + port, _ := strconv.ParseInt(envOr(EnvContainerPort, fmt.Sprint(Port)), 10, 32) + memoryLimit, _ := strconv.ParseInt(envOr(EnvMemoryLimit, fmt.Sprint(MemoryLimit)), 10, 32) + minScale, _ := strconv.ParseInt(envOr(EnvMinScale, fmt.Sprint(MinScale)), 10, 32) + maxScale, _ := strconv.ParseInt(envOr(EnvMaxScale, fmt.Sprint(MaxScale)), 10, 32) + maxConcurrency, _ := strconv.ParseInt(envOr(EnvMaxConcurrency, fmt.Sprint(MaxConcurrency)), 10, 32) + cpuLimit, _ := strconv.ParseInt(envOr(EnvCPULimit, fmt.Sprint(CPULimit)), 10, 32) + + + return &container.Container{ + Port: uint32(port), + MemoryLimit: uint32(memoryLimit), + MinScale: uint32(minScale), + MaxScale: uint32(maxScale), + MaxConcurrency: uint32(maxConcurrency), + CPULimit: uint32(cpuLimit), + Sandbox: GetSandboxVersion(), + } + +} + func WaitForNamespaceReady(client *scw.Client, NamespaceContainer *container.Namespace) (*container.Namespace, error) { fmt.Println("waiting for namespace to be ready") @@ -154,26 +206,30 @@ func UpdateDeployedContainer( client *scw.Client, Container *container.Container, PathRegistry string, - EnvironmentVariables map[string]string, - Secrets []*container.Secret, ) (*container.Container, error) { api := container.NewAPI(client) Redeploy := true - port, _ := strconv.ParseInt(envOr(EnvContainerPort, "80"), 10, 32) - - Port := uint32(port) + containerEnv := getContainerEnvVariables() + Secrets := getSecrets() + EnvironmentVariables := getKeyValue(EnvEnvironmentVariables) updatedContainer, err := api.UpdateContainer(&container.UpdateContainerRequest{ Region: Container.Region, ContainerID: Container.ID, RegistryImage: &PathRegistry, Redeploy: &Redeploy, - Port: &Port, EnvironmentVariables: &EnvironmentVariables, SecretEnvironmentVariables: Secrets, + MemoryLimit: &containerEnv.MemoryLimit, + MinScale: &containerEnv.MinScale, + MaxScale: &containerEnv.MaxScale, + CPULimit: &containerEnv.CPULimit, + Port: &containerEnv.Port, + MaxConcurrency: &containerEnv.MaxConcurrency, + Sandbox: containerEnv.Sandbox, }) if err != nil { @@ -183,64 +239,36 @@ func UpdateDeployedContainer( return updatedContainer, nil } -func GetSandboxVersion()container.ContainerSandbox { - - sandbox := envOr(EnvSandbox, Sandbox.String()) - - if(sandbox == "v1"){ - return container.ContainerSandboxV1 - } - - if(sandbox == "v2"){ - return container.ContainerSandboxV2 - } - - return container.ContainerSandboxUnknownSandbox - -} func CreateContainerAndDeploy( client *scw.Client, NamespaceContainer *container.Namespace, PathRegistry string, - EnvironmentVariables map[string]string, - Secrets []*container.Secret, ContainerName string, ) (*container.Container, error) { api := container.NewAPI(client) - port, _ := strconv.ParseInt(envOr(EnvContainerPort, fmt.Sprint(Port)), 10, 32) - memoryLimit, _ := strconv.ParseInt(envOr(EnvMemoryLimit, fmt.Sprint(MemoryLimit)), 10, 32) - minScale, _ := strconv.ParseInt(envOr(EnvMinScale, fmt.Sprint(MinScale)), 10, 32) - maxScale, _ := strconv.ParseInt(envOr(EnvMaxScale, fmt.Sprint(MaxScale)), 10, 32) - maxConcurrency, _ := strconv.ParseInt(envOr(EnvMaxConcurrency, fmt.Sprint(MaxConcurrency)), 10, 32) - cpuLimit, _ := strconv.ParseInt(envOr(EnvCPULimit, fmt.Sprint(CPULimit)), 10, 32) - - Port := uint32(port) - MemoryLimit := uint32(memoryLimit) - MinScale := uint32(minScale) - MaxScale := uint32(maxScale) - MaxConcurrency := uint32(maxConcurrency) - CPULimit := uint32(cpuLimit) - Sandbox := GetSandboxVersion() + containerEnv := getContainerEnvVariables() + Secrets := getSecrets() + EnvironmentVariables := getKeyValue(EnvEnvironmentVariables) createdContainer, err := api.CreateContainer(&container.CreateContainerRequest{ Description: &Description, - MaxConcurrency: &MaxConcurrency, - MemoryLimit: &MemoryLimit, - MinScale: &MinScale, - MaxScale: &MaxScale, - CPULimit: &CPULimit, Name: ContainerName, NamespaceID: NamespaceContainer.ID, - Port: &Port, Region: NamespaceContainer.Region, RegistryImage: &PathRegistry, Timeout: &Timeout, EnvironmentVariables: &EnvironmentVariables, SecretEnvironmentVariables: Secrets, - Sandbox: Sandbox, + MemoryLimit: &containerEnv.MemoryLimit, + MinScale: &containerEnv.MinScale, + MaxScale: &containerEnv.MaxScale, + CPULimit: &containerEnv.CPULimit, + Port: &containerEnv.Port, + MaxConcurrency: &containerEnv.MaxConcurrency, + Sandbox: containerEnv.Sandbox, }) if err != nil { diff --git a/dns.go b/dns.go index c8877c5..0285f37 100644 --- a/dns.go +++ b/dns.go @@ -155,7 +155,7 @@ func AddDNSRecord( Changes := []*domain.RecordChange{ { - Add: &domain.RecordChangeAdd{ + Set: &domain.RecordChangeSet{ Records: Records, }, }, diff --git a/main.go b/main.go index 16da7fb..fb534cb 100644 --- a/main.go +++ b/main.go @@ -10,25 +10,25 @@ import ( ) const ( - EnvType = "INPUT_TYPE" - EnvAccessKey = "INPUT_SCW_ACCESS_KEY" - EnvContainerNamespaceID = "INPUT_SCW_CONTAINERS_NAMESPACE_ID" - EnvContainerPort = "INPUT_SCW_CONTAINER_PORT" - EnvDNS = "INPUT_SCW_DNS" - EnvDNSPrefix = "INPUT_SCW_DNS_PREFIX" - EnvRegion = "INPUT_SCW_REGION" - EnvPathRegistry = "INPUT_SCW_REGISTRY" - EnvProjectID = "INPUT_SCW_PROJECT_ID" - EnvSecretKey = "INPUT_SCW_SECRET_KEY" - EnvMemoryLimit = "INPUT_SCW_MEMORY_LIMIT" - EnvMinScale = "INPUT_SCW_MIN_SCALE" - EnvMaxScale = "INPUT_SCW_MAX_SCALE" - EnvMaxConcurrency = "INPUT_SCW_MAX_CONCURRENCY" - EnvCPULimit = "INPUT_SCW_CPU_LIMIT" - EnvSandbox = "INPUT_SCW_SANDBOX" - EnvRootZone = "INPUT_ROOT_ZONE" - EnvEnvironmentVariables = "INPUT_SCW_ENVIRONMENT_VARIABLES" - EnvSecrets = "INPUT_SCW_SECRETS" + EnvType = "INPUT_TYPE" + EnvAccessKey = "INPUT_SCW_ACCESS_KEY" + EnvContainerNamespaceID = "INPUT_SCW_CONTAINERS_NAMESPACE_ID" + EnvContainerPort = "INPUT_SCW_CONTAINER_PORT" + EnvDNS = "INPUT_SCW_DNS" + EnvDNSPrefix = "INPUT_SCW_DNS_PREFIX" + EnvRegion = "INPUT_SCW_REGION" + EnvPathRegistry = "INPUT_SCW_REGISTRY" + EnvProjectID = "INPUT_SCW_PROJECT_ID" + EnvSecretKey = "INPUT_SCW_SECRET_KEY" + EnvMemoryLimit = "INPUT_SCW_MEMORY_LIMIT" + EnvMinScale = "INPUT_SCW_MIN_SCALE" + EnvMaxScale = "INPUT_SCW_MAX_SCALE" + EnvMaxConcurrency = "INPUT_SCW_MAX_CONCURRENCY" + EnvCPULimit = "INPUT_SCW_CPU_LIMIT" + EnvSandbox = "INPUT_SCW_SANDBOX" + EnvRootZone = "INPUT_ROOT_ZONE" + EnvEnvironmentVariables = "INPUT_SCW_ENVIRONMENT_VARIABLES" + EnvSecrets = "INPUT_SCW_SECRETS" ) var ( @@ -121,8 +121,6 @@ func DeployContainer( Namespace *container.Namespace, ContainerName string, PathRegistry string, - EnvironmentVariables map[string]string, - Secrets []*container.Secret, ) (*container.Container, error) { fmt.Println("Container Name: ", ContainerName) @@ -135,7 +133,7 @@ func DeployContainer( fmt.Println("Container already exists and will be updated", ExistingContainer) - Container, err := UpdateDeployedContainer(Client, ExistingContainer, PathRegistry, EnvironmentVariables, Secrets) + Container, err := UpdateDeployedContainer(Client, ExistingContainer, PathRegistry) if err != nil { fmt.Println("unable to redeploy this serverless container : ", err) @@ -148,7 +146,7 @@ func DeployContainer( return container, err } else { - Container, err := CreateContainerAndDeploy(Client, Namespace, PathRegistry, EnvironmentVariables, Secrets, ContainerName) + Container, err := CreateContainerAndDeploy(Client, Namespace, PathRegistry, ContainerName) if err != nil { fmt.Println("unable to create or deploy a serverless container : ", err) @@ -199,8 +197,6 @@ func Deploy( Client *scw.Client, Region scw.Region, PathRegistry string, - EnvironmentVariables map[string]string, - Secrets []*container.Secret, ) (*container.Container, *container.Domain, error) { // Create or get a serverless container namespace @@ -216,7 +212,7 @@ func Deploy( ContainerName := GetContainerName(PathRegistry) - Container, err := DeployContainer(Client, namespaceContainer, ContainerName, PathRegistry, EnvironmentVariables, Secrets) + Container, err := DeployContainer(Client, namespaceContainer, ContainerName, PathRegistry) if err != nil { fmt.Println("unable to deploy a serverless container : ", err) @@ -281,26 +277,10 @@ func getKeyValue(key string) map[string]string { return KeyValue } -func getSecrets() []*container.Secret { - SecretsMap := getKeyValue(EnvSecrets) - Secrets := make([]*container.Secret, 0) - - for key, value := range SecretsMap { - Secrets = append(Secrets, &container.Secret{ - Key: key, - Value: &value, - }) - } - - return Secrets -} - func main() { PathRegistry := os.Getenv(EnvPathRegistry) MaybeRegion := envOr(EnvRegion, "fr-par") Type := envOr(EnvType, "deploy") - EnvironmentVariables := getKeyValue(EnvEnvironmentVariables) - Secrets := getSecrets() if PathRegistry == "" { fmt.Println("Env Registry is not set") @@ -326,7 +306,7 @@ func main() { } if Type == "deploy" { - Container, Domain, err := Deploy(Client, Region, PathRegistry, EnvironmentVariables, Secrets) + Container, Domain, err := Deploy(Client, Region, PathRegistry) if err != nil { fmt.Println("unable to deploy: ", err)