diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6ceafec..7086d55 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,7 +25,8 @@ - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as + expected) #### Checklist: @@ -33,4 +34,4 @@ - [ ] My change requires a change to the documentation. -- [ ] I have updated the documentation accordingly. \ No newline at end of file +- [ ] I have updated the documentation accordingly. diff --git a/.github/release.yml b/.github/release.yml index 9cbf0b9..5adf76d 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -4,6 +4,7 @@ changelog: exclude: labels: - ignore-for-release + - skip authors: - pagopa-github-bot categories: diff --git a/.github/workflows/assignee.yml b/.github/workflows/assignee.yml deleted file mode 100644 index 0611917..0000000 --- a/.github/workflows/assignee.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Auto Assign - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the main branch - pull_request_target: - branches: - - main - types: [ opened, reopened ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: Assign Me - # You may pin to the exact commit or the version. - uses: kentaro-m/auto-assign-action@v1.2.1 - with: - configuration-path: '.github/auto_assign.yml' diff --git a/.github/workflows/check_metadata_pr.yml b/.github/workflows/check_metadata_pr.yml deleted file mode 100644 index c687c53..0000000 --- a/.github/workflows/check_metadata_pr.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Check PR - -# Controls when the workflow will run -on: - pull_request_target: - branches: - - main - types: [ opened, labeled, unlabeled, reopened ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - name: Check Labels - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - - name: Verify PR Labels - uses: jesusvasquez333/verify-pr-label-action@v1.4.0 - with: - github-token: '${{ secrets.GITHUB_TOKEN }}' - valid-labels: 'bug, enhancement, breaking-change, ignore-for-release' - pull-request-number: '${{ github.event.pull_request.number }}' - - - name: Label Check - if: ${{ !contains(github.event.pull_request.labels.*.name, 'breaking-change') && !contains(github.event.pull_request.labels.*.name, 'enhancement') && !contains(github.event.pull_request.labels.*.name, 'bug') && !contains(github.event.pull_request.labels.*.name, 'ignore-for-release') }} - uses: actions/github-script@v3 - with: - script: | - core.setFailed('Missing required labels') diff --git a/.github/workflows/check_pr.yml b/.github/workflows/check_pr.yml new file mode 100644 index 0000000..0763155 --- /dev/null +++ b/.github/workflows/check_pr.yml @@ -0,0 +1,191 @@ +name: Check PR + +# Controls when the workflow will run +on: + pull_request: + branches: + - main + types: [ opened, synchronize, labeled, unlabeled, reopened, edited ] + + +permissions: + pull-requests: write + + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + auto_assign: + name: Auto Assign + + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Assign Me + # You may pin to the exact commit or the version. + uses: kentaro-m/auto-assign-action@v1.2.1 + with: + configuration-path: '.github/auto_assign.yml' + + check_format: + name: Check Format + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Formatting + id: format + continue-on-error: true + uses: findologic/intellij-format-action@main + with: + path: . + fail-on-changes: false + + - uses: actions/github-script@v6.3.3 + if: steps.format.outcome != 'success' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + console.log(context); + var comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + for (const comment of comments.data) { + console.log(comment); + if (comment.body.includes('Comment this PR with')){ + github.rest.issues.deleteComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id + }) + } + } + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Comment this PR with *update_code* to update `openapi.json` and format the code. Consider to use pre-commit to format the code.' + }) + core.setFailed('Format your code.') + + check_size: + runs-on: ubuntu-latest + name: Check Size + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check Size + uses: actions/github-script@v6.3.3 + env: + IGNORED_FILES: openapi.json, openapi-node.json + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const additions = context.payload.pull_request.additions || 0 + const deletions = context.payload.pull_request.deletions || 0 + var changes = additions + deletions + console.log('additions: '+additions+' + deletions: '+deletions+ ' = total changes: ' + changes); + + const { IGNORED_FILES } = process.env + const ignored_files = IGNORED_FILES.trim().split(',').filter(word => word.length > 0); + if (ignored_files.length > 0){ + var ignored = 0 + const execSync = require('child_process').execSync; + for (const file of IGNORED_FILES.trim().split(',')) { + + const ignored_additions_str = execSync('git --no-pager diff --numstat origin/main..origin/${{ github.head_ref}} | grep ' + file + ' | cut -f 1', { encoding: 'utf-8' }) + const ignored_deletions_str = execSync('git --no-pager diff --numstat origin/main..origin/${{ github.head_ref}} | grep ' + file + ' | cut -f 2', { encoding: 'utf-8' }) + + const ignored_additions = ignored_additions_str.split('\n').map(elem=> parseInt(elem || 0)).reduce( + (accumulator, currentValue) => accumulator + currentValue, + 0); + const ignored_deletions = ignored_deletions_str.split('\n').map(elem=> parseInt(elem || 0)).reduce( + (accumulator, currentValue) => accumulator + currentValue, + 0); + + ignored += ignored_additions + ignored_deletions; + } + changes -= ignored + console.log('ignored lines: ' + ignored + ' , consider changes: ' + changes); + } + + if (changes < 200){ + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['size/small'] + }) + + + var labels = await github.rest.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + + if (labels.data.find(label => label.name == 'size/large')){ + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: 'size/large' + }) + } + } + + if (changes > 400){ + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['size/large'] + }) + + var comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + for (const comment of comments.data) { + if (comment.body.includes('This PR exceeds the recommended size')){ + github.rest.issues.deleteComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id + }) + } + } + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'This PR exceeds the recommended size of 400 lines. Please make sure you are NOT addressing multiple issues with one PR. _Note this PR might be rejected due to its size._' + }) + + var labels = await github.rest.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + + if (labels.data.find(label => label.name == 'size/small')){ + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: 'size/small' + }) + } + + } + diff --git a/.github/workflows/code_review.yml b/.github/workflows/code_review.yml new file mode 100644 index 0000000..5055b17 --- /dev/null +++ b/.github/workflows/code_review.yml @@ -0,0 +1,118 @@ +name: Code Review + +# Controls when the workflow will run +on: + pull_request: + branches: + - main + types: + - opened + - synchronize + - reopened + push: + branches: + - main + + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + PROJECT_KEY: "pagopa-spontaneus-payments" + +permissions: + id-token: write + contents: read + deployments: write + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + code-review: + name: Code Review + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Code Review + uses: pagopa/github-actions-template/maven-code-review@v1.4.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + sonar_token: ${{ secrets.SONAR_TOKEN }} + project_key: ${{env.PROJECT_KEY}} + coverage_exclusions: "**/config/*,**/*Mock*,**/model/**,**/entity/*" + cpd_exclusions: "**/model/**,**/entity/*" + + smoke-test: + name: Smoke Test + runs-on: ubuntu-latest + environment: + name: dev + steps: + - name: Checkout + id: checkout + uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656657ea2c6707 + + - name: Login + id: login + # from https://github.com/Azure/login/commits/master + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 + with: + client-id: ${{ secrets.CLIENT_ID }} + tenant-id: ${{ secrets.TENANT_ID }} + subscription-id: ${{ secrets.SUBSCRIPTION_ID }} + + - name: Run Service on Docker + shell: bash + id: run_service_docker + run: | + cd ./docker + chmod +x ./run_docker.sh + ./run_docker.sh local + + - name: Run Integration Tests + shell: bash + id: run_integration_test + run: | + export SUBKEY=${{ secrets.SUBKEY }} + export CANARY=${{ inputs.canary }} + export CUCUMBER_PUBLISH_TOKEN=${{ secrets.CUCUMBER_PUBLISH_TOKEN }} + + cd ./integration-test + chmod +x ./run_integration_test.sh + ./run_integration_test.sh local + + + delete_github_deployments: + runs-on: ubuntu-latest + needs: smoke-test + if: ${{ always() }} + steps: + - name: Delete Previous deployments + uses: actions/github-script@v6 + env: + SHA_HEAD: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.sha) || github.sha}} + with: + script: | + const { SHA_HEAD } = process.env + + const deployments = await github.rest.repos.listDeployments({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: SHA_HEAD + }); + await Promise.all( + deployments.data.map(async (deployment) => { + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id, + state: 'inactive' + }); + return github.rest.repos.deleteDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id + }); + }) + ); diff --git a/.github/workflows/create_dashboard.yaml b/.github/workflows/create_dashboard.yaml new file mode 100644 index 0000000..61fa251 --- /dev/null +++ b/.github/workflows/create_dashboard.yaml @@ -0,0 +1,84 @@ +name: Create Dashboard + +# Controls when the workflow will run +on: + push: + branches: + - main + paths: + - 'openapi/**' + - '.github/workflows/create_dashboard.yaml' + - '.opex/**' + + workflow_dispatch: + +permissions: + id-token: write + contents: read + deployments: write + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + dashboard: + # The type of runner that the job will run on + runs-on: ubuntu-22.04 + + strategy: + matrix: + environment: [prod] + environment: + name: ${{ matrix.environment }} + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Checkout + id: checkout + # from https://github.com/actions/checkout/commits/main + uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656657ea2c6707 + with: + persist-credentials: false + + # from https://github.com/pagopa/opex-dashboard-azure-action/ + - uses: pagopa/opex-dashboard-azure-action@v1.1.2 + with: + environment: ${{ matrix.environment }} + api-name: + config: .opex/env/${{ matrix.environment }}/config.yaml + client-id: ${{ secrets.CLIENT_ID }} + tenant-id: ${{ secrets.TENANT_ID }} + subscription-id: ${{ secrets.SUBSCRIPTION_ID }} + # from https://github.com/pagopa/opex-dashboard-azure-action/pkgs/container/opex-dashboard-azure-action + docker-version: sha256:e4245954566cd3470e1b5527d33bb58ca132ce7493eac01be9e808fd25a11c8d + + delete_github_deployments: + runs-on: ubuntu-latest + needs: dashboard + if: ${{ always() }} + steps: + - name: Delete Previous deployments + uses: actions/github-script@v6 + env: + SHA_HEAD: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.sha) || github.sha}} + with: + script: | + const { SHA_HEAD } = process.env + + const deployments = await github.rest.repos.listDeployments({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: SHA_HEAD + }); + await Promise.all( + deployments.data.map(async (deployment) => { + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id, + state: 'inactive' + }); + return github.rest.repos.deleteDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id + }); + }) + ); diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 035b70f..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Auto Deploy - -# Controls when the workflow will run -on: - pull_request: - branches: - - main - types: [ closed ] - - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - if: ${{ github.event.pull_request.merged }} - name: Call Azure Build Pipeline - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - # default skip bump versioning - - name: Set as default skip bump versioning - run: | - echo "SEMVER=skip" >> $GITHUB_ENV - - - name: Set major - run: | - echo "SEMVER=major" >> $GITHUB_ENV - if: ${{ contains(github.event.pull_request.labels.*.name, 'breaking-change') }} - - - name: Set minor - run: | - echo "SEMVER=minor" >> $GITHUB_ENV - if: ${{ contains(github.event.pull_request.labels.*.name, 'enhancement') }} - - - name: Set patch - run: | - echo "SEMVER=patch" >> $GITHUB_ENV - if: ${{ contains(github.event.pull_request.labels.*.name, 'bug') }} - - - name: Set skip - run: | - echo "SEMVER=skip" >> $GITHUB_ENV - if: ${{ contains(github.event.pull_request.labels.*.name, 'ignore-for-release') }} - - - name: Azure Pipelines Action - Jversion - uses: jacopocarlini/azure-pipelines@v1.3 - with: - azure-devops-project-url: https://dev.azure.com/pagopaspa/pagoPA-projects - azure-pipeline-name: 'pagopa-spontaneous-payments.deploy' - azure-devops-token: ${{ secrets.AZURE_DEVOPS_TOKEN }} - azure-template-parameters: '{"ENV": "dev", "SEMVER": "${{env.SEMVER}}", "TEST": "true"}' - azure-pipeline-variables: '{"system.debug": "true"}' - diff --git a/.github/workflows/deploy_with_github_runner.yml b/.github/workflows/deploy_with_github_runner.yml new file mode 100644 index 0000000..8e8e564 --- /dev/null +++ b/.github/workflows/deploy_with_github_runner.yml @@ -0,0 +1,126 @@ +name: Deploy on AKS + +on: + workflow_call: + inputs: + environment: + required: true + description: The name of the environment where to deploy + type: string + target: + required: true + description: The environment target of the job + type: string + +env: + APP_NAME: pagopaspontaneouspayments + + +permissions: + id-token: write + contents: read + +jobs: + create_runner: + name: Create Runner + runs-on: ubuntu-22.04 + environment: + name: ${{ inputs.environment }} + if: ${{ inputs.target == inputs.environment || inputs.target == 'all' }} + outputs: + runner_name: ${{ steps.create_github_runner.outputs.runner_name }} + steps: + - name: Create GitHub Runner + id: create_github_runner + # from https://github.com/pagopa/eng-github-actions-iac-template/tree/main/azure/github-self-hosted-runner-azure-create-action + uses: pagopa/eng-github-actions-iac-template/azure/github-self-hosted-runner-azure-create-action@main + with: + client_id: ${{ secrets.CLIENT_ID }} + tenant_id: ${{ secrets.TENANT_ID }} + subscription_id: ${{ secrets.SUBSCRIPTION_ID }} + container_app_environment_name: ${{ vars.CONTAINER_APP_ENVIRONMENT_NAME }} + resource_group_name: ${{ vars.CONTAINER_APP_ENVIRONMENT_RESOURCE_GROUP_NAME }} # RG of the runner + pat_token: ${{ secrets.BOT_TOKEN_GITHUB }} + self_hosted_runner_image_tag: "v1.4.1" + + deploy: + needs: [ create_runner ] + runs-on: [ self-hosted, "${{ needs.create_runner.outputs.runner_name }}" ] + if: ${{ inputs.target == inputs.environment || inputs.target == 'all' }} + name: Deploy on AKS + environment: ${{ inputs.environment }} + steps: + - name: Deploy + uses: pagopa/github-actions-template/aks-deploy@main + with: + branch: ${{ github.ref_name }} + client_id: ${{ secrets.CLIENT_ID }} + subscription_id: ${{ secrets.SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.TENANT_ID }} + env: ${{ inputs.environment }} + namespace: ${{ vars.NAMESPACE }} + cluster_name: ${{ vars.CLUSTER_NAME }} + resource_group: ${{ vars.CLUSTER_RESOURCE_GROUP }} + app_name: ${{ env.APP_NAME }} + helm_upgrade_options: "--debug" + + cleanup_runner: + name: Cleanup Runner + needs: [ create_runner, deploy ] + if: ${{ success() || failure() && inputs.target == inputs.environment || inputs.target == 'all' }} + runs-on: ubuntu-22.04 + environment: ${{ inputs.environment }} + steps: + - name: Cleanup GitHub Runner + id: cleanup_github_runner + # from https://github.com/pagopa/eng-github-actions-iac-template/tree/main/azure/github-self-hosted-runner-azure-cleanup-action + uses: pagopa/eng-github-actions-iac-template/azure/github-self-hosted-runner-azure-cleanup-action@0ee2f58fd46d10ac7f00bce4304b98db3dbdbe9a + with: + client_id: ${{ secrets.CLIENT_ID }} + tenant_id: ${{ secrets.TENANT_ID }} + subscription_id: ${{ secrets.SUBSCRIPTION_ID }} + resource_group_name: ${{ vars.CONTAINER_APP_ENVIRONMENT_RESOURCE_GROUP_NAME }} + runner_name: ${{ needs.create_runner.outputs.runner_name }} + pat_token: ${{ secrets.BOT_TOKEN_GITHUB }} + + update_openapi: + needs: [ deploy ] + runs-on: ubuntu-latest + name: Update OpenAPI + if: ${{ inputs.target == inputs.environment || inputs.target == 'all' }} + environment: ${{ inputs.environment }} + steps: + - name: Checkout + id: checkout + # from https://github.com/actions/checkout/commits/main + uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656657ea2c6707 + with: + persist-credentials: false + + - name: Setup Terraform + # from https://github.com/hashicorp/setup-terraform/commits/main + uses: hashicorp/setup-terraform@8feba2b913ea459066180f9cb177f58a881cf146 + with: + terraform_version: "1.3.6" + + - name: Login + id: login + # from https://github.com/Azure/login/commits/master + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 + with: + client-id: ${{ secrets.CLIENT_ID }} + tenant-id: ${{ secrets.TENANT_ID }} + subscription-id: ${{ secrets.SUBSCRIPTION_ID }} + + + - name: Terraform Apply + shell: bash + run: | + cd ./infra + export ARM_CLIENT_ID="${{ secrets.CLIENT_ID }}" + export ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) + export ARM_TENANT_ID=$(az account show --query tenantId --output tsv) + export ARM_USE_OIDC=true + export ARM_ACCESS_KEY=$(az storage account keys list --resource-group io-infra-rg --account-name pagopainfraterraform${{inputs.environment}} --query '[0].value' -o tsv) + bash ./terraform.sh init weu-${{ inputs.environment }} + bash ./terraform.sh apply weu-${{ inputs.environment }} -auto-approve diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml new file mode 100644 index 0000000..c405e3e --- /dev/null +++ b/.github/workflows/integration_test.yml @@ -0,0 +1,116 @@ +name: Integration Tests + +on: + schedule: + - cron: '00 08 * * *' + + workflow_dispatch: + inputs: + environment: + required: true + type: choice + description: Select the Environment + options: + - dev + - uat + - prod + canary: + description: 'run the tests on canary version' + required: false + type: boolean + default: false + notify: + required: false + type: boolean + description: 'send the slack notification' + default: true + + +permissions: + id-token: write + contents: read + deployments: write + + +jobs: + integration_test: + name: Test ${{(github.event.inputs == null && 'dev') || inputs.environment }} + runs-on: ubuntu-latest + environment: ${{(github.event.inputs == null && 'dev') || inputs.environment }} + steps: + - name: Checkout + id: checkout + uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656657ea2c6707 + + - name: Login + id: login + # from https://github.com/Azure/login/commits/master + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 + with: + client-id: ${{ secrets.CLIENT_ID }} + tenant-id: ${{ secrets.TENANT_ID }} + subscription-id: ${{ secrets.SUBSCRIPTION_ID }} + + - name: Run Integration Tests + shell: bash + run: | + export SUBKEY=${{ secrets.SUBKEY }} + export CANARY=${{ inputs.canary }} + export CUCUMBER_PUBLISH_TOKEN=${{ secrets.CUCUMBER_PUBLISH_TOKEN }} + + cd ./integration-test + chmod +x ./run_integration_test.sh + ./run_integration_test.sh ${{( github.event.inputs == null && 'dev') || inputs.environment }} + + notify: + needs: [ integration_test ] + runs-on: ubuntu-latest + name: Notify + if: ${{ always() && inputs.notify == 'true' }} + steps: + - name: Report Status + if: ${{ inputs.notify }} + uses: ravsamhq/notify-slack-action@v2 + with: + status: ${{ needs.integration_test.result }} + token: ${{ secrets.GITHUB_TOKEN }} + notify_when: 'failure,skipped' + notification_title: '<{run_url}|Scheduled Integration Test> has {status_message}' + message_format: '{emoji} <{run_url}|{workflow}> {status_message} in <{repo_url}|{repo}>' + footer: 'Linked to <{workflow_url}| workflow file>' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + + delete_github_deployments: + runs-on: ubuntu-latest + needs: integration_test + if: ${{ always() }} + steps: + - name: Delete Previous deployments + uses: actions/github-script@v6 + env: + SHA_HEAD: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.sha) || github.sha}} + with: + script: | + const { SHA_HEAD } = process.env + + const deployments = await github.rest.repos.listDeployments({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: SHA_HEAD + }); + await Promise.all( + deployments.data.map(async (deployment) => { + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id, + state: 'inactive' + }); + return github.rest.repos.deleteDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id + }); + }) + ); diff --git a/.github/workflows/release_deploy.yml b/.github/workflows/release_deploy.yml new file mode 100644 index 0000000..3e53e2c --- /dev/null +++ b/.github/workflows/release_deploy.yml @@ -0,0 +1,150 @@ +name: Release And Deploy + +#test + +# Controls when the workflow will run +on: + pull_request: + types: [ closed ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + inputs: + environment: + required: true + type: choice + description: Select the Environment + options: + - dev + - uat + - prod + - all + beta: + required: false + type: boolean + description: deploy beta version on AKS + default: false + skip_release: + required: false + type: boolean + description: skip the release. Only deploy + default: false + + +permissions: + packages: write + contents: write + issues: write + id-token: write + actions: read + + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + semver: ${{ steps.get_semver.outputs.semver }} + environment: ${{ steps.get_env.outputs.environment }} + steps: + - name: pull request rejected + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged != true + run: | + echo "❌ PR was closed without a merge" + exit 1 + + # Set Semvar + - run: echo "SEMVER=patch" >> $GITHUB_ENV + + - if: ${{ (github.event.pull_request.merged && contains(github.event.pull_request.labels.*.name, 'breaking-change')) }} + run: echo "SEMVER=major" >> $GITHUB_ENV + + - if: ${{ inputs.environment == 'uat' }} + run: echo "SEMVER=minor" >> $GITHUB_ENV + + - if: ${{ inputs.environment == 'prod' }} + run: echo "SEMVER=skip" >> $GITHUB_ENV + + - if: ${{ github.ref_name != 'main' }} + run: echo "SEMVER=buildNumber" >> $GITHUB_ENV + + - if: ${{ inputs.skip_release }} + run: echo "SEMVER=skip" >> $GITHUB_ENV + + - id: get_semver + name: Set Output + run: echo "semver=${{env.SEMVER}}" >> $GITHUB_OUTPUT + + # Set Environment + - run: echo "ENVIRNOMENT=${{ inputs.environment}}" >> $GITHUB_ENV + + - if: ${{ inputs.environment == null }} + run: echo "ENVIRNOMENT=dev" >> $GITHUB_ENV + + - id: get_env + name: Set Output + run: echo "environment=${{env.ENVIRNOMENT}}" >> $GITHUB_OUTPUT + + + release: + name: Create a New Release + runs-on: ubuntu-latest + needs: [setup] + outputs: + version: ${{ steps.release.outputs.version }} + steps: + - name: Make Release + id: release + uses: pagopa/github-actions-template/maven-release@v1.5.4 + with: + semver: ${{ needs.setup.outputs.semver }} + github_token: ${{ secrets.BOT_TOKEN_GITHUB }} + beta: ${{ inputs.beta }} + skip_ci: false + + image: + needs: [ setup, release ] + name: Build and Push Docker Image + runs-on: ubuntu-latest + if: ${{ inputs.semver != 'skip' }} + steps: + - name: Build and Push + id: semver + uses: pagopa/github-actions-template/ghcr-build-push@v1.5.4 + with: + branch: ${{ github.ref_name}} + github_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ needs.release.outputs.version }} + + deploy_aks: + name: Deploy on AKS + needs: [ setup, release, image ] + if: ${{ always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} + strategy: + matrix: + environment: [ dev, uat, prod ] + uses: ./.github/workflows/deploy_with_github_runner.yml + with: + environment: ${{ matrix.environment }} + target: ${{ needs.setup.outputs.environment }} + secrets: inherit + + notify: + needs: [ setup, release, deploy_aks ] + runs-on: ubuntu-latest + name: Notify + if: always() + steps: + - name: Report Status + if: ${{ needs.setup.outputs.environment == 'prod' || needs.setup.outputs.environment == 'all' }} + uses: ravsamhq/notify-slack-action@v2 + with: + status: ${{ needs.deploy_aks.result }} + token: ${{ secrets.GITHUB_TOKEN }} + notification_title: 'New Release on Production ${{ needs.release.outputs.version }} has {status_message}' + message_format: '{emoji} <{run_url}|{workflow}> {status_message} in <{repo_url}|{repo}>' + footer: 'Linked to <{workflow_url}| workflow file>' + icon_success: ':white_check_mark:' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/sonar_analysis.yml b/.github/workflows/sonar_analysis.yml deleted file mode 100644 index 08c0db0..0000000 --- a/.github/workflows/sonar_analysis.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Sonar Analysis - -# Controls when the workflow will run -on: - push: - branches: - - main - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - name: Call Azure Build Pipeline - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: Azure Pipelines Action - Jversion - uses: jacopocarlini/azure-pipelines@v1.3 - with: - azure-devops-project-url: https://dev.azure.com/pagopaspa/pagoPA-projects - # TODO: set name - azure-pipeline-name: 'pagopa-api-config.code-review' - azure-devops-token: ${{ secrets.AZURE_DEVOPS_TOKEN }} - azure-pipeline-variables: '{"system.debug": "true"}' - diff --git a/.github/workflows/update_code.yml b/.github/workflows/update_code.yml new file mode 100644 index 0000000..ed41d83 --- /dev/null +++ b/.github/workflows/update_code.yml @@ -0,0 +1,86 @@ +name: Update Code + +on: + issue_comment: + types: [created, edited] + + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + update: + name: Update Openapi and Formatting + runs-on: ubuntu-latest + if: ${{ contains(github.event.comment.body, 'update_code') }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + token: ${{ secrets.BOT_TOKEN_GITHUB }} + + - name: Checkout Pull Request + run: hub pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + + - name: Update OpenApi/Swagger file + run: | + cd ./openapi + chmod +x ./generate_openapi.sh + ./generate_openapi.sh + + - name: Formatting + id: format + uses: findologic/intellij-format-action@main + with: + path: . + fail-on-changes: false + + - name: Commit files + run: | + git config --local user.email "pagopa-github-bot@pagopa.it" + git config --local user.name "pagopa-github-bot" + git commit -a -m "Formatting" + git push + + + notify: + needs: [ update ] + runs-on: ubuntu-latest + name: Notify + if: ${{ always() && contains(needs.*.result, 'failure') }} + steps: + - name: Notify if Failure + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + var comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }); + for (const comment of comments.data) { + if (comment.body.includes('Update Code is failed. Please retry.')){ + github.rest.issues.deleteComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id + }) + } + } + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Update Code is failed. Please retry.' + }) + core.setFailed('Update Code is failed. Please retry.') diff --git a/.github/workflows/update_infra.yml b/.github/workflows/update_infra.yml deleted file mode 100644 index 9dcea49..0000000 --- a/.github/workflows/update_infra.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Open a PR in Infra repository - -on: - pull_request: - branches: - - main - types: [ closed ] - paths: - - 'openapi/openapi.json' - - - workflow_dispatch: - -jobs: - pull-request: - if: ${{ github.event.pull_request.merged }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - # prepare openapi template for infra repo - - run: | - mkdir -p "${GITHUB_WORKSPACE}/infra" - jq '."servers"[0]."url" |= "${host}/gps/spontaneous-payments-service/v1"' "${GITHUB_WORKSPACE}/openapi/openapi.json" > "${GITHUB_WORKSPACE}/infra/_openapi.json.tpl" - - # open a PR on infra repo - - name: Create pull request - uses: jacopocarlini/action-pull-request-another-repo@main - env: - API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} - with: - source_folder: 'infra' - destination_repo: 'pagopa/pagopa-infra' - destination_folder: 'src/domains/gps-app/api/spontaneous-payments-service/v1' - destination_base_branch: 'main' - destination_head_branch: 'SpontaneousPayments-swagger-update' - user_email: 'github-bot@pagopa.it' - user_name: 'pagopa-github-bot' - allow_force_push: 'true' diff --git a/.identity/00_data.tf b/.identity/00_data.tf new file mode 100644 index 0000000..8273e72 --- /dev/null +++ b/.identity/00_data.tf @@ -0,0 +1,52 @@ +data "azurerm_storage_account" "tf_storage_account"{ + name = "pagopainfraterraform${var.env}" + resource_group_name = "io-infra-rg" +} + +data "azurerm_resource_group" "dashboards" { + name = "dashboards" +} + +data "azurerm_kubernetes_cluster" "aks" { + name = local.aks_cluster.name + resource_group_name = local.aks_cluster.resource_group_name +} + +data "github_organization_teams" "all" { + root_teams_only = true + summary_only = true +} + +data "azurerm_key_vault" "key_vault" { + name = "pagopa-${var.env_short}-kv" + resource_group_name = "pagopa-${var.env_short}-sec-rg" +} + +data "azurerm_key_vault" "domain_key_vault" { + name = "pagopa-${var.env_short}-${local.domain}-kv" + resource_group_name = "pagopa-${var.env_short}-${local.domain}-sec-rg" +} + +data "azurerm_resource_group" "apim_resource_group" { + name = "${local.product}-api-rg" +} + +data "azurerm_key_vault_secret" "key_vault_sonar" { + name = "sonar-token" + key_vault_id = data.azurerm_key_vault.key_vault.id +} + +data "azurerm_key_vault_secret" "key_vault_bot_token" { + name = "bot-token-github" + key_vault_id = data.azurerm_key_vault.key_vault.id +} + +data "azurerm_key_vault_secret" "key_vault_cucumber_token" { + name = "cucumber-token" + key_vault_id = data.azurerm_key_vault.key_vault.id +} + +data "azurerm_key_vault_secret" "key_vault_integration_test_subkey" { + name = "integration-test-subkey" + key_vault_id = data.azurerm_key_vault.key_vault.id +} diff --git a/.identity/02_application_action.tf b/.identity/02_application_action.tf new file mode 100644 index 0000000..d6a7a24 --- /dev/null +++ b/.identity/02_application_action.tf @@ -0,0 +1,96 @@ +module "github_runner_app" { + source = "git::https://github.com/pagopa/github-actions-tf-modules.git//app-github-runner-creator?ref=main" + + app_name = local.app_name + + subscription_id = data.azurerm_subscription.current.id + + github_org = local.github.org + github_repository = local.github.repository + github_environment_name = var.env + + container_app_github_runner_env_rg = local.container_app_environment.resource_group +} + +resource "null_resource" "github_runner_app_permissions_to_namespace" { + triggers = { + aks_id = data.azurerm_kubernetes_cluster.aks.id + service_principal_id = module.github_runner_app.client_id + namespace = local.domain + version = "v2" + } + + provisioner "local-exec" { + command = < /dev/null; then + if [ "$ACTION" = "init" ]; then + echo "[INFO] init tf on ENV: ${ENV}" + terraform "$ACTION" -backend-config="${BACKEND_CONFIG_PATH}" $other + elif [ "$ACTION" = "output" ] || [ "$ACTION" = "state" ] || [ "$ACTION" = "taint" ]; then + # init terraform backend + terraform init -reconfigure -backend-config="${BACKEND_CONFIG_PATH}" + terraform "$ACTION" $other + else + # init terraform backend + echo "[INFO] init tf on ENV: ${ENV}" + terraform init -reconfigure -backend-config="${BACKEND_CONFIG_PATH}" + + echo "[INFO] run tf with: ${ACTION} on ENV: ${ENV} and other: >${other}<" + terraform "${ACTION}" -var-file="./env/${ENV}/terraform.tfvars" -compact-warnings $other + fi +else + echo "[ERROR] ACTION not allowed." + exit 1 +fi diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml index 12dae5b..4b0f513 100644 --- a/helm/values-dev.yaml +++ b/helm/values-dev.yaml @@ -25,11 +25,13 @@ microservice-chart: service: create: true type: ClusterIP - port: 8080 + ports: + - 8080 ingress: create: true host: "weudev.gps.internal.dev.platform.pagopa.it" path: /pagopa-spontaneous-payments-service/(.*) + servicePort: 8080 serviceAccount: create: false annotations: {} @@ -49,8 +51,8 @@ microservice-chart: cpu: "0.5" autoscaling: enable: true - minReplica: 3 - maxReplica: 10 + minReplica: 1 + maxReplica: 2 pollingInterval: 30 # seconds cooldownPeriod: 60 # seconds triggers: @@ -85,4 +87,12 @@ microservice-chart: tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" nodeSelector: {} tolerations: [] - affinity: {} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node_type + operator: In + values: + - user diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml index 8dd4a76..2e8e678 100644 --- a/helm/values-prod.yaml +++ b/helm/values-prod.yaml @@ -25,11 +25,13 @@ microservice-chart: service: create: true type: ClusterIP - port: 8080 + ports: + - 8080 ingress: create: true host: "weuprod.gps.internal.platform.pagopa.it" path: /pagopa-spontaneous-payments-service/(.*) + servicePort: 8080 serviceAccount: create: false annotations: {} @@ -85,4 +87,12 @@ microservice-chart: tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" nodeSelector: {} tolerations: [] - affinity: {} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node_type + operator: In + values: + - user diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml index 1f483bb..9d1dc2e 100644 --- a/helm/values-uat.yaml +++ b/helm/values-uat.yaml @@ -25,11 +25,13 @@ microservice-chart: service: create: true type: ClusterIP - port: 8080 + ports: + - 8080 ingress: create: true host: "weuuat.gps.internal.uat.platform.pagopa.it" path: /pagopa-spontaneous-payments-service/(.*) + servicePort: 8080 serviceAccount: create: false annotations: {} @@ -85,4 +87,12 @@ microservice-chart: tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d" nodeSelector: {} tolerations: [] - affinity: {} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node_type + operator: In + values: + - user diff --git a/infra/04_apim_api.tf b/infra/04_apim_api.tf new file mode 100644 index 0000000..b24ae4d --- /dev/null +++ b/infra/04_apim_api.tf @@ -0,0 +1,56 @@ +locals { + repo_name = "TODO" # TODO add the name of the repository + + display_name = "TODO" # TODO + description = "TODO" # TODO + path = "TODO" # TODO add your base path + + host = "api.${var.apim_dns_zone_prefix}.${var.external_domain}" + hostname = var.hostname +} + +resource "azurerm_api_management_group" "api_group" { + name = local.apim.product_id + resource_group_name = local.apim.rg + api_management_name = local.apim.name + display_name = local.display_name + description = local.description +} + +resource "azurerm_api_management_api_version_set" "api_version_set" { + name = format("%s-${local.repo_name}", var.env_short) + resource_group_name = local.apim.rg + api_management_name = local.apim.name + display_name = local.display_name + versioning_scheme = "Segment" +} + +module "api_v1" { + source = "git::https://github.com/pagopa/terraform-azurerm-v3.git//api_management_api?ref=v6.7.0" + + name = format("%s-${local.repo_name}", var.env_short) + api_management_name = local.apim.name + resource_group_name = local.apim.rg + product_ids = [local.apim.product_id] + subscription_required = true + + version_set_id = azurerm_api_management_api_version_set.api_version_set.id + api_version = "v1" + + description = local.description + display_name = local.display_name + path = local.path + protocols = ["https"] + + service_url = null + + content_format = "openapi" + content_value = templatefile("../openapi/openapi.json", { + host = local.host + }) + + xml_content = templatefile("./policy/_base_policy.xml", { + hostname = var.hostname + }) +} + diff --git a/infra/99_locals.tf b/infra/99_locals.tf new file mode 100644 index 0000000..5ed42d0 --- /dev/null +++ b/infra/99_locals.tf @@ -0,0 +1,10 @@ +locals { + product = "${var.prefix}-${var.env_short}" + + apim = { + name = "${local.product}-apim" + rg = "${local.product}-api-rg" + product_id = "TODO" # TODO product id to import from pagopa-infra + } +} + diff --git a/infra/99_main.tf b/infra/99_main.tf new file mode 100644 index 0000000..c62f391 --- /dev/null +++ b/infra/99_main.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.30.0" + } + azuread = { + source = "hashicorp/azuread" + version = "2.30.0" + } + azapi = { + source = "Azure/azapi" + version = "= 1.3.0" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} +} + +provider "azapi" {} + +data "azurerm_subscription" "current" {} + +data "azurerm_client_config" "current" {} diff --git a/infra/99_variables.tf b/infra/99_variables.tf new file mode 100644 index 0000000..4cfc3e4 --- /dev/null +++ b/infra/99_variables.tf @@ -0,0 +1,50 @@ +# general + +variable "prefix" { + type = string + validation { + condition = ( + length(var.prefix) <= 6 + ) + error_message = "Max length is 6 chars." + } +} + +variable "env" { + type = string +} + +variable "env_short" { + type = string + validation { + condition = ( + length(var.env_short) == 1 + ) + error_message = "Length must be 1 chars." + } +} + +variable "tags" { + type = map(any) + default = { + CreatedBy = "Terraform" + } +} + +variable "apim_dns_zone_prefix" { + type = string + default = null + description = "The dns subdomain for apim." +} + +variable "external_domain" { + type = string + default = null + description = "Domain for delegation" +} + +variable "hostname" { + type = string + default = null + description = "Hostname for the API" +} diff --git a/infra/env/weu-dev/backend.ini b/infra/env/weu-dev/backend.ini new file mode 100644 index 0000000..22e6a99 --- /dev/null +++ b/infra/env/weu-dev/backend.ini @@ -0,0 +1 @@ +subscription=DEV-pagoPA diff --git a/infra/env/weu-dev/backend.tfvars b/infra/env/weu-dev/backend.tfvars new file mode 100644 index 0000000..619395b --- /dev/null +++ b/infra/env/weu-dev/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "io-infra-rg" +storage_account_name = "pagopainfraterraformdev" +container_name = "azurermstate" +key = ".infra.tfstate" # TODO diff --git a/infra/env/weu-dev/terraform.tfvars b/infra/env/weu-dev/terraform.tfvars new file mode 100644 index 0000000..63a0705 --- /dev/null +++ b/infra/env/weu-dev/terraform.tfvars @@ -0,0 +1,15 @@ +prefix = "pagopa" +env = "dev" +env_short = "d" + +tags = { + CreatedBy = "Terraform" + Environment = "Dev" + Owner = "pagoPA" + Source = "https://github.com/pagopa/your-repository" # TODO + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} + +apim_dns_zone_prefix = "dev.platform" +external_domain = "pagopa.it" +hostname = "weudev..internal.dev.platform.pagopa.it" # TODO diff --git a/infra/env/weu-prod/backend.ini b/infra/env/weu-prod/backend.ini new file mode 100644 index 0000000..6318425 --- /dev/null +++ b/infra/env/weu-prod/backend.ini @@ -0,0 +1 @@ +subscription=PROD-pagoPA diff --git a/infra/env/weu-prod/backend.tfvars b/infra/env/weu-prod/backend.tfvars new file mode 100644 index 0000000..dac1727 --- /dev/null +++ b/infra/env/weu-prod/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "io-infra-rg" +storage_account_name = "pagopainfraterraformprod" +container_name = "azurermstate" +key = ".infra.tfstate" # TODO diff --git a/infra/env/weu-prod/terraform.tfvars b/infra/env/weu-prod/terraform.tfvars new file mode 100644 index 0000000..77f85af --- /dev/null +++ b/infra/env/weu-prod/terraform.tfvars @@ -0,0 +1,15 @@ +prefix = "pagopa" +env = "prod" +env_short = "p" + +tags = { + CreatedBy = "Terraform" + Environment = "Prod" + Owner = "pagoPA" + Source = "https://github.com/pagopa/your-repository" # TODO + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} + +apim_dns_zone_prefix = "platform" +external_domain = "pagopa.it" +hostname = "weuprod..internal.platform.pagopa.it" # TODO diff --git a/infra/env/weu-uat/backend.ini b/infra/env/weu-uat/backend.ini new file mode 100644 index 0000000..1a01415 --- /dev/null +++ b/infra/env/weu-uat/backend.ini @@ -0,0 +1 @@ +subscription=UAT-pagoPA diff --git a/infra/env/weu-uat/backend.tfvars b/infra/env/weu-uat/backend.tfvars new file mode 100644 index 0000000..6f406b1 --- /dev/null +++ b/infra/env/weu-uat/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "io-infra-rg" +storage_account_name = "pagopainfraterraformuat" +container_name = "azurermstate" +key = ".infra.tfstate" # TODO diff --git a/infra/env/weu-uat/terraform.tfvars b/infra/env/weu-uat/terraform.tfvars new file mode 100644 index 0000000..e8160f1 --- /dev/null +++ b/infra/env/weu-uat/terraform.tfvars @@ -0,0 +1,15 @@ +prefix = "pagopa" +env = "uat" +env_short = "u" + +tags = { + CreatedBy = "Terraform" + Environment = "Uat" + Owner = "pagoPA" + Source = "https://github.com/pagopa/your-repository" # TODO + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} + +apim_dns_zone_prefix = "uat.platform" +external_domain = "pagopa.it" +hostname = "weuuat..internal.uat.platform.pagopa.it" # TODO diff --git a/infra/policy/_base_policy.xml b/infra/policy/_base_policy.xml new file mode 100644 index 0000000..e3b583c --- /dev/null +++ b/infra/policy/_base_policy.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/infra/terraform.sh b/infra/terraform.sh new file mode 100755 index 0000000..b4691c8 --- /dev/null +++ b/infra/terraform.sh @@ -0,0 +1,191 @@ +#!/bin/bash +############################################################ +# Terraform script for managing infrastructure on Azure +# Fingerprint: d2hhdHlvdXdhbnQ/Cg== +############################################################ +# Global variables +# Version format x.y accepted +vers="1.1" +script_name=$(basename "$0") +git_repo="https://raw.githubusercontent.com/pagopa/eng-common-scripts/main/azure/${script_name}" +tmp_file="${script_name}.new" + +# Define functions +function clean_environment() { + rm -rf .terraform* + rm tfplan 2>/dev/null + echo "cleaned!" +} + +function help_usage() { + echo "terraform.sh Version ${vers}" + echo + echo "Usage: ./script.sh [ACTION] [ENV] [OTHER OPTIONS]" + echo "es. ACTION: init, apply, plan, etc." + echo "es. ENV: dev, uat, prod, etc." + echo + echo "Available actions:" + echo " clean Remove .terraform* folders and tfplan files" + echo " help This help" + echo " list List every environment available" + echo " summ Generate summary of Terraform plan" + echo " * any terraform option" +} + +function init_terraform() { + if [ -n "$env" ]; then + terraform init -reconfigure -backend-config="./env/$env/backend.tfvars" + else + echo "ERROR: no env configured!" + exit 1 + fi +} + +function list_env() { + # Check if env directory exists + if [ ! -d "./env" ]; then + echo "No environment directory found" + exit 1 + fi + + # List subdirectories under env directory + env_list=$(ls -d ./env/*/ 2>/dev/null) + + # Check if there are any subdirectories + if [ -z "$env_list" ]; then + echo "No environments found" + exit 1 + fi + + # Print the list of environments + echo "Available environments:" + for env in $env_list; do + env_name=$(echo "$env" | sed 's#./env/##;s#/##') + echo "- $env_name" + done +} + +function other_actions() { + if [ -n "$env" ] && [ -n "$action" ]; then + terraform "$action" -var-file="./env/$env/terraform.tfvars" -compact-warnings $other + else + echo "ERROR: no env or action configured!" + exit 1 + fi +} + +function state_output_taint_actions() { + terraform $action $other +} + +function tfsummary() { + action="plan" + other="-out=tfplan" + other_actions + if [ -n "$(command -v tf-summarize)" ]; then + tf-summarize -separate-tree tfplan && rm tfplan 2>/dev/null + else + echo "tf-summarize is not installed" + fi +} + +function update_script() { + # Check if the repository was cloned successfully + if ! curl -sL "$git_repo" -o "$tmp_file"; then + echo "Error cloning the repository" + rm "$tmp_file" 2>/dev/null + return 1 + fi + + # Check if a newer version exists + remote_vers=$(sed -n '8s/vers="\(.*\)"/\1/p' "$tmp_file") + if [ "$(printf '%s\n' "$vers" "$remote_vers" | sort -V | tail -n 1)" == "$vers" ]; then + echo "The local script version is equal to or newer than the remote version." + rm "$tmp_file" 2>/dev/null + return 0 + fi + + # Check the fingerprint + local_fingerprint=$(sed -n '4p' "$0") + remote_fingerprint=$(sed -n '4p' "$tmp_file") + + if [ "$local_fingerprint" != "$remote_fingerprint" ]; then + echo "The local and remote file fingerprints do not match." + rm "$tmp_file" 2>/dev/null + return 0 + fi + + # Show the current and available versions to the user + echo "Current script version: $vers" + echo "Available script version: $remote_vers" + + # Ask the user if they want to update the script + read -rp "Do you want to update the script to version $remote_vers? (y/n): " answer + + if [ "$answer" == "y" ] || [ "$answer" == "Y" ]; then + # Replace the local script with the updated version + cp "$tmp_file" "$script_name" + chmod +x "$script_name" + rm "$tmp_file" 2>/dev/null + + echo "Script successfully updated to version $remote_vers" + else + echo "Update canceled by the user" + fi + + rm "$tmp_file" 2>/dev/null +} + +# Check arguments number +if [ "$#" -lt 1 ]; then + help_usage + exit 0 +fi + +# Parse arguments +action=$1 +env=$2 +shift 2 +other=$@ + +if [ -n "$env" ]; then + # shellcheck source=/dev/null + source "./env/$env/backend.ini" + if [ -z "$(command -v az)" ]; then + echo "az not found, cannot proceed" + exit 1 + fi + az account set -s "${subscription}" +fi + +# Call appropriate function based on action +case $action in + clean) + clean_environment + ;; + ?|help) + help_usage + ;; + init) + init_terraform + init_terraform "$other" + ;; + list) + list_env + ;; + output|state|taint) + init_terraform + state_output_taint_actions $other + ;; + summ) + init_terraform + tfsummary "$other" + ;; + update) + update_script + ;; + *) + # [ -z "$TF_INIT" ] && terraform init + other_actions "$other" + ;; +esac