diff --git a/.tekton/pr-differ.yaml b/.tekton/pr-differ.yaml new file mode 100644 index 0000000..ccc9441 --- /dev/null +++ b/.tekton/pr-differ.yaml @@ -0,0 +1,177 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + name: pr-differ + annotations: + # The event we are targeting as seen from the webhook payload + # this can be an array too, i.e: [pull_request, push] + pipelinesascode.tekton.dev/on-event: "[pull_request]" + + # The branch or tag we are targeting (ie: main, refs/tags/*) + pipelinesascode.tekton.dev/on-target-branch: "[main,devel]" + + # Fetch the git-clone task from hub, we are able to reference later on it + # with taskRef and it will automatically be embedded into our pipeline. + pipelinesascode.tekton.dev/task: "git-clone" + + # Use maven task from hub + # pipelinesascode.tekton.dev/task-1: "[pre-commit]" + + # You can add more tasks in here to reuse, browse the one you like from here + # https://hub.tekton.dev/ + # example: + # pipelinesascode.tekton.dev/task-2: "[github-add-labels]" + pipelinesascode.tekton.dev/task-1: "[.tekton/task/github-add-comment.yaml]" + + # How many runs we want to keep attached to this event + pipelinesascode.tekton.dev/max-keep-runs: "2" +spec: + params: + # The variable with brackets are special to Pipelines as Code + # They will automatically be expanded with the events from Github. + - name: repo_url + value: "{{ repo_url }}" + - name: revision + value: "{{ revision }}" + - name: pull_request_number + value: "{{ pull_request_number }}" + - name: git_auth_secret + value: "{{ git_auth_secret }}" + - name: source_branch + value: "{{source_branch}}" + - name: target_branch + value: "{{target_branch}}" + + podTemplate: + nodeSelector: + kubernetes.io/arch: amd64 + pipelineSpec: + params: + - name: repo_url + - name: revision + - name: pull_request_number + - name: git_auth_secret + workspaces: + - name: source + tasks: + - name: fetch-repository-pr + taskRef: + resolver: cluster + params: + - name: kind + value: task + - name: name + value: git-clone + - name: namespace + value: openshift-pipelines + workspaces: + - name: output + workspace: source + params: + - name: URL + value: $(params.repo_url) + - name: REVISION + value: $(params.revision) + - name: DEPTH + value: 0 + - name: SUBDIRECTORY + value: pr + + - name: fetch-repository-main + taskRef: + resolver: cluster + params: + - name: kind + value: task + - name: name + value: git-clone + - name: namespace + value: openshift-pipelines + workspaces: + - name: output + workspace: source + params: + - name: URL + value: $(params.repo_url) + - name: REVISION + value: 'main' + - name: DEPTH + value: 0 + - name: SUBDIRECTORY + value: main + + - name: differ + runAfter: + - fetch-repository-main + - fetch-repository-pr + workspaces: + - name: source + workspace: source + taskSpec: + workspaces: + - name: source + steps: + - name: differ + image: quay.io/stormshift/gitops-differ:202501031515 + imagePullPolicy: Always + workingDir: $(workspaces.source.path) + securityContext: + runAsNonRoot: true + runAsUser: 65532 + env: + - name: WORKSPACE + value: $(workspaces.source.path) + script: | + set -euxo pipefail + + ${WORKSPACE}/pr/helper/differ.sh ${WORKSPACE}/pr ${WORKSPACE}/main + + cp -v /tmp/diff-overview.md ${WORKSPACE}/diff-overview.md + + - name: notify-deployment + runAfter: + - differ + workspaces: + - name: comment-file + workspace: source + params: + - name: REQUEST_URL + value: "$(params.repo_url)/pull/$(params.pull_request_number)" + - name: PAC_GITHUB_SECRET + value: "$(params.git_auth_secret)" + - name: COMMENT_OR_FILE + value: "diff-overview.md" + taskRef: + name: github-add-comment + # finally: + # - name: notify-linter-on-failure + # workspaces: + # - name: comment-file + # workspace: source + # when: + # - input: $(tasks.pre-commit.status) + # operator: in + # values: ["Failed"] + # params: + # - name: REQUEST_URL + # value: "$(params.repo_url)/pull/$(params.pull_request_number)" + # - name: PAC_GITHUB_SECRET + # value: "$(params.git_auth_secret)" + # - name: COMMENT_OR_FILE + # value: "notify-linter-on-failure.txt" + # taskRef: + # name: github-add-comment + + workspaces: + - name: source + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + # This workspace will inject secret to help the git-clone task to be able to + # checkout the private repositories + diff --git a/.tekton/task/github-add-comment.yaml b/.tekton/task/github-add-comment.yaml new file mode 100644 index 0000000..2e67183 --- /dev/null +++ b/.tekton/task/github-add-comment.yaml @@ -0,0 +1,190 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: github-add-comment + labels: + app.kubernetes.io/version: "0.7" + annotations: + tekton.dev/categories: Git + tekton.dev/pipelines.minVersion: "0.17.0" + tekton.dev/tags: github + tekton.dev/displayName: "add github comment" + tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le" +spec: + description: >- + This Task will add a comment to a pull request or an issue. + + It can take either a filename or a comment as input and can + post the comment back to GitHub accordingly. + + workspaces: + - name: comment-file + optional: true + description: The optional workspace containing comment file to be posted. + + params: + - name: GITHUB_HOST_URL + description: | + The GitHub host, adjust this if you run a GitHub enteprise. + default: "api.github.com" + type: string + + - name: API_PATH_PREFIX + description: | + The API path prefix, GitHub Enterprise has a prefix e.g. /api/v3 + default: "" + type: string + + - name: REQUEST_URL + description: | + The GitHub issue or pull request URL where we want to add a new + comment. + type: string + + - name: COMMENT_OR_FILE + description: | + The actual comment to add or the filename containing comment to post. + type: string + + - name: PAC_GITHUB_SECRET + description: | + The name of the Kubernetes Secret that contains the GitHub token. + type: string + + - name: PAC_GITHUB_SECRET_KEY + description: | + The key within the Kubernetes Secret that contains the GitHub token. + type: string + default: .git-credentials + + - name: AUTH_TYPE + description: | + The type of authentication to use. You could use the less secure "Basic" for example + type: string + default: Bearer + + - name: COMMENT_TAG + description: | + An invisible tag to be added into the comment. The tag is made + invisible by embedding in an an HTML comment. The tag allows for later + retrieval of the comment, and it allows replacing an existing comment. + type: string + default: "" + + - name: REPLACE + description: | + When a tag is specified, and `REPLACE` is `true`, look for a comment + with a matching tag and replace it with the new comment. + type: string + default: "false" # Alternative value: "true" + + steps: + - name: post-comment + workingDir: $(workspaces.comment-file.path) + env: + - name: GIT_CREDENTIALS + valueFrom: + secretKeyRef: + name: $(params.PAC_GITHUB_SECRET) + key: $(params.PAC_GITHUB_SECRET_KEY) + + image: registry.access.redhat.com/ubi8/ubi-minimal:8.2 + script: | + #!/usr/libexec/platform-python + import json + import os + import http.client + import sys + import urllib.parse + + bearer = urllib.parse.urlparse(os.environ["GIT_CREDENTIALS"]) + + authHeader = "$(params.AUTH_TYPE) " + bearer.password + + split_url = urllib.parse.urlparse( + "$(params.REQUEST_URL)").path.split("/") + + # This will convert https://github.com/foo/bar/pull/202 to + # api url path /repos/foo/issues/ + api_url = "{base}/repos/{package}/issues/{id}".format( + base="$(params.API_PATH_PREFIX)", package="/".join(split_url[1:3]), id=split_url[-1]) + + # Only support FILE on my case + commentParamValue = """$(params.COMMENT_OR_FILE)""" + + # check if workspace is bound and parameter passed is a filename or not + if "$(workspaces.comment-file.bound)" == "true" and os.path.exists(commentParamValue): + commentParamValue = open(commentParamValue, "r").read() + + else: + commentParamValue = """ 😱 An unexpected error has occurred, please check log files.""" + + # If a tag was specified, append it to the comment + if "$(params.COMMENT_TAG)": + commentParamValue += "".format(tag="$(params.COMMENT_TAG)") + + data = { + "body": commentParamValue, + } + + # This is for our fake github server + if "$(params.GITHUB_HOST_URL)".startswith("http://"): + conn = http.client.HTTPConnection("$(params.GITHUB_HOST_URL)".replace("http://", "")) + else: + conn = http.client.HTTPSConnection("$(params.GITHUB_HOST_URL)") + + # If REPLACE is true, we need to search for comments first + matching_comment = "" + if "$(params.REPLACE)" == "true": + if not "$(params.COMMENT_TAG)": + print("REPLACE requested but no COMMENT_TAG specified") + sys.exit(1) + r = conn.request( + "GET", + api_url + "/comments", + headers={ + "User-Agent": "TektonCD, the peaceful cat", + "Authorization": authHeader, + }) + + resp = conn.getresponse() + if not str(resp.status).startswith("2"): + print("Error: %d" % (resp.status)) + print(resp.read()) + sys.exit(1) + print(resp.status) + + comments = json.loads(resp.read()) + print(comments) + # If more than one comment is found take the last one + matching_comment = [x for x in comments if '$(params.COMMENT_TAG)' in x['body']][-1:] + if matching_comment: + matching_comment = matching_comment[0]['url'] + + if matching_comment: + method = "PATCH" + target_url = urllib.parse.urlparse(matching_comment).path + else: + method = "POST" + target_url = api_url + "/comments" + + print("Sending data to GitHub with {} ".format(method)) + # Don't print anymore... + # print(data) + r = conn.request( + method, + target_url, + body=json.dumps(data), + headers={ + "User-Agent": "TektonCD, the peaceful cat", + "Authorization": authHeader, + }) + resp = conn.getresponse() + if not str(resp.status).startswith("2"): + print("Error: %d" % (resp.status)) + print(resp.read()) + sys.exit(1) + else: + print("a GitHub comment has been {} to $(params.REQUEST_URL)".format( + "updated" if matching_comment else "added")) diff --git a/README.md b/README.md index e4ce191..359c3ab 100644 --- a/README.md +++ b/README.md @@ -27,19 +27,15 @@ Rollout via OpenShift GitOps / ArgoCD and Red Hat Advances Cluster Manager. -## Seal secrets +# Build differ image ```bash -kubeseal \ - --controller-name sealed-secret-controller-sealed-secrets \ - --controller-namespace sealed-secrets \ - --fetch-cert +export VERSION=$(date +%Y%m%d%H%M) +export IMAGE="quay.io/stormshift/gitops-differ:${VERSION}" +podman build --platform linux/amd64,linux/arm64 \ + -f gitops-differ.Containerfile \ + --manifest ${IMAGE} . +podman manifest push ${IMAGE} -kubeseal \ - --controller-name sealed-secret-controller-sealed-secrets \ - --controller-namespace sealed-secrets \ - --format yaml \ - < <(oc create secret generic test --from-literal=key1=supersecret --dry-run=client -o yaml) - -``` +``` \ No newline at end of file diff --git a/configuration/overlays/isar/cluster-scope/Proxy/cluster.yaml b/configuration/base/cluster-scope/Proxy/cluster.yaml similarity index 100% rename from configuration/overlays/isar/cluster-scope/Proxy/cluster.yaml rename to configuration/base/cluster-scope/Proxy/cluster.yaml diff --git a/configuration/overlays/stormshift-ocp5/cluster-scope/Proxy/kustomization.yaml b/configuration/base/cluster-scope/Proxy/kustomization.yaml similarity index 100% rename from configuration/overlays/stormshift-ocp5/cluster-scope/Proxy/kustomization.yaml rename to configuration/base/cluster-scope/Proxy/kustomization.yaml diff --git a/configuration/base/cluster-scope/kustomization.yaml b/configuration/base/cluster-scope/kustomization.yaml new file mode 100644 index 0000000..6f746f2 --- /dev/null +++ b/configuration/base/cluster-scope/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- Proxy/ diff --git a/configuration/base/kustomization.yaml b/configuration/base/kustomization.yaml index 3d2393a..fb8aeb8 100644 --- a/configuration/base/kustomization.yaml +++ b/configuration/base/kustomization.yaml @@ -4,3 +4,4 @@ kind: Kustomization resources: - namespace/openshift-config/ + - cluster-scope/ diff --git a/configuration/overlays/coe-cluster/cluster-scope/Proxy/cluster.yaml b/configuration/overlays/coe-cluster/cluster-scope/Proxy/cluster.yaml deleted file mode 100644 index 4c80196..0000000 --- a/configuration/overlays/coe-cluster/cluster-scope/Proxy/cluster.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: config.openshift.io/v1 -kind: Proxy -metadata: - annotations: - argocd.argoproj.io/sync-options: "ServerSideApply=true,Validate=false" - name: cluster -spec: - trustedCA: - name: user-ca-bundle-v1 \ No newline at end of file diff --git a/configuration/overlays/coe-cluster/kustomization.yaml b/configuration/overlays/coe-cluster/kustomization.yaml index 2767c38..fac6ee7 100644 --- a/configuration/overlays/coe-cluster/kustomization.yaml +++ b/configuration/overlays/coe-cluster/kustomization.yaml @@ -12,7 +12,6 @@ resources: # subject=C = US, ST = North Carolina, L = Raleigh, O = "Red Hat, Inc.", OU = Red Hat IT, CN = Red Hat IT Root CA, emailAddress = infosec@redhat.com # issuer=C = US, ST = North Carolina, L = Raleigh, O = "Red Hat, Inc.", OU = Red Hat IT, CN = Red Hat IT Root CA, emailAddress = infosec@redhat.com - namespace/openshift-config/ConfigMap/user-ca-bundle-v1.yaml - - cluster-scope/Proxy/cluster.yaml - namespace/openshift-config/ExternalSecret/ocp-coe-cert.yaml - cluster-scope/APIServer/cluster.yaml diff --git a/configuration/overlays/isar/cluster-scope/kustomization.yaml b/configuration/overlays/isar/cluster-scope/kustomization.yaml index ca9fffd..58898a7 100644 --- a/configuration/overlays/isar/cluster-scope/kustomization.yaml +++ b/configuration/overlays/isar/cluster-scope/kustomization.yaml @@ -2,7 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - Proxy/cluster.yaml - Console/cluster.yaml - ConsoleNotification/ - OAuth/cluster.yaml diff --git a/configuration/overlays/stormshift-ocp4/kustomization.yaml b/configuration/overlays/stormshift-ocp4/kustomization.yaml index ae5a161..8a1a2ea 100644 --- a/configuration/overlays/stormshift-ocp4/kustomization.yaml +++ b/configuration/overlays/stormshift-ocp4/kustomization.yaml @@ -5,6 +5,7 @@ kind: Kustomization resources: - ../common/ - cluster-scope/ + - namespace/ - ../../../apps/astra-trident/overlays/stormshift-ocp4/ # Custom logo diff --git a/configuration/overlays/stormshift-ocp4/namespace/kustomization.yaml b/configuration/overlays/stormshift-ocp4/namespace/kustomization.yaml new file mode 100644 index 0000000..c16f0a3 --- /dev/null +++ b/configuration/overlays/stormshift-ocp4/namespace/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - openshift-ingress/ + - openshift-ingress-operator/ diff --git a/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/IngressController/default.yaml b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/IngressController/default.yaml new file mode 100644 index 0000000..c21c732 --- /dev/null +++ b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/IngressController/default.yaml @@ -0,0 +1,10 @@ +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: default + namespace: openshift-ingress-operator + annotations: + argocd.argoproj.io/sync-options: "ServerSideApply=true,Validate=false" +spec: + defaultCertificate: + name: ocp-coe-cert diff --git a/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/kustomization.yaml b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/kustomization.yaml new file mode 100644 index 0000000..335a0eb --- /dev/null +++ b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress-operator/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - IngressController/default.yaml diff --git a/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/ExternalSecret/ocp-coe-cert.yaml b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/ExternalSecret/ocp-coe-cert.yaml new file mode 100644 index 0000000..10f7f23 --- /dev/null +++ b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/ExternalSecret/ocp-coe-cert.yaml @@ -0,0 +1,24 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: ocp-coe-cert +spec: + data: + - remoteRef: + key: coe-lab/certificate/api.ocp4.stormshift.coe.muc.redhat.com + property: cert_and_intermediate_pem + secretKey: tls.crt + - remoteRef: + key: coe-lab/certificate/api.ocp4.stormshift.coe.muc.redhat.com + property: key + secretKey: tls.key + refreshInterval: 12h + secretStoreRef: + kind: ClusterSecretStore + name: redhat-vault + target: + creationPolicy: Owner + deletionPolicy: Retain + name: ocp-coe-cert + template: + type: kubernetes.io/tls diff --git a/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/kustomization.yaml b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/kustomization.yaml new file mode 100644 index 0000000..dd7c805 --- /dev/null +++ b/configuration/overlays/stormshift-ocp4/namespace/openshift-ingress/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: openshift-ingress + +resources: +- ExternalSecret/ocp-coe-cert.yaml diff --git a/configuration/overlays/stormshift-ocp5/cluster-scope/Proxy/cluster.yaml b/configuration/overlays/stormshift-ocp5/cluster-scope/Proxy/cluster.yaml deleted file mode 100644 index 3b15d35..0000000 --- a/configuration/overlays/stormshift-ocp5/cluster-scope/Proxy/cluster.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: config.openshift.io/v1 -kind: Proxy -metadata: - annotations: - argocd.argoproj.io/sync-options: "ServerSideApply=true,Validate=false" - name: cluster -spec: - trustedCA: - name: redhat-current-it-root-cas diff --git a/configuration/overlays/stormshift-ocp5/cluster-scope/kustomization.yaml b/configuration/overlays/stormshift-ocp5/cluster-scope/kustomization.yaml index 3a54f2b..1eeb2e0 100644 --- a/configuration/overlays/stormshift-ocp5/cluster-scope/kustomization.yaml +++ b/configuration/overlays/stormshift-ocp5/cluster-scope/kustomization.yaml @@ -2,4 +2,3 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - MachineConfig/ -- Proxy/ diff --git a/gitops-differ.Containerfile b/gitops-differ.Containerfile new file mode 100644 index 0000000..9d371eb --- /dev/null +++ b/gitops-differ.Containerfile @@ -0,0 +1,8 @@ +FROM registry.redhat.io/ubi9/ubi-minimal:latest + +ADD helper/install-kustomize.sh /usr/local/bin/ + +RUN microdnf install -y diffutils tar gzip \ + && install-kustomize.sh + + diff --git a/helper/differ.sh b/helper/differ.sh new file mode 100755 index 0000000..df905dd --- /dev/null +++ b/helper/differ.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# set -euo pipefail +# set -x +PR_FOLDER=$1 +MAIN_FOLDER=$2 + +kustomize_folders=( + "configuration/overlays/isar" +# "configuration/overlays/coe-cluster" + "configuration/overlays/stormshift-ocp1" +# "configuration/overlays/stormshift-ocp2" +# "configuration/overlays/stormshift-ocp3" + "configuration/overlays/stormshift-ocp4" + "configuration/overlays/stormshift-ocp5" +# "configuration/overlays/stormshift-ocp6" +# "configuration/overlays/stormshift-ocp7" +# "configuration/overlays/stormshift-ocp8" +# "configuration/overlays/stormshift-rhacm" +) + +declare -a kustomize_folders_with_changes + +echo -e "# Diff overview \n\n" > /tmp/diff-overview.md + +echo -e "|Environment|Amount of diff lines|" >> /tmp/diff-overview.md +echo -e "|---|---|" >> /tmp/diff-overview.md + + +for folder in ${kustomize_folders[@]}; do + + env_name=$(basename $folder) + echo "Let's check $folder" + + kustomize build \ + ${PR_FOLDER}/$folder \ + > /tmp/${env_name}.pr.yaml + + kustomize build \ + ${MAIN_FOLDER}/$folder \ + > /tmp/${env_name}.main.yaml + + diff -Nuar \ + /tmp/${env_name}.main.yaml \ + /tmp/${env_name}.pr.yaml \ + > /tmp/${env_name}.diff + + echo "Created /tmp/${env_name}.diff" + amount_of_diff_lines=$(cat /tmp/${env_name}.diff | wc -l) + if [ "$amount_of_diff_lines" -gt "0" ]; then + kustomize_folders_with_changes+=($folder) + fi + echo -e "|\`$folder\`| $amount_of_diff_lines" >> /tmp/diff-overview.md +done; + + +for folder in ${kustomize_folders_with_changes[@]}; do + env_name=$(basename $folder) + echo "Dump diff $folder ($env_name)"; + echo -e "\n\n" >> /tmp/diff-overview.md + echo "
" >> /tmp/diff-overview.md + echo -e "Diff $folder\n\n" >> /tmp/diff-overview.md + echo '```diff' >> /tmp/diff-overview.md + cat /tmp/${env_name}.diff >> /tmp/diff-overview.md + echo '```' >> /tmp/diff-overview.md + echo '
' >> /tmp/diff-overview.md + echo -e "\n\n" >> /tmp/diff-overview.md + +done; diff --git a/helper/install-kustomize.sh b/helper/install-kustomize.sh new file mode 100755 index 0000000..6e70651 --- /dev/null +++ b/helper/install-kustomize.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +ARCH=$(uname -i) + + +case $ARCH in + + aarch64) + GO_ARCH=arm64 + ;; + + x86_64) + GO_ARCH=amd64 + ;; + *) + exit 99 + ;; +esac + +echo "Download kustomize_v5.5.0_linux_${GO_ARCH}.tar.gz" +curl -# -L -O https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.5.0/kustomize_v5.5.0_linux_${GO_ARCH}.tar.gz +tar xzf kustomize_v5.5.0_linux_${GO_ARCH}.tar.gz +mv -v kustomize /usr/local/bin/ +rm -v kustomize_v5.5.0_linux_${GO_ARCH}.tar.gz