Skip to content

Commit ab6334a

Browse files
frewilhelmjakobmoellerdevikhandamirov
authored
Implement Single Layer OCI Artifacts (#98)
Fixes #75 --------- Co-authored-by: Jakob Möller <[email protected]> Co-authored-by: ikhandamirov <[email protected]> Co-authored-by: Ilya Khandamirov <[email protected]>
1 parent fb4ec80 commit ab6334a

File tree

107 files changed

+3971
-2431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+3971
-2431
lines changed

.github/workflows/tests.yaml

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ permissions:
1616

1717
jobs:
1818
tests:
19-
runs-on: ubuntu-latest
19+
runs-on: large_runner
2020
steps:
2121
- name: Checkout
2222
uses: actions/checkout@v4
@@ -105,81 +105,24 @@ jobs:
105105
kubectl wait pod -l app=protected-registry1 --for condition=Ready --timeout 5m
106106
kubectl wait pod -l app=protected-registry2 --for condition=Ready --timeout 5m
107107
108-
- name: Install external CRDs
109-
run: kubectl apply --server-side -k https://github.com/openfluxcd/artifact//config/crd?ref=v0.1.1
108+
- name: Setup Flux CLI
109+
uses: fluxcd/flux2/action@73fff7404f76953c0a224d12ca0dd276b8d9be63
110110

111-
- name: Checkout helm-controller
112-
uses: actions/checkout@v4
113-
with:
114-
repository: openfluxcd/helm-controller
115-
path: helm-controller
116-
117-
# TODO: Create helm-controller image in public repository to omit rebuilds
118-
- name: Install helm-controller
119-
env:
120-
IMG: localhost:31000/helm-controller:latest
121-
run: |
122-
make -C helm-controller docker-build
123-
make -C helm-controller docker-push
124-
make -C helm-controller install
125-
make -C helm-controller deploy
126-
kubectl wait deployment.apps/helm-controller --for condition=Available --namespace helm-system --timeout 5m
127-
kubectl logs --tail -1 -l app=helm-controller -n helm-system -f --ignore-errors &> helm-controller.log &
128-
129-
- name: Checkout kustomize-controller
130-
uses: actions/checkout@v4
131-
with:
132-
repository: openfluxcd/kustomize-controller
133-
path: kustomize-controller
111+
- name: Install Flux in Kind
112+
run: flux install
134113

135-
# TODO: Create kustomize-controller image in public repository to omit rebuilds
136-
- name: Install kustomize-controller
137-
env:
138-
IMG: localhost:31000/kustomize-controller:latest
139-
run: |
140-
make -C kustomize-controller docker-build
141-
make -C kustomize-controller docker-push
142-
make -C kustomize-controller install
143-
make -C kustomize-controller deploy
144-
kubectl wait deployment.apps/kustomize-controller --for condition=Available --namespace kustomize-system --timeout 5m
145-
kubectl logs --tail -1 -l app=kustomize-controller -n kustomize-system -f --ignore-errors &> kustomize-controller.log &
146-
147-
# TODO: Replace once the release with the 'skipDigestGeneration' field in the component constructor is available
148-
# uses: open-component-model/ocm-setup-action@main
149-
# with:
150-
# version: v0.19.0-rc.1
151-
- name: Set up cache for ocm (temporarily)
152-
uses: actions/cache@v4
153-
with:
154-
path: |
155-
ocm/bin
156-
key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
157-
restore-keys: |
158-
${{ env.cache_name }}-${{ runner.os }}-go-
159-
env:
160-
cache_name: dummy-cache
161-
- name: Checkout OCM (temporarily)
162-
uses: actions/checkout@v4
163-
with:
164-
repository: open-component-model/ocm
165-
path: ocm
166-
- name: Build OCM (temporarily)
167-
run: |
168-
make -C ocm bin/ocm
169-
echo "${{ github.workspace }}/ocm/bin" >> "$GITHUB_PATH"
114+
- name: Setup ocm
115+
uses: open-component-model/ocm-setup-action@9bb4321df9c9eb033b54ef3563101b299a754336
170116

171117
- name: Run e2e test
172118
env:
173119
RESOURCE_TIMEOUT: 5m
174-
HELM_CHART: ghcr.io/stefanprodan/charts/podinfo:6.7.1
175120
IMAGE_REFERENCE: ghcr.io/stefanprodan/podinfo:6.7.1
176121
CONTROLLER_LOG_PATH: ./ocm-k8s-toolkit-controller.log
177-
IMAGE_REGISTRY_URL: http://localhost:31000
178-
INTERNAL_IMAGE_REGISTRY_URL: http://registry-internal.default.svc.cluster.local:5000
179-
PROTECTED_REGISTRY_URL: http://localhost:31001
180-
INTERNAL_PROTECTED_REGISTRY_URL: http://protected-registry1-internal.default.svc.cluster.local:5001
181-
PROTECTED_REGISTRY_URL2: http://localhost:31002
182-
INTERNAL_PROTECTED_REGISTRY_URL2: http://protected-registry2-internal.default.svc.cluster.local:5002
122+
PROTECTED_REGISTRY_URL: http://localhost:31002
123+
INTERNAL_PROTECTED_REGISTRY_URL: http://protected-registry1-internal.default.svc.cluster.local:5002
124+
PROTECTED_REGISTRY_URL2: http://localhost:31003
125+
INTERNAL_PROTECTED_REGISTRY_URL2: http://protected-registry2-internal.default.svc.cluster.local:5003
183126
run: make test-e2e
184127

185128
- name: Publish logs on failure
@@ -188,7 +131,7 @@ jobs:
188131
with:
189132
name: controller-logs
190133
# Currently, it is planned that the integration tests runs on every commit on a PR. Therefore, we could
191-
# produce a lot of logs. To note clutter the storage, the retention-days are reduced to 1.
134+
# produce a lot of logs. To not clutter the storage, the retention-days are reduced to 1.
192135
retention-days: 1
193136
path: |
194137
helm-controller.log

Makefile

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ else
1010
GOBIN=$(shell go env GOBIN)
1111
endif
1212

13+
OS ?= $(shell go env GOOS)
14+
ARCH ?= $(shell go env GOARCH)
15+
16+
1317
# CONTAINER_TOOL defines the container tool to be used for building images.
1418
# Be aware that the target commands are only tested with Docker which is
1519
# scaffolded by default. However, you might want to replace it to use other
@@ -64,7 +68,7 @@ vet: ## Run go vet against code.
6468
go vet ./...
6569

6670
.PHONY: test
67-
test: manifests generate envtest ## Run tests.
71+
test: manifests generate envtest zot-registry ## Run tests.
6872
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6973

7074
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
@@ -152,7 +156,7 @@ deploy: deploy-cert-manager manifests kustomize ## Deploy controller to the K8s
152156
$(call set-images)
153157
$(KUSTOMIZE) build config/default-zot-https | $(KUBECTL) apply -f -
154158

155-
# Undeploy target undeploys the controller, its zot regostry and related certificates.
159+
# Undeploy target undeploys the controller, its zot registry and related certificates.
156160
# However, it does not undeploy the cert-manager, which might still be needed by other applications in the cluster.
157161
# If you wish to undeploy cert manager as well, execute 'make undeploy-cert-manager' in addition.
158162
.PHONY: undeploy
@@ -171,6 +175,7 @@ KUBECTL ?= kubectl
171175
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
172176
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
173177
ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
178+
ZOT_BINARY ?= $(LOCALBIN)/zot-registry
174179

175180
## Tool Versions
176181
KUSTOMIZE_VERSION ?= v5.4.1
@@ -211,6 +216,14 @@ deploy-cert-manager: ## Deploy cert-manager to the K8s cluster specified in ~/.k
211216
undeploy-cert-manager: ## Undeploy cert-manager from the K8s cluster specified in ~/.kube/config.
212217
$(KUBECTL) delete --ignore-not-found=$(IGNORE_NOT_FOUND) -f $(CERT-MANAGER_YAML)
213218

219+
.PHONY: zot-registry
220+
zot-registry: $(LOCALBIN) ## Download zot registry binary locally if necessary.
221+
ifeq (, $(shell which $(ZOT_BINARY)))
222+
wget "https://github.com/project-zot/zot/releases/download/$(ZOT_VERSION)/zot-$(OS)-$(ARCH)-minimal" \
223+
-O $(ZOT_BINARY) \
224+
&& chmod u+x $(ZOT_BINARY)
225+
endif
226+
214227
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
215228
# $1 - target path with name of binary (ideally with version)
216229
# $2 - package url which can be installed

PROJECT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@ resources:
7171
kind: Replication
7272
path: github.com/open-component-model/ocm-k8s-toolkit/api/v1alpha1
7373
version: v1alpha1
74-
version: "3"
74+
version: "3"

api/v1alpha1/common_types.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,32 @@ type ResourceInfo struct {
113113
// +required
114114
Digest string `json:"digest,omitempty"`
115115
}
116+
117+
type BlobInfo struct {
118+
// Digest is the digest of the blob.
119+
Digest string `json:"digest"`
120+
121+
// Tag/Version of the blob.
122+
// Corresponds to the tag the blob is available in the OCI registry.
123+
Tag string `json:"tag"`
124+
125+
// Size is the number of bytes of the blob.
126+
// Can be used to determine how to file should be handled when downloaded (memory/disk).
127+
Size int64 `json:"size"`
128+
}
129+
130+
// OCIArtifactInfo contains information on how to locate an OCI Artifact.
131+
type OCIArtifactInfo struct {
132+
// OCI repository name
133+
// +required
134+
Repository string `json:"repository"`
135+
136+
// Manifest digest
137+
// Used to fetch single layer OCI artifact and remove manifests
138+
// +required
139+
Digest string `json:"digest"`
140+
141+
// Blob
142+
// +required
143+
Blob BlobInfo `json:"blob"`
144+
}

api/v1alpha1/component_types.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"fmt"
2121
"time"
2222

23-
corev1 "k8s.io/api/core/v1"
2423
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2524
)
2625

@@ -100,12 +99,6 @@ type ComponentStatus struct {
10099
// +optional
101100
Conditions []metav1.Condition `json:"conditions,omitempty"`
102101

103-
// ArtifactRef references the generated artifact containing a list of
104-
// component descriptors. This list can be used by other controllers to
105-
// avoid re-downloading (and potentially also re-verifying) the components.
106-
// +optional
107-
ArtifactRef corev1.LocalObjectReference `json:"artifactRef,omitempty"`
108-
109102
// Component specifies the concrete version of the component that was
110103
// fetched after based on the semver constraints during the last successful
111104
// reconciliation.
@@ -117,6 +110,12 @@ type ComponentStatus struct {
117110
// in the order the configuration data was applied.
118111
// +optional
119112
EffectiveOCMConfig []OCMConfiguration `json:"effectiveOCMConfig,omitempty"`
113+
114+
// OCIArtifact references the generated OCI artifact containing a list of
115+
// component descriptors. This list can be used by other controllers to
116+
// avoid re-downloading (and potentially also re-verifying) the components.
117+
// +optional
118+
OCIArtifact *OCIArtifactInfo `json:"ociArtifact,omitempty"`
120119
}
121120

122121
// +kubebuilder:object:root=true
@@ -180,6 +179,28 @@ func (in *Component) GetVerifications() []Verification {
180179
return in.Spec.Verify
181180
}
182181

182+
func (in *Component) GetOCIArtifact() *OCIArtifactInfo {
183+
return in.Status.OCIArtifact
184+
}
185+
186+
// GetOCIRepository returns the name of the OCI repository of the OCI artifact in which the component
187+
// descriptors are stored.
188+
func (in *Component) GetOCIRepository() string {
189+
return in.Status.OCIArtifact.Repository
190+
}
191+
192+
// GetManifestDigest returns the manifest digest of the OCI artifact, in which the component descriptors
193+
// are stored.
194+
func (in *Component) GetManifestDigest() string {
195+
return in.Status.OCIArtifact.Digest
196+
}
197+
198+
// GetBlobDigest returns the blob digest of the OCI artifact, in which the component descriptors
199+
// are stored.
200+
func (in *Component) GetBlobDigest() string {
201+
return in.Status.OCIArtifact.Blob.Digest
202+
}
203+
183204
// +kubebuilder:object:root=true
184205

185206
// ComponentList contains a list of Component.

api/v1alpha1/condition_types.go

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,16 @@ limitations under the License.
1717
package v1alpha1
1818

1919
const (
20-
// SecretFetchFailedReason is used when the controller failed to fetch its secrets.
21-
SecretFetchFailedReason = "SecretFetchFailed"
22-
2320
// ConfigFetchFailedReason is used when the controller failed to fetch its configs.
2421
ConfigFetchFailedReason = "ConfigFetchFailed"
2522

26-
// VerificationsInvalidReason is used when the controller failed to gather the verification information.
27-
VerificationsInvalidReason = "VerificationsInvalid"
28-
2923
// ConfigureContextFailedReason is used when the controller failed to create an authenticated context.
3024
ConfigureContextFailedReason = "ConfigureContextFailed"
3125

3226
// CheckVersionFailedReason is used when the controller failed to check for new versions.
3327
CheckVersionFailedReason = "CheckVersionFailed"
3428

35-
// RepositorySpecInvalidReason is used when the referenced repository spec cannot be unmarshaled and therefore is
29+
// RepositorySpecInvalidReason is used when the referenced repository spec cannot be unmarshalled and therefore is
3630
// invalid.
3731
RepositorySpecInvalidReason = "RepositorySpecInvalid"
3832

@@ -42,7 +36,7 @@ const (
4236
// ComponentIsNotReadyReason is used when the referenced component is not Ready yet.
4337
ComponentIsNotReadyReason = "ComponentIsNotReady"
4438

45-
// ComponentIsNotReadyReason is used when the referenced component is not Ready yet.
39+
// ReplicationFailedReason is used when the referenced component is not Ready yet.
4640
ReplicationFailedReason = "ReplicationFailed"
4741

4842
// VerificationFailedReason is used when the signature verification of a component failed.
@@ -57,23 +51,50 @@ const (
5751
// GetComponentVersionFailedReason is used when the component cannot be fetched.
5852
GetComponentVersionFailedReason = "GetComponentVersionFailed"
5953

60-
// StorageReconcileFailedReason is used when there was a problem reconciling the artifact storage.
61-
StorageReconcileFailedReason = "StorageReconcileFailed"
54+
// MarshalFailedReason is used when we fail to marshal a struct.
55+
MarshalFailedReason = "MarshalFailed"
56+
57+
// YamlToJSONDecodeFailedReason is used when we fail to decode yaml to json.
58+
YamlToJSONDecodeFailedReason = "YamlToJsonDecodeFailed"
59+
60+
// CreateOCIRepositoryNameFailedReason is used when we fail to create an OCI repository name.
61+
CreateOCIRepositoryNameFailedReason = "CreateOCIRepositoryNameFailed"
62+
63+
// CreateOCIRepositoryFailedReason is used when we fail to create an OCI repository.
64+
CreateOCIRepositoryFailedReason = "CreateOCIRepositoryFailed"
65+
66+
// PushOCIArtifactFailedReason is used when we fail to push an OCI artifact.
67+
PushOCIArtifactFailedReason = "PushOCIArtifactFailed"
6268

63-
// ReconcileArtifactFailedReason is used when we fail in creating an Artifact.
64-
ReconcileArtifactFailedReason = "ReconcileArtifactFailed"
69+
// FetchOCIArtifactFailedReason is used when we fail to fetch an OCI artifact.
70+
FetchOCIArtifactFailedReason = "FetchOCIArtifactFailed"
6571

66-
// GetArtifactFailedReason is used when we fail in getting an Artifact.
67-
GetArtifactFailedReason = "GetArtifactFailed"
72+
// CopyOCIArtifactFailedReason is used when we fail to copy an OCI artifact.
73+
CopyOCIArtifactFailedReason = "CopyOCIArtifactFailed"
74+
75+
// DeleteArtifactFailedReason is used when we fail to copy an OCI artifact.
76+
DeleteOCIArtifactFailedReason = "DeleteOCIArtifactFailed"
77+
78+
// OCIRepositoryExistsFailedReason is used when we fail to check the existence of an OCI repository.
79+
OCIRepositoryExistsFailedReason = "OCIRepositoryExistsFailed"
6880

6981
// ResolveResourceFailedReason is used when we fail in resolving a resource.
7082
ResolveResourceFailedReason = "ResolveResourceFailed"
7183

7284
// GetResourceAccessFailedReason is used when we fail in getting a resource access(es).
7385
GetResourceAccessFailedReason = "GetResourceAccessFailed"
7486

75-
// GetComponentForArtifactFailedReason is used when we fail in getting a component for an artifact.
76-
GetComponentForArtifactFailedReason = "GetComponentForArtifactFailed"
87+
// GetBlobAccessFailedReason is used when we fail to get a blob access.
88+
GetBlobAccessFailedReason = "GetBlobAccessFailed"
89+
90+
// VerifyResourceFailedReason is used when we fail to verify a resource.
91+
VerifyResourceFailedReason = "VerifyResourceFailed"
92+
93+
// GetResourceFailedReason is used when we fail to get the resource.
94+
GetResourceFailedReason = "GetResourceFailed"
95+
96+
// CompressGzipFailedReason is used when we fail to compress to gzip.
97+
CompressGzipFailedReason = "CompressGzipFailed"
7798

7899
// StatusSetFailedReason is used when we fail to set the component status.
79100
StatusSetFailedReason = "StatusSetFailed"
@@ -84,14 +105,17 @@ const (
84105
// ConfigurationFailedReason is used when a resource was not able to be configured.
85106
ConfigurationFailedReason = "ConfigurationFailed"
86107

87-
// LocalizationRuleGenerationFailedReason is used when the controller failed to localize an artifact.
108+
// CreateTGZFailedReason is used when a TGZ creation failed.
109+
CreateTGZFailedReason = "CreateTGZFailed"
110+
111+
// LocalizationRuleGenerationFailedReason is used when the controller failed to localize an OCI artifact.
88112
LocalizationRuleGenerationFailedReason = "LocalizationRuleGenerationFailed"
89113

90114
// LocalizationIsNotReadyReason is used when a controller is waiting to get the localization result.
91115
LocalizationIsNotReadyReason = "LocalizationIsNotReady"
92116

93-
// UniqueIDGenerationFailedReason is used when the controller failed to generate a unique identifier for a pending artifact.
94-
// This can happen if the artifact is based on multiple other sources but these sources could not be used
117+
// UniqueIDGenerationFailedReason is used when the controller failed to generate a unique identifier for a pending OCI artifact.
118+
// This can happen if the OCI artifact is based on multiple other sources but these sources could not be used
95119
// to determine a unique identifier.
96120
UniqueIDGenerationFailedReason = "UniqueIDGenerationFailed"
97121

0 commit comments

Comments
 (0)