diff --git a/.github/workflows/dependacheck.yaml b/.github/workflows/dependacheck.yaml index 24e17a94..89fb8b88 100644 --- a/.github/workflows/dependacheck.yaml +++ b/.github/workflows/dependacheck.yaml @@ -9,7 +9,7 @@ jobs: dependacheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.7 - name: Check that images are checked by dependabot run: | ./tools/dependacheck/dependacheck.sh diff --git a/.github/workflows/diagrams-render.yaml b/.github/workflows/diagrams-render.yaml index a67cb7e1..7315e3d5 100644 --- a/.github/workflows/diagrams-render.yaml +++ b/.github/workflows/diagrams-render.yaml @@ -17,7 +17,7 @@ jobs: name: Render Drawio diagrams runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.7 - name: Install Task uses: Arduino/actions/setup-taskfile@master - name: Clean render diff --git a/.github/workflows/dplsh-build-release.yaml b/.github/workflows/dplsh-build-release.yaml index 6cdfe3f2..28950137 100644 --- a/.github/workflows/dplsh-build-release.yaml +++ b/.github/workflows/dplsh-build-release.yaml @@ -35,7 +35,7 @@ jobs: image-url: ghcr.io/danskernesdigitalebibliotek/dpl-platform/dplsh steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.7 - name: Install Task uses: arduino/setup-task@v2 - name: Log in to the Container registry @@ -66,7 +66,7 @@ jobs: # run som tests on the image, while still avoiding to have to rebuild the # image when we do the final build. - name: Build and export to Docker - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: tools/dplsh load: true @@ -80,7 +80,7 @@ jobs: working-directory: tools/dplsh - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: tools/dplsh platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/markdown-lint.yaml b/.github/workflows/markdown-lint.yaml index b4265e22..2fd3e157 100644 --- a/.github/workflows/markdown-lint.yaml +++ b/.github/workflows/markdown-lint.yaml @@ -10,7 +10,7 @@ jobs: name: Lint Markdown runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.7 # git with HTTP authentication provides an easy way for us to install # unreleased commits of NPM projects. - name: Reconfigure git to use HTTP authentication diff --git a/.github/workflows/shellcheck.yaml b/.github/workflows/shellcheck.yaml index 57aa2ab1..e8325af9 100644 --- a/.github/workflows/shellcheck.yaml +++ b/.github/workflows/shellcheck.yaml @@ -13,7 +13,7 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.7 - name: shellcheck uses: reviewdog/action-shellcheck@v1 with: diff --git a/.github/workflows/terraform-lint.yaml b/.github/workflows/terraform-lint.yaml index 642aaf61..df93e596 100644 --- a/.github/workflows/terraform-lint.yaml +++ b/.github/workflows/terraform-lint.yaml @@ -11,7 +11,7 @@ jobs: terraform_format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.7 - uses: hashicorp/setup-terraform@v3.1.1 - name: Terraform fmt id: fmt diff --git a/docs/images/lagoon-ui-tasks-page.png b/docs/images/lagoon-ui-tasks-page.png new file mode 100644 index 00000000..0f1a9e53 Binary files /dev/null and b/docs/images/lagoon-ui-tasks-page.png differ diff --git a/docs/runbooks/changing-and-releasing-new-dplsh-version.md b/docs/runbooks/changing-and-releasing-new-dplsh-version.md new file mode 100644 index 00000000..1b8f8bfc --- /dev/null +++ b/docs/runbooks/changing-and-releasing-new-dplsh-version.md @@ -0,0 +1,23 @@ +# Make changes to DPLSH + +## When to use + +When for example the `kubectl` or other dependencies needs updating + +## Make the change + +1. Go to the DPLSH directory and make the necessary changes on a new branch +2. Build DPLSH locally by running `IMAGE_URL=dplsh IMAGE_TAG=someTagName + task build` +3. Test that it works by running `DPLSH_IMAGE=dplsh:local ./dplsh` and running + what ever commands need to be run to test that the change has the desired effect +4. Check what version DPLSH is at here: + +5. Push the branch, have it review and merge it into `main` +6. Push a new tag to `main`. The tag should look like this: `dplsh-x.x.x`. + (If in doubt about what version to bump to; read this: ) +7. Wait for main to automically build and release the new version +8. Go to your main branch, enter the `/infrastructure` directory and + run `../tools/dplsh/dplsh.sh --update`. + +You are done and have the newest version of DPLSH on your machine. diff --git a/docs/runbooks/ui-sync-site-state.md b/docs/runbooks/ui-sync-site-state.md new file mode 100644 index 00000000..deec6265 --- /dev/null +++ b/docs/runbooks/ui-sync-site-state.md @@ -0,0 +1,69 @@ +# UI: Synchronize site state + +## When to use + +If you want to synchronize state from one environment into another environment. + +For example, you may want to synchronize state to a PR environment to run your +code in a more realistic setup. + +Or you may want to synchronize a main (production) environment state to a +moduletest environment, if requested by the customer. + +## Prerequisites + +- A user with access to the relevant project through the + [Lagoon UI](https://ui.lagoon.dplplat01.dpl.reload.dk/) + +If you have access to the dpl-platform setup and can run task in the taskfile +(for platform engineers, not developers of the CMS) you may want to synchronize +site state using the related task (runbook WIP). + +## Procedure + +1. Go to the [Lagoon UI] website and log in +2. Navigate to the relevant project by selecting in the list +3. Pick the *target* environment in the list of environments. E.g. if you are + synchronizing state from `main` to `pr-775` you should select `pr-775`. +4. In the left-hand side pick the "Tasks" menu point + +Now you are at the tasks UI and can execute tasks for this environment. It +should look something like this: + +![Tasks page in the Lagoon UI](../images/lagoon-ui-tasks-page.png) + +Now we need to execute 3 tasks to synchronize the whole state and make it +available on visits to the target site: + + +5. Run task "Copy database between environments \[drush sql-sync\]": + + - Select the task in the "Select a task..." dropdown. + - Select the source environment. E.g. if you are synchronizing from `main` to + `pr-775` select `main` in the dropdown. + - Click "Run task" to start the task. + The task appears in the top of the list of tasks. You can click it to see + log output. Once the task completes verify that the log output states that + the synchronization worked. + + +6. Run task "Copy files between environments \[drush rsync\]": + + - Select the task in the "Select a task..." dropdown. + - Select the source environment as above. + - Click "Run task" to start the task. + The task output can be viewed as described in point 5. + The task will fail. Verify that the error is a list of statements saying + `> rsync: [receiver] failed to set times on ...`. As long as these are the + only errors in the output, the synchronization succeeded. + + +7. Run task "Clear Drupal caches \[drupal cache-clear\]" to clear the caches: + + - Select the task in the "Select a task..." dropdown. + - Select the source environment as above. + - Click "Run task" to start the task. + Once the task completes the environment has been fully synced and caches + are cleared so the state will be reflected when you visit the site. + E.g. if you were synchronizing state from `main` to `pr-775`, the `pr-775` + environment will now have the same state as `main`. diff --git a/docs/runbooks/upgrading-aks.md b/docs/runbooks/upgrading-aks.md index e0cea057..d377ec08 100644 --- a/docs/runbooks/upgrading-aks.md +++ b/docs/runbooks/upgrading-aks.md @@ -81,8 +81,11 @@ for background info on this operation. aware that the admin node-pool where harbor runs has a tendency to take a long time as the harbor pvcs are slow to migrate to the new node. -Monitor via eg. + Monitor via eg. -```shell -watch -n 5 kubectl get nodes -``` + ```shell + watch -n 5 kubectl get nodes + ``` + +5. Go to `dplsh's` Dockerfile and update the `KUBECTL_VERSION` version to + match that of the upgraded AKS version diff --git a/infrastructure/Taskfile.yml b/infrastructure/Taskfile.yml index d3154c16..fcda0e48 100644 --- a/infrastructure/Taskfile.yml +++ b/infrastructure/Taskfile.yml @@ -78,7 +78,7 @@ tasks: Use Terraform to provision the infrastructure for an environment. dir: "{{.dir_infra}}" cmds: - - terraform apply + - terraform apply {{.OPTIONS}} infra:keyvault:secret:set: deps: [_req_env, _infra:terraform:init] @@ -123,7 +123,12 @@ tasks: ) --query value -o tsv cmds: - - cmd: terraform -chdir={{.dir_env_repos}} apply {{.OPTIONS}} + - cmd: | + if [ -z "{{.SKIP}}" ]; then + terraform -chdir={{.dir_env_repos}} apply {{.OPTIONS}} + else + echo "Skipped provisioning." + fi terraform:import: @@ -657,7 +662,7 @@ tasks: PROJECT_NAME: "{{.PROJECT_NAME}}" preconditions: - sh: "[ ! -z \"{{.PROJECT_NAME}}\" ]" - msg: "Missing PROJECT_ID or PROJECT_NAME - at least one must be set" + msg: "Missing PROJECT_NAME" lagoon:add:cluster: deps: [cluster:auth] @@ -884,7 +889,12 @@ tasks: ) --query value -o tsv cmds: - - dpladm/bin/sync-site.sh + - | + if [ -z "{{.SKIP}}" ]; then + ./dpladm/bin/sync-site.sh + else + echo "Skipped repo sync." + fi preconditions: - *require_site @@ -930,14 +940,43 @@ tasks: vars: sites: sh: cat {{.dir_env}}/sites.yaml | yq '.sites | keys | .[]' + START_FROM_SITE: "{{.START_FROM_SITE}}" cmds: - task: env_repos:provision vars: OPTIONS: "{{.INITIAL_TERRAFORM_OPTIONS}}" + SKIP: "{{.SKIP_PROVISION}}" - for: { var: sites } task: site:full-sync vars: SITE: "{{.ITEM}}" + SKIP_ENSURE_PROJECT: "{{.SKIP_ENSURE_PROJECT}}" + SKIP_CAPTURE_DEPLOY_KEY: "{{.SKIP_CAPTURE_DEPLOY_KEY}}" + SKIP_PROVISION: "{{.SKIP_PROVISION}}" + SKIP_FIRST_DEPLOYMENT: "{{.SKIP_FIRST_DEPLOYMENT}}" + SKIP_REPO_SYNC: "{{.SKIP_REPO_SYNC}}" + SKIP: + sh: | + if [ -z "{{.START_FROM_SITE}}" ]; then + exit 0 + fi + pos_startfrom=$(echo "{{.sites}}" | awk -v item="{{.START_FROM_SITE}}" '{if($0 == item) print NR}') + pos_currentsite=$(echo "{{.sites}}" | awk -v item="{{.ITEM}}" '{if($0 == item) print NR}') + + if [ -z "$pos_startfrom" ] || [ -z "$pos_currentsite" ]; then + exit 0 + fi + + if [ "$pos_startfrom" -le "$pos_currentsite" ]; then + exit 0 + else + echo -n "true" + exit 0 + fi + - for: { var: sites } + task: site:autoscaler + vars: + SITE: "{{.ITEM}}" site:full-sync: desc: Performs a full syncrhonization from sites.yaml for a single site to running state @@ -946,18 +985,23 @@ tasks: - task: site:lagoon:project:ensure vars: SITE: "{{.SITE}}" + SKIP: "{{.SKIP_ENSURE_PROJECT}}{{.SKIP}}" - task: site:lagoon:project:capture-deploy-key vars: SITE: "{{.SITE}}" + SKIP: "{{.SKIP_CAPTURE_DEPLOY_KEY}}{{.SKIP}}" - task: env_repos:provision vars: OPTIONS: -refresh=false + SKIP: "{{.SKIP_PROVISION}}{{.SKIP}}" - task: site:lagoon:ensure-first-deployment vars: SITE: "{{.SITE}}" + SKIP: "{{.SKIP_FIRST_DEPLOYMENT}}{{.SKIP}}" - task: site:sync vars: SITE: "{{.SITE}}" + SKIP: "{{.SKIP_REPO_SYNC}}{{.SKIP}}" preconditions: - *require_site @@ -975,14 +1019,65 @@ tasks: sh: if [ "{{.SITE_PLAN}}" = "{{.webmaster_plan_name}}" ]; then echo "{{.production_branch}}|{{.moduletest_branch}}"; else echo "{{.production_branch}}"; fi cmds: - | - if [ "$(lagoon get project --project "{{.SITE}}" --output-json | jq '.data[0].id' --raw-output)" = "0" ]; then - PROJECT_NAME="{{.SITE}}" GIT_URL="{{.GIT_URL}}" BRANCHES="{{.BRANCHES}}" task lagoon:project:add; + if [ -z "{{.SKIP}}" ]; then + if [ "$(lagoon get project --project "{{.SITE}}" --output-json | jq '.data[0].id' --raw-output)" = "0" ]; then + PROJECT_NAME="{{.SITE}}" GIT_URL="{{.GIT_URL}}" BRANCHES="{{.BRANCHES}}" task lagoon:project:add; + else + PROJECT_NAME="{{.SITE}}" GIT_URL="{{.GIT_URL}}" BRANCHES="{{.BRANCHES}}" task lagoon:project:update; + fi else - PROJECT_NAME="{{.SITE}}" GIT_URL="{{.GIT_URL}}" BRANCHES="{{.BRANCHES}}" task lagoon:project:update; + echo "Skipped project ensure." fi preconditions: - *require_site + sites:check-caa: + desc: | + Checks if a site's primary and secondary domains have CAA records registered, and if they do report it. + If a site has these records they must be updated to allow zerossl to provision certificates for the site. + cmds: + - | + cat {{.dir_env}}/sites.yaml \ + | yq '.sites[] | [ .primary-domain ] + .secondary-domains | .[] | select(. | contains("dplplat01.dpl.reload.dk") | not)' \ + | xargs -I % -n 1 bash -c 'if (( $(dig % CAA | grep issue | wc -l) > 0 )); then echo "There are CAAs for domain %"; fi' + + sites:incomplete-deployments: + desc: | + Gets the latest deployment for each production environment and prints its status if it is *not* complete. + cmds: + - | + lagoon list projects --output-json \ + | jq -r '.data[].projectname' \ + | while read -r projectname; do echo "$projectname: $(lagoon list deployments -e main -p $projectname --output-json | jq '.data[0].status')"; done \ + | grep -v "complete" + + sites:grep-in-deploy-log: + desc: | + Given a needle `NEEDLE` this task finds all sites whose *latest* deployment log contains a given string + cmds: + - | + set -e + lagoon list projects --output-json \ + | jq -r '.data[].projectname' \ + | while read -r projectname; do \ + buildname=$(lagoon list deployments -e main -p $projectname --output-json | jq '.data[0].name' --raw-output) + echo "$projectname: $(lagoon get deployment -e main -p $projectname --name $buildname --logs | grep -E '{{ .NEEDLE }}' | wc -l) matches" + done \ + | grep -v ": 0 matches" + echo "done" + + sites:latest-backup: + desc: Show the timestamp for the last successful backup for each site + vars: + SITES: + sh: lagoon list projects --output-json | jq -r ".data[].projectname" + cmds: + - for: { var: SITES } + cmd: | + DATE=$(lagoon list backups -p {{.ITEM}} -e main --output-json | jq -r '.data[0].created') + echo "{{.ITEM}}: ${DATE}" + silent: true + site:lagoon:project:capture-deploy-key: # TODO: print a big message if a deploy key is newly captured, so we know to commit changes! desc: Gets the deploy key for a particular project from Lagoon and persists it in sites.yaml @@ -993,7 +1088,12 @@ tasks: sh: lagoon get project-key --project "{{.SITE}}" --output-json | jq '.data[0].publickey' --raw-output SITE: "{{.SITE}}" cmds: - - yq -i e '.sites["{{.SITE}}"].deploy_key |= "{{.DEPLOY_KEY}}" | (... | select(tag == "!!merge")) tag = ""' sites.yaml + - | + if [ -z "{{.SKIP}}" ]; then + yq -i e '.sites["{{.SITE}}"].deploy_key |= "{{.DEPLOY_KEY}}" | (... | select(tag == "!!merge")) tag = ""' sites.yaml + else + echo "Skipped capture deploy key." + fi preconditions: - *require_site @@ -1005,16 +1105,42 @@ tasks: SITE: "{{.SITE}}" cmds: - | - if [ "$(lagoon list deployments --project "{{.SITE}}" --environment {{.production_branch}} --output-json | jq '.data | length')" = "0" ]; then - lagoon deploy branch --project "{{.SITE}}" --branch "{{.production_branch}}"; + if [ -z "{{.SKIP}}" ]; then + if [ "$(lagoon list deployments --project "{{.SITE}}" --environment {{.production_branch}} --output-json | jq '.data | length')" = "0" ]; then + lagoon deploy branch --project "{{.SITE}}" --branch "{{.production_branch}}"; + fi + else + echo "Skipped deploying branch." fi - | - if [ "$(yq '.sites[env(SITE)].plan' sites.yaml)" = "{{.webmaster_plan_name}}" -a "$(lagoon list deployments --project "{{.SITE}}" --environment {{.moduletest_branch}} --output-json | jq '.data | length')" = "0" ]; then - lagoon deploy branch --project "{{.SITE}}" --branch "{{.moduletest_branch}}"; + if [ -z "{{.SKIP}}" ]; then + if [ "$(yq '.sites[env(SITE)].plan' sites.yaml)" = "{{.webmaster_plan_name}}" -a "$(lagoon list deployments --project "{{.SITE}}" --environment {{.moduletest_branch}} --output-json | jq '.data | length')" = "0" ]; then + lagoon deploy branch --project "{{.SITE}}" --branch "{{.moduletest_branch}}"; + fi fi preconditions: - *require_site + sites:report-is-set-up: + desc: | + Loops through all the sites in sites.yaml and reports whether their logo or logotext has been changed. + We use this as an indication for whether the site owners have startet setting up the site. + cmds: + - | + cat {{.dir_env}}/sites.yaml | yq '.sites | keys | .[]' \ + | xargs -n 1 -I % bash -c 'set -e; if (( $(curl -s https://varnish.main.%.dplplat01.dpl.reload.dk/ | grep "\"header__logo-desktop-link\"" -A 8 | grep "\"logo-fallback\s*\"" -A 4 | grep "Logo title (bold)" | wc -l) > 0 )); then echo "% not yet set up"; fi' + + certs:clear-queue: + desc: | + Because cert-manager sometimes hangs while provisioning certificates it helps to clear the whole queue + of uncompleted certificates. This command removes any certificate that has an order not in either + valid (certificate is good!) or ready (almost ready, will be provisioned in seconds) state. + cmds: + - | + kubectl get order -A -o yaml | \ + yq '.items | filter(.status.state != "valid" and .status.state != "ready") | .[].metadata | .namespace + " " + .name' | \ + xargs -n 2 bash -c 'kubectl delete certificate -n $0 $(echo "$1" | sed -r "s/^([0-9a-z\.\-]+-tls)-[a-z0-9]+-[a-z0-9]+$/\1/i")' + ui-password: deps: [cluster:auth] desc: Get the password to access a given user interface @@ -1034,3 +1160,179 @@ tasks: msg: "Could not find directory {{.dir_infra}}" - sh: "[ -d {{.dir_configuration}} ]" msg: "Could not find directory {{.dir_configuration}}" + + site:admin:password:set: + desc: Sets the password for the admin of the selected site + deps: [lagoon:cli:config, cluster:auth] + dir: "{{.dir_env}}" + vars: + PROJECT: "{{.PROJECT}}" + PASSWORD: "{{.PASSWORD}}" + contacts: + sh: yq '.sites.{{.PROJECT}}.contacts[] | path | .[-1]' "{{.dir_env}}/contacts-and-their-sites.yaml" + cmds: + - lagoon ssh --project {{.PROJECT}} --environment main -C "drush user:password admin '{{.PASSWORD}}'" + - for: { var: contacts, as: INDEX} + task: mail:send + vars: + SUBJECT: "Logininformation til jeres nye bibliotekssite" + RECIPIENT: + sh: yq '.sites.{{.PROJECT}}.contacts[{{.INDEX}}].email' "{{.dir_env}}/contacts-and-their-sites.yaml" + CONTACTNAME: + sh: yq '.sites.{{.PROJECT}}.contacts[{{.INDEX}}].name' "{{.dir_env}}/contacts-and-their-sites.yaml" + PASSWORD: "{{.PASSWORD}}" + PROJECT: "{{.PROJECT}}" + + + site:local-admin:password:create-and-notify: + desc: Sets the password for the admin of the selected site + deps: [lagoon:cli:config, cluster:auth] + dir: "{{.dir_env}}" + vars: + PROJECT: "{{.PROJECT}}" + PASSWORD: "{{.PASSWORD}}" + MAIL: "{{.MAIL}}" + USERNAME: "{{.USERNAME}}" + CONTACTNAME: "{{.CONTACTNAME}}" + cmds: + - lagoon ssh --project {{.PROJECT}} --environment main -C "drush user:create '{{.USERNAME}}' --mail='{{.MAIL}}' --password='{{.PASSWORD}}'" + - lagoon ssh --project {{.PROJECT}} --environment main -C "drush user:role:add 'local_administrator' '{{.USERNAME}}'" + - task: mail:send + vars: + SUBJECT: "Logininformation til jeres nye bibliotekssite" + RECIPIENT: "{{.MAIL}}" + CONTACTNAME: "{{.CONTACTNAME}}" + PASSWORD: "{{.PASSWORD}}" + PROJECT: "{{.PROJECT}}" + CONTENT: | + Kære {{.CONTACTNAME}} + + Læs venligst hele mailen før du går i gang. Den indeholder 2 afsnit: + + 1. Instruktion om opsætning af brugere + 2. Loginoplysninger + + + + Instruktion om opsætning af brugere: + + Du får hermed adgang til jeres nyt bibliotekssite. Bemærk at medsendte bruger er ens for begge jer, der er kontaktpersoner. Så den første af jer der går ind på sitet skal skifte kodeord og oprette den anden som bruger. Det er vigtigt, at I vælger egne kodeord, så det kun er jer selv der kender det. + + Den brugerkonto der følger med denne mail er af typen Admin, og dermed den brugertype der har flest rettigheder i løsningen (se manualen for beskrivelse af de forskellige brugertyper). Overvej grundigt hvilke brugertyper I giver andre brugere. Af sikkerhedshensyn er det bedre at starte med færre rettigheder for den enkelte, og så "opgradere" dem hvis det bliver nødvendigt. + + Så helt kort: + + - Nulstil kodeord så snart du er logget ind, så det kun er dig der kender det + + - Brug admin-brugeren til at oprette andre brugere, men begræns deres muligheder + + Du kan se mere omkring dette i manualen her: + https://www.folkebibliotekernescms.dk/main/startopsaetning/systembrugere/ + + + + Loginoplysninger: + + Brugernavn: {{.USERNAME}} + Password: {{.PASSWORD}} + + Disse login-oplysninger kan bruges på følgende web-addresse: https://varnish.main.{{.PROJECT}}.dplplat01.dpl.reload.dk + + + Vi håber I kommer godt igang med vores nye løsning. + + Med venlig hilsen + Det Digitale Folkebibliotek + + site:local-admin:password:reset: + desc: Resets the password for the local admin of a site + deps: [cluster:auth, lagoon:cli:config] + dir: "{{.dir_env}}" + vars: + PROJECT: "{{.PROJECT}}" + USERNAME: "{{.USERNAME}}" + EMAIL: "{{.EMAIL}}" + PASSWORD: + sh: $RANDOM | md5sum | head -c 20 + cmds: + - lagoon ssh --project {{.PROJECT}} --environment main -C "drush user:password {{.USERNAME}} '{{.PASSWORD}}'" + - task: mail:send + vars: + SUBJECT: "Nulstilling af bibliotekssite password" + RECIPIENT: "{{.EMAIL}}" + PASSWORD: "{{.PASSWORD}}" + CONTENT: | + Hej, + + Du har bedt om at få nulstillet dit password til jeres bibliotekssite. + Dit nye password er: {{.PASSWORD}} + Vi anbefaler at du ændrer passwordet til noget du selv kan huske. + + Med venlig hilsen + Det Digitale Folkebibliotek + + mail:send: + desc: Sends an email from DoNotReply@folkebibliotekernescms.dk + deps: [cluster:auth] + vars: + RECIPIENT: "{{.RECIPIENT}}" + SUBJECT: "{{.SUBJECT}}" + CONTENT: "{{.CONTENT}}" + CONNECTION_STRING: + sh: az communication list-key + --name communication-servicesa5e3 + --resource-group + $( + terraform -chdir={{.dir_infra}} output -json | jq --raw-output ".resourcegroup_name.value | select (.!=null)" + ) + --query "primaryConnectionString" + --output tsv + cmd: + -| + az communication email send --sender "DoNotReply@folkebibliotekernescms.dk" + --subject "{{.SUBJECT}}" + --to "{{.RECIPIENT}}" + --text "{{.CONTENT}}" + --connection-string "{{.CONNECTION_STRING}}" + + site:admins:credentials:mail: + desc: Sent email with credentials and site info to admin user on a library site + deps: [cluster:auth, lagoon:cli:config] + dir: "{{.dir_env}}" + vars: + siteadmins: + sh: cat {{.dir_env}}/contacts-and-their-sites.yaml | yq '.sites | keys | .[]' + cmds: + - for: { var: siteadmins } + task: site:admin:password:set + vars: + PROJECT: "{{.ITEM}}" + PASSWORD: + sh: $RANDOM | md5sum | head -c 20 + + site:local-admin:admin: + desc: Switches the local admin user to an admin user + deps: [cluster:auth, lagoon:cli:config] + dir: "{{.dir_env}}" + vars: + PROJECT: "{{.PROJECT}}" + ENVIRONMENT: "{{.ENVIRONMENT}}" + ADMINS: + sh: lagoon ssh -p {{.PROJECT}} -e {{.ENVIRONMENT}} -C "drush sqlq 'SELECT GROUP_CONCAT(entity_id) FROM user__roles WHERE roles_target_id=\"local_administrator\"'" | sed 's/,/\n/g' + cmds: + - for: { var: ADMINS, as: ITEM } + task: site:local-admin:admin:execute + vars: + ADMINID: "{{.ITEM}}" + + site:local-admin:admin:execute: + desc: Switches the local admin user to an admin user + dir: "{{.dir_env}}" + vars: + PROJECT: "{{.PROJECT}}" + ENVIRONMENT: "{{.ENVIRONMENT}}" + ADMIN: + sh: lagoon ssh -p {{.PROJECT}} -e {{.ENVIRONMENT}} -C "drush uinf --field='name' --uid='{{.ADMINID}}'" + cmds: + - lagoon ssh --project {{.PROJECT}} --environment {{.ENVIRONMENT}} -C "drush user:role:add 'administrator' '{{.ADMIN}}'" + - lagoon ssh --project {{.PROJECT}} --environment {{.ENVIRONMENT}} -C "drush user:role:remove 'local_administrator' '{{.ADMIN}}'" diff --git a/infrastructure/dpladm/autoscaler.template.yaml b/infrastructure/dpladm/autoscaler.template.yaml index 4db10ecd..089bd2a6 100644 --- a/infrastructure/dpladm/autoscaler.template.yaml +++ b/infrastructure/dpladm/autoscaler.template.yaml @@ -15,7 +15,7 @@ spec: - resource: name: cpu target: - averageUtilization: 70 + averageUtilization: 500 type: Utilization type: Resource minReplicas: 1 diff --git a/infrastructure/dpladm/bin/dpladm-shared.source b/infrastructure/dpladm/bin/dpladm-shared.source index 2b3c9724..81c965b0 100755 --- a/infrastructure/dpladm/bin/dpladm-shared.source +++ b/infrastructure/dpladm/bin/dpladm-shared.source @@ -60,27 +60,50 @@ function getCleanWorkspacePath { function renderProfileTemplate { # Name of the site local siteName=$1 + # Env of the site + local siteEnv=$2 # Which dpl-cms release to use. - local releaseTag=$2 + local releaseTag=$3 # Image registry to pull the release from - local releaseImageRepository=$3 + local releaseImageRepository=$4 # Name of the container-image that contains the built release - local releaseImageName=$4 + local releaseImageName=$5 # Cron schedule for importing translations - local importTranslationsCron=$5 + local importTranslationsCron=$6 + # Flag for whether or not to autogenerate routes + local autogenerateRoutes=${7:-} # The primary domain of the site (optional) - local primaryDomain=${6:-} + local primaryDomain=${8:-} # A space-seperated list of secondary domains (optional) - local secondaryDomainsString=${7:-} + local secondaryDomainsString=${9:-} PRIMARY_DOMAIN="" - ENABLE_ROUTES="" + + if [[ "${autogenerateRoutes}" == "redirect" ]]; then + autogenerateRoutes="false" + secondaryDomainsString="${secondaryDomainsString} varnish.main.${siteName}.dplplat01.dpl.reload.dk nginx.main.${siteName}.dplplat01.dpl.reload.dk" + fi + + if [[ -z "${autogenerateRoutes}" && -n "${primaryDomain}" ]]; then + autogenerateRoutes="false" + fi + + if [[ -z "${autogenerateRoutes}" ]]; then + autogenerateRoutes="true" + fi + # This is a little bit terrible. As we're injecting this into a yaml- # document we need to maintain the indentation local routesIndent=" " local singleRouteIndent="${routesIndent} " + + ENABLE_ROUTES=$(cat << EndOfMessage +${routesIndent}autogenerateRoutes: ${autogenerateRoutes} +EndOfMessage +) if [[ -n "${primaryDomain}" ]]; then - ENABLE_ROUTES+=$(cat << EndOfMessage + ENABLE_ROUTES=$(cat << EndOfMessage +${routesIndent}autogenerateRoutes: ${autogenerateRoutes} ${routesIndent}routes: ${routesIndent} - varnish: EndOfMessage @@ -89,8 +112,8 @@ EndOfMessage fi # Only render secondary domains if we have a primary domain. + SECONDARY_DOMAINS="" if [[ -n "${primaryDomain}" && -n "${secondaryDomainsString}" ]]; then - SECONDARY_DOMAINS="" IFS=' ' for secondaryDomain in ${secondaryDomainsString}; do SECONDARY_DOMAINS+=$(cat << EndOfMessage @@ -111,6 +134,7 @@ EndOfMessage export RELEASE_TAG="${releaseTag}" export ENABLE_ROUTES export LAGOON_PROJECT_NAME="${siteName}" + export LAGOON_ENVIRONMENT="${siteEnv}" export LAGOON_IMAGES_RELEASE_TAG export PRIMARY_DOMAIN export SECONDARY_DOMAINS @@ -120,7 +144,7 @@ EndOfMessage # Tell envsubst which variables to replace. This allows other variables to # remain untouched. # shellcheck disable=SC2016 - local variablesToSubst='$RELEASE_IMAGE_REPOSITORY $RELEASE_IMAGE_NAME $RELEASE_TAG $ENABLE_ROUTES $LAGOON_IMAGES_RELEASE_TAG $LAGOON_PROJECT_NAME $PRIMARY_DOMAIN $SECONDARY_DOMAINS $IMPORT_TRANSLATIONS_CRON' + local variablesToSubst='$RELEASE_IMAGE_REPOSITORY $RELEASE_IMAGE_NAME $RELEASE_TAG $ENABLE_ROUTES $LAGOON_IMAGES_RELEASE_TAG $LAGOON_PROJECT_NAME $LAGOON_ENVIRONMENT $PRIMARY_DOMAIN $SECONDARY_DOMAINS $IMPORT_TRANSLATIONS_CRON' # Loop through the files we know to contain variables that needs replacing. local templateFiles=( @@ -128,6 +152,8 @@ EndOfMessage "lagoon/cli.dockerfile" "lagoon/nginx.dockerfile" "lagoon/php.dockerfile" + "lagoon/conf/nginx/metrics/version.txt" + "lagoon/conf/nginx/metrics/version.json" "README.md" ) for templateFile in "${templateFiles[@]}" @@ -146,8 +172,9 @@ function syncEnvRepo { local releaseImageRepository=$4 local releaseImageName=$5 local importTranslationsCron=$6 - local primaryDomain="${7:-}" - local secondaryDomains="${8:-}" + local autogenerateRoutes="${7:-}" + local primaryDomain="${8:-}" + local secondaryDomains="${9:-}" # TODO, preflight checks that verifies this repository looks good to go. # makes most sense to do when we're doing more complicated things inside @@ -180,7 +207,7 @@ function syncEnvRepo { # Enter the template and rendered it cd "${repoName}" - renderProfileTemplate "${siteName}" "${releaseTag}" "${releaseImageRepository}" "${releaseImageName}" "${importTranslationsCron}" "${primaryDomain}" "${secondaryDomains}" + renderProfileTemplate "${siteName}" "${branchName}" "${releaseTag}" "${releaseImageRepository}" "${releaseImageName}" "${importTranslationsCron}" "${autogenerateRoutes}" "${primaryDomain}" "${secondaryDomains}" # Detect changes local changedFiles diff --git a/infrastructure/dpladm/bin/sync-site.sh b/infrastructure/dpladm/bin/sync-site.sh index 66c2fa23..1f74e3e0 100755 --- a/infrastructure/dpladm/bin/sync-site.sh +++ b/infrastructure/dpladm/bin/sync-site.sh @@ -84,6 +84,16 @@ function getSiteSecondaryDomains { return } +function getSiteAutogenerateRoutes { + local autogenerateRoutes + autogenerateRoutes=$(yq eval ".sites.${1}.autogenerateRoutes" "${2}") + if [[ "${autogenerateRoutes}" == "null" ]]; then + echo "" + return + fi + echo "${autogenerateRoutes}" +} + function getSiteImportTranslationsCron { local importTranslationsCron importTranslationsCron=$(yq eval ".sites.${1}.importTranslationsCron" "${2}") @@ -126,6 +136,7 @@ set +o errexit # Get the primary and secondary domains from site.yml. primaryDomain=$(getSitePrimaryDomain "${SITE}" "${SITES_CONFIG}") secondaryDomains=$(getSiteSecondaryDomains "${SITE}" "${SITES_CONFIG}") +autogenerateRoutes=$(getSiteAutogenerateRoutes "${SITE}" "${SITES_CONFIG}") releaseTag=$(getSiteDplCmsRelease "${SITE}" "${SITES_CONFIG}") siteImageRepository=$(getSiteReleaseImageRepository "${SITE}" "${SITES_CONFIG}" || exit 1) failOnErr $? "${siteImageRepository}" @@ -136,8 +147,8 @@ importTranslationsCron=$(getSiteImportTranslationsCron "${SITE}" "${SITES_CONFIG set -o errexit # Synchronise the sites environment repository. -syncEnvRepo "${SITE}" "${releaseTag}" "${BRANCH}" "${siteImageRepository}" "${siteReleaseImageName}" "${importTranslationsCron}" "${primaryDomain}" "${secondaryDomains}" +syncEnvRepo "${SITE}" "${releaseTag}" "${BRANCH}" "${siteImageRepository}" "${siteReleaseImageName}" "${importTranslationsCron}" "${autogenerateRoutes}" "${primaryDomain}" "${secondaryDomains}" if [ "${plan}" = "webmaster" ] && [ "${BRANCH}" = "main" ]; then - syncEnvRepo "${SITE}" "${releaseTag}" "moduletest" "${siteImageRepository}" "${siteReleaseImageName}" "${importTranslationsCron}" + syncEnvRepo "${SITE}" "${releaseTag}" "moduletest" "${siteImageRepository}" "${siteReleaseImageName}" "${importTranslationsCron}" "${autogenerateRoutes}" "${primaryDomain}" "${secondaryDomains}" fi diff --git a/infrastructure/dpladm/env-repo-template/standard/.lagoon.yml b/infrastructure/dpladm/env-repo-template/standard/.lagoon.yml index 11fd2e96..41aa3d2d 100644 --- a/infrastructure/dpladm/env-repo-template/standard/.lagoon.yml +++ b/infrastructure/dpladm/env-repo-template/standard/.lagoon.yml @@ -10,6 +10,7 @@ tasks: - run: name: If drupal is not installed command: | + set -e if tables=$(drush sqlq "show tables like 'node';") && [ -z "$tables" ]; then drush si --existing-config -y fi @@ -18,6 +19,7 @@ tasks: - run: name: drush deploy command: | + set -e if [[ -f config/sync/system.site.yml ]]; then echo "Config detected, doing a drush deploy" drush deploy @@ -37,6 +39,7 @@ tasks: # it will be gone. name: Create module upload directory in public files command: | + set -e if [[ ! -d "web/sites/default/files/modules_local" ]]; then echo "Creating directory for module uploads" mkdir web/sites/default/files/modules_local @@ -45,6 +48,7 @@ tasks: - run: name: Import translations command: | + set -e; drush locale-check drush locale-update service: cli @@ -71,6 +75,20 @@ $SECONDARY_DOMAINS schedule: "${IMPORT_TRANSLATIONS_CRON}" command: drush dpl_po:import-remote-config-po da https://danskernesdigitalebibliotek.github.io/dpl-cms/translations/da.config.po service: cli + moduletest: + cronjobs: + - name: drush cron + schedule: "M/15 * * * *" + command: drush cron + service: cli + - name: import translations + schedule: "${IMPORT_TRANSLATIONS_CRON}" + command: drush locale-check && drush locale-update + service: cli + - name: import danish config translations + schedule: "${IMPORT_TRANSLATIONS_CRON}" + command: drush dpl_po:import-remote-config-po da https://danskernesdigitalebibliotek.github.io/dpl-cms/translations/da.config.po + service: cli container-registries: github: diff --git a/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/http_log_format.conf b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/http_log_format.conf new file mode 100644 index 00000000..3e561d88 --- /dev/null +++ b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/http_log_format.conf @@ -0,0 +1,2 @@ +log_format upstreaminfo '{"time": "$time_iso8601", "remote_addr": "$proxy_add_x_forwarded_for", "x-forward-for": "$proxy_add_x_forwarded_for", "bytes_sent": $bytes_sent, "request_time": $request_time, "status":$status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri", "request_query": "$args", "request_length": $request_length, "duration": $request_time,"method": "$request_method", "http_referrer": "$http_referer", "http_user_agent": "$http_user_agent" }'; +access_log /dev/stdout upstreaminfo; diff --git a/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.json b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.json new file mode 100644 index 00000000..9e03dace --- /dev/null +++ b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.json @@ -0,0 +1,9 @@ +{ + "site": "${LAGOON_PROJECT_NAME}", + "env": "${LAGOON_ENVIRONMENT}", + "imageVersion": { + "repository": "${RELEASE_IMAGE_REPOSITORY}", + "image": "${RELEASE_IMAGE_NAME}", + "tag": "${RELEASE_TAG}" + } +} diff --git a/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.txt b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.txt new file mode 100644 index 00000000..e42772dc --- /dev/null +++ b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/metrics/version.txt @@ -0,0 +1 @@ +site_image_version{site="${LAGOON_PROJECT_NAME}" env="${LAGOON_ENVIRONMENT}" repository="${RELEASE_IMAGE_REPOSITORY}" image="${RELEASE_IMAGE_NAME}" tag="${RELEASE_TAG}"} diff --git a/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/server_append_drupal_serve_metrics.conf b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/server_append_drupal_serve_metrics.conf new file mode 100644 index 00000000..0bf27b39 --- /dev/null +++ b/infrastructure/dpladm/env-repo-template/standard/lagoon/conf/nginx/server_append_drupal_serve_metrics.conf @@ -0,0 +1,7 @@ + location /_metrics/ { + set $metrics_file_extension ".txt"; + if ($http_accept ~ "application/json") { + set $metrics_file_extension ".json"; + } + try_files $uri$metrics_file_extension $uri @drupal; + } diff --git a/infrastructure/dpladm/env-repo-template/standard/lagoon/nginx.dockerfile b/infrastructure/dpladm/env-repo-template/standard/lagoon/nginx.dockerfile index 6bc2aa06..26c6b9bb 100644 --- a/infrastructure/dpladm/env-repo-template/standard/lagoon/nginx.dockerfile +++ b/infrastructure/dpladm/env-repo-template/standard/lagoon/nginx.dockerfile @@ -21,5 +21,12 @@ RUN fix-permissions /etc/nginx/conf.d/drupal/server_append_drupal_modules_local. COPY lagoon/conf/nginx/server_append_drupal_rewrite_registration.conf /etc/nginx/conf.d/drupal/server_append_drupal_rewrite_registration.conf RUN fix-permissions /etc/nginx/conf.d/drupal/server_append_drupal_rewrite_registration.conf +COPY lagoon/conf/nginx/metrics /app/web/_metrics +COPY lagoon/conf/nginx/server_append_drupal_serve_metrics.conf /etc/nginx/conf.d/drupal/server_append_drupal_serve_metrics.conf +RUN fix-permissions /etc/nginx/conf.d/drupal/server_append_drupal_serve_metrics.conf + +COPY lagoon/conf/nginx/http_log_format.conf /etc/nginx/conf.d/http_log_format.conf +RUN fix-permissions /etc/nginx/conf.d/http_log_format.conf + # Define where the Drupal Root is located ENV WEBROOT=web diff --git a/infrastructure/environments/dplplat01/configuration/cert-manager/cert-manager-values.yaml b/infrastructure/environments/dplplat01/configuration/cert-manager/cert-manager-values.yaml index b7d5dec8..a3ed2351 100644 --- a/infrastructure/environments/dplplat01/configuration/cert-manager/cert-manager-values.yaml +++ b/infrastructure/environments/dplplat01/configuration/cert-manager/cert-manager-values.yaml @@ -6,4 +6,4 @@ ingressShim: defaultIssuerName: zerossl-production defaultIssuerKind: ClusterIssuer defaultIssuerGroup: cert-manager.io -maxConcurrentChallenges: 10 +maxConcurrentChallenges: 50 diff --git a/infrastructure/environments/dplplat01/configuration/loki/loki-values.template.yaml b/infrastructure/environments/dplplat01/configuration/loki/loki-values.template.yaml index 4632acc2..a4c6b2b5 100644 --- a/infrastructure/environments/dplplat01/configuration/loki/loki-values.template.yaml +++ b/infrastructure/environments/dplplat01/configuration/loki/loki-values.template.yaml @@ -5,20 +5,26 @@ ingress: enabled: false # Back the loki instances with storage as a buffer -persistence: - enabled: true - accessModes: - - ReadWriteOnce - size: 16Gi - -compactor: - retention_enabled: true -limits_config: - # We keep logs for 3 months. - retention_period: 93d +backend: + autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 6 + targetCPUUtilizationPercentage: 70 + targetMemoryUtilizationPercentage: 70 + persistence: + enabled: true + accessModes: + - ReadWriteOnce + size: 32Gi loki: auth_enabled: false + compactor: + retention_enabled: true + limits_config: + # We keep logs for 1 month. + retention_period: 30d structuredConfig: # Setup our index and the azure blob-storage as the storage backend. storage_config: @@ -48,7 +54,6 @@ loki: prefix: loki_index_ period: 24h - write: replicas: 2 persistence: diff --git a/infrastructure/environments/dplplat01/configuration/prometheus/prometheus-values.yaml b/infrastructure/environments/dplplat01/configuration/prometheus/prometheus-values.yaml index 0e0368a2..7cfd5d79 100644 --- a/infrastructure/environments/dplplat01/configuration/prometheus/prometheus-values.yaml +++ b/infrastructure/environments/dplplat01/configuration/prometheus/prometheus-values.yaml @@ -54,8 +54,8 @@ prometheus: accessModes: ["ReadWriteOnce"] resources: requests: - # Setup a 100Gigabyte disk for holding the metrics. - storage: 100Gi + # Setup a disk for holding the metrics. + storage: 500Gi defaultRules: disabled: diff --git a/infrastructure/environments/dplplat01/contacts-and-their-sites.yaml b/infrastructure/environments/dplplat01/contacts-and-their-sites.yaml new file mode 100644 index 00000000..1341ddd0 --- /dev/null +++ b/infrastructure/environments/dplplat01/contacts-and-their-sites.yaml @@ -0,0 +1,7 @@ +sites: + somesitename: + contacts: + - name: "some nam" + email: "some@email.tld" + - name: "another name" + email: "another@email.tld" diff --git a/infrastructure/environments/dplplat01/infrastructure/main.tf b/infrastructure/environments/dplplat01/infrastructure/main.tf index 36009122..0b4816c0 100644 --- a/infrastructure/environments/dplplat01/infrastructure/main.tf +++ b/infrastructure/environments/dplplat01/infrastructure/main.tf @@ -5,18 +5,20 @@ module "environment" { environment_name = "dplplat01" # This variable current _has_ to match the pattern # .dpl.reload.dk - lagoon_domain_base = "dplplat01.dpl.reload.dk" - random_seed = "LahYegheePhohGeew9Fa" - node_pool_system_count = 1 - node_pool_app_default_count_min = 2 - node_pool_app_default_count_max = 7 + lagoon_domain_base = "dplplat01.dpl.reload.dk" + random_seed = "LahYegheePhohGeew9Fa" + node_pools = { + "app4" : { min : 11, max : 20, vm : "Standard_E4s_v3", max_pods : 70 }, + "admin6": { count : 1, vm : "Standard_E4s_v3", role : "admin", max_pods : 60, }, + } + node_pool_system_count = 3 # We've increased this quite a bit to test performance. The ideal starting- # point seems to be in the range 102400 - 204800 to get enough IOPS to # maintain performance during a Drupal site-install. # When copying this value, consider leaving it out and falling back to the # default of 102400. - sql_storage_mb = 409600 - control_plane_version = "1.26.10" + sql_storage_mb = 409600 + control_plane_version = "1.28.9" } # Outputs, for values that comes straight from the dpl-platform-environment diff --git a/infrastructure/environments/dplplat01/lagoon/lagoon-remote-values.template.yaml b/infrastructure/environments/dplplat01/lagoon/lagoon-remote-values.template.yaml index 10e6a586..4423f816 100644 --- a/infrastructure/environments/dplplat01/lagoon/lagoon-remote-values.template.yaml +++ b/infrastructure/environments/dplplat01/lagoon/lagoon-remote-values.template.yaml @@ -8,7 +8,7 @@ lagoon-build-deploy: - "--harbor-username=admin" - "--harbor-password=$HARBOR_ADMIN_PASS" - "--enable-qos" - - "--qos-max-builds=15" + - "--qos-max-builds=5" rabbitMQUsername: "lagoon" rabbitMQPassword: "$RABBITMQ_PASS" rabbitMQHostname: "lagoon-core-broker.lagoon-core.svc.cluster.local" diff --git a/infrastructure/environments/dplplat01/sites.yaml b/infrastructure/environments/dplplat01/sites.yaml index 01c8dbab..dc4a4aee 100644 --- a/infrastructure/environments/dplplat01/sites.yaml +++ b/infrastructure/environments/dplplat01/sites.yaml @@ -2,11 +2,11 @@ x-defaults: &default-release-image-source releaseImageRepository: ghcr.io/danskernesdigitalebibliotek releaseImageName: dpl-cms-source - dpl-cms-release: "2024.18.2" -x-early-movers: &early-movers-release-image-source + dpl-cms-release: "2024.28.0" +x-webmaster: &webmaster-release-image-source releaseImageRepository: ghcr.io/danskernesdigitalebibliotek releaseImageName: dpl-cms-source - dpl-cms-release: "2024.18.2" + dpl-cms-release: "2024.28.0" sites: # Site objects are indexed by a unique key that must be a valid lagoon, and # github project name. That is, alphanumeric and dashes. @@ -16,16 +16,23 @@ sites: description: "A site to test new releases on" releaseImageRepository: ghcr.io/danskernesdigitalebibliotek releaseImageName: dpl-cms-source - dpl-cms-release: "2024.18.3" + dpl-cms-release: "2024.29.1" + plan: webmaster deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIhuA0K7CNvRoe+Xx7RaXG4+a8KcSpzuWn+G4sUPzNWx" cms-school: name: "CMS-skole" description: "Et site til undervisning i CMSet" - releaseImageRepository: ghcr.io/danskernesdigitalebibliotek - releaseImageName: dpl-cms-source - dpl-cms-release: "2024.18.3" importTranslationsCron: "0 * * * *" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ6SzfPFf/XeLeqI342kxuJAlATpDMtgAfqlrLTTbW2m" + plan: webmaster + <<: *default-release-image-source + bibliotek-test: + name: "Bibliotekstest" + description: "Et site hvor bibliotekerne kan teste" + importTranslationsCron: "0 * * * *" + plan: webmaster + deploy_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvhy79hHjLcQJCcMNwci1Q/P/O2LwD4IzBVfkmRGKom + <<: *default-release-image-source customizable-canary: name: "Customizable bibliotek - eksempel" description: "Eksempel på bibliotek der kører på 'webmaster' plan, og derfor har et modultest-miljø" @@ -37,21 +44,35 @@ sites: name: "Aabenraa Biblioteker og Kulturhuse" description: "The library site for Aabenraa" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEMyXdV9INXfJeWlvQAke7jOtWWHTokbPoQ/0vjZ0S1D" + primary-domain: www.aabenraabib.dk + secondary-domains: + - aabenraabib.dk + autogenerateRoutes: true <<: *default-release-image-source aalborg: name: "Aalborg Bibliotekerne" description: "The main library site for Aalborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE8+vj/1goR+Y42JMD/NbL4PXM4N6DifKbRZjJdyAURp" - <<: *early-movers-release-image-source + primary-domain: www.aalborgbibliotekerne.dk + secondary-domains: + - aalborgbibliotekerne.dk + autogenerateRoutes: "redirect" + plan: webmaster + <<: *webmaster-release-image-source aarhus: name: "Aarhus Kommunes Biblioteker" description: "The library site for Aarhus" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFL+uMeEfsaHEzbNxOmBB8dX32OLo63CTomG8VZvuiN2" - <<: *default-release-image-source + plan: webmaster + <<: *webmaster-release-image-source aero: name: "Ærø Folkebibliotek" description: "The library site for Ærø" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDJNI7OU7O3X0AYNJSyZ9VkdSGaD5mAQmhcRMW72TpKi" + primary-domain: www.arrebib.dk + secondary-domains: + - arrebib.dk + autogenerateRoutes: true <<: *default-release-image-source albertslund: name: "Albertslund Bibliotek" @@ -62,6 +83,10 @@ sites: name: "Allerød Biblioteker" description: "The library site for Allerød" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOlK4u+5C8Y+euVj0Q+s7ZsNWMeUqSKgVg+845d3XX1s" + primary-domain: www.bibliotek.alleroed.dk + secondary-domains: + - bibliotek.alleroed.dk + autogenerateRoutes: true <<: *default-release-image-source assens: name: "AssensBibliotekerne" @@ -72,6 +97,10 @@ sites: name: "Ballerup Bibliotekerne" description: "The library site for Ballerup" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKnoDa5OsU/7RESGoGwvRv/piSndDnLShEyaBDP2pW1r" + primary-domain: bib.ballerup.dk + secondary-domains: + - www.bib.ballerup.dk + autogenerateRoutes: true <<: *default-release-image-source billund: name: "Billund Bibliotekerne og Borgerservice" @@ -81,6 +110,7 @@ sites: - www.billundbib.dk - billundbibliotek.dk - www.billundbibliotek.dk + autogenerateRoutes: "redirect" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOsUy+dVkL+KxOYz8zSel7mNkcKrEnqDZPHmsU4sfMv/" <<: *default-release-image-source bornholm: @@ -97,11 +127,19 @@ sites: name: "Brønderslev Bibliotek" description: "The library site for Brønderslev" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPocm02vNblShmSFlQqWsIszR/AXsbT5Jmwj8fDwjSwO" + primary-domain: www.bronderslevbib.dk + secondary-domains: + - bronderslevbib.dk + autogenerateRoutes: true <<: *default-release-image-source dragor: name: "Dragør Bibliotek" description: "The library site for Dragør" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAwkmlUnVYpnRLKQDohUcg58fFYn+UdPGDU2AUWoTybo" + primary-domain: www.drabib.dk + secondary-domains: + - drabib.dk + autogenerateRoutes: true <<: *default-release-image-source egedal: name: "Egedal Bibliotekerne" @@ -112,6 +150,14 @@ sites: name: "Esbjerg Kommunes Biblioteker" description: "The library site for Esbjerg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBQFAh4UeSmcPTFtXj5W/ZKhelJcAornaFYIYJUP0hH9" + primary-domain: www.esbjergbibliotek.dk + secondary-domains: + - esbjergbibliotek.dk + - ekb.dk + - www.ekb.dk + - esbbib.dk + - www.esbbib.dk + autogenerateRoutes: true <<: *default-release-image-source faaborg-midtfyn: name: "Faaborg-Midtfyn Bibliotekerne" @@ -122,21 +168,40 @@ sites: name: "Favrskov Bibliotekerne" description: "The library site for Favrskov" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINqAkzzI+VgHhM7NpOQaEe7XSUo2iWU/cVXvt8rq88uK" + primary-domain: favrskovbib.dk + secondary-domains: + - www.favrskovbib.dk + - favrskovbibliotekerne.dk + - www.favrskovbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source faxe: name: "Faxe Kommunes Bibliotek & Borgerservice" description: "The library site for Faxe" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBkdxUoBx0ZAXfMfA0rRUNo2EcUK39fp0M/zKJPOcYx2" - <<: *default-release-image-source + primary-domain: "www.faxebibliotek.dk" + secondary-domains: + - "faxebibliotek.dk" + autogenerateRoutes: true + plan: webmaster + <<: *webmaster-release-image-source fredensborg: name: "Fredensborg Bibliotekerne" description: "The library site for Fredensborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKxoe8V6eyofhPOEe18qZACQAoWjfgCjN3yxcTWVjyxV" + primary-domain: www.fredensborgbibliotekerne.dk + secondary-domains: + - fredensborgbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source fredericia: name: "Fredericia Bibliotek" description: "The library site for Fredericia" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA2SgYgOoWn6jbg+U91/PcxmfRIxoSWbTANKP++LKanO" + primary-domain: fredericiabib.dk + secondary-domains: + - www.fredericiabib.dk + autogenerateRoutes: true <<: *default-release-image-source frederiksberg: name: "Biblioteket Frederiksberg" @@ -147,16 +212,26 @@ sites: name: "Frederikshavn Kommunes Biblioteker" description: "The library site for Frederikshavn" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZcYBGIGrw0aei4UFmWcNMiQ4ZbJbBR7OU7q5Bsu/lz" + primary-domain: bibl.frederikshavn.dk + autogenerateRoutes: true <<: *default-release-image-source frederikssund: name: "Frederikssund Bibliotekerne" description: "The library site for Frederikssund" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOSWh56XpMvlK6CMz2bi3RZoUXUWFUVw7eo/cfaxmE/1" + primary-domain: www.bibliotekerne.frederikssund.dk + secondary-domains: + - bibliotekerne.frederikssund.dk + autogenerateRoutes: true <<: *default-release-image-source fureso: name: "Furesø Bibliotek & Borgerservice" description: "The library site for Furesø" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+OntBSayMdg22NU1xDnoMsuW1E69uNwvcmeEgt8wlQ" + primary-domain: furbib.dk + secondary-domains: + - www.furbib.dk + autogenerateRoutes: true <<: *default-release-image-source gentofte: name: "Gentofte Bibliotekerne" @@ -172,11 +247,20 @@ sites: name: "Glostrup Bibliotek" description: "The library site for Glostrup" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBMV2GongJbNSRKHl2OUNd2Md5Y9PxKMLxyU8BprGV1L" + primary-domain: www.glostrupbib.dk + secondary-domains: + - glostrupbib.dk + autogenerateRoutes: true <<: *default-release-image-source greve: name: "Greve Bibliotek" description: "The library site for Greve" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMjwn5wHT3u7AIfYN0FMPtxidi+vUmcE1cZpWeg1pPm9" + primary-domain: www.grevebibliotek.dk + secondary-domains: + - grevebib.dk + - www.grevebib.dk + autogenerateRoutes: true <<: *default-release-image-source gribskov: name: "Gribskov Biblioteker" @@ -192,16 +276,28 @@ sites: name: "Haderslev Bibliotekerne" description: "The library site for Haderslev" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsEjJ7Yqh8JPF1UglkMDQbksKwAeZLSZeqWRCWFXMkR" + primary-domain: haderslevbibliotekerne.dk + secondary-domains: + - www.haderslevbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source halsnaes: name: "Halsnæs Bibliotekerne" description: "The library site for Halsnæs" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMB+INXad3Fl3fbnPVnDJcMq1L907fu5J4S7rL3nUv84" + primary-domain: bibliotekerne.halsnaes.dk + secondary-domains: + - www.bibliotekerne.halsnaes.dk + autogenerateRoutes: true <<: *default-release-image-source hedensted: name: "Hedensted Bibliotekerne" description: "The library site for Hedensted" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID34dCc953IPi1leCQyIOo4XMOvuRz84qam4P1r9Dzuh" + primary-domain: hedenstedbib.dk + secondary-domains: + - www.hedenstedbib.dk + autogenerateRoutes: true <<: *default-release-image-source helsingor: name: "Helsingør Kommunes Biblioteker" @@ -214,27 +310,45 @@ sites: primary-domain: www.herlevbibliotek.dk secondary-domains: - herlevbibliotek.dk + autogenerateRoutes: "redirect" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsQ7blUGjtlSdPU4AV7PR21o2Eqg5IMKTCFX3PV/2Mf" <<: *default-release-image-source herning: name: "Herning Bibliotekerne" description: "The main library site for Herning" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA4LZWJFrRQQD65WohscqcmX0uqx7/zXFsK/o2tVY/9B" - <<: *early-movers-release-image-source + primary-domain: www.herningbib.dk + secondary-domains: + - herningbib.dk + autogenerateRoutes: true + plan: webmaster + <<: *webmaster-release-image-source hillerod: name: "Hillerød Bibliotekerne" description: "The library site for Hillerød" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMpZ969v19pbZ6ILz1krcNBccZMkUK3ok5S1HjF7u5Y1" + primary-domain: hilbib.dk + secondary-domains: + - www.hilbib.dk + autogenerateRoutes: true <<: *default-release-image-source hjorring: name: "Hjørring Bibliotekerne" description: "The library site for Hjørring" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJw8nFZITPe1eVE9BUmtxWWuJUKNezmJgRa3QS1T0nWI" + primary-domain: hjbib.dk + secondary-domains: + - www.hjbib.dk + autogenerateRoutes: true <<: *default-release-image-source hoje-taastrup: name: "Høje-Taastrup Kommunes Biblioteker" description: "The library site for Høje-Taastrup" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILiVBegVlQMb0OfQCfJAv87mLMe37xAaGCQc42i0j+2H" + primary-domain: bibliotek.htk.dk + secondary-domains: + - www.bibliotek.htk.dk + autogenerateRoutes: true <<: *default-release-image-source holbaek: name: "Holbæk Bibliotekerne" @@ -245,31 +359,57 @@ sites: name: "Holstebro Bibliotek" description: "The library site for Holstebro" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQNXpvIAg6/lHe/RVocj2losQ6Q2TIN/S5IFdY17g0Y" + primary-domain: www.holstebrobibliotek.dk + secondary-domains: + - holstebrobibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source horsens: name: "Horsens Bibliotek" description: "The library site for Horsens" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFR0Fs3s0SyO3kSWPJd2flAItMWSvN0elpWrqHuJSjjz" + primary-domain: horsensbibliotek.dk + secondary-domains: + - www.horsensbibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source horsholm: name: "Hørsholm Bibliotek" description: "The library site for Hørsholm" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDAyQTTt/8Wnhyz03LUWjVrAuhohatAUuBx3dtmM8wa8" + primary-domain: biblioteket.horsholm.dk + secondary-domains: + - www.biblioteket.horsholm.dk + autogenerateRoutes: redirect <<: *default-release-image-source hvidovre: name: "HvidovreBibliotekerne" description: "The library site for Hvidovre" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINf+6OcOZOpd8hdtNcBm7wA8jYe6CtdYbW8iUrDjWapZ" + primary-domain: www.hvidovrebib.dk + secondary-domains: + - hvidovrebib.dk + - www.hvidovrebibliotekerne.dk + - hvidovrebibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source ikast-brande: name: "Ikast-Brande Bibliotek" description: "The library site for Ikast-Brande" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKpSICadbqfwDoZgxSro2QlhWCNKMfN4Juhpg+S+57Jg" + primary-domain: www.ikast-brandebibliotek.dk + secondary-domains: + - ikast-brandebibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source ishoj: name: "Ishøj Bibliotek" description: "The library site for Ishøj" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAwD4x4QUSQlylgELoKuxBwP7PqHke5gbv4mkog82GK" + primary-domain: www.ishojbib.dk + secondary-domains: + - ishojbib.dk + autogenerateRoutes: true <<: *default-release-image-source jammerbugt: name: "Jammerbugt Bibliotekerne" @@ -280,6 +420,10 @@ sites: name: "Kalundborg Biblioteker" description: "The library site for Kallundborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+tCuK/9Ywp8AizLtg+GflsiGcB8QVDWNbXBwznxHkw" + primary-domain: www.kalundborgbib.dk + secondary-domains: + - kalundborgbib.dk + autogenerateRoutes: true <<: *default-release-image-source kerteminde: name: "Kerteminde Bibliotekerne" @@ -292,22 +436,39 @@ sites: primary-domain: bibliotek.kk.dk secondary-domains: - www.bibliotek.kk.dk + - nginx.main.kobenhavn.dplplat01.dpl.reload.dk + - varnish.main.kobenhavn.dplplat01.dpl.reload.dk + plan: webmaster deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHaTkDvjLW/b2qVj8FIvtX9x3TxFFZTENn+w2CFELeoC" - <<: *default-release-image-source + <<: *webmaster-release-image-source koge: name: "KøgeBibliotekerne" description: "The library site for Køge" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMRB54Z7o6Vt3qOucjvE7No6LN2NdBNtfRi2f4y+UQdA" + primary-domain: www.koegebib.dk + secondary-domains: + - koegebib.dk + - www.koegebibliotekerne.dk + - koegebibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source kolding: name: "Koldingbibliotekerne" description: "The library site for Kolding" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBIP5Rlg98TBW8mdIbqcksbxpT0epIbAe56iAcEmi2z6" + primary-domain: koldingbib.dk + secondary-domains: + - www.koldingbib.dk + - koldingbibliotekerne.dk + - www.koldingbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source laeso: name: "Læsø Bibliotek" description: "The library site for Læsø" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGBAqZWP02LnFU7Iwlj9ebWeX3efwl9tkRzidSIjo6FF" + primary-domain: biblioteket.laesoe.dk + autogenerateRoutes: true <<: *default-release-image-source langeland: name: "Langeland Bibliotek" @@ -318,36 +479,59 @@ sites: name: "Lejre Bibliotek & Arkiv" description: "The library site for Lejre" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJUCoDJmWFsXa3nZe7XBa/v1nahzl2GeoT46XAW7ZVQG" - <<: *default-release-image-source - lemvig: - name: "Lemvig Bibliotek" - description: "The library site for Lemvig" - deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINLPu/T7RI4zFZ5+JYJqttf2IAU2GIcUOyRfqA3PlB9W" + primary-domain: lejrebib.dk + secondary-domains: + - www.lejrebib.dk + - lejrebibliotek.dk + - www.lejrebibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source lolland: name: "LollandBibliotekerne" description: "The library site for Lolland" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDHoX6Huapt+Rjz1pgyyYRLAHpgsgctmi+Fs37tVIbjN" + primary-domain: lollandbib.dk + secondary-domains: + - www.lollandbib.dk + autogenerateRoutes: true <<: *default-release-image-source lyngby-taarbaek: name: "Lyngby-Taarbæk Bibliotekerne" description: "The library site for Lyngby-Taarbæk" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeXHvVXTlOXtrK8kSR12qZQH1YHto+PpWx0rac/1QMe" + primary-domain: www.lyngbybib.dk + secondary-domains: + - lyngbybib.dk + autogenerateRoutes: true <<: *default-release-image-source mariagerfjord: name: "Mariagerfjord Bibliotekerne" description: "The library site for Mariagerfjord" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFeTDNC6HBZrpSy73UadgOdr8sjxpsKZkwGARuJ3X8rC" + primary-domain: mfbib.dk + secondary-domains: + - www.mfbib.dk + - mariagerfjordbibliotekerne.dk + - www.mariagerfjordbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source middelfart: name: "Middelfart Bibliotek" description: "The library site for Middelfart" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL+cnxhliA+siikDk40SlviShSK6MmC3g/3spAVey0ht" + primary-domain: www.middelfartbibliotek.dk + secondary-domains: + - middelfartbibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source morso: name: "Morsø Folkebibliotek" description: "The library site for Morsø" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAVce9r/E16lOPiiZEcjzEW40nuxCCt7ahv5NYUPwU8P" + primary-domain: www.bibliotekmorsoe.dk + secondary-domains: + - bibliotekmorsoe.dk + autogenerateRoutes: true <<: *default-release-image-source naestved: name: "Næstved Bibliotek og Borgerservice" @@ -358,6 +542,10 @@ sites: name: "Norddjurs Biblioteker" description: "The library site for Norddjurs" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICgrEOr/QVP8FkakoeoFwqqYMMroLzUEu2ieyLLWGmsB" + primary-domain: norddjursbib.dk + secondary-domains: + - www.norddjursbib.dk + autogenerateRoutes: true <<: *default-release-image-source nordfyn: name: "Bibliotek og Borgerservice Nordfyns Kommune" @@ -368,11 +556,19 @@ sites: name: "Nyborg Bibliotek" description: "The library site for Nyborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMpG7Br//TQnc3LRdkXCR80mD0C6vsZg36ZVibTUfdyS" + primary-domain: www.nyborgbibliotek.dk + secondary-domains: + - nyborgbibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source odder: name: "Odder Bibliotek" description: "The library site for Odder" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHppEy2QVzOCwuLSQqf4OOMxiVtfbuxMQzatS4HBXXYB" + primary-domain: www.bibliotek.odder.dk + secondary-domains: + - bibliotek.odder.dk + autogenerateRoutes: true <<: *default-release-image-source odense: name: "Odense Biblioteker og Borgerservice" @@ -383,26 +579,48 @@ sites: name: "Odsherred Bibliotek og Kulturhuse" description: "The library site for Odsherred" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKO7a1/SEglnKZ3RJpSYKSaadeeVXr6xb5b5MJIEeYmc" + primary-domain: odsbib.dk + secondary-domains: + - www.odsbib.dk + autogenerateRoutes: true <<: *default-release-image-source randers: name: "Randers Bibliotek" description: "The library site for Randers" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEmOBUxVFYKHM8QNQ3od1a8e7+w+oFlE871SxH1+FN4R" + primary-domain: www.randersbib.dk + secondary-domains: + - randersbib.dk + - randersbibliotek.dk + - www.randersbibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source rebild: name: "Rebild Bibliotekerne" description: "The library site for Rebild" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ7BXhw6xig5W2AjtX7eqnnrWHKnavFqHdgc+5vY2U3T" + primary-domain: www.rebildbib.dk + secondary-domains: + - rebildbib.dk + autogenerateRoutes: true <<: *default-release-image-source ringkobing-skjern: name: "Ringkøbing-Skjern Bibliotekerne" description: "The library site for Ringkøbing-Skjern" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFDaximGZYZQWR0IX2sP/e94hfbHQrKVD5mTqiCvpIW2" + primary-domain: riskbib.dk + secondary-domains: + - www.riskbib.dk + autogenerateRoutes: true <<: *default-release-image-source ringsted: name: "Ringsted Bibliotek & Borgerservice" description: "The library site for Ringsted" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGimIWKuDZGYhgEmh26pImLTGtIHvh9xEw1lHfxxplJz" + primary-domain: ringstedbib.dk + secondary-domains: + - www.ringstedbib.dk + autogenerateRoutes: true <<: *default-release-image-source rodovre: name: "Rødovre Bibliotek" @@ -418,41 +636,62 @@ sites: name: "Rudersdal Bibliotekerne" description: "The library site for Rudersdal" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMS9z1DqqOV7+ycLji2x8PYZeBgpUKvZLPlBu5/8IPDy" + primary-domain: rudbib.dk + secondary-domains: + - www.rudbib.dk + - rudersdalbibliotekerne.dk + - www.rudersdalbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source samso: name: "Samsø Bibliotek" description: "The library site for Samsø" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFZcxFuzVNn72t0dnDsnEX60NZ0OJ5ce4HxgI1PtIKFp" + primary-domain: "bibliotek.samsoe.dk" + secondary-domains: + - "www.bibliotek.samsoe.dk" + autogenerateRoutes: true <<: *default-release-image-source silkeborg: name: "Silkeborg Bibliotekerne" description: "The library site for Silkeborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHudvU3HuWcnnCOFlQU5Tvgkb/v6b2DttwUTN7Vl0sQV" + primary-domain: silkeborgbib.dk + secondary-domains: + - www.silkeborgbib.dk + autogenerateRoutes: true <<: *default-release-image-source skanderborg: name: "Skanderborg Bibliotek" description: "The library site for Skanderborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ3uD7iCaZUa5HRmzs9esYCFoVnmPp5KKee+q5FPyR+Z" + primary-domain: www.bibliotek.skanderborg.dk + secondary-domains: + - bibliotek.skanderborg.dk + autogenerateRoutes: true <<: *default-release-image-source skive: name: "Skive Bibliotek" description: "The library site for Skive" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGpJAKCBMKM9G0qvUGeCRSvz8QNg27r7sDedj15HP7Hh" - <<: *default-release-image-source - slagelse: - name: "Slagelse Biblioteker og Borgerservice" - description: "The library site for Slagelse" - deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAQdh4Doe9DRLdCMApkRLmApfudvVgcVBr27fSG9gwHm" + primary-domain: www.skivebibliotek.dk + secondary-domains: + - skivebibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source solrod: name: "Solrød Bibliotek og Kulturhus" description: "The library site for Solrød" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF1GwZ4r8QZ7Vebdqiz/mtkifrLU+ZSvlAJshdXjCh5J" - <<: *early-movers-release-image-source + <<: *default-release-image-source sonderborg: name: "Biblioteket Sønderborg" description: "The library site for Sønderborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJKta0DYtcxlP5VNCAQFVtRSbzJRSEs1YY3zsSxVQgfi" + primary-domain: biblioteket.sonderborg.dk + secondary-domains: + - www.biblioteket.sonderborg.dk + autogenerateRoutes: true <<: *default-release-image-source soro: name: "Sorø Bibliotek" @@ -463,16 +702,28 @@ sites: name: "Stevns Bibliotekerne" description: "The library site for Stevns" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINmstZ41PSBjLAxu8cE4Oi7G1oktlH1FFJBNbLT1GAez" + primary-domain: www.stevnsbib.dk + secondary-domains: + - stevnsbib.dk + autogenerateRoutes: true <<: *default-release-image-source struer: name: "Struer Bibliotek" description: "The library site for Struer" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAcZDg9Veyvl3u/TGG0lIw6Z8osrEZwd4HhcXvbABAsH" + primary-domain: "www.struerbibliotek.dk" + secondary-domains: + - "struerbibliotek.dk" + autogenerateRoutes: "redirect" <<: *default-release-image-source sydslesvig: name: "Dansk Centralbibliotek for Sydslesvig e.V." description: "The library site for Dansk Centralbibliotek for Sydslesvig e.V." deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH5J5WxZ7j+tCGTPOt36J6r1Vnth7PXXcdvYzP2TPph0" + primary-domain: www.dcbib.dk + secondary-domains: + - dcbib.dk + autogenerateRoutes: true <<: *default-release-image-source svendborg: name: "Svendborg Bibliotek" @@ -483,54 +734,88 @@ sites: name: "Syddjurs Bibliotek" description: "The library site for Syddjurs" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINhp6QNrL71jlzbhSPRoTcRQS6b8Ztpx+JLZVxUhNSVK" + primary-domain: syddjursbibliotek.dk + secondary-domains: + - www.syddjursbibliotek.dk + autogenerateRoutes: true <<: *default-release-image-source taarnby: name: "Tårnby Kommunebiblioteker" description: "The library site for Tårnby" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF0F5bqQwdmAdMcDHVT8xxK0tOEGZYp21WIZ1zydr28O" - <<: *default-release-image-source + plan: webmaster + primary-domain: taarnbybib.dk + secondary-domains: + - www.taarnbybib.dk + autogenerateRoutes: true + <<: *webmaster-release-image-source thisted: name: "Biblioteket i Thy" description: "The library site for Thisted" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII8zoNSiwkKmOSHvtKxSMJiDC9EWbTzhkAUd1+csvnne" - <<: *default-release-image-source - tonder: - name: "Tønder Kommunes Biblioteker" - description: "The library site for Tønder" - deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUpgNIeuCbzprGnyr+TKcWCvS1aYS49unqhNNVYQGNf" + primary-domain: bib.kulturrummet.dk + autogenerateRoutes: true <<: *default-release-image-source vallensbaek: name: "Vallensbæk Bibliotek" description: "The library site for Vallensbæk" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM1BwEGpOF6YrjToeH8iD2cALRjCdk1XOrHl7Yj9NPUE" + primary-domain: kulturogborgerhus.vallensbaek.dk + secondary-domains: + - www.kulturogborgerhus.vallensbaek.dk + autogenerateRoutes: true <<: *default-release-image-source varde: name: "Varde Bibliotek" description: "The library site for Varde" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINk4ZKSj49vjmu9/wQAuK/LC8B7Q7dF7B+0N4JIRcGCp" + primary-domain: www.vardebib.dk + secondary-domains: + - vardebib.dk + autogenerateRoutes: true <<: *default-release-image-source vejen: name: "Vejen Kommunes Biblioteker" description: "The library site for Vejen" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKEKCWFJdpWpxSXpP0fXHBkZG6v0mENmOEsyJEDIqnoQ" + primary-domain: vejbib.dk + secondary-domains: + - www.vejbib.dk + autogenerateRoutes: true <<: *default-release-image-source vejle: name: "Vejle Bibliotekerne" description: "The library site for Vejle" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILj79u24Ev3uo0WLgNVyMT+V0921M7a8qdM7Q/GyOdZl" + primary-domain: vejlebib.dk + secondary-domains: + - www.vejlebib.dk + autogenerateRoutes: true <<: *default-release-image-source vesthimmerland: name: "Vesthimmerlands Biblioteker" description: "The library site for Vesthimmerland" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKNqMIGZql1EAivzzOPpcq2DmC5tPnA1KvLgtnJBqd1F" + primary-domain: "www.vhbib.dk" + secondary-domains: + - "vhbib.dk" + autogenerateRoutes: "redirect" <<: *default-release-image-source viborg: name: "Viborg Bibliotekerne" description: "The library site for Viborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINOTdXuLPGfLvqVJYmsF06Bdgmrff2tKl4PS7pRg4fFx" + primary-domain: viborgbib.dk + secondary-domains: + - www.viborgbib.dk + autogenerateRoutes: true <<: *default-release-image-source vordingborg: name: "Vordingborg Bibliotekerne" description: "The library site for Vordingborg" deploy_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICeMmI9ufAPgkQvdcFEg0EAMNNuLbXHxw2MXhVdtPT3w" + primary-domain: www.vordingborgbibliotekerne.dk + secondary-domains: + - vordingborgbibliotekerne.dk + autogenerateRoutes: true <<: *default-release-image-source diff --git a/infrastructure/terraform/modules/dpl-platform-environment/aks.tf b/infrastructure/terraform/modules/dpl-platform-environment/aks.tf index c18c4f1c..114c751a 100644 --- a/infrastructure/terraform/modules/dpl-platform-environment/aks.tf +++ b/infrastructure/terraform/modules/dpl-platform-environment/aks.tf @@ -1,6 +1,7 @@ # Setup a single cluster in a single availabillity zone. resource "azurerm_kubernetes_cluster" "cluster" { name = "aks-${var.environment_name}-01" + sku_tier = "Standard" location = var.location resource_group_name = azurerm_resource_group.rg.name dns_prefix = var.environment_name @@ -18,6 +19,9 @@ resource "azurerm_kubernetes_cluster" "cluster" { node_count = var.node_pool_system_count vm_size = var.node_pool_system_vm_sku + # Sync node version with control plane version of k8s + orchestrator_version = var.control_plane_version + # Attach the cluster to our private network. vnet_subnet_id = azurerm_subnet.aks.id @@ -60,42 +64,15 @@ resource "azurerm_kubernetes_cluster" "cluster" { } } -# Add a nodepool for administrative workloads -resource "azurerm_kubernetes_cluster_node_pool" "admin" { - name = "admin" - kubernetes_cluster_id = azurerm_kubernetes_cluster.cluster.id - vnet_subnet_id = azurerm_subnet.aks.id - node_labels = { - "noderole.dplplatform" : "admin" - } - zones = [ - "1", - ] - - vm_size = var.node_pool_admin_vm_sku - - # Enable autoscaling. - enable_auto_scaling = true - min_count = var.node_pool_admin_count_min - max_count = var.node_pool_admin_count_max - node_count = var.node_pool_admin_count_min - - lifecycle { - ignore_changes = [ - # Changed by the autoscaler, so we need to ignore it. - node_count - ] - } -} - - # Add a application default nodepool. -resource "azurerm_kubernetes_cluster_node_pool" "app_default" { - name = "appdefault" +resource "azurerm_kubernetes_cluster_node_pool" "pool" { + for_each = var.node_pools + name = each.key + orchestrator_version = var.control_plane_version kubernetes_cluster_id = azurerm_kubernetes_cluster.cluster.id vnet_subnet_id = azurerm_subnet.aks.id node_labels = { - "noderole.dplplatform" : "application" + "noderole.dplplatform" : try(each.value.role, "application") } zones = [ "1", @@ -106,20 +83,13 @@ resource "azurerm_kubernetes_cluster_node_pool" "app_default" { # low resource requests, we're keeping the number of pods on a node low to # avoid running the nodes too hot. # Be aware that changing this value will destroy and recreate the nodepool. - max_pods = 30 + max_pods = try(each.value.max_pods, 30) - vm_size = var.node_pool_app_default_vm_sku + vm_size = each.value.vm # Enable autoscaling. - enable_auto_scaling = true - min_count = var.node_pool_app_default_count_min - max_count = var.node_pool_app_default_count_max - node_count = var.node_pool_app_default_count_min - - lifecycle { - ignore_changes = [ - # Changed by the autoscaler, so we need to ignore it. - node_count - ] - } + enable_auto_scaling = try(each.value.min, try(each.value.max, null)) != null ? true : false + min_count = try(each.value.min, null) + max_count = try(each.value.max, null) + node_count = try(each.value.count, null) } diff --git a/infrastructure/terraform/modules/dpl-platform-environment/variables.tf b/infrastructure/terraform/modules/dpl-platform-environment/variables.tf index 4a3f0c67..9faaafc7 100644 --- a/infrastructure/terraform/modules/dpl-platform-environment/variables.tf +++ b/infrastructure/terraform/modules/dpl-platform-environment/variables.tf @@ -31,40 +31,10 @@ variable "location" { default = "West Europe" } -variable "node_pool_admin_count_max" { - description = "The maximum number of pods to autoscale the administration nodepool to" - default = 3 - type = number -} - -variable "node_pool_admin_count_min" { - description = "The minimum number of pods to autoscale the administration nodepool to, also used as the initial count for the nodepool" - default = 1 - type = number -} - -variable "node_pool_admin_vm_sku" { - description = "The SKU of the virtual machines used for the administration nodepool" - default = "Standard_B4ms" - type = string -} - -variable "node_pool_app_default_count_max" { - description = "The maximum number of pods to autoscale the default application nodepool to" - default = 3 - type = number -} - -variable "node_pool_app_default_count_min" { - description = "The minimum number of pods to autoscale the default application nodepool to, also used as the initial count for the nodepool" - default = 1 - type = number -} - -variable "node_pool_app_default_vm_sku" { - description = "The SKU of the virtual machines used for the default application nodepool" - default = "Standard_B4ms" - type = string +variable "node_pools" { + description = "The node pools (other than the system one) used for the cluster" + default = {} + type = map(any) } variable "node_pool_system_count" { @@ -87,7 +57,7 @@ variable "random_seed" { variable "sql_sku" { description = "The SKU used for MariaDB" type = string - default = "GP_Gen5_2" + default = "GP_Gen5_4" } variable "sql_version" { diff --git a/tools/dplsh/Dockerfile b/tools/dplsh/Dockerfile index 9e6a2042..bdfdd917 100644 --- a/tools/dplsh/Dockerfile +++ b/tools/dplsh/Dockerfile @@ -2,15 +2,15 @@ ARG DPLSH_BUILD_VERSION=latest # Use an intermediate images as a way to have dependabot track our dependency # https://hub.docker.com/r/alpine/helm/tags?page=1&ordering=last_updated -FROM alpine/helm:3.14.1 as helm +FROM alpine/helm:3.15.3 as helm # https://hub.docker.com/r/hashicorp/terraform/tags?page=1&ordering=last_updated -FROM hashicorp/terraform:1.7.3 as terraform +FROM hashicorp/terraform:1.9.2 as terraform # We use the official azure cli as a base-image. It is itself based on alpine # and is quite minimal. # https://mcr.microsoft.com/v2/azure-cli/tags/list -FROM mcr.microsoft.com/azure-cli:2.57.0 +FROM mcr.microsoft.com/azure-cli:2.62.0 # See https://github.com/go-task/task/releases ARG TASK_VERSION=v3.36.0 @@ -25,7 +25,7 @@ ARG KREW_VERSION=v0.4.4 ARG CERT_MANAGER_VERIFIER_VERSION=0.3.0 # The kubectl version can be bumped as we upgrade the cluster minor version. -ARG KUBECTL_VERSION=v1.26.10 +ARG KUBECTL_VERSION=v1.27.9 # kubelogin is a client-go credential plugin implementing azure authentication. # https://github.com/Azure/kubelogin/releases ARG KUBELOGIN_VERSION=v0.0.34 @@ -47,7 +47,8 @@ RUN apk add --no-cache \ shadow \ vim \ yq \ - openssh + openssh \ + bind-tools # Add task, a modern Make equivalent. RUN curl -sL https://taskfile.dev/install.sh | bash -s -- -b /usr/local/bin ${TASK_VERSION}