diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index 21a126b..88e3ffd 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -4,6 +4,11 @@ on: pull_request: types: [opened, synchronize, reopened] branches: [ main ] + repository_dispatch: + types: [primazactl-test] + +env: + GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} jobs: build: @@ -13,7 +18,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: "^1.19" + go-version: "^1.20" - name: Set up Python uses: actions/setup-python@v4 @@ -27,6 +32,20 @@ jobs: - name: Lint python run: make lint + - name: Set Version and Images + id: sets-version + run: | + # set version based on job type + if [[ "${{github.event_name}}" == "repository_dispatch" ]]; then + primaza_version=${{ github.event.client_payload.version }} + echo "GIT_ORG=${{ github.event.client_payload.organization }}" >> $GITHUB_ENV + echo "RUN_FROM=release" >> $GITHUB_ENV + echo "VERSION=$primaza_version" >> $GITHUB_ENV + else + echo "RUN_FROM=config" >> $GITHUB_ENV + echo "VERSION=latest" >> $GITHUB_ENV + fi + - name: run dry-run run: make test-dry-run @@ -34,12 +53,33 @@ jobs: run: make test-local-no-setup - name: run test with users + env: + CLEAN: clusters run: make test-users - name: run test with output + env: + CLEAN: clusters run: make test-output - name: run apply command + env: + CLEAN: clusters run: make test-apply + - name: run test version + if: ${{ env.VERSION == 'nightly' }} + env: + RUN_FROM: release + CLEAN: clusters + run: make test-version + - name: trigger release + if: ${{ github.event_name == 'repository_dispatch' }} + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.BOT_TOKEN }} + repository: ${{ github.repository_owner }}/primazactl + event-type: primazactl-release + client-payload: '{"version": "${{ env.VERSION }}", + "organization": "${{ env.GIT_ORG }}"}' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0a6d91c..1d82bb2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,6 +10,12 @@ on: description: "create a version for primazctl" required: true default: "latest" + organization: + description: "git organization from which to get the primaza release" + required: true + default: "primaza" + repository_dispatch: + types: [primazactl-release] permissions: contents: write @@ -26,24 +32,31 @@ jobs: python-version: "3.10" architecture: "x64" + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: "^1.20" + - name: Checkout code uses: actions/checkout@v3 - - name: Set Version and Manifests + - name: Set Version and Draft release run: | # set version based on dispatch type - version="latest" + draft_release="true" if [[ "${{github.event_name}}" == "workflow_dispatch" ]]; then version=${{ github.event.inputs.version }} + draft_release="false" + echo "GIT_ORG=${{ github.event.inputs.organization }}" >> $GITHUB_ENV elif [[ "${{github.ref_type}}" == "tag" ]]; then version=${{ github.ref_name }} + elif [[ "${{github.event_name}}" == "repository_dispatch" ]]; then + version=${{ github.event.client_payload.version }} + draft_release="false" + echo "GIT_ORG=${{ github.event.client_payload.organization }}" >> $GITHUB_ENV fi echo "VERSION=$version" >> $GITHUB_ENV - echo "PRIMAZA_CTL_VERSION=$version" >> $GITHUB_ENV - echo "PRIMAZA_CONFIG_FILE=primaza_main_config_$version.yaml" >> $GITHUB_ENV - echo "WORKER_CONFIG_FILE=primaza_worker_config_$version.yaml" >> $GITHUB_ENV - echo "APPLICATION_AGENT_CONFIG_FILE=application_agent_config_$version.yaml" >> $GITHUB_ENV - echo "SERVICE_AGENT_CONFIG_FILE=service_agent_config_$version.yaml" >> $GITHUB_ENV + echo "DRAFT_RELEASE=$draft_release" >> $GITHUB_ENV - name: Test and make manifests id: test-and-manifests @@ -55,7 +68,7 @@ jobs: run: make single-binary - name: Delete previous release and tag - if: ${{ env.VERSION == 'latest' }} + if: ${{ env.VERSION == 'latest' || env.VERSION == 'nightly' }} uses: dev-drprasad/delete-tag-and-release@v0.2.1 with: delete_release: true # default: false @@ -63,7 +76,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Release for tag event if: ${{ github.ref_type == 'tag' }} uses: softprops/action-gh-release@v1 @@ -73,10 +85,6 @@ jobs: generate_release_notes: true files: | ./out/venv3/dist/primazactl - ${{ env.PRIMAZA_CONFIG_FILE }} - ${{ env.WORKER_CONFIG_FILE }} - ${{ env.APPLICATION_AGENT_CONFIG_FILE }} - ${{ env.SERVICE_AGENT_CONFIG_FILE }} - name: Release for non tag events if: ${{ github.ref_type != 'tag' }} @@ -84,11 +92,7 @@ jobs: with: tag_name: ${{ env.VERSION }} body: "Release version ${{ env.VERSION }}" - draft: true + draft: ${{ env.DRAFT_RELEASE }} generate_release_notes: true files: | ./out/venv3/dist/primazactl - ${{ env.PRIMAZA_CONFIG_FILE }} - ${{ env.WORKER_CONFIG_FILE }} - ${{ env.APPLICATION_AGENT_CONFIG_FILE }} - ${{ env.SERVICE_AGENT_CONFIG_FILE }} diff --git a/Makefile b/Makefile index 90fcb0d..bc8895a 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,17 @@ PRIMAZA_CTL_VERSION ?= $(shell git describe --tags --always --abbrev=8 --dirty) SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec -IMG ?= ghcr.io/primaza/primaza:$(VERSION) -IMG_APP ?= ghcr.io/primaza/primaza-agentapp:$(VERSION) -IMG_SVC ?= ghcr.io/primaza/primaza-agentsvc:$(VERSION) -IMG_APP_LOCAL ?= agentapp:$(VERSION) -IMG_SVC_LOCAL ?= agentsvc:$(VERSION) +# SET RUN_FROM to config the create config files or release to use a release +RUN_FROM ?= config +GIT_ORG ?= primaza +IMG = ghcr.io/$(GIT_ORG)/primaza:$(VERSION) +IMG_APP = ghcr.io/$(GIT_ORG)/primaza-agentapp:$(VERSION) +IMG_SVC = ghcr.io/$(GIT_ORG)/primaza-agentsvc:$(VERSION) +IMG_APP_LOCAL = agentapp:$(VERSION) +IMG_SVC_LOCAL = agentsvc:$(VERSION) + +# set CLEAN to "clusters" to only refresh clusters +CLEAN ?= all PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) @@ -87,10 +93,10 @@ APPLICATION_NAMESPACE ?= primaza-application SERVICE_NAMESPACE ?= primaza-service SERVICE_ACCOUNT_NAMESPACE ?= worker-sa -PRIMAZA_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/primaza_config_$(VERSION).yaml -WORKER_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/worker_config_$(VERSION).yaml -APPLICATION_AGENT_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/application_agent_config_$(VERSION).yaml -SERVICE_AGENT_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/service_agent_config_$(VERSION).yaml +PRIMAZA_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/control_plane_config_$(VERSION).yaml +WORKER_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/crds_config_$(VERSION).yaml +APPLICATION_AGENT_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/application_namespace_config_$(VERSION).yaml +SERVICE_AGENT_CONFIG_FILE ?= $(PRIMAZA_CONFIG_DIR)/service_namespace_config_$(VERSION).yaml KIND_CONFIG_DIR ?= $(SCRIPTS_DIR)/src/primazatest/config TENANT_KIND_CONFIG_FILE ?= $(KIND_CONFIG_DIR)/kind-main.yaml @@ -150,7 +156,10 @@ image: docker tag $(IMG_SVC) $(IMG_SVC_LOCAL) .PHONY: kind-clusters -kind-clusters: config image +kind-clusters: image +ifeq ($(CLEAN),all) + $(MAKE) image +endif -kind delete cluster --name $(KIND_CLUSTER_TENANT_NAME) -kind delete cluster --name $(KIND_CLUSTER_JOIN_NAME) kind create cluster --config $(TENANT_KIND_CONFIG_FILE) --name $(KIND_CLUSTER_TENANT_NAME) && kubectl wait --for condition=Ready nodes --all --timeout=600s @@ -164,7 +173,13 @@ kind-clusters: config image kind load docker-image $(IMG_SVC_LOCAL) --name $(KIND_CLUSTER_JOIN_NAME) .PHONY: setup-test -setup-test: clean image primazactl config kind-clusters +setup-test: clean kind-clusters +ifeq ($(CLEAN),all) + $(MAKE) primazactl +endif +ifeq ($(RUN_FROM),config) + $(MAKE) config +endif .PHONY: clone clone: clean-temp @@ -185,6 +200,8 @@ primazactl: ## Setup virtual environment .PHONY: single-binary single-binary: ## Release primazactl as single binary + echo '__version__ = "$(PRIMAZA_CTL_VERSION)"' > $(VERSION_FILE) + echo '__primaza_version__ = "$(VERSION)"' >> $(VERSION_FILE) -rm -rf $(PYTHON_VENV_DIR) python3 -m venv $(PYTHON_VENV_DIR) $(PYTHON_VENV_DIR)/bin/pip3 install --upgrade pyinstaller @@ -204,31 +221,55 @@ lint: primazactl ## Check python code .PHONY: test-local test-local: setup-test +ifeq ($(RUN_FROM),config) $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -e $(WORKER_CONFIG_FILE) -f $(PRIMAZA_CONFIG_FILE) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -a $(APPLICATION_AGENT_CONFIG_FILE) -s $(SERVICE_AGENT_CONFIG_FILE) -j $(SERVICE_ACCOUNT_NAMESPACE) +else + $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -j $(SERVICE_ACCOUNT_NAMESPACE) -v $(VERSION) -g $(GIT_ORG) +endif + +.PHONY: test-version +test-version: setup-test + $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -v $(VERSION) -g $(GIT_ORG) .PHONY: test-released test-released: make kind-clusters - $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -v $(VERSION) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) + $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -v $(VERSION) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -g $(GIT_ORG) .PHONY: test-users test-users: setup-test create-users +ifeq ($(RUN_FROM),config) $(PYTHON_VENV_DIR)/bin/primazatest -u -i $(OUTPUT_DIR)/users -p $(PYTHON_VENV_DIR) -e $(WORKER_CONFIG_FILE) -f $(PRIMAZA_CONFIG_FILE) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -a $(APPLICATION_AGENT_CONFIG_FILE) -s $(SERVICE_AGENT_CONFIG_FILE) +else + $(PYTHON_VENV_DIR)/bin/primazatest -u -i $(OUTPUT_DIR)/users -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -v $(VERSION) -g $(GIT_ORG) +endif .PHONY: test-dry-run test-dry-run: setup-test +ifeq ($(RUN_FROM),config) $(PYTHON_VENV_DIR)/bin/primazatest -d -p $(PYTHON_VENV_DIR) -e $(WORKER_CONFIG_FILE) -f $(PRIMAZA_CONFIG_FILE) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -a $(APPLICATION_AGENT_CONFIG_FILE) -s $(SERVICE_AGENT_CONFIG_FILE) -t $(OPTIONS_FILE) +else + $(PYTHON_VENV_DIR)/bin/primazatest -d -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -v $(VERSION) -t $(OPTIONS_FILE) -g $(GIT_ORG) +endif .PHONY test-local-no-setup: +ifeq ($(RUN_FROM),config) $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -e $(WORKER_CONFIG_FILE) -f $(PRIMAZA_CONFIG_FILE) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -a $(APPLICATION_AGENT_CONFIG_FILE) -s $(SERVICE_AGENT_CONFIG_FILE) +else + $(PYTHON_VENV_DIR)/bin/primazatest -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -v $(VERSION) -g $(GIT_ORG) +endif .PHONY: test-output test-output: setup-test +ifeq ($(RUN_FROM),config) $(PYTHON_VENV_DIR)/bin/primazatest -o -p $(PYTHON_VENV_DIR) -e $(WORKER_CONFIG_FILE) -f $(PRIMAZA_CONFIG_FILE) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -a $(APPLICATION_AGENT_CONFIG_FILE) -s $(SERVICE_AGENT_CONFIG_FILE) +else + $(PYTHON_VENV_DIR)/bin/primazatest -o -p $(PYTHON_VENV_DIR) -c $(KUBE_KIND_CLUSTER_JOIN_NAME) -m $(KUBE_KIND_CLUSTER_TENANT_NAME) -v $(VERSION) -g $(GIT_ORG) +endif .PHONY: test-apply test-apply: setup-test - $(PYTHON_VENV_DIR)/bin/primazatest -t $(OPTIONS_FILE) -p $(PYTHON_VENV_DIR) + $(PYTHON_VENV_DIR)/bin/primazatest -t $(OPTIONS_FILE) -p $(PYTHON_VENV_DIR) -v $(VERSION) -g $(GIT_ORG) .PHONY: create-users create-users: primazactl @@ -245,20 +286,30 @@ create-users: primazactl .PHONY: test test: setup-test test-local test-released +.PHONY: clean +clean: +ifeq ($(CLEAN),clusters) + $(MAKE) delete-clusters +else + $(MAKE) clean-all +endif + .PHONY: clean-temp clean-temp: -chmod 755 $(TEMP_DIR)/bin/k8s/* - rm -rf $(TEMP_DIR) + -rm -rf $(TEMP_DIR) + +.PHONY: clean-all +clean-all: clean-temp delete-clusters + -rm -rf $(OUTPUT_DIR) + -rm -rf $(SCRIPTS_DIR)/build + -rm -rf $(SCRIPTS_DIR)/dist + -rm -rf $(SCRIPTS_DIR)/src/rh_primaza_control.egg-info + -rm -rf $(LOCALBIN) + -docker image rm $(IMG_APP_LOCAL) + -docker image rm $(IMG_SVC_LOCAL) -.PHONY: clean -clean: clean-temp - rm -rf $(OUTPUT_DIR) - rm -rf $(SCRIPTS_DIR)/build - rm -rf $(SCRIPTS_DIR)/dist - rm -rf $(SCRIPTS_DIR)/src/rh_primaza_control.egg-info - rm -rf $(LOCALBIN) +.PHONY: delete-clusters +delete-clusters: -kind delete cluster --name $(KIND_CLUSTER_TENANT_NAME) -kind delete cluster --name $(KIND_CLUSTER_JOIN_NAME) - - -docker image rm $(IMG_APP_LOCAL) - -docker image rm $(IMG_SVC_LOCAL) diff --git a/scripts/src/primazactl/cmd/apply/defaults.py b/scripts/src/primazactl/cmd/apply/defaults.py index 1ad97a6..0c571b2 100644 --- a/scripts/src/primazactl/cmd/apply/defaults.py +++ b/scripts/src/primazactl/cmd/apply/defaults.py @@ -9,8 +9,8 @@ "tenant": DEFAULT_TENANT, "version": __primaza_version__, "kubeconfig": from_env(), - "tenant_config": "primaza_config_latest.yaml", - "worker_config": "worker_config_latest.yaml", - "service_agent_config": "service_agent_config_latest.yaml", - "app_agent_config": "application_agent_config_latest.yaml", + "tenant_config": "control_plane_config_latest.yaml", + "worker_config": "crds_config_latest.yaml", + "service_agent_config": "service_namespace_config_latest.yaml", + "app_agent_config": "application_namespace_config_latest.yaml", "service_account_namespace": WORKER_NAMESPACE} diff --git a/scripts/src/primazactl/kube/customnamespaced.py b/scripts/src/primazactl/kube/customnamespaced.py index 97a1079..90a5629 100644 --- a/scripts/src/primazactl/kube/customnamespaced.py +++ b/scripts/src/primazactl/kube/customnamespaced.py @@ -66,8 +66,7 @@ def create(self): raise e else: logger.log_info(f'UNCHANGED: {self.body["kind"]} ' - f'{self.body["metadata"]["name"]} ' - 'already exists', + f'{self.body["metadata"]["name"]} already exists', settings.dry_run_active()) def read(self) -> client.V1Namespace | None: diff --git a/scripts/src/primazactl/kubectl/constants.py b/scripts/src/primazactl/kubectl/constants.py index 4d10325..72311d2 100644 --- a/scripts/src/primazactl/kubectl/constants.py +++ b/scripts/src/primazactl/kubectl/constants.py @@ -1,5 +1,15 @@ -PRIMAZA_CONFIG: str = "primaza_main_config" -WORKER_CONFIG: str = "primaza_worker_config" -APP_AGENT_CONFIG: str = "application_agent_config" -SVC_AGENT_CONFIG: str = "service_agent_config" -REPOSITORY: str = "primaza/primazactl" +import os + +PRIMAZA_CONFIG: str = "control_plane_config" +WORKER_CONFIG: str = "crds_config" +APP_AGENT_CONFIG: str = "application_namespace_config" +SVC_AGENT_CONFIG: str = "service_namespace_config" +REPOSITORY: str = "primaza/primaza" +TEST_REPOSITORY_OVERRIDE: str = "primaza-test-only-repository-override" + + +def get_repository(): + override_repo = os.getenv(TEST_REPOSITORY_OVERRIDE) + if override_repo: + return override_repo + return REPOSITORY diff --git a/scripts/src/primazactl/kubectl/manifest.py b/scripts/src/primazactl/kubectl/manifest.py index a97c231..f53206b 100644 --- a/scripts/src/primazactl/kubectl/manifest.py +++ b/scripts/src/primazactl/kubectl/manifest.py @@ -5,7 +5,7 @@ from github import Auth, Github import semver import requests -from.constants import REPOSITORY +from.constants import get_repository from.apply import apply_manifest @@ -18,9 +18,12 @@ class Manifest(object): def __init__(self, namespace: str, path: str, version: str = None, type: str = None): + logger.log_entry(f"namespace: {namespace}, path: {path}, " + f"version: {version}, type: {type}") self.path = path self.namespace = namespace - self.version = version + if version: + self.version = version[1:] if version.startswith("v") else version self.type = type def replace_ns(self, body): @@ -55,13 +58,10 @@ def load_manifest(self): logger.log_entry(f"path: {self.path}, version: {self.version}, " f"type: {self.type}") if self.path: - with open(self.path, 'r') as manifest: - self.body = yaml.safe_load_all(manifest) - self.update_namespace() + return yaml.safe_load_all(open(self.path, 'r')) else: manifest = self.__set_config_content() - self.body = yaml.safe_load_all(manifest) - self.update_namespace() + return yaml.safe_load_all(manifest) def apply(self, api_client: client, action: str = "create"): logger.log_entry(f"action: {action}") @@ -101,35 +101,45 @@ def __set_config_content(self): logger.log_entry() g = self.build_github_client() - repo = g.get_repo(REPOSITORY) + repo = g.get_repo(get_repository()) releases = repo.get_releases() latest_release = None + latest_version = None for release in releases: logger.log_info(f"release found - name: {release.id}") logger.log_info(f" tag: {release.tag_name}") - if self.version == "latest": - if release.tag_name == "latest": - return self.__get_config_content(release) - - elif semver.VersionInfo.isvalid(release.tag_name): - if self.version and \ - semver.compare(self.version, release.tag_name) == 0: - logger.log_info(f"match found: {release.tag_name}") - return self.__get_config_content(release) - elif not latest_release or \ - semver.compare(release.tag_name, - latest_release.tag_name) > 1: - logger.log_info(f"later match found: {release.tag_name}") - latest_release = release + if self.version == "latest" and release.tag_name == "latest": + return self.__get_config_content(release) + elif self.version == "nightly" and release.tag_name == "nightly": + return self.__get_config_content(release) + elif self.version != "latest" and self.version != "nightly": + version = release.tag_name[1:] \ + if release.tag_name.startswith("v") \ + else release.tag_name + if semver.VersionInfo.isvalid(version): + if self.version and \ + semver.compare(self.version, version) == 0: + logger.log_info(f"match found: {release.tag_name}") + return self.__get_config_content(release) + elif not latest_version or \ + semver.compare(version, + latest_version) > 1: + logger.log_info(f"later match found: " + f"{release.tag_name}") + latest_version = version + latest_release = release + else: + logger.log_info(f"Ignore release tag {release.tag_name} " + f"- it is not a valid semver") if latest_release: return self.__get_config_content(latest_release) raise RuntimeError(f"A release was not found in repository " - f"{REPOSITORY} for version {self.version}") + f"{get_repository()} for version {self.version}") def __get_config_content(self, release): logger.log_entry(f"release = {release.tag_name}") @@ -144,7 +154,7 @@ def __get_config_content(self, release): return response.text.encode("utf-8") raise RuntimeError(f"Failed to get release asset {asset_name} " - f"from {REPOSITORY} " + f"from {get_repository()} " f"for version {self.version}") diff --git a/scripts/src/primazactl/types.py b/scripts/src/primazactl/types.py index 1a517d0..a468402 100644 --- a/scripts/src/primazactl/types.py +++ b/scripts/src/primazactl/types.py @@ -13,10 +13,11 @@ def existing_file(arg): def semvertag_or_latest(arg): - if arg != "latest" and not semver.VersionInfo.isvalid(arg): - raise ArgumentTypeError( - f"--version is not a valid semantic version: {arg}") - + if arg != "latest" and arg != "nightly": + version = arg[1:] if arg.startswith("v") else arg + if not semver.VersionInfo.isvalid(version): + raise ArgumentTypeError( + f"--version is not a valid semantic version: {arg}") return arg diff --git a/scripts/src/primazatest/runtest.py b/scripts/src/primazatest/runtest.py index 45b8932..a03ff7e 100644 --- a/scripts/src/primazatest/runtest.py +++ b/scripts/src/primazatest/runtest.py @@ -4,7 +4,11 @@ import time import os import yaml +import tempfile from primazactl.utils.command import Command +from primazactl.kubectl.manifest import Manifest +from primazactl.kubectl.constants import PRIMAZA_CONFIG, WORKER_CONFIG, \ + APP_AGENT_CONFIG, SVC_AGENT_CONFIG, TEST_REPOSITORY_OVERRIDE PASS = '\033[92mPASS\033[0m' SUCCESS = '\033[92mSUCCESS\033[0m' @@ -53,6 +57,8 @@ def run_and_check(venv_dir, args, expect_msg, expect_error_msg, fail_msg): outcome = True + print(f"command output:\n{ctl_out}") + if expect_msg: if ctl_out: print(f"Response was:\n{ctl_out}") @@ -615,6 +621,7 @@ def test_dry_run(command_args, dry_run_type): outcome = check_dry_run(dry_run_type, command_args.main_config, + command_args.version, worker_resp, COMMAND_TENANT, TENANT) @@ -638,6 +645,7 @@ def test_dry_run(command_args, dry_run_type): worker_outcome = check_dry_run(dry_run_type, command_args.worker_config, + command_args.version, worker_resp, COMMAND_JOIN, CLUSTER_ENVIRONMENT) @@ -659,6 +667,7 @@ def test_dry_run(command_args, dry_run_type): app_outcome = check_dry_run(dry_run_type, command_args.app_config, + command_args.version, app_resp, COMMAND_APP_NS, APPLICATION_NAMESPACE) @@ -682,6 +691,7 @@ def test_dry_run(command_args, dry_run_type): service_outcome = check_dry_run(dry_run_type, command_args.service_config, + command_args.version, service_resp, COMMAND_SVC_NS, SERVICE_NAMESPACE) @@ -697,88 +707,109 @@ def test_dry_run(command_args, dry_run_type): def test_dry_run_with_options(command_args): - options_yaml = update_options_file(command_args.options_file) + options_yaml = update_options_file(command_args) tenant = options_yaml["name"] cluster_options = options_yaml["clusterEnvironments"][0] cluster_env = cluster_options["name"] app_namespace = cluster_options["applicationNamespaces"][0]["name"] svc_namespace = cluster_options["serviceNamespaces"][0]["name"] - command = [f"{command_args.venv_dir}/bin/primazactl", "apply", - "-p", command_args.options_file, - "-y", "server"] - resp, err = run_cmd(command) + with tempfile.NamedTemporaryFile(mode="w+") as options_file: + with open(options_file.name, 'w') as options: + yaml.dump(options_yaml, options) - if err: - print(f"[{FAIL}] Unexpected error response: {err}") - outcome = False - elif resp: - outcome = True - out_lines = None - index = 0 - for line in resp.splitlines(): - if line.strip(' \t\n\r') == "": - if index == 0: - cfg = command_args.main_config - cmd = COMMAND_TENANT - name = tenant - index = 1 - elif index == 1: - cfg = command_args.worker_config - cmd = COMMAND_JOIN - name = cluster_env - index = 2 - elif index == 2: - cfg = command_args.app_config - cmd = COMMAND_APP_NS - name = app_namespace - index = 3 - elif index == 3: - cfg = command_args.service_config - cmd = COMMAND_SVC_NS - name = svc_namespace - index = 4 - - if index < 4: - print(f"check the output:{cfg}:{cmd}:{name}:") - print(f"output is: {out_lines}") - outcome = outcome & check_dry_run("server", cfg, out_lines, - cmd, name) - - out_lines = "" - else: - out_lines = f"{out_lines}\n{line}" if out_lines else line + command = [f"{command_args.venv_dir}/bin/primazactl", "apply", + "-p", options_file.name, + "-y", "server"] + resp, err = run_cmd(command) - else: - print(f"[{FAIL}] no response received for dry-run test") - outcome = False + if err: + print(f"[{FAIL}] Unexpected error response: {err}") + outcome = False + elif resp: + outcome = True + out_lines = None + index = 0 + version = command_args.version + for line in resp.splitlines(): + if line.strip(' \t\n\r') == "": + if index == 0: + cfg = command_args.main_config + cmd = COMMAND_TENANT + name = tenant + index = 1 + elif index == 1: + cfg = command_args.worker_config + cmd = COMMAND_JOIN + name = cluster_env + index = 2 + elif index == 2: + cfg = command_args.app_config + cmd = COMMAND_APP_NS + name = app_namespace + index = 3 + elif index == 3: + cfg = command_args.service_config + cmd = COMMAND_SVC_NS + name = svc_namespace + index = 4 + + if index < 4: + print(f"check the output:{cfg}:{cmd}:{name}:") + print(f"output is: {out_lines}") + outcome = outcome & check_dry_run("server", cfg, + version, out_lines, + cmd, name) + + out_lines = "" + else: + out_lines = f"{out_lines}\n{line}" if out_lines else line + + else: + print(f"[{FAIL}] no response received for dry-run test") + outcome = False return outcome -def check_dry_run(dry_run_type, manifest_file, resp, +def check_dry_run(dry_run_type, manifest_file, version, resp, check_command, subject_name): - with open(manifest_file, 'r') as manifest: - manifest_yaml = yaml.safe_load_all(manifest) - manifest_list = list(manifest_yaml) - - expect_lines = 0 if dry_run_type == "client" else len(manifest_list) - if check_command == COMMAND_TENANT: + manifest_yaml = get_manifest_yaml(manifest_file, + version, + PRIMAZA_CONFIG) expected_last_message = f"Dry run create primaza tenant " \ f"{subject_name} successfully completed" elif check_command == COMMAND_JOIN: + manifest_yaml = get_manifest_yaml(manifest_file, + version, + WORKER_CONFIG) expected_last_message = f"Dry run join cluster {subject_name} " \ f"successfully completed" elif check_command == COMMAND_APP_NS: + manifest_yaml = get_manifest_yaml(manifest_file, + version, + APP_AGENT_CONFIG) expected_last_message = f"Dry run create application namespace " \ f"{subject_name} successfully completed" elif check_command == COMMAND_SVC_NS: + manifest_yaml = get_manifest_yaml(manifest_file, + version, + SVC_AGENT_CONFIG) expected_last_message = f"Dry run create service namespace " \ f"{subject_name} successfully completed" else: expected_last_message = "successfully completed" + manifest_yaml = None + + if dry_run_type == "client": + expect_lines = 0 + else: + if manifest_yaml: + expect_lines = len(list(manifest_yaml)) + else: + expect_lines = 1 outcome = True @@ -819,7 +850,9 @@ def test_output(command_args, dry_run_type=None): TENANT_FOR_OUTPUT, None, True, dry_run_type, "yaml") - outcome = check_output(command_args.main_config, worker_resp) + outcome = check_output(command_args.main_config, + command_args.version, + PRIMAZA_CONFIG, worker_resp) if outcome: print(f"[{PASS}] output yaml tenant install test passed. " f"dry-run={dry_run_type}") @@ -838,7 +871,9 @@ def test_output(command_args, dry_run_type=None): None, None, True, dry_run_type, "yaml") - worker_outcome = check_output(command_args.worker_config, worker_resp) + worker_outcome = check_output(command_args.worker_config, + command_args.version, + WORKER_CONFIG, worker_resp) if worker_outcome: print(f"[{PASS}] output yaml worker join test passed. ", f"dry-run={dry_run_type}") @@ -857,7 +892,9 @@ def test_output(command_args, dry_run_type=None): command_args.service_account_namespace, None, None, True, dry_run_type, "yaml") - app_outcome = check_output(command_args.app_config, app_resp) + app_outcome = check_output(command_args.app_config, + command_args.version, + APP_AGENT_CONFIG, app_resp) if app_outcome: print(f"[{PASS}] output yaml application namespace create test " f"passed. dry-run={dry_run_type}") @@ -876,7 +913,9 @@ def test_output(command_args, dry_run_type=None): command_args.service_account_namespace, None, None, True, dry_run_type, "yaml") - service_outcome = check_output(command_args.service_config, service_resp) + service_outcome = check_output(command_args.service_config, + command_args.version, + SVC_AGENT_CONFIG, service_resp) if service_outcome: print(f"[{PASS}] output yaml service namespace create test " @@ -888,11 +927,10 @@ def test_output(command_args, dry_run_type=None): return outcome & worker_outcome & app_outcome & service_outcome -def check_output(manifest_file, resp): +def check_output(manifest_file, version, type, resp): - with open(manifest_file, 'r') as manifest: - manifest_yaml = yaml.safe_load_all(manifest) - manifest_list = list(manifest_yaml) + manifest_yaml = get_manifest_yaml(manifest_file, version, type) + manifest_list = list(manifest_yaml) outcome = True response_yaml = yaml.safe_load(resp) @@ -915,7 +953,7 @@ def check_output(manifest_file, resp): def test_apply(command_args): - options_yaml = update_options_file(command_args.options_file) + options_yaml = update_options_file(command_args) tenant = options_yaml["name"] cluster_options = options_yaml["clusterEnvironments"][0] sa_n = cluster_options.get("serviceAccountNamespace", None) @@ -923,44 +961,49 @@ def test_apply(command_args): app_namespace = cluster_options["applicationNamespaces"][0]["name"] svc_namespace = cluster_options["serviceNamespaces"][0]["name"] - if(sa_n and sa_n != "kube-system"): + if sa_n and sa_n != "kube-system": run_cmd(["kubectl", "create", "namespace", sa_n, "--context", cluster_options["targetCluster"]["context"]]) - command = [f"{command_args.venv_dir}/bin/primazactl", "apply", - "-p", command_args.options_file] - out, err = run_cmd(command) + with tempfile.NamedTemporaryFile(mode="w+") as options_file: + with open(options_file.name, 'w') as options: + yaml.dump(options_yaml, options) - install_all_outcome = True - if err: - print(f"[{FAIL}] Unexpected error response: {err}") - install_all_outcome = False - elif out: - if not check_apply_out(out, f"Create primaza tenant {tenant} " - f"successfully completed"): - install_all_outcome = False - elif not check_apply_out(out, "Join cluster " - f"{cluster_env} " - "successfully completed"): - install_all_outcome = False - elif not check_apply_out(out, "Create application namespace " - f"{app_namespace} " - "successfully completed"): - install_all_outcome = False - elif not check_apply_out(out, "Create service namespace " - f"{svc_namespace} " - "successfully completed"): - install_all_outcome = False - elif not check_apply_out(out, "Primaza install from options " - "file complete"): + command = [f"{command_args.venv_dir}/bin/primazactl", "apply", + "-p", options_file.name] + + out, err = run_cmd(command) + + install_all_outcome = True + if err: + print(f"[{FAIL}] Unexpected error response: {err}") install_all_outcome = False + elif out: + if not check_apply_out(out, f"Create primaza tenant {tenant} " + f"successfully completed"): + install_all_outcome = False + elif not check_apply_out(out, "Join cluster " + f"{cluster_env} " + "successfully completed"): + install_all_outcome = False + elif not check_apply_out(out, "Create application namespace " + f"{app_namespace} " + "successfully completed"): + install_all_outcome = False + elif not check_apply_out(out, "Create service namespace " + f"{svc_namespace} " + "successfully completed"): + install_all_outcome = False + elif not check_apply_out(out, "Primaza install from options " + "file complete"): + install_all_outcome = False + else: + print(f"[{PASS}] apply options file " + f"{command_args.options_file} passed") else: - print(f"[{PASS}] apply options file " - f"{command_args.options_file} passed") - else: - print(f"[{FAIL}] apply options file " - f"{command_args.options_file} did not produce any output") + print(f"[{FAIL}] apply options file " + f"{command_args.options_file} did not produce any output") return install_all_outcome @@ -973,8 +1016,8 @@ def check_apply_out(out, expect_out): return True -def update_options_file(options_file): - with open(options_file) as options: +def update_options_file(command_args): + with open(command_args.options_file) as options: options_yaml = yaml.safe_load(options) main_url = get_cluster_internal_url( @@ -987,14 +1030,21 @@ def update_options_file(options_file): replace("kind-", "")) target_cluster["internalUrl"] = worker_url - print(options_yaml) + if command_args.version != "latest": + options_yaml["version"] = command_args.version + options_yaml["manifestDirectory"] = "" - with open(options_file, 'w') as options: - yaml.dump(options_yaml, options) + print(options_yaml) return options_yaml +def get_manifest_yaml(config_file, version, type): + manifest = Manifest("", config_file, + version, type) + return manifest.load_manifest() + + def main(): parser = argparse.ArgumentParser( prog='runtest', @@ -1060,9 +1110,18 @@ def main(): help="namespace used for hosting the service account" "shared with" "Primaza's Control Plane(existing namespace).") + parser.add_argument("-g", "--git-organization", + dest="git_org", + required=False, + type=str, + help="Githib organization, to obtain a release from, " + "when using version.") args = parser.parse_args() + if args.git_org: + os.environ[TEST_REPOSITORY_OVERRIDE] = f"{args.git_org}/primaza" + if args.dry_run: outcome = test_dry_run(args, "client") outcome = outcome & test_dry_run(args, "server") diff --git a/scripts/src/primazatest/users/config/service-agent-bad.yaml b/scripts/src/primazatest/users/config/service-agent-bad.yaml index 31d53ee..79cc991 100644 --- a/scripts/src/primazatest/users/config/service-agent-bad.yaml +++ b/scripts/src/primazatest/users/config/service-agent-bad.yaml @@ -87,6 +87,7 @@ rules: - primaza.io resources: - registeredservices + - serviceclasses verbs: - create - delete @@ -173,6 +174,15 @@ rules: - create - get - delete + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - create + - get + - delete + - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding