From 4cb9550b41f8402daaab2a1da44516e6d5287667 Mon Sep 17 00:00:00 2001 From: Britney Wang Date: Tue, 24 Mar 2026 18:37:14 +0800 Subject: [PATCH 1/4] ci: publish on charmhub --- .github/workflows/deploy.yaml | 297 ++++++++++++++++++---------------- 1 file changed, 162 insertions(+), 135 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 4a4064b1..b6c3aac0 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -1,10 +1,11 @@ name: Deploy -on: - push: - branches: - - charming - - main +# on: +# push: +# branches: +# - charming +# - main +on: pull_request env: CHARMCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS: true @@ -28,152 +29,178 @@ jobs: cd charm charmcraft pack -v --project-dir ./ - - name: Upload charm + - name: Upload charm to artifact uses: actions/upload-artifact@v4 with: name: ubuntu-security-api-charm path: ./charm/*.charm - pack-rock: + # pack-rock: + # runs-on: ubuntu-latest + # steps: + # - name: Checkout Code + # uses: actions/checkout@v3 + + # - name: Setup LXD + # uses: canonical/setup-lxd@main + + # - name: Setup Rockcraft + # run: sudo snap install rockcraft --classic --channel=latest/edge + + # - name: Pack Rock + # run: rockcraft pack -v + + # - name: Upload Rock + # uses: actions/upload-artifact@v4 + # with: + # name: ubuntu-security-api-rock + # path: ./*.rock + + # publish-image: + # runs-on: ubuntu-latest + # needs: pack-rock + # outputs: + # image_url: ${{ steps.set_image_url.outputs.image_url }} + # steps: + # - name: Get Rock + # uses: actions/download-artifact@v4 + # with: + # name: ubuntu-security-api-rock + + # - name: Set image URL + # id: set_image_url + # run: echo "image_url=ghcr.io/canonical/ubuntu-security-api:$(date +%s)-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT + + # - name: Push to GHCR + # run: skopeo --insecure-policy copy oci-archive:$(ls *.rock) docker://${{ steps.set_image_url.outputs.image_url }} --dest-creds "canonical:${{ secrets.GITHUB_TOKEN }}" + + publish-charm: runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Setup LXD - uses: canonical/setup-lxd@main - - - name: Setup Rockcraft - run: sudo snap install rockcraft --classic --channel=latest/edge - - - name: Pack Rock - run: rockcraft pack -v - - - name: Upload Rock - uses: actions/upload-artifact@v4 - with: - name: ubuntu-security-api-rock - path: ./*.rock - - publish-image: - runs-on: ubuntu-latest - needs: pack-rock - outputs: - image_url: ${{ steps.set_image_url.outputs.image_url }} - steps: - - name: Get Rock - uses: actions/download-artifact@v4 - with: - name: ubuntu-security-api-rock - - - name: Set image URL - id: set_image_url - run: echo "image_url=ghcr.io/canonical/ubuntu-security-api:$(date +%s)-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT - - - name: Push to GHCR - run: skopeo --insecure-policy copy oci-archive:$(ls *.rock) docker://${{ steps.set_image_url.outputs.image_url }} --dest-creds "canonical:${{ secrets.GITHUB_TOKEN }}" - - deploy-staging: - runs-on: - [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] - needs: [pack-charm, publish-image] - environment: - name: staging - url: https://staging.ubuntu.com/security/api/docs - steps: - - name: Install Dependencies - run: | - sudo snap install juju --classic - sudo snap install vault --classic - - - name: Download Charm Artifact - uses: actions/download-artifact@v4 - with: - name: ubuntu-security-api-charm - - - name: Configure Vault and Juju - env: - VAULT_ADDR: "https://vault.admin.canonical.com:8200" - VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} - VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} - run: | - set -e - export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} - export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} - export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} - export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common - export CHARM_NAME=${{ vars.CHARM_NAME }} - - export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") - - mkdir -p ~/.local/share/juju - vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml - USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") - PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") - printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml - - - name: Deploy Application to staging - run: | - export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} - export CHARM_NAME=${{ vars.CHARM_NAME }} - - if juju status --color --relations | grep -q "^$CHARM_NAME\\s"; then - echo "Application '$CHARM_NAME' exists. Running juju refresh..." - juju refresh $CHARM_NAME --path ./*.charm --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - else - echo "Application '$CHARM_NAME' not found. Running juju deploy..." - juju deploy ./*.charm $CHARM_NAME --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - fi - - deploy-production: - runs-on: - [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] - needs: [pack-charm, publish-image] + needs: pack-charm environment: name: production url: https://ubuntu.com/security/api/docs + outputs: + charm_url: ${{ steps.publish.outputs.charm_url }} + charm_revision: ${{ steps.publish.outputs.charm_revision }} steps: - - name: Install Dependencies - run: | - sudo snap install juju --classic - sudo snap install vault --classic + - name: Setup Charmcraft + run: sudo snap install charmcraft --classic --channel=latest/beta - name: Download Charm Artifact uses: actions/download-artifact@v4 with: name: ubuntu-security-api-charm + # run-id: 23486477073 + # github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Configure Vault and Juju + - name: Publish charm to CharmHub + id: publish env: - VAULT_ADDR: "https://vault.admin.canonical.com:8200" - VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} - VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} + CHARMCRAFT_AUTH: ${{ secrets.CHARMCRAFT_AUTH_TOKEN }} run: | set -e - export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} - export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} - export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} - export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common - export CHARM_NAME=${{ vars.CHARM_NAME }} - - - export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") - - mkdir -p ~/.local/share/juju - vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml - USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") - PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") - printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml - - - name: Deploy Application to production - run: | - export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} - export CHARM_NAME=${{ vars.CHARM_NAME }} - - if juju status --color --relations | grep -q "^$CHARM_NAME\\s"; then - echo "Application '$CHARM_NAME' exists. Running juju refresh..." - juju refresh $CHARM_NAME --path ./*.charm --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - else - echo "Application '$CHARM_NAME' not found. Running juju deploy..." - juju deploy ./*.charm $CHARM_NAME --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - fi + CHARM_FILE=$(ls *.charm) + OUTPUT=$(charmcraft upload "$CHARM_FILE" --release beta ) + CHARM_URL=$(echo "$OUTPUT" | jq -r '.charm_url') + CHARM_REVISION=$(echo "$OUTPUT" | jq -r '.revision') + echo "charm_url=$CHARM_URL" >> $GITHUB_OUTPUT + echo "charm_revision=$CHARM_REVISION" >> $GITHUB_OUTPUT + echo "Published charm: $CHARM_URL (revision: $CHARM_REVISION)" + + # deploy-staging: + # runs-on: + # [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] + # needs: [publish-charm, publish-image] + # environment: + # name: staging + # url: https://staging.ubuntu.com/security/api/docs + # steps: + # - name: Install Dependencies + # run: | + # sudo snap install juju --classic + # sudo snap install vault --classic + + # - name: Configure Vault and Juju + # env: + # VAULT_ADDR: "https://vault.admin.canonical.com:8200" + # VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} + # VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} + # run: | + # set -e + # export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} + # export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} + # export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} + # export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common + # export CHARM_NAME=${{ vars.CHARM_NAME }} + + # export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + + # mkdir -p ~/.local/share/juju + # vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml + # USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") + # PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") + # printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml + + # - name: Deploy Application to staging + # run: | + # export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} + # export CHARM_NAME=${{ vars.CHARM_NAME }} + # export CHARM_REVISION=${{ needs.publish-charm.outputs.charm_revision }} + + # if juju status --color --relations | grep -q "^$CHARM_NAME\s"; then + # echo "Application '$CHARM_NAME' exists. Running juju refresh..." + # juju refresh $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # else + # echo "Application '$CHARM_NAME' not found. Running juju deploy..." + # juju deploy $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # fi + + # deploy-production: + # runs-on: + # [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] + # needs: [publish-charm, publish-image] + # environment: + # name: production + # url: https://ubuntu.com/security/api/docs + # steps: + # - name: Install Dependencies + # run: | + # sudo snap install juju --classic + # sudo snap install vault --classic + + # - name: Configure Vault and Juju + # env: + # VAULT_ADDR: "https://vault.admin.canonical.com:8200" + # VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} + # VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} + # run: | + # set -e + # export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} + # export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} + # export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} + # export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common + # export CHARM_NAME=${{ vars.CHARM_NAME }} + + + # export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + + # mkdir -p ~/.local/share/juju + # vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml + # USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") + # PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") + # printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml + + # - name: Deploy Application to production + # run: | + # export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} + # export CHARM_NAME=${{ vars.CHARM_NAME }} + # export CHARM_REVISION=${{ needs.publish-charm.outputs.charm_revision }} + + # if juju status --color --relations | grep -q "^$CHARM_NAME\s"; then + # echo "Application '$CHARM_NAME' exists. Running juju refresh..." + # juju refresh $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # else + # echo "Application '$CHARM_NAME' not found. Running juju deploy..." + # juju deploy $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # fi From c96ea488ee8ce2ead5fcbb76c7d151d71cf8eba4 Mon Sep 17 00:00:00 2001 From: Britney Wang Date: Wed, 25 Mar 2026 17:21:30 +0800 Subject: [PATCH 2/4] ci: release on charmhub --- .github/workflows/deploy.yaml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index b6c3aac0..ad96f487 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -29,7 +29,7 @@ jobs: cd charm charmcraft pack -v --project-dir ./ - - name: Upload charm to artifact + - name: Upload charm uses: actions/upload-artifact@v4 with: name: ubuntu-security-api-charm @@ -78,12 +78,17 @@ jobs: runs-on: ubuntu-latest needs: pack-charm environment: - name: production - url: https://ubuntu.com/security/api/docs + name: staging + url: https://staging.ubuntu.com/security/api/docs outputs: charm_url: ${{ steps.publish.outputs.charm_url }} charm_revision: ${{ steps.publish.outputs.charm_revision }} + env: + CHARMCRAFT_AUTH: ${{ secrets.CHARMCRAFT_AUTH_TOKEN }} steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Setup Charmcraft run: sudo snap install charmcraft --classic --channel=latest/beta @@ -95,18 +100,23 @@ jobs: # github-token: ${{ secrets.GITHUB_TOKEN }} - name: Publish charm to CharmHub - id: publish - env: - CHARMCRAFT_AUTH: ${{ secrets.CHARMCRAFT_AUTH_TOKEN }} + id: publish + working-directory: charm/ run: | set -e + cp ../*.charm . CHARM_FILE=$(ls *.charm) - OUTPUT=$(charmcraft upload "$CHARM_FILE" --release beta ) + OUTPUT=$(charmcraft upload "$CHARM_FILE" -v) CHARM_URL=$(echo "$OUTPUT" | jq -r '.charm_url') CHARM_REVISION=$(echo "$OUTPUT" | jq -r '.revision') echo "charm_url=$CHARM_URL" >> $GITHUB_OUTPUT echo "charm_revision=$CHARM_REVISION" >> $GITHUB_OUTPUT echo "Published charm: $CHARM_URL (revision: $CHARM_REVISION)" + + - name: Release charm to latest/beta + run: | + charmcraft release ubuntu-security-api --revision=${{ steps.publish.outputs.charm_revision }} --channel=beta + echo "Released ubuntu-security-api, revision ${{ steps.publish.outputs.charm_revision }} to beta channel" # deploy-staging: # runs-on: From e2163df6b7c8a6b7a45da7b48b3d8935be102fee Mon Sep 17 00:00:00 2001 From: Britney Wang Date: Thu, 26 Mar 2026 20:25:28 +0800 Subject: [PATCH 3/4] ci: publish private charm --- .github/workflows/deploy.yaml | 253 ++++++++++++++++++---------------- charm/charmcraft.yaml | 10 +- 2 files changed, 140 insertions(+), 123 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index ad96f487..743eb40d 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -22,7 +22,7 @@ jobs: uses: canonical/setup-lxd@main - name: Setup Charmcraft - run: sudo snap install charmcraft --classic --channel=latest/edge + run: sudo snap install charmcraft --classic - name: Pack charm run: | @@ -35,141 +35,151 @@ jobs: name: ubuntu-security-api-charm path: ./charm/*.charm - # pack-rock: - # runs-on: ubuntu-latest - # steps: - # - name: Checkout Code - # uses: actions/checkout@v3 - - # - name: Setup LXD - # uses: canonical/setup-lxd@main - - # - name: Setup Rockcraft - # run: sudo snap install rockcraft --classic --channel=latest/edge - - # - name: Pack Rock - # run: rockcraft pack -v + pack-rock: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 - # - name: Upload Rock - # uses: actions/upload-artifact@v4 - # with: - # name: ubuntu-security-api-rock - # path: ./*.rock + - name: Setup LXD + uses: canonical/setup-lxd@main - # publish-image: - # runs-on: ubuntu-latest - # needs: pack-rock - # outputs: - # image_url: ${{ steps.set_image_url.outputs.image_url }} - # steps: - # - name: Get Rock - # uses: actions/download-artifact@v4 - # with: - # name: ubuntu-security-api-rock + - name: Setup Rockcraft + run: sudo snap install rockcraft --classic --channel=latest/edge - # - name: Set image URL - # id: set_image_url - # run: echo "image_url=ghcr.io/canonical/ubuntu-security-api:$(date +%s)-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT + - name: Pack Rock + run: rockcraft pack -v - # - name: Push to GHCR - # run: skopeo --insecure-policy copy oci-archive:$(ls *.rock) docker://${{ steps.set_image_url.outputs.image_url }} --dest-creds "canonical:${{ secrets.GITHUB_TOKEN }}" + - name: Upload Rock + uses: actions/upload-artifact@v4 + with: + name: ubuntu-security-api-rock + path: ./*.rock - publish-charm: + publish-image: runs-on: ubuntu-latest - needs: pack-charm - environment: - name: staging - url: https://staging.ubuntu.com/security/api/docs + needs: pack-rock outputs: - charm_url: ${{ steps.publish.outputs.charm_url }} - charm_revision: ${{ steps.publish.outputs.charm_revision }} - env: - CHARMCRAFT_AUTH: ${{ secrets.CHARMCRAFT_AUTH_TOKEN }} + image_url: ${{ steps.set_image_url.outputs.image_url }} steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Setup Charmcraft - run: sudo snap install charmcraft --classic --channel=latest/beta - - - name: Download Charm Artifact + - name: Get Rock uses: actions/download-artifact@v4 with: - name: ubuntu-security-api-charm - # run-id: 23486477073 - # github-token: ${{ secrets.GITHUB_TOKEN }} + name: ubuntu-security-api-rock - - name: Publish charm to CharmHub - id: publish - working-directory: charm/ - run: | - set -e - cp ../*.charm . - CHARM_FILE=$(ls *.charm) - OUTPUT=$(charmcraft upload "$CHARM_FILE" -v) - CHARM_URL=$(echo "$OUTPUT" | jq -r '.charm_url') - CHARM_REVISION=$(echo "$OUTPUT" | jq -r '.revision') - echo "charm_url=$CHARM_URL" >> $GITHUB_OUTPUT - echo "charm_revision=$CHARM_REVISION" >> $GITHUB_OUTPUT - echo "Published charm: $CHARM_URL (revision: $CHARM_REVISION)" - - - name: Release charm to latest/beta - run: | - charmcraft release ubuntu-security-api --revision=${{ steps.publish.outputs.charm_revision }} --channel=beta - echo "Released ubuntu-security-api, revision ${{ steps.publish.outputs.charm_revision }} to beta channel" + - name: Set image URL + id: set_image_url + run: echo "image_url=ghcr.io/canonical/ubuntu-security-api:$(date +%s)-${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT - # deploy-staging: - # runs-on: - # [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] - # needs: [publish-charm, publish-image] + - name: Push to GHCR + run: skopeo --insecure-policy copy oci-archive:$(ls *.rock) docker://${{ steps.set_image_url.outputs.image_url }} --dest-creds "canonical:${{ secrets.GITHUB_TOKEN }}" + + # publish-charm: + # runs-on: ubuntu-latest + # needs: pack-charm # environment: # name: staging # url: https://staging.ubuntu.com/security/api/docs + # outputs: + # charm_url: ${{ steps.publish.outputs.charm_url }} + # charm_revision: ${{ steps.publish.outputs.charm_revision }} + # env: + # CHARMCRAFT_AUTH: ${{ secrets.CHARMCRAFT_AUTH_TOKEN }} # steps: - # - name: Install Dependencies - # run: | - # sudo snap install juju --classic - # sudo snap install vault --classic - - # - name: Configure Vault and Juju - # env: - # VAULT_ADDR: "https://vault.admin.canonical.com:8200" - # VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} - # VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} - # run: | - # set -e - # export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} - # export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} - # export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} - # export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common - # export CHARM_NAME=${{ vars.CHARM_NAME }} + # - name: Checkout Code + # uses: actions/checkout@v3 - # export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + # - name: Setup Charmcraft + # run: sudo snap install charmcraft --classic --channel=latest/beta - # mkdir -p ~/.local/share/juju - # vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml - # USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") - # PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") - # printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml + # - name: Download Charm Artifact + # uses: actions/download-artifact@v4 + # with: + # name: ubuntu-security-api-charm + # # run-id: 23486477073 + # # github-token: ${{ secrets.GITHUB_TOKEN }} - # - name: Deploy Application to staging + # - name: Publish charm to CharmHub + # id: publish + # working-directory: charm/ # run: | - # export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} - # export CHARM_NAME=${{ vars.CHARM_NAME }} - # export CHARM_REVISION=${{ needs.publish-charm.outputs.charm_revision }} + # set -e + # cp ../*.charm . + # CHARM_FILE=$(ls *.charm) + # OUTPUT=$(charmcraft upload "$CHARM_FILE" -v) + # CHARM_URL=$(echo "$OUTPUT" | jq -r '.charm_url') + # CHARM_REVISION=$(echo "$OUTPUT" | jq -r '.revision') + # echo "charm_url=$CHARM_URL" >> $GITHUB_OUTPUT + # echo "charm_revision=$CHARM_REVISION" >> $GITHUB_OUTPUT + # echo "Published charm: $CHARM_URL (revision: $CHARM_REVISION)" + + # - name: Release charm to latest/beta + # run: | + # charmcraft release ubuntu-security-api --revision=${{ steps.publish.outputs.charm_revision }} --channel=beta + # echo "Released ubuntu-security-api, revision ${{ steps.publish.outputs.charm_revision }} to beta channel" + + deploy-staging: + runs-on: + [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] + needs: [pack-charm, publish-image] + environment: + name: staging + url: https://staging.ubuntu.com/security/api/docs + steps: + - name: Install Dependencies + run: | + sudo snap install juju --classic + sudo snap install vault --classic + + - name: Configure Vault and Juju + env: + VAULT_ADDR: "https://vault.admin.canonical.com:8200" + VAULT_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }} + VAULT_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }} + run: | + set -e + export CONTROLLER_NAME=${{ vars.JUJU_CONTROLLER_NAME }} + export MODEL_NAME=${{ vars.JUJU_MODEL_NAME }} + export VAULT_SECRET_PATH_ROLE=secret/prodstack6/roles/${MODEL_NAME} + export VAULT_SECRET_PATH_COMMON=secret/prodstack6/juju/common + export CHARM_NAME=${{ vars.CHARM_NAME }} + export PRIVATE_CHARM_NAME="${{ vars.CHARM_NAME }}-private" + + export VAULT_TOKEN=$(vault write -f -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + + mkdir -p ~/.local/share/juju + vault read -field=controller_config "${VAULT_SECRET_PATH_COMMON}/controllers/${CONTROLLER_NAME}" | base64 -d > ~/.local/share/juju/controllers.yaml + USERNAME=$(vault read -field=username "${VAULT_SECRET_PATH_ROLE}/juju") + PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") + printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml + + - name: Deploy Application to staging + run: | + export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} + export CHARM_NAME=${{ vars.CHARM_NAME }} + export PRIVATE_CHARM_NAME="${{ vars.CHARM_NAME }}-private" + + if juju status --color --relations | grep -q "^$CHARM_NAME\\s"; then + echo "Application '$CHARM_NAME' exists. Running juju refresh..." + juju refresh $CHARM_NAME --path ./*.charm --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + else + echo "Application '$CHARM_NAME' not found. Running juju deploy..." + juju deploy ./*.charm $CHARM_NAME --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + fi + + if juju status --color --relations | grep -q "^$PRIVATE_CHARM_NAME\\s"; then + echo "Application '$PRIVATE_CHARM_NAME' exists. Running juju refresh..." + juju refresh $PRIVATE_CHARM_NAME --path ./*.charm --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + else + echo "Application '$PRIVATE_CHARM_NAME' not found. Running juju deploy..." + juju deploy ./*.charm $PRIVATE_CHARM_NAME --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + fi - # if juju status --color --relations | grep -q "^$CHARM_NAME\s"; then - # echo "Application '$CHARM_NAME' exists. Running juju refresh..." - # juju refresh $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - # else - # echo "Application '$CHARM_NAME' not found. Running juju deploy..." - # juju deploy $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - # fi # deploy-production: # runs-on: # [self-hosted, self-hosted-linux-amd64-jammy-private-endpoint-medium] - # needs: [publish-charm, publish-image] + # needs: [publish-image] # environment: # name: production # url: https://ubuntu.com/security/api/docs @@ -203,14 +213,13 @@ jobs: # - name: Deploy Application to production # run: | - # export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} - # export CHARM_NAME=${{ vars.CHARM_NAME }} - # export CHARM_REVISION=${{ needs.publish-charm.outputs.charm_revision }} - - # if juju status --color --relations | grep -q "^$CHARM_NAME\s"; then - # echo "Application '$CHARM_NAME' exists. Running juju refresh..." - # juju refresh $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - # else - # echo "Application '$CHARM_NAME' not found. Running juju deploy..." - # juju deploy $CHARM_NAME --revision=$CHARM_REVISION --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} - # fi + # export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} + # export CHARM_NAME=${{ vars.CHARM_NAME }} + + # if juju status --color --relations | grep -q "^$CHARM_NAME\\s"; then + # echo "Application '$CHARM_NAME' exists. Running juju refresh..." + # juju refresh $CHARM_NAME --path ./*.charm --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # else + # echo "Application '$CHARM_NAME' not found. Running juju deploy..." + # juju deploy ./*.charm $CHARM_NAME --resource flask-app-image=${{ needs.publish-image.outputs.image_url }} + # fi \ No newline at end of file diff --git a/charm/charmcraft.yaml b/charm/charmcraft.yaml index afcc7b34..5bdd04f9 100644 --- a/charm/charmcraft.yaml +++ b/charm/charmcraft.yaml @@ -42,4 +42,12 @@ config: description: "Second read-replica connection string" oauth-token-salt: type: secret - description: "Salt used to encode and decode OAuth tokens" \ No newline at end of file + description: "Salt used to encode and decode OAuth tokens" + +# XXX: Workaround for pypa/setuptools-scm#1302 (cyclic build dependency via cosl -> hatchling). +# Remove once charmcraft snap includes the fix from canonical/charmcraft#2602. +parts: + charm: + plugin: charm + charm-binary-python-packages: + - cosl \ No newline at end of file From 325b2ecea8396670c73983072a420574e26452fd Mon Sep 17 00:00:00 2001 From: Britney Wang Date: Fri, 27 Mar 2026 15:21:57 +0800 Subject: [PATCH 4/4] ci: publish private charm image --- .github/workflows/deploy.yaml | 11 +++++++---- charm/charmcraft.yaml | 10 +--------- requirements.txt | 1 + 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 743eb40d..16c17fb1 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -22,7 +22,7 @@ jobs: uses: canonical/setup-lxd@main - name: Setup Charmcraft - run: sudo snap install charmcraft --classic + run: sudo snap install charmcraft --classic --channel=latest/edge - name: Pack charm run: | @@ -90,14 +90,12 @@ jobs: # uses: actions/checkout@v3 # - name: Setup Charmcraft - # run: sudo snap install charmcraft --classic --channel=latest/beta + # run: sudo snap install charmcraft --classic --channel=latest/edge # - name: Download Charm Artifact # uses: actions/download-artifact@v4 # with: # name: ubuntu-security-api-charm - # # run-id: 23486477073 - # # github-token: ${{ secrets.GITHUB_TOKEN }} # - name: Publish charm to CharmHub # id: publish @@ -153,6 +151,11 @@ jobs: PASSWORD=$(vault read -field=password "${VAULT_SECRET_PATH_ROLE}/juju") printf "controllers:\n %s:\n user: %s\n password: %s\n" "$CONTROLLER_NAME" "$USERNAME" "$PASSWORD" > ~/.local/share/juju/accounts.yaml + - name: Download Charm Artifact + uses: actions/download-artifact@v4 + with: + name: ubuntu-security-api-charm + - name: Deploy Application to staging run: | export JUJU_MODEL=admin/${{ vars.JUJU_MODEL_NAME }} diff --git a/charm/charmcraft.yaml b/charm/charmcraft.yaml index 5bdd04f9..afcc7b34 100644 --- a/charm/charmcraft.yaml +++ b/charm/charmcraft.yaml @@ -42,12 +42,4 @@ config: description: "Second read-replica connection string" oauth-token-salt: type: secret - description: "Salt used to encode and decode OAuth tokens" - -# XXX: Workaround for pypa/setuptools-scm#1302 (cyclic build dependency via cosl -> hatchling). -# Remove once charmcraft snap includes the fix from canonical/charmcraft#2602. -parts: - charm: - plugin: charm - charm-binary-python-packages: - - cosl \ No newline at end of file + description: "Salt used to encode and decode OAuth tokens" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index edb4297d..70989cec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +flask canonicalwebteam.flask-base @ git+https://github.com/canonical/canonicalwebteam.flask-base@add-compression-override-option setuptools<81 alchemy-mock==0.4.3