diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitignore b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitignore new file mode 100644 index 00000000..24ff2e41 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitignore @@ -0,0 +1,11 @@ +venv/ +build/ +*.charm +.tox/ +.coverage +__pycache__/ +*.py[cod] +.idea +.vscode/ +*.swp +.stestr/ diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitreview b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitreview new file mode 100644 index 00000000..d4d99db2 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=review.opendev.org +port=29418 +project=openstack/charm-{{ cookiecutter.service_name }}-k8s.git +defaultbranch=main diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.stestr.conf b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.stestr.conf new file mode 100644 index 00000000..e4750de4 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.stestr.conf @@ -0,0 +1,3 @@ +[DEFAULT] +test_path=./tests/unit +top_dir=./tests diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.zuul.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.zuul.yaml new file mode 100644 index 00000000..d5249227 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/.zuul.yaml @@ -0,0 +1,11 @@ +- project: + templates: + - openstack-python3-charm-jobs + - openstack-cover-jobs + - microk8s-func-test + vars: + charm_build_name: {{ cookiecutter.service_name }}-k8s + juju_channel: 3.2/stable + juju_classic_mode: false + microk8s_channel: 1.26-strict/stable + microk8s_classic_mode: false diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/charmcraft.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/charmcraft.yaml index ab6239a8..ac49568b 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/charmcraft.yaml +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/charmcraft.yaml @@ -7,11 +7,22 @@ bases: - name: "ubuntu" channel: "22.04" parts: + update-certificates: + plugin: nil + override-build: | + apt update + apt install -y ca-certificates + update-ca-certificates + charm: + after: [update-certificates] build-packages: - git - libffi-dev - libssl-dev + - rustc + - cargo + - pkg-config charm-binary-python-packages: - cryptography - jsonschema diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/config.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/config.yaml index 606b5357..ac6a1965 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/config.yaml +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/config.yaml @@ -7,19 +7,19 @@ options: default: glance.juju description: | The hostname or address of the admin endpoints that should be advertised - in the glance image provider. + in the glance image provider. type: string os-internal-hostname: default: glance.juju description: | The hostname or address of the internal endpoints that should be advertised - in the glance image provider. + in the glance image provider. type: string os-public-hostname: default: glance.juju description: | The hostname or address of the internal endpoints that should be advertised - in the glance image provider. + in the glance image provider. type: string region: default: RegionOne diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/fetch-libs.sh b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/fetch-libs.sh new file mode 100755 index 00000000..f7433018 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/fetch-libs.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +echo "INFO: Fetching libs from charmhub." +# charmcraft fetch-lib charms.data_platform_libs.v0.database_requires +# charmcraft fetch-lib charms.keystone_k8s.v1.identity_service +# charmcraft fetch-lib charms.rabbitmq_k8s.v0.rabbitmq +# charmcraft fetch-lib charms.traefik_k8s.v1.ingress diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/metadata.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/metadata.yaml index b86a5d9a..11836c1f 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/metadata.yaml +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/metadata.yaml @@ -9,9 +9,14 @@ description: | version: 3 bases: - name: ubuntu - channel: 20.04/stable + channel: 22.04/stable +assumes: + - k8s-api + - juju >= 3.2 tags: - openstack +source: https://opendev.org/openstack/charm-{{ cookiecutter.service_name }}-k8s +issues: https://bugs.launchpad.net/charm-{{ cookiecutter.service_name }}-k8s containers: {{ cookiecutter.service_name }}-api: diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/osci.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/osci.yaml new file mode 100644 index 00000000..ff482b08 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/osci.yaml @@ -0,0 +1,10 @@ +- project: + templates: + - charm-publish-jobs + vars: + needs_charm_build: true + charm_build_name: {{ cookiecutter.service_name }}-k8s + build_type: charmcraft + publish_charm: true + charmcraft_channel: 2.0/stable + publish_channel: 2023.1/edge diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/rename.sh b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/rename.sh new file mode 100755 index 00000000..d0c35c97 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/rename.sh @@ -0,0 +1,13 @@ +#!/bin/bash +charm=$(grep "charm_build_name" osci.yaml | awk '{print $2}') +echo "renaming ${charm}_*.charm to ${charm}.charm" +echo -n "pwd: " +pwd +ls -al +echo "Removing bad downloaded charm maybe?" +if [[ -e "${charm}.charm" ]]; +then + rm "${charm}.charm" +fi +echo "Renaming charm here." +mv ${charm}_*.charm ${charm}.charm diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/requirements.txt b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/requirements.txt index 99f36564..20a477f7 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/requirements.txt +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/requirements.txt @@ -2,7 +2,7 @@ ops jinja2 git+https://github.com/openstack/charm-ops-sunbeam#egg=ops_sunbeam lightkube -# These are only needeed if the charm relates to ceph -git+https://github.com/openstack/charm-ops-interface-ceph-client#egg=interface_ceph_client -# Charmhelpers is only present as interface_ceph_client uses it. -git+https://github.com/juju/charm-helpers.git#egg=charmhelpers + +# Uncomment below if charm relates to ceph +# git+https://github.com/openstack/charm-ops-interface-ceph-client#egg=interface_ceph_client +# git+https://github.com/juju/charm-helpers.git#egg=charmhelpers diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/charm.py b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/charm.py index 369e647d..176dd211 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/charm.py +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/charm.py @@ -29,7 +29,7 @@ class {{ cookiecutter.service_name[0]|upper}}{{cookiecutter.service_name[1:] }}O @property def service_conf(self) -> str: """Service default configuration file.""" - return f"/etc/{{ cookiecutter.service_name }}/{{ cookiecutter.service_name }}.conf" + return "/etc/{{ cookiecutter.service_name }}/{{ cookiecutter.service_name }}.conf" @property def service_user(self) -> str: @@ -43,6 +43,7 @@ class {{ cookiecutter.service_name[0]|upper}}{{cookiecutter.service_name[1:] }}O @property def service_endpoints(self): + """Return service endpoints for the service.""" return [ { 'service_name': '{{ cookiecutter.service_name }}', @@ -54,6 +55,7 @@ class {{ cookiecutter.service_name[0]|upper}}{{cookiecutter.service_name[1:] }}O @property def default_public_ingress_port(self): + """Ingress Port for API service.""" return {{ cookiecutter.ingress_port }} diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/parts/identity-data b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/parts/identity-data index 4b4af021..706d9d13 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/parts/identity-data +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/parts/identity-data @@ -1,10 +1,23 @@ -{% if identity_service.internal_host -%} -www_authenticate_uri = {{ identity_service.internal_protocol }}://{{ identity_service.internal_host }}:{{ identity_service.internal_port }} +{% if identity_service.admin_auth_url -%} +auth_url = {{ identity_service.admin_auth_url }} +interface = admin +{% elif identity_service.internal_auth_url -%} +auth_url = {{ identity_service.internal_auth_url }} +interface = internal +{% elif identity_service.internal_host -%} auth_url = {{ identity_service.internal_protocol }}://{{ identity_service.internal_host }}:{{ identity_service.internal_port }} +interface = internal +{% endif -%} +{% if identity_service.public_auth_url -%} +www_authenticate_uri = {{ identity_service.public_auth_url }} +{% elif identity_service.internal_host -%} +www_authenticate_uri = {{ identity_service.internal_protocol }}://{{ identity_service.internal_host }}:{{ identity_service.internal_port }} +{% endif -%} auth_type = password project_domain_name = {{ identity_service.service_domain_name }} user_domain_name = {{ identity_service.service_domain_name }} project_name = {{ identity_service.service_project_name }} username = {{ identity_service.service_user_name }} password = {{ identity_service.service_password }} -{% endif -%} +service_token_roles = {{ identity_service.admin_role }} +service_token_roles_required = True diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/wsgi-template.conf.j2 b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/wsgi-template.conf.j2 index b34c076e..c9def84b 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/wsgi-template.conf.j2 +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/src/templates/wsgi-template.conf.j2 @@ -1,10 +1,11 @@ Listen {{ wsgi_config.public_port }} + WSGIDaemonProcess {{ wsgi_config.group }} processes=3 threads=1 user={{ wsgi_config.user }} group={{ wsgi_config.group }} \ display-name=%{GROUP} WSGIProcessGroup {{ wsgi_config.group }} - {% if ingress_internal.ingress_path -%} - WSGIScriptAlias {{ ingress_internal.ingress_path }} {{ wsgi_config.wsgi_public_script }} + {% if ingress_public.ingress_path -%} + WSGIScriptAlias {{ ingress_public.ingress_path }} {{ wsgi_config.wsgi_public_script }} {% endif -%} WSGIScriptAlias / {{ wsgi_config.wsgi_public_script }} WSGIApplicationGroup %{GLOBAL} diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/test-requirements.txt b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/test-requirements.txt index 8057d2c6..d1a61d34 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/test-requirements.txt +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/test-requirements.txt @@ -1,17 +1,9 @@ # This file is managed centrally. If you find the need to modify this as a # one-off, please don't. Intead, consult #openstack-charms and ask about # requirements management in charms via bot-control. Thank you. -charm-tools>=2.4.4 -coverage>=3.6 -mock>=1.2 -flake8>=2.2.4,<=2.4.1 -pyflakes==2.1.1 -stestr>=2.2.0 -requests>=2.18.4 -psutil -# oslo.i18n dropped py35 support -oslo.i18n<4.0.0 -git+https://github.com/openstack-charmers/zaza.git#egg=zaza -git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack -pytz # workaround for 14.04 pip/tox -pyudev # for ceph-* charm unit tests (not mocked?) + +coverage +mock +flake8 +stestr +ops diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tests/tests.yaml b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tests/tests.yaml new file mode 100644 index 00000000..34e47f18 --- /dev/null +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tests/tests.yaml @@ -0,0 +1,18 @@ +gate_bundles: + - smoke +smoke_bundles: + - smoke +configure: + - zaza.openstack.charm_tests.keystone.setup.add_tempest_roles +tests: [] +tests_options: + trust: + - smoke + ignore_hard_deploy_errors: + - smoke + + tempest: + default: + smoke: True + +target_deploy_status: [] diff --git a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tox.ini b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tox.ini index 31301b80..0bc536c1 100644 --- a/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tox.ini +++ b/ops-sunbeam/shared_code/sunbeam_charm/{{cookiecutter.service_name}}/tox.ini @@ -1,77 +1,80 @@ # Operator charm (with zaza): tox.ini [tox] -envlist = pep8,py3 skipsdist = True -# NOTE: Avoid build/test env pollution by not enabling sitepackages. +envlist = pep8,py3 sitepackages = False -# NOTE: Avoid false positives by not skipping missing interpreters. skip_missing_interpreters = False -# NOTES: -# * We avoid the new dependency resolver by pinning pip < 20.3, see -# https://github.com/pypa/pip/issues/9187 -# * Pinning dependencies requires tox >= 3.2.0, see -# https://tox.readthedocs.io/en/latest/config.html#conf-requires -# * It is also necessary to pin virtualenv as a newer virtualenv would still -# lead to fetching the latest pip in the func* tox targets, see -# https://stackoverflow.com/a/38133283 -requires = pip < 20.3 - virtualenv < 20.0 -# NOTE: https://wiki.canonical.com/engineering/OpenStack/InstallLatestToxOnOsci -minversion = 3.2.0 +minversion = 3.18.0 + +[vars] +src_path = {toxinidir}/src/ +tst_path = {toxinidir}/tests/ +lib_path = {toxinidir}/lib/ +pyproject_toml = {toxinidir}/pyproject.toml +all_path = {[vars]src_path} {[vars]tst_path} [testenv] -setenv = VIRTUAL_ENV={envdir} - PYTHONHASHSEED=0 - CHARM_DIR={envdir} +basepython = python3 +setenv = + PYTHONPATH = {toxinidir}:{[vars]lib_path}:{[vars]src_path} +passenv = + HOME + PYTHONPATH install_command = pip install {opts} {packages} commands = stestr run --slowest {posargs} -whitelist_externals = - git - add-to-archive.py - bash - charmcraft -passenv = HOME TERM CS_* OS_* TEST_* -deps = -r{toxinidir}/test-requirements.txt +allowlist_externals = + git + charmcraft + {toxinidir}/fetch-libs.sh + {toxinidir}/rename.sh +deps = + -r{toxinidir}/test-requirements.txt -[testenv:py35] -basepython = python3.5 -# python3.5 is irrelevant on a focal+ charm. -commands = /bin/true +[testenv:fmt] +description = Apply coding style standards to code +deps = + black + isort +commands = + isort {[vars]all_path} --skip-glob {[vars]lib_path} --skip {toxinidir}/.tox + black --config {[vars]pyproject_toml} {[vars]all_path} --exclude {[vars]lib_path} -[testenv:py36] -basepython = python3.6 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt +[testenv:build] +basepython = python3 +deps = +commands = + charmcraft -v pack + {toxinidir}/rename.sh -[testenv:py37] -basepython = python3.7 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt - -[testenv:py38] -basepython = python3.8 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt +[testenv:fetch] +basepython = python3 +deps = +commands = + {toxinidir}/fetch-libs.sh [testenv:py3] basepython = python3 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt +deps = + {[testenv]deps} + -r{toxinidir}/requirements.txt -[testenv:pep8] -basepython = python3 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = flake8 {posargs} src unit_tests tests +[testenv:py38] +basepython = python3.8 +deps = {[testenv:py3]deps} + +[testenv:py39] +basepython = python3.9 +deps = {[testenv:py3]deps} + +[testenv:py310] +basepython = python3.10 +deps = {[testenv:py3]deps} [testenv:cover] -# Technique based heavily upon -# https://github.com/openstack/nova/blob/master/tox.ini basepython = python3 -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt +deps = {[testenv:py3]deps} setenv = {[testenv]setenv} PYTHON=coverage run @@ -83,6 +86,66 @@ commands = coverage xml -o cover/coverage.xml coverage report +[testenv:pep8] +description = Alias for lint +deps = {[testenv:lint]deps} +commands = {[testenv:lint]commands} + +[testenv:lint] +description = Check code against coding style standards +deps = + black + flake8<6 # Pin version until https://github.com/savoirfairelinux/flake8-copyright/issues/19 is merged + flake8-docstrings + flake8-copyright + flake8-builtins + pyproject-flake8 + pep8-naming + isort + codespell +commands = + codespell {[vars]all_path} + # pflake8 wrapper supports config from pyproject.toml + pflake8 --exclude {[vars]lib_path} --config {toxinidir}/pyproject.toml {[vars]all_path} + isort --check-only --diff {[vars]all_path} --skip-glob {[vars]lib_path} + black --config {[vars]pyproject_toml} --check --diff {[vars]all_path} --exclude {[vars]lib_path} + +[testenv:func-noop] +basepython = python3 +deps = + git+https://github.com/openstack-charmers/zaza.git@libjuju-3.1#egg=zaza + git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack + git+https://opendev.org/openstack/tempest.git#egg=tempest +commands = + functest-run-suite --help + +[testenv:func] +basepython = python3 +deps = {[testenv:func-noop]deps} +commands = + functest-run-suite --keep-model + +[testenv:func-smoke] +basepython = python3 +deps = {[testenv:func-noop]deps} +setenv = + TEST_MODEL_SETTINGS = automatically-retry-hooks=true + TEST_MAX_RESOLVE_COUNT = 5 +commands = + functest-run-suite --keep-model --smoke + +[testenv:func-dev] +basepython = python3 +deps = {[testenv:func-noop]deps} +commands = + functest-run-suite --keep-model --dev + +[testenv:func-target] +basepython = python3 +deps = {[testenv:func-noop]deps} +commands = + functest-run-suite --keep-model --bundle {posargs} + [coverage:run] branch = True concurrency = multiprocessing @@ -91,44 +154,8 @@ source = . omit = .tox/* - */charmhelpers/* - unit_tests/* - -[testenv:venv] -basepython = python3 -commands = {posargs} - -[testenv:build] -basepython = python3 -deps = -r{toxinidir}/build-requirements.txt -commands = - charmcraft build - -[testenv:func-noop] -basepython = python3 -commands = - functest-run-suite --help - -[testenv:func] -basepython = python3 -commands = - functest-run-suite --keep-model - -[testenv:func-smoke] -basepython = python3 -commands = - functest-run-suite --keep-model --smoke - -[testenv:func-dev] -basepython = python3 -commands = - functest-run-suite --keep-model --dev - -[testenv:func-target] -basepython = python3 -commands = - functest-run-suite --keep-model --bundle {posargs} + tests/* + src/templates/* [flake8] -# Ignore E902 because the unit_tests directory is missing in the built charm. -ignore = E402,E226,E902 +ignore=E226,W504