Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Template updates #8

Merged
merged 13 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions .github/workflows/deploy.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,40 @@ jobs:
- name: Install package
run: poetry install
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging that I got a PermissionError here on my test innovate_tagging project. I side-stepped it by commenting out poetry config virtualenvs.create false on the "Install and configure poetry" task


- name: Install jq for fingerprinter
run: sudo apt-get -y install jq

- name: Update env with promotion version that was provided
if: github.event.inputs.version
run: echo "target_version=${{ github.event.inputs.version }}" >> $GITHUB_ENV

- name: Update env with promotion version if not provided
if: '! env.target_version'
shell: bash
run: |
source ./scripts/globals.sh
target_version=$(get_promotion_version ${{ github.event.inputs.cluster }})
echo "target_version=${target_version}" >> $GITHUB_ENV
# $1 will be package name, $2 will be current version
set $(poetry version)

case "${{ github.event.inputs.cluster }}" in
dev)
version="$2"
echo "Would set version to '$version' (from poetry version)"
;;
eval)
# substitute '_' for '-' in APP_NAME
url="https://${1//_/-}.iamdev.s.uw.edu/status"
version=$(curl --silent $url | python -c "import json, sys; print(json.load(sys.stdin)['version'])")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you hate this and want jq back I can do that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm totally good with this

echo "After consulting dev the eval version will be ${version}"
;;
prod)
# substitute '_' for '-' in APP_NAME
url="https://${1//_/-}.iameval.s.uw.edu/status"
version=$(curl --silent $url | python -c "import json, sys; print(json.load(sys.stdin)['version'])")
echo "After consulting eval the prod version will be ${version}"
;;
*)
echo "Invalid cluster! Pick one of dev|eval|prod"
exit 1
;;
esac
echo "target_version=${version}" >> $GITHUB_ENV

- name: Auth to Google Cloud
# important! this 'auth' is referenced as `steps.auth` on the next job
Expand All @@ -80,10 +101,14 @@ jobs:
run: |-
echo '${{ steps.auth.outputs.access_token }}' | docker login -u oauth2accesstoken --password-stdin https://us-docker.pkg.dev

- name: Deploy version ${{ env.target_version }}
- name: Tag version ${{ env.target_version }} for ${{ github.event.inputs.cluster }}
id: deploy
run: |
echo "::notice::Deploying appid version ${{ env.target_version }} to ${{ github.event.inputs.cluster }}"
./scripts/build.sh \
--deploy ${{ inputs.cluster }} \
-dversion ${{ env.target_version }}
# timestamp and deploy_tag are not DRY - see also release-on-push-to-main.yaml
timestamp=$(date --utc +%Y.%m.%d.%H.%M.%S)
deploy_tag="deploy-${{ github.event.inputs.cluster }}.${timestamp}.v${{ env.target_version }}"
echo "::notice::Deploying appid version ${{ env.target_version }} to ${{ github.event.inputs.cluster }} as ${deploy_tag}"
# this will create a new tag (deploy_tag) on an existing tag (env.target_version)
docker buildx imagetools create \
--tag us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}:${deploy_tag} \
us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}:${{ env.target_version }}
2 changes: 1 addition & 1 deletion .github/workflows/finalize-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Finalize Template
on:
workflow_dispatch:
inputs:
app-name:
app_name:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bugfix - caused the provided app name to always be ignored due to failed lookup

required: false
description: >
This is the name of your app; if left blank, it will match the
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pull-request.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
file: ./Dockerfile
push: true
target: dependencies
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}.dependencies:${{ env.pr_tag }}
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}.dependencies:${{ env.pr_tag }}
secret-files: |
"gcloud_auth_credentials=${{ steps.auth.outputs.credentials_file_path }}"

Expand All @@ -82,7 +82,7 @@ jobs:
file: ./Dockerfile
push: true
target: app
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}.app:${{ env.pr_tag }}
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}.app:${{ env.pr_tag }}

- name: Build and push Docker image (tests)
uses: docker/build-push-action@v5
Expand All @@ -91,11 +91,11 @@ jobs:
file: ./Dockerfile
push: true
target: tests
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}.tests:${{ env.pr_tag }}
tags: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}.tests:${{ env.pr_tag }}

- uses: mshick/add-pr-comment@v2
env:
image: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}.app:${{ env.pr_tag }}
image: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}.app:${{ env.pr_tag }}
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
allow-repeats: false
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/release-on-push-to-main.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ jobs:
push: true
target: app
tags: |
us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}:${{ steps.get-version.outputs.version }}
us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}:${{ env.DEPLOYMENT_ID }}
us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}:${{ steps.get-version.outputs.version }}
us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}:${{ env.DEPLOYMENT_ID }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on your comment in the body of the PR, didn't you intend to remove DEPLOYMENT_ID from this?

It will also need to be removed from the Dockerfile template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I successfully removed all the DEPLOYMENT_ID stuff

secret-files: |
"gcloud_auth_credentials=${{ steps.auth.outputs.credentials_file_path }}"

5 changes: 3 additions & 2 deletions Dockerfile → Dockerfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ RUN --mount=type=secret,id=gcloud_auth_credentials \
poetry install --only main --no-root --no-interaction

FROM dependencies AS app

# If you change your app directory to e.g., use src/ you MUST
# change the APP_MODULE here to match OR supply a --build-arg
ARG APP_MODULE=${template:app_name_underscore}
ARG DEPLOYMENT_ID
ARG APP_MODULE=example_app
ARG FLASK_PORT=5000
ENV FLASK_ENV=development \
PYTHONPATH=${APP_MODULE} \
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ click the button above that says "Use this template"

You will be asked to name your new repository. To take full advantage
of the automation and kubernetes capabilities, you should create your new
repository under the "UWIT-IAM" namespace; this gives you access to
repository under the "UWIT-IAM" namespace; this gives you access to
secrets that are consumable in your Github actions.

Once you have done that, follow the instructions for
Expand All @@ -22,12 +22,12 @@ Once you have done that, follow the instructions for
If you are reading this, and you are not in the `flask-example` template repository,
then you haven't yet finalized your template!

To finalize the template, visit your repository on GitHub,
To finalize the template, visit your repository on GitHub,
then click on "Actions."

Click the "Finalize Template" workflow, and click "Run this workflow."

A pull request will be generated for you to review and merge! This message will
A pull request will be generated for you to review and merge! This message will
self-destruct after running that workflow.

## Updating the template
Expand All @@ -37,15 +37,15 @@ This very basic templating engine does not allow for conditional logic.
To use an argument name inside a document, make sure the document is named `<name>.
template.<ext>`, the final file name will be `<name>.<ext>`.

You can use any supported argument with the format: `${template:<arg_name>}`; all
values are treated as strings.
You can use any supported argument with the format: `${template:<arg_name>}`; all
values are treated as strings.

Functionally:

```
# foo.template.yaml

- policy-name: ${template:app_name}-policy
- policy-name: ${template:app_name_hyphen}-policy
```

becomes:
Expand All @@ -60,8 +60,8 @@ becomes:
### About templating templates...

Please note that `.template.` files are interpolated before any other templating
engine does anything; you may freely nest the `${template:<arg_name>}` syntax inside
other strings that other templating engines might use.
engine does anything; you may freely nest the `${template:<arg_name>}` syntax inside
other strings that other templating engines might use.

## Supported Values

Expand Down
6 changes: 3 additions & 3 deletions example_app/app.template.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@app.route("/", methods=("GET",))
def index():
print("Hello there")
return 'OK', 200
return "OK", 200


APP_VERSION = None
Expand All @@ -19,7 +19,7 @@ def index():
def status():
global APP_VERSION
if APP_VERSION is None:
APP_VERSION = importlib_metadata.version("${template:app_name}")
APP_VERSION = importlib_metadata.version("${template:app_name_underscore}")

deployment_id = os.environ.get("DEPLOYMENT_ID")
status = 200 if deployment_id else 503
Expand All @@ -28,4 +28,4 @@ def status():


if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
app.run(host="0.0.0.0", port=5000)
23 changes: 0 additions & 23 deletions fingerprints.template.yaml

This file was deleted.

6 changes: 3 additions & 3 deletions kubernetes-config/README.template.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Template Kubernetes Configuration

The basic kubernetes configuration provided here will subscribe you
to the [basic-web-service helm chart].
The basic kubernetes configuration provided here will subscribe you
to the [basic-web-service helm chart].

After finalizing your template, you should copy the files in this directory
into the [gcp-k8] repository, in the `dev/${template:app_name}` directory.

Unless you change the values generated for you, your app will
expect to run at `https://${template:app_name}.iamdev.s.uw.edu`.
expect to run at `https://${template:app_name_hyphen}.iamdev.s.uw.edu`.


[gcp-k8]: https://github.com/uwit-iam/gcp-k8
Expand Down
6 changes: 3 additions & 3 deletions kubernetes-config/automation.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
name: ${template:app_name}-policy
name: ${template:app_name_hyphen}-policy
namespace: default # must be 'default' in MCI, even if app itself is not in default
spec:
imageRepositoryRef:
name: ${template:app_name}-gar
name: ${template:app_name_hyphen}-gar
filterTags:
pattern: '^deploy-dev.(?P<ts>[0-9\.]+)\.v.+$'
extract: '$ts'
Expand All @@ -19,7 +19,7 @@ spec:
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
name: ${template:app_name}-gar
name: ${template:app_name_hyphen}-gar
namespace: default # must be 'default' in MCI, even if app itself is not in default
spec:
image: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}
Expand Down
8 changes: 4 additions & 4 deletions kubernetes-config/helm-release.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: ${template:app_name}
name: ${template:app_name_hyphen}
namespace: default
spec:
values:
app:
name: ${template:app_name}
name: ${template:app_name_hyphen}
clusterDomain: iamdev.s.uw.edu
replicaCount: 1
ports:
Expand Down Expand Up @@ -45,8 +45,8 @@ spec:
memory: "64M"
cpu: "100m"
image:
name: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name}
tag: latest # {"$imagepolicy": "default:${template:app_name}-policy:tag"}
name: us-docker.pkg.dev/uwit-mci-iam/containers/${template:app_name_hyphen}
tag: latest # {"$imagepolicy": "default:${template:app_name_hyphen}-policy:tag"}

chart:
spec:
Expand Down
5 changes: 4 additions & 1 deletion pyproject.template.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.poetry]
name = "${template:app_name}"
name = "${template:app_name_underscore}"
version = "0.1.0"
description = ""
authors = []
Expand All @@ -23,3 +23,6 @@ priority = "explicit"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.black]
line-length = 119
43 changes: 20 additions & 23 deletions scripts/finalize-template.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,40 @@ def get_parser():
"Fills out argument templates, then destroys, saves the new files,"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This source file got "blackened" and thus the changes are pretty noisy. The key here is in (new) lines 41-47 which define an app_name_hyphen and app_name_underscore so things can be more explicitly provided in a way that works regardless of what you named the repository

"and destroys all template files, including this script."
)
parser.add_argument('--app-name', required=True)
parser.add_argument('--maintainer', required=True)
parser.add_argument('--keepalive', required=False, default=False, action='store_true', dest='meta_keepalive')
parser.add_argument("--app-name", required=True)
parser.add_argument("--maintainer", required=True)
parser.add_argument("--keepalive", required=False, default=False, action="store_true", dest="meta_keepalive")
return parser


def get_template_files():
return [
str(path.joinpath()) for path in list(Path('.').rglob('*.template.*'))
]
return [str(path.joinpath()) for path in list(Path(".").rglob("*.template.*"))]


def finalize_template_file(path: str, args: Dict[str, Any]):
with open(path) as f:
template = f.read()

for key, val in args.items():
template = template.replace(
f'${{template:{key}}}', str(val)
)
template = template.replace(f"${{template:{key}}}", str(val))

new_file_name = path.replace('.template', '')
with open(new_file_name, 'w') as f:
new_file_name = path.replace(".template", "")
with open(new_file_name, "w") as f:
f.write(template)

logging.info(
f"Generated {new_file_name} from {path}"
)
logging.info(f"Generated {new_file_name} from {path}")
return new_file_name


def main():
args = get_parser().parse_args()
values = {
k: v for k, v in vars(args).items()
if not k.startswith('meta_')
}
values = {k: v for k, v in vars(args).items() if not k.startswith("meta_")}
# add explicit values for only-hypen and only-underscore variants of the app name
# this is important because
# 1) Python package names cannot contain hyphens when importing ('django-utils' illegal; must be 'django_utils')
# 2) subdomains cannot contain underscores and we seed our application subdomains with the application name
values["app_name_hyphen"] = values["app_name"].replace("_", "-")
values["app_name_underscore"] = values["app_name"].replace("-", "_")
logging.basicConfig(level=logging.INFO)
logging.getLogger(__name__).setLevel(logging.INFO)

Expand All @@ -58,16 +55,16 @@ def main():
for t in templates:
finalize_template_file(t, values)
if not args.meta_keepalive:
logging.info(f'Deleting template {t}')
logging.info(f"Deleting template {t}")
os.remove(t)

os.system('poetry update')
os.system("poetry update")

logging.info('Deleting myself, too. My purpose is fulfilled. Byeeeeeeeeee!')
logging.info("Deleting myself, too. My purpose is fulfilled. Byeeeeeeeeee!")
os.remove(__file__)

safe_app_name = args.app_name.replace("-", "_")
shutil.move("example_app", safe_app_name)
# this rename tied to Dockerfile.template
shutil.move("example_app", values["app_name_underscore"])


if __name__ == "__main__":
Expand Down
Loading