Skip to content

Commit c7b99ca

Browse files
committed
merge
2 parents fba88a9 + db39895 commit c7b99ca

File tree

22 files changed

+1025
-469
lines changed

22 files changed

+1025
-469
lines changed

.github/workflows/build.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ defaults:
2424
jobs:
2525
test:
2626
name: Run tests
27-
runs-on: ubuntu-22.04
27+
runs-on: ubuntu-24.04
2828

2929
steps:
3030
- name: Checkout repository
@@ -74,7 +74,7 @@ jobs:
7474
7575
build-docker:
7676
name: Build Docker image
77-
runs-on: ubuntu-22.04
77+
runs-on: ubuntu-24.04
7878
needs: test
7979
permissions:
8080
contents: read
@@ -128,7 +128,7 @@ jobs:
128128

129129
test-helm:
130130
name: Run Helm chart tests
131-
runs-on: ubuntu-22.04
131+
runs-on: ubuntu-24.04
132132
needs: build-docker
133133

134134
steps:

.github/workflows/publish.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ defaults:
1919
jobs:
2020
publish-go-module:
2121
name: Publish go module
22-
runs-on: ubuntu-22.04
22+
runs-on: ubuntu-24.04
2323

2424
steps:
2525
- name: Trigger registration on sum.golang.org
@@ -34,7 +34,7 @@ jobs:
3434
3535
validate:
3636
name: Run validations
37-
runs-on: ubuntu-22.04
37+
runs-on: ubuntu-24.04
3838

3939
steps:
4040
- name: Checkout repository
@@ -55,7 +55,7 @@ jobs:
5555
5656
publish-docker:
5757
name: Publish Docker image
58-
runs-on: ubuntu-22.04
58+
runs-on: ubuntu-24.04
5959
needs: validate
6060
permissions:
6161
contents: read
@@ -106,7 +106,7 @@ jobs:
106106

107107
publish-crds:
108108
name: Publish CRD image
109-
runs-on: ubuntu-22.04
109+
runs-on: ubuntu-24.04
110110
needs: validate
111111
permissions:
112112
contents: read
@@ -140,7 +140,7 @@ jobs:
140140
141141
publish-chart:
142142
name: Publish chart to github packages
143-
runs-on: ubuntu-22.04
143+
runs-on: ubuntu-24.04
144144
needs: validate
145145
permissions:
146146
contents: read

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ defaults:
3737
jobs:
3838
release:
3939
name: Trigger release
40-
runs-on: ubuntu-22.04
40+
runs-on: ubuntu-24.04
4141
permissions:
4242
contents: write
4343

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ RUN make envtest \
2525
&& CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go
2626

2727
# Create final image
28-
FROM alpine:3.20
28+
FROM alpine:3.21
2929
WORKDIR /
3030
ENV GNUPGHOME=/tmp
3131
ENTRYPOINT ["/usr/local/bin/manager"]

README.md

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Here, components are understood as sets of Kubernetes resources (such as deploym
1212

1313
Thus, components are similar to flux kustomizations, but have some important advantages:
1414
- They use the [component-operator-runtime](https://github.com/sap/component-operator-runtime) framework to render and deploy dependent objects; therefore the manifest source can be any input that is understood by component-operator-runtime's [KustomizeGenerator](https://sap.github.io/component-operator-runtime/docs/generators/kustomize/) or [HelmGenerator](https://sap.github.io/component-operator-runtime/docs/generators/helm/). In particular, go-templatized kustomizations are allowed; check the [component-operator-runtime documentation](https://sap.github.io/component-operator-runtime/docs) for details.
15-
- It is possible to pin components to a specific source revision through the `spec.revision` field.
15+
- It is possible to pin components to a specific source revision or digest through the `spec.revision` and `spec.digest` fields, respectively.
1616
- Dependencies (as specified in `spec.dependencies`) are not only honored at creation/update, but also on deletion.
1717

1818
A sample component could look like this:
@@ -111,12 +111,12 @@ sourceRef:
111111

112112
Cross-namespace references are allowed; if namespace is not provided, the source will be assumed to exist in the component's namespace.
113113

114-
### Source revision
114+
### Source revision and digest
115115

116-
It is possible to pin a `Component` resource to a specific revision of the source artifact by setting `spec.revision`.
117-
Pinning means that the component will remain in a `Pending` state, until the used source object's revision matches the the value
118-
specified in `spec.revision`. More precisely, in case of flux source resources, the field refers to `status.artifact.revision` of the flux object.
119-
It should be noted that a revision mismatch in the above sense never blocks the deletion of the component.
116+
It is possible to pin a `Component` resource to a specific revision or digest of the source artifact by setting `spec.revision` and `spec.digest`, respectively.
117+
Pinning means that the component will remain in a `Pending` state, until the used source object's revision or digest matches the the value
118+
specified in `spec.revision` or `spec.digest`. In case of flux sources, revision and digest refer to `status.artifact.revision` and `status.artifact.digest` of the according flux object.
119+
It should be noted that a revision or digest mismatch in the above sense never blocks the deletion of the component.
120120

121121
### Source path
122122

@@ -154,6 +154,33 @@ The replacements may be defined either inline in `spec.postBuild.substitute` as
154154
the keys of the secrets will be interpreted as variable names (and therefore have to be valid bash variable names). If multiple secrets, and
155155
maybe inline substitutions are provided, they will be merged in the usual order (secrets in order of appearance, and then inline content).
156156

157+
### Adoption policy
158+
159+
It can happen that a dependent object exists in the cluster already, but is not managed by the component object being reconciled (the ownership is determined through the label `component-operator.cs.sap.com/owner-id`). The behaviour of component-operator in that situation can be configured by setting `spec.adoptionPolicy`. The following values are possible:
160+
- `IfUnowned` (which is also the default behaviour if the adoption policy attribute is unset): adopt existing objects, unless they have the above label set, but with a value pointing to a different owning component; in that case, a failure will occur
161+
- `Never`: always fail if an object already exists (not owned by the current component of course)
162+
- `Always`: always adopt existing objects.
163+
164+
The adoption policy can be overridden on a per-object level by setting annotation `component-operator.cs.sap.com/adoption-policy`.
165+
166+
### Update policy
167+
168+
It is possible to tweak how component-operator performs updates of dependent objects by setting `spec.updatePolicy`. The following values are supported:
169+
- `Replace`: use a PUT request to update the object; this corresponds to `kubectl replace`
170+
- `Recreate`: delete and recreate objects which are to be updated
171+
- `SsaMerge`: use a server-side-apply PATCH request to update the object; this corresponds to `kubectl apply --server-side --force-conflicts`
172+
- `SsaOverride` (which is the default behaviour if the update policy is not specified): same as `SsaMerge` and, in addition, claim all existing fields that have a field owner starting with prefix `kubectl` or `helm`; this reverts changes done by these field managers, respectively drops affected fields if not specified by the submitted intent and not owned by somebody else.
173+
174+
The update policy can be overridden on a per-object level by setting annotation `component-operator.cs.sap.com/update-policy`.
175+
176+
### Delete policy
177+
178+
It is possible to tweak what happens with dependents objects when the owning component is deleted. By default objects are deleted.
179+
By setting `spec.deletePolicy` to `Orphan`, dependent objects will not be deleted in that case, but just left around in the cluster.
180+
Note that this affects only the case when the component is deleted. If a depdendent object becomes obsolete because a new revision
181+
of the component manifests does no longer contain it, it will still be removed from the cluster.
182+
The delete policy can be overridden on a per-object level by setting annotation `component-operator.cs.sap.com/delete-policy`.
183+
157184
### Dependencies
158185

159186
As with flux kustomizations, it is possible to declare dependencies between `Component` objects, that means, to list other components,

api/v1alpha1/types.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ type ComponentSpec struct {
2424
component.RequeueSpec `json:",inline"`
2525
component.RetrySpec `json:",inline"`
2626
component.TimeoutSpec `json:",inline"`
27+
component.PolicySpec `json:",inline"`
2728
// +required
2829
SourceRef SourceReference `json:"sourceRef"`
30+
Digest string `json:"digest,omitempty"`
2931
Revision string `json:"revision,omitempty"`
3032
Path string `json:"path,omitempty"`
3133
Values *apiextensionsv1.JSON `json:"values,omitempty"`
@@ -36,26 +38,29 @@ type ComponentSpec struct {
3638
}
3739

3840
// SourceReference models the source of the templates used to render the dependent resources.
39-
// Exactly one of the options must be provided. Before accessing the Url() or Revision() methods,
40-
// a SourceReference must be loaded by calling LoadSourceReference().
41+
// Exactly one of the options must be provided. Before accessing the Url(), Digest() or Revision() methods,
42+
// a SourceReference must be loaded by calling Init().
4143
type SourceReference struct {
44+
HttpRepository *HttpRepository `json:"httpRepository,omitempty"`
4245
FluxGitRepository *FluxGitRepository `json:"fluxGitRepository,omitempty"`
4346
FluxOciRepository *FluxOciRepository `json:"fluxOciRepository,omitempty"`
4447
FluxBucket *FluxBucket `json:"fluxBucket,omitempty"`
4548
FluxHelmChart *FluxHelmChart `json:"fluxHelmChart,omitempty"`
4649
url string `json:"-"`
50+
digest string `json:"-"`
4751
revision string `json:"-"`
4852
loaded bool `json:"-"`
4953
}
5054

5155
// Initialize source reference. This is meant to be called by the reconciler.
5256
// Other consumers should probably not (need to) call this.
53-
func (r *SourceReference) Init(url string, revision string) {
57+
func (r *SourceReference) Init(url string, digest string, revision string) {
5458
if r.loaded {
5559
// note: this panic indicates a programmatic error on the consumer side
5660
panic("reference already initialized")
5761
}
5862
r.url = url
63+
r.digest = digest
5964
r.revision = revision
6065
r.loaded = true
6166
}
@@ -71,8 +76,18 @@ func (r *SourceReference) Url() string {
7176
return r.url
7277
}
7378

79+
// Get the digest of a loaded source reference. Calling Digest() on a not-loaded source reference will panic.
80+
// The returned digest uniquely identifies the content of the referenced archive.
81+
func (r *SourceReference) Digest() string {
82+
if !r.loaded {
83+
// note: this panic indicates a programmatic error on the consumer side
84+
panic("access to unloaded reference")
85+
}
86+
return r.digest
87+
}
88+
7489
// Get the revision of a loaded source reference. Calling Revision() on a not-loaded source reference will panic.
75-
// The returned revision is unique for the referenced archive (usually a Git SHA or hash or digest).
90+
// The returned revision is often but not always unique for the referenced archive (usually a Git SHA or hash or digest).
7691
func (r *SourceReference) Revision() string {
7792
if !r.loaded {
7893
// note: this panic indicates a programmatic error on the consumer side
@@ -83,12 +98,27 @@ func (r *SourceReference) Revision() string {
8398

8499
// Check if source reference equals other given source reference.
85100
func (r *SourceReference) Equals(s *SourceReference) bool {
86-
return equal(r.FluxGitRepository, s.FluxGitRepository) &&
101+
return equal(r.HttpRepository, s.HttpRepository) &&
102+
equal(r.FluxGitRepository, s.FluxGitRepository) &&
87103
equal(r.FluxOciRepository, s.FluxOciRepository) &&
88104
equal(r.FluxBucket, s.FluxBucket) &&
89105
equal(r.FluxHelmChart, s.FluxHelmChart)
90106
}
91107

108+
// Reference to a generic http repository.
109+
type HttpRepository struct {
110+
// URL of the source. Authentication is currently not supported. The operator will make HEAD requests to retrieve the digest/revision
111+
// and a potentially redirected actual location of the source artifact. Redirects will be followed as long as the response does not
112+
// contain the specified digest header.
113+
Url string `json:"url,omitempty"`
114+
// Name of the header containing the digest of the source artifact. The returned header value can be any format, but must uniquely identify the
115+
// content of the source artifact. Defaults to the ETag header.
116+
DigestHeader string `json:"digestHeader,omitempty"`
117+
// Name of the header containing the revision of the source artifact. The returned header value can be any format.
118+
// Defaults to the header specified in DigestHeader.
119+
RevisionHeader string `json:"revisionHeader,omitempty"`
120+
}
121+
92122
// Reference to a flux GitRepository.
93123
type FluxGitRepository struct {
94124
NamespacedName `json:",inline"`
@@ -163,7 +193,9 @@ func (n NamespacedName) String() string {
163193
// ComponentStatus defines the observed state of Component.
164194
type ComponentStatus struct {
165195
component.Status `json:",inline"`
196+
LastAttemptedDigest string `json:"lastAttemptedDigest,omitempty"`
166197
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
198+
LastAppliedDigest string `json:"lastAppliedDigest,omitempty"`
167199
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
168200
}
169201

@@ -195,7 +227,7 @@ func (c *Component) NamespacedName() apitypes.NamespacedName {
195227

196228
// Reports the readiness of the component.
197229
func (c *Component) IsReady() bool {
198-
return c.Status.IsReady()
230+
return c.Status.ObservedGeneration == c.Generation && c.Status.IsReady()
199231
}
200232

201233
// +kubebuilder:object:root=true

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chart/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ apiVersion: v2
22
name: component-operator
33
description: A Helm chart for https://github.com/sap/component-operator
44
type: application
5-
version: 0.1.8
6-
appVersion: v0.1.8
5+
version: 0.1.13
6+
appVersion: v0.1.13

chart/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# component-operator
22

3-
![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.1.8](https://img.shields.io/badge/AppVersion-v0.1.8-informational?style=flat-square)
3+
![Version: 0.1.13](https://img.shields.io/badge/Version-0.1.13-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.1.13](https://img.shields.io/badge/AppVersion-v0.1.13-informational?style=flat-square)
44

55
A Helm chart for https://github.com/sap/component-operator
66

0 commit comments

Comments
 (0)