12
12
TAG := $(shell git rev-parse --short HEAD)
13
13
OPERATOR_NAME := stackable-cockpit
14
14
VERSION := $(shell cargo metadata --format-version 1 | jq -r '.packages[] | select(.name=="stackable-cockpitd") | .version')
15
+ ARCH := $(shell uname -m | sed -e 's#x86_64#amd64#' | sed -e 's#aarch64#arm64#')
15
16
16
17
DOCKER_REPO := docker.stackable.tech
17
18
ORGANIZATION := stackable
18
- # this will be overwritten by an environmental variable if called from the github action
19
+ OCI_REGISTRY_HOSTNAME := oci.stackable.tech
20
+ OCI_REGISTRY_PROJECT_IMAGES := sdp
21
+ OCI_REGISTRY_PROJECT_CHARTS := sdp-charts
22
+ # This will be overwritten by an environmental variable if called from the github action
19
23
HELM_REPO := https://repo.stackable.tech/repository/helm-dev
24
+ HELM_CHART_NAME := ${OPERATOR_NAME}
20
25
HELM_CHART_ARTIFACT := target/helm/${OPERATOR_NAME}-${VERSION}.tgz
21
26
22
27
SHELL =/usr/bin/env bash -euo pipefail
@@ -27,11 +32,84 @@ SHELL=/usr/bin/env bash -euo pipefail
27
32
28
33
# # Docker related targets
29
34
docker-build :
30
- docker build --force-rm --build-arg VERSION=${VERSION} -t " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} " -f docker/Dockerfile .
35
+ docker build --force-rm --build-arg VERSION=${VERSION} -t " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} -${ARCH} " -f docker/Dockerfile .
36
+ docker tag " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} -${ARCH} " " ${OCI_REGISTRY_HOSTNAME} /${OCI_REGISTRY_PROJECT_IMAGES} /${OPERATOR_NAME} :${VERSION} -${ARCH} "
31
37
32
38
docker-publish :
39
+ # Push to Nexus
33
40
echo " ${NEXUS_PASSWORD} " | docker login --username github --password-stdin " ${DOCKER_REPO} "
34
- docker push --all-tags " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} "
41
+ DOCKER_OUTPUT=$$(docker push --all-tags "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}" ) ; \
42
+ # Obtain the digest of the pushed image from the output of `docker push`, because signing by tag is deprecated and will be removed from cosign in the future\
43
+ REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}-${ARCH}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }' ) ; \
44
+ if [ -z " $$ REPO_DIGEST_OF_IMAGE" ]; then\
45
+ echo ' Could not find repo digest for container image: ${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}' ; \
46
+ exit 1; \
47
+ fi ; \
48
+ # This generates a signature and publishes it to the registry, next to the image\
49
+ # Uses the keyless signing flow with Github Actions as identity provider\
50
+ cosign sign -y " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} @$$ REPO_DIGEST_OF_IMAGE" ; \
51
+ # Generate the SBOM for the operator image, this leverages the already generated SBOM for the operator binary by cargo-cyclonedx\
52
+ syft scan --output cyclonedx-json=sbom.json --select-catalogers " -cargo-auditable-binary-cataloger" --scope all-layers --source-name " ${OPERATOR_NAME} " --source-version " ${VERSION} " " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} @$$ REPO_DIGEST_OF_IMAGE" ; \
53
+ # Determine the PURL for the container image\
54
+ PURL=" pkg:docker/${ORGANIZATION} /${OPERATOR_NAME} @$$ REPO_DIGEST_OF_IMAGE?repository_url=${DOCKER_REPO} " ; \
55
+ # Get metadata from the image\
56
+ IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}" ) ; \
57
+ IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-${ARCH}" ) ; \
58
+ # Merge the SBOM with the metadata for the operator\
59
+ jq -s ' {"metadata":{"component":{"description":"' " $$ IMAGE_NAME. $$ IMAGE_DESCRIPTION" ' ","supplier":{"name":"Stackable GmbH","url":["https://stackable.tech/"]},"author":"Stackable GmbH","purl":"' " $$ PURL" ' ","publisher":"Stackable GmbH"}}} * .[0]' sbom.json > sbom.merged.json; \
60
+ # Attest the SBOM to the image\
61
+ cosign attest -y --predicate sbom.merged.json --type cyclonedx " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} @$$ REPO_DIGEST_OF_IMAGE"
62
+
63
+ # Push to Harbor
64
+ # We need to use "value" here to prevent the variable from being recursively expanded by make (username contains a dollar sign, since it's a Harbor bot)
65
+ docker login --username '${value OCI_REGISTRY_SDP_USERNAME}' --password '${OCI_REGISTRY_SDP_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}'
66
+ DOCKER_OUTPUT=$$(docker push --all-tags '${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}');\
67
+ # Obtain the digest of the pushed image from the output of `docker push`, because signing by tag is deprecated and will be removed from cosign in the future\
68
+ REPO_DIGEST_OF_IMAGE=$$(echo "$$DOCKER_OUTPUT" | awk '/^${VERSION}-${ARCH}: digest: sha256:[0-9a-f]{64} size: [0-9]+$$/ { print $$3 }');\
69
+ if [ -z "$$REPO_DIGEST_OF_IMAGE" ]; then\
70
+ echo 'Could not find repo digest for container image: ${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}';\
71
+ exit 1;\
72
+ fi;\
73
+ # This generates a signature and publishes it to the registry, next to the image\
74
+ # Uses the keyless signing flow with Github Actions as identity provider\
75
+ cosign sign -y "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE";\
76
+ # Generate the SBOM for the operator image, this leverages the already generated SBOM for the operator binary by cargo-cyclonedx\
77
+ syft scan --output cyclonedx-json=sbom.json --select-catalogers "-cargo-auditable-binary-cataloger" --scope all-layers --source-name "${OPERATOR_NAME}" --source-version "${VERSION}" "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE";\
78
+ # Determine the PURL for the container image\
79
+ PURL="pkg:docker/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE?repository_url=${OCI_REGISTRY_HOSTNAME}";\
80
+ # Get metadata from the image\
81
+ IMAGE_DESCRIPTION=$$(docker inspect --format='{{.Config.Labels.description}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
82
+ IMAGE_NAME=$$(docker inspect --format='{{.Config.Labels.name}}' "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}-${ARCH}");\
83
+ # Merge the SBOM with the metadata for the operator\
84
+ jq -s '{"metadata":{"component":{"description":"'"$$IMAGE_NAME. $$IMAGE_DESCRIPTION"'","supplier":{"name":"Stackable GmbH","url":["https://stackable.tech/"]},"author":"Stackable GmbH","purl":"'"$$PURL"'","publisher":"Stackable GmbH"}}} * .[0]' sbom.json > sbom.merged.json;\
85
+ # Attest the SBOM to the image\
86
+ cosign attest -y --predicate sbom.merged.json --type cyclonedx "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}@$$REPO_DIGEST_OF_IMAGE"
87
+
88
+ # This assumes "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-amd64 and "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}-arm64 are build and pushed
89
+ docker-manifest-list-build :
90
+ docker manifest create " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} " --amend " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} -amd64" --amend " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} -arm64"
91
+ docker manifest create " ${OCI_REGISTRY_HOSTNAME} /${OCI_REGISTRY_PROJECT_IMAGES} /${OPERATOR_NAME} :${VERSION} " --amend " ${OCI_REGISTRY_HOSTNAME} /${OCI_REGISTRY_PROJECT_IMAGES} /${OPERATOR_NAME} :${VERSION} -amd64" --amend " ${OCI_REGISTRY_HOSTNAME} /${OCI_REGISTRY_PROJECT_IMAGES} /${OPERATOR_NAME} :${VERSION} -arm64"
92
+
93
+ docker-manifest-list-publish :
94
+ # Push to Nexus
95
+ echo " ${NEXUS_PASSWORD} " | docker login --username github --password-stdin " ${DOCKER_REPO} "
96
+ # `docker manifest push` directly returns the digest of the manifest list
97
+ # As it is an experimental feature, this might change in the future
98
+ # Further reading: https://docs.docker.com/reference/cli/docker/manifest/push/
99
+ DIGEST_NEXUS=$$(docker manifest push "${DOCKER_REPO}/${ORGANIZATION}/${OPERATOR_NAME}:${VERSION}" ) ; \
100
+ # Refer to image via its digest (oci.stackable.tech/sdp/airflow@sha256:0a1b2c...)\
101
+ # This generates a signature and publishes it to the registry, next to the image\
102
+ # Uses the keyless signing flow with Github Actions as identity provider\
103
+ cosign sign -y " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} @$$ DIGEST_NEXUS"
104
+
105
+ # Push to Harbor
106
+ # We need to use "value" here to prevent the variable from being recursively expanded by make (username contains a dollar sign, since it's a Harbor bot)
107
+ docker login --username '${value OCI_REGISTRY_SDP_USERNAME}' --password '${OCI_REGISTRY_SDP_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}'
108
+ DIGEST_HARBOR=$$(docker manifest push "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}");\
109
+ # Refer to image via its digest (oci.stackable.tech/sdp/airflow@sha256:0a1b2c...);\
110
+ # This generates a signature and publishes it to the registry, next to the image\
111
+ # Uses the keyless signing flow with Github Actions as identity provider\
112
+ cosign sign -y "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}@$$DIGEST_HARBOR"
35
113
36
114
# TODO remove if not used/needed
37
115
docker : docker-build docker-publish
@@ -40,8 +118,25 @@ print-docker-tag:
40
118
@echo " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} "
41
119
42
120
helm-publish :
121
+ # Push to Nexus
43
122
curl --fail -u " github:${NEXUS_PASSWORD} " --upload-file " ${HELM_CHART_ARTIFACT} " " ${HELM_REPO} /"
44
123
124
+ # Push to Harbor
125
+ # We need to use "value" here to prevent the variable from being recursively expanded by make (username contains a dollar sign, since it's a Harbor bot)
126
+ helm registry login --username '${value OCI_REGISTRY_SDP_CHARTS_USERNAME}' --password '${OCI_REGISTRY_SDP_CHARTS_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}'
127
+ # Obtain the digest of the pushed artifact from the output of `helm push`, because signing by tag is deprecated and will be removed from cosign in the future\
128
+ HELM_OUTPUT=$$(helm push '${HELM_CHART_ARTIFACT}' 'oci://${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_CHARTS}' 2>&1);\
129
+ REPO_DIGEST_OF_ARTIFACT=$$(echo "$$HELM_OUTPUT" | awk '/^Digest: sha256:[0-9a-f]{64}$$/ { print $$2 }');\
130
+ if [ -z "$$REPO_DIGEST_OF_ARTIFACT" ]; then\
131
+ echo 'Could not find repo digest for helm chart: ${HELM_CHART_NAME}';\
132
+ exit 1;\
133
+ fi;\
134
+ # Login to Harbor, needed for cosign to be able to push the signature for the Helm chart\
135
+ docker login --username '${value OCI_REGISTRY_SDP_CHARTS_USERNAME}' --password '${OCI_REGISTRY_SDP_CHARTS_PASSWORD}' '${OCI_REGISTRY_HOSTNAME}';\
136
+ # This generates a signature and publishes it to the registry, next to the chart artifact\
137
+ # Uses the keyless signing flow with Github Actions as identity provider\
138
+ cosign sign -y "${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_CHARTS}/${HELM_CHART_NAME}@$$REPO_DIGEST_OF_ARTIFACT"
139
+
45
140
helm-package :
46
141
mkdir -p target/helm && helm package --destination target/helm deploy/helm/${OPERATOR_NAME}
47
142
@@ -62,29 +157,41 @@ config:
62
157
cp -r deploy/config-spec/* " deploy/helm/${OPERATOR_NAME} /configs" ; \
63
158
fi
64
159
65
- # crds:
66
- # mkdir -p deploy/helm/"${OPERATOR_NAME}"/crds
67
- # cargo run --bin "${OPERATOR_NAME}" -- crd | yq eval '.metadata.annotations["helm.sh/resource-policy"]="keep"' - > "deploy/helm/${OPERATOR_NAME}/crds/crds.yaml"
160
+ # crds:
161
+ # mkdir -p deploy/helm/"${OPERATOR_NAME}"/crds
162
+ # cargo run --bin stackable- "${OPERATOR_NAME}" -- crd | yq eval '.metadata.annotations["helm.sh/resource-policy"]="keep"' - > "deploy/helm/${OPERATOR_NAME}/crds/crds.yaml"
68
163
69
164
chart-lint : compile-chart
70
165
docker run -it -v $(shell pwd) :/build/helm-charts -w /build/helm-charts quay.io/helmpack/chart-testing:v3.5.0 ct lint --config deploy/helm/ct.yaml
71
166
72
167
clean : chart-clean
73
168
cargo clean
74
169
docker rmi --force " ${DOCKER_REPO} /${ORGANIZATION} /${OPERATOR_NAME} :${VERSION} "
170
+ docker rmi --force ' ${OCI_REGISTRY_HOSTNAME}/${OCI_REGISTRY_PROJECT_IMAGES}/${OPERATOR_NAME}:${VERSION}'
75
171
76
172
regenerate-charts : chart-clean compile-chart
77
173
78
- # The explicit '--extra-experimental-features flakes' parameter was added,
79
- # because the command requires Flakes to be enabled, but most non-Nix users
80
- # don't enable them via the global nix rc file.
81
174
regenerate-nix :
82
- nix run --extra-experimental-features flakes -f . regenerateNixLockfiles
175
+ nix run --extra-experimental-features " nix-command flakes" -f . regenerateNixLockfiles
83
176
84
177
build : regenerate-charts regenerate-nix helm-package docker-build
85
178
179
+ # This target is used by the CI
180
+ # It doesn't make use of any nix dependencies and thus aviods building the
181
+ # operator unnecessarily often.
182
+ build-ci : regenerate-charts helm-package docker-build
183
+
86
184
publish : docker-publish helm-publish
87
185
88
- run-dev :
186
+ check-nix :
187
+ @which nix || (echo " Error: 'nix' is not installed. Please install it to proceed." ; exit 1)
188
+
189
+ check-kubernetes :
190
+ @kubectl cluster-info > /dev/null 2>&1 || (echo " Error: Kubernetes is not running or kubectl is not properly configured." ; exit 1)
191
+
192
+ run-dev : check-nix check-kubernetes
89
193
kubectl apply -f deploy/stackable-operators-ns.yaml
90
- nix run -f. tilt -- up --port 5480 --namespace stackable-operators
194
+ nix run --extra-experimental-features " nix-command flakes" -f. tilt -- up --port 5480 --namespace stackable-operators
195
+
196
+ stop-dev : check-nix check-kubernetes
197
+ nix run --extra-experimental-features " nix-command flakes" -f. tilt -- down
0 commit comments