diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fcadb2c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..fada03f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,54 @@ +name: Bug Report +description: Something is not working + +body: + - type: markdown + attributes: + value: | + Thank you for submitting an issue. Please fill in the template below + information about the bug you encountered. + + - type: textarea + id: summary + attributes: + label: Summary + description: Please explain the bug in a few short sentences. + placeholder: Detail the bug here... + validations: + required: true + + - type: textarea + id: what-should-happen + attributes: + label: What Should Happen Instead? + description: Please explain what the expected behavior is. + placeholder: Explain the expected outcome... + validations: + required: true + + - type: textarea + id: reproduction-steps + attributes: + label: Reproduction Steps + description: Are you able to consistently reproduce the issue? Please add a list of steps that lead to the bug. + placeholder: "1.\n2.\n" + validations: + required: true + + - type: textarea + id: suggest-fix + attributes: + label: Can you suggest a fix? + description: How do you propose that the issue be fixed? + placeholder: Suggest a fix if you have one... + + - type: textarea + id: contribute-fix + attributes: + label: Are you interested in contributing with a fix? + description: yes/no, or @mention maintainers. Community contributions are welcome. + placeholder: Are you willing to contribute a fix? + + - type: markdown + attributes: + value: Thank you for making the rocks better diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..b727d0e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,21 @@ +--- +name: Feature Request +about: Suggest a new feature +--- + + + +#### Summary + + +#### Why is this important? + + +#### Are you interested in contributing to this feature? + + + + \ No newline at end of file diff --git a/.github/workflows/cla-check.yaml b/.github/workflows/cla-check.yaml new file mode 100644 index 0000000..75e5796 --- /dev/null +++ b/.github/workflows/cla-check.yaml @@ -0,0 +1,9 @@ +name: cla-check +on: [pull_request_target] + +jobs: + cla-check: + runs-on: ubuntu-latest + steps: + - name: Check if CLA signed + uses: canonical/has-signed-canonical-cla@v1 diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml new file mode 100644 index 0000000..b33dd52 --- /dev/null +++ b/.github/workflows/pull_request.yaml @@ -0,0 +1,41 @@ +name: Push Multiarch Images +on: + pull_request: + push: + branches: + - main + +jobs: + build-and-push-arch-specifics: + name: Build Rocks and Push Arch Specific Images + uses: canonical/k8s-workflows/.github/workflows/build_rocks.yaml@main + with: + owner: ${{ github.repository_owner }} + trivy-image-config: "trivy.yaml" + multiarch-awareness: true + cache-action: ${{ (github.event_name == 'push') && 'save' || 'restore' }} + # pinning to use rockcraft 1.3.0 feature `entrypoint-service` + rockcraft-revisions: '{"amd64": "1783", "arm64": "1784"}' + arch-skipping-maximize-build-space: '["arm64"]' + platform-labels: '{"arm64": ["self-hosted", "Linux", "ARM64", "jammy"]}' + run-tests: + uses: canonical/k8s-workflows/.github/workflows/run_tests.yaml@main + needs: [build-and-push-arch-specifics] + secrets: inherit + with: + rock-metas: ${{ needs.build-and-push-arch-specifics.outputs.rock-metas }} + scan-images: + uses: canonical/k8s-workflows/.github/workflows/scan_images.yaml@main + needs: [build-and-push-arch-specifics] + secrets: inherit + with: + upload-result: ${{ github.event_name == 'push' }} + images: ${{ needs.build-and-push-arch-specifics.outputs.images }} + trivy-image-config: ./trivy.yaml + build-and-push-multiarch-manifest: + name: Combine Rocks and Push Multiarch Manifest + uses: canonical/k8s-workflows/.github/workflows/assemble_multiarch_image.yaml@main + needs: [build-and-push-arch-specifics] + with: + rock-metas: ${{ needs.build-and-push-arch-specifics.outputs.rock-metas }} + dry-run: ${{ github.event_name != 'push' }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f9d73b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.rock +**/__pycache__ +.pytest_cache +.venv +.tox diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index bc3c58a..4a548b8 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# pinniped-rocks \ No newline at end of file +# pinniped-rocks diff --git a/tests/.copyright.tmpl b/tests/.copyright.tmpl new file mode 100644 index 0000000..1eb2340 --- /dev/null +++ b/tests/.copyright.tmpl @@ -0,0 +1,2 @@ +Copyright ${years} ${owner}. +See LICENSE file for licensing details diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..9367a5b --- /dev/null +++ b/tests/integration/__init__.py @@ -0,0 +1,4 @@ +# +# Copyright 2024 Canonical, Ltd. +# See LICENSE file for licensing details +# diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 0000000..1ca658c --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,5 @@ +# +# Copyright 2024 Canonical, Ltd. +# See LICENSE file for licensing details +# +pytest_plugins = ["k8s_test_harness.plugin"] diff --git a/tests/integration/test_pinniped.py b/tests/integration/test_pinniped.py new file mode 100644 index 0000000..de50596 --- /dev/null +++ b/tests/integration/test_pinniped.py @@ -0,0 +1,43 @@ +# +# Copyright 2024 Canonical, Ltd. +# See LICENSE file for licensing details +# + +import pytest +from k8s_test_harness import harness +from k8s_test_harness.util import constants, env_util, k8s_util + +IMG_PLATFORM = "amd64" +INSTALL_NAME = "pinniped" + + +@pytest.mark.parametrize("version", ["v0.30.0"]) +def test_pinniped(function_instance: harness.Instance, version: str): + rock = env_util.get_build_meta_info_for_rock_version( + "pinniped-server", version, IMG_PLATFORM + ) + + # This helm chart requires the registry to be separated from the image. + rock_image = rock.image + registry = "docker.io" + parts = rock_image.split("/") + if len(parts) > 1: + registry = parts[0] + rock_image = "/".join(parts[1:]) + + helm_command = k8s_util.get_helm_install_command( + name=INSTALL_NAME, + chart_name="oci://registry-1.docker.io/bitnamicharts/pinniped", + images=[k8s_util.HelmImage(uri=rock_image)], + namespace=constants.K8S_NS_KUBE_SYSTEM, + set_configs=[f"image.registry={registry}"], + ) + function_instance.exec(helm_command) + + k8s_util.wait_for_deployment( + function_instance, "pinniped-concierge", constants.K8S_NS_KUBE_SYSTEM + ) + + k8s_util.wait_for_deployment( + function_instance, "pinniped-supervisor", constants.K8S_NS_KUBE_SYSTEM + ) diff --git a/tests/requirements-dev.txt b/tests/requirements-dev.txt new file mode 100644 index 0000000..a66721a --- /dev/null +++ b/tests/requirements-dev.txt @@ -0,0 +1,5 @@ +black==24.3.0 +codespell==2.2.4 +flake8==6.0.0 +isort==5.12.0 +licenseheaders==0.8.8 diff --git a/tests/requirements-test.txt b/tests/requirements-test.txt new file mode 100644 index 0000000..61f4f37 --- /dev/null +++ b/tests/requirements-test.txt @@ -0,0 +1,6 @@ +coverage[toml]==7.2.5 +pytest==7.3.1 +PyYAML==6.0.1 +tenacity==8.2.3 +charmed-kubeflow-chisme>=0.4 +git+https://github.com/canonical/k8s-test-harness.git@main diff --git a/tests/sanity/__init__.py b/tests/sanity/__init__.py new file mode 100644 index 0000000..9367a5b --- /dev/null +++ b/tests/sanity/__init__.py @@ -0,0 +1,4 @@ +# +# Copyright 2024 Canonical, Ltd. +# See LICENSE file for licensing details +# diff --git a/tests/sanity/test_pinniped.py b/tests/sanity/test_pinniped.py new file mode 100644 index 0000000..2dd195f --- /dev/null +++ b/tests/sanity/test_pinniped.py @@ -0,0 +1,36 @@ +# +# Copyright 2024 Canonical, Ltd. +# See LICENSE file for licensing details +# + +import pytest +from k8s_test_harness.util import docker_util, env_util + +# In the future, we may also test ARM +IMG_PLATFORM = "amd64" +IMG_NAME = "pinniped-server" + +EXPECTED_FILES = [ + "/usr/local/bin/pinniped-server", + "/usr/local/bin/pinniped-concierge-kube-cert-agent", + "/usr/local/bin/pinniped-concierge", + "/usr/local/bin/pinniped-supervisor", + "/usr/local/bin/local-user-authenticator", +] + +EXPECTED_HELPSTR = "pinniped-concierge provides a generic API for mapping " + + +@pytest.mark.parametrize("version", ["v0.30.0"]) +def test_pinniped(version: str): + rock = env_util.get_build_meta_info_for_rock_version( + IMG_NAME, version, IMG_PLATFORM + ) + + docker_run = docker_util.run_in_docker( + rock.image, ["/usr/local/bin/pinniped-concierge", "--help"] + ) + assert EXPECTED_HELPSTR in docker_run.stdout + + # check rock filesystem + docker_util.ensure_image_contains_paths(rock.image, EXPECTED_FILES) diff --git a/tests/tox.ini b/tests/tox.ini new file mode 100644 index 0000000..09d625d --- /dev/null +++ b/tests/tox.ini @@ -0,0 +1,82 @@ +[tox] +no_package = True +skip_missing_interpreters = True +env_list = format, lint, integration, sanity +min_version = 4.0.0 + +[testenv] +set_env = + PYTHONBREAKPOINT=pdb.set_trace + PY_COLORS=1 +pass_env = + PYTHONPATH + +[testenv:format] +description = Apply coding style standards to code +deps = -r {tox_root}/requirements-dev.txt +commands = + licenseheaders -t {tox_root}/.copyright.tmpl -cy -o 'Canonical, Ltd' -d {tox_root}/sanity + isort {tox_root}/sanity --profile=black + black {tox_root}/sanity + + licenseheaders -t {tox_root}/.copyright.tmpl -cy -o 'Canonical, Ltd' -d {tox_root}/integration + isort {tox_root}/integration --profile=black + black {tox_root}/integration + +[testenv:lint] +description = Check code against coding style standards +deps = -r {tox_root}/requirements-dev.txt +commands = + codespell {tox_root}/sanity + flake8 {tox_root}/sanity + licenseheaders -t {tox_root}/.copyright.tmpl -cy -o 'Canonical, Ltd' -d {tox_root}/sanity --dry + isort {tox_root}/sanity --profile=black --check + black {tox_root}/sanity --check --diff + + codespell {tox_root}/integration + flake8 {tox_root}/integration + licenseheaders -t {tox_root}/.copyright.tmpl -cy -o 'Canonical, Ltd' -d {tox_root}/integration --dry + isort {tox_root}/integration --profile=black --check + black {tox_root}/integration --check --diff + +[testenv:sanity] +description = Run integration tests +deps = + -r {tox_root}/requirements-test.txt +commands = + pytest -v \ + --maxfail 1 \ + --tb native \ + --log-cli-level DEBUG \ + --disable-warnings \ + {posargs} \ + {tox_root}/sanity +pass_env = + TEST_* + ROCK_* + BUILT_ROCKS_METADATA + +[testenv:integration] +description = Run integration tests +deps = + -r {tox_root}/requirements-test.txt +commands = + pytest -v \ + --maxfail 1 \ + --tb native \ + --log-cli-level DEBUG \ + --disable-warnings \ + {posargs} \ + {tox_root}/integration +pass_env = + TEST_* + ROCK_* + BUILT_ROCKS_METADATA + +[flake8] +max-line-length = 120 +select = E,W,F,C,N +# E231 rule is not aware of f-strings +ignore = W503,E231 +exclude = venv,.git,.tox,.tox_env,.venv,build,dist,*.egg_info +show-source = true diff --git a/trivy.yaml b/trivy.yaml new file mode 100644 index 0000000..c895d69 --- /dev/null +++ b/trivy.yaml @@ -0,0 +1,3 @@ +timeout: 20m +scan: + offline-scan: true diff --git a/v0.30.0/rockcraft.yaml b/v0.30.0/rockcraft.yaml new file mode 100644 index 0000000..e68d517 --- /dev/null +++ b/v0.30.0/rockcraft.yaml @@ -0,0 +1,47 @@ +name: pinniped-server +summary: pinniped ROCK image. +description: > + This rock is a drop in replacement for the + ghcr.io/vmware-tanzu/pinniped/pinniped-server:v0.30.0 image. +version: v0.30.0 +license: Apache-2.0 + +base: ubuntu@24.04 +build-base: ubuntu@24.04 +platforms: + amd64: + +entrypoint-service: pinniped +services: + pinniped: + command: /usr/local/bin/pinniped-server [ -h ] + override: replace + startup: enabled + +parts: + build-deps: + plugin: nil + build-snaps: + - go/1.22/stable + + pinniped: + after: [build-deps] + plugin: go + source-type: git + source: https://github.com/vmware-tanzu/pinniped + source-tag: v0.30.0 + source-depth: 1 + override-build: | + export CGO_ENABLED=0 + + mkdir -p $CRAFT_PART_INSTALL/usr/local/bin + + go build -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -s" \ + -o $CRAFT_PART_INSTALL/usr/local/bin/pinniped-concierge-kube-cert-agent \ + ./cmd/pinniped-concierge-kube-cert-agent/... + go build -v -trimpath -ldflags "$(hack/get-ldflags.sh) -w -s" \ + -o $CRAFT_PART_INSTALL/usr/local/bin/pinniped-server ./cmd/pinniped-server/... + + ln -sf /usr/local/bin/pinniped-server $CRAFT_PART_INSTALL/usr/local/bin/pinniped-concierge + ln -sf /usr/local/bin/pinniped-server $CRAFT_PART_INSTALL/usr/local/bin/pinniped-supervisor + ln -sf /usr/local/bin/pinniped-server $CRAFT_PART_INSTALL/usr/local/bin/local-user-authenticator