Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ linters:
settings:
dupword:
# Do not choke on SQL statements like `INSERT INTO things (foo, bar, baz) VALUES (TRUE, TRUE, TRUE)`.
ignore: [ "TRUE", "FALSE", "NULL" ]
ignore: ["TRUE", "FALSE", "NULL"]
errcheck:
check-type-assertions: false
# Report about assignment of errors to blank identifier.
Expand Down Expand Up @@ -103,7 +103,7 @@ linters:
min-occurrences: 5
ignore-tests: true
ignore-string-values:
- '^[a-zA-Z_-]{1,16}$' # ignore short identifiers like "account" or "project_id"
- "^[a-zA-Z_-]{1,16}$" # ignore short identifiers like "account" or "project_id"
gocritic:
enabled-checks:
- boolExprSimplify
Expand Down Expand Up @@ -136,7 +136,7 @@ linters:
# for github.com/sapcc/vpa_butler
- k8s.io/client-go
toolchain-forbidden: true
go-version-pattern: 1\.\d+(\.0)?$
go-version-pattern: 1\.\d+(\.\d+)?$
gosec:
excludes:
# gosec wants us to set a short ReadHeaderTimeout to avoid Slowloris attacks, but doing so would expose us to Keep-Alive race conditions (see https://iximiuz.com/en/posts/reverse-proxy-http-keep-alive-and-502s/
Expand Down
1 change: 1 addition & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

[default.extend-words]
ded = "ded"

[files]
extend-exclude = [
Expand Down
18 changes: 11 additions & 7 deletions Makefile.maker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ metadata:
url: https://github.com/cobaltcore-dev/cloud-profile-sync

binaries:
- name: cloud-profile-sync
- name: cloud-profile-sync
fromPackage: .
installTo: bin/
installTo: bin/

golang:
setGoModVersion: true
Expand Down Expand Up @@ -35,12 +35,16 @@ renovate:

reuse:
annotations:
- paths:
- '**/zz_generated.deepcopy.go'
- 'crd/*'
SPDX-FileCopyrightText: 2020 The Kubernetes Authors # this is the copyright line for kubebuilder which generates those files
SPDX-License-Identifier: Apache-2.0
- paths:
- "**/zz_generated.deepcopy.go"
- "crd/*"
SPDX-FileCopyrightText: 2020 The Kubernetes Authors # this is the copyright line for kubebuilder which generates those files
SPDX-License-Identifier: Apache-2.0

verbatim: |
gardener-crds: install-controller-gen
@controller-gen crd paths="github.com/gardener/gardener/pkg/apis/core/v1beta1" output:crd:artifacts:config=crd

typos:
extendWords:
ded: ded
16 changes: 16 additions & 0 deletions cloudprofilesync/imageupdater.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou
}

for _, sourceImage := range sourceImages {
supportInPlaceUpdate := slices.Contains(sourceImage.Capabilities[FeatureCapability], USIFeature)
// Always write the full tag version (legacy path, safe for running Shoots).
if idx, exists := existingVersions[sourceImage.Version]; exists {
image.Versions[idx].Architectures = sourceImage.Architectures
Expand All @@ -103,6 +104,11 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou
},
Architectures: sourceImage.Architectures,
})
if supportInPlaceUpdate {
image.Versions[len(image.Versions)-1].InPlaceUpdates = &gardenerv1beta1.InPlaceUpdates{
Supported: supportInPlaceUpdate,
}
}
existingVersions[sourceImage.Version] = len(image.Versions) - 1
}
}
Expand All @@ -116,13 +122,23 @@ func (iu *ImageUpdater) Update(ctx context.Context, cpSpec *gardenerv1beta1.Clou
existing.Architectures = append(existing.Architectures, arch)
}
}
if supportInPlaceUpdate {
existing.InPlaceUpdates = &gardenerv1beta1.InPlaceUpdates{
Supported: supportInPlaceUpdate,
}
}
} else {
image.Versions = append(image.Versions, gardenerv1beta1.MachineImageVersion{
ExpirableVersion: gardenerv1beta1.ExpirableVersion{
Version: sourceImage.CleanVersion,
},
Architectures: slices.Clone(sourceImage.Architectures),
})
if supportInPlaceUpdate {
image.Versions[len(image.Versions)-1].InPlaceUpdates = &gardenerv1beta1.InPlaceUpdates{
Supported: supportInPlaceUpdate,
}
}
Comment thread
adziauho marked this conversation as resolved.
existingVersions[sourceImage.CleanVersion] = len(image.Versions) - 1
}
}
Expand Down
44 changes: 44 additions & 0 deletions cloudprofilesync/imageupdater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,25 @@ var _ = Describe("ImageUpdater", func() {
Expect(json.Unmarshal(cpSpec.ProviderConfig.Raw, &fromProvider)).To(Succeed())
Expect(fromProvider).To(Equal(mockSource.images))
})

It("in-place update support", func(ctx SpecContext) {
mockSource.images = []cloudprofilesync.SourceImage{{
Version: "1.0.0",
Architectures: []string{"amd64"},
Capabilities: map[string]gardencorev1beta1.CapabilityValues{"feature": {cloudprofilesync.USIFeature}}},
}
updater := cloudprofilesync.ImageUpdater{
Log: logr.Discard(),
Source: &mockSource,
ImageName: "test",
}
var cpSpec gardencorev1beta1.CloudProfileSpec
Expect(updater.Update(ctx, &cpSpec)).To(Succeed())
Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1))
Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0"))
Expect(cpSpec.MachineImages[0].Versions[0].InPlaceUpdates.Supported).To(BeTrue())
})

})

Describe("flag ON (dual-write clean version)", func() {
Expand All @@ -249,6 +268,7 @@ var _ = Describe("ImageUpdater", func() {
versions := cpSpec.MachineImages[0].Versions
versionStrings := []string{versions[0].Version, versions[1].Version}
Expect(versionStrings).To(ContainElements("2254.0.0-baremetal-sci-usi-amd64", "2254.0.0"))
Expect(versions[0].InPlaceUpdates.Supported).To(BeTrue())
})

It("does not add a duplicate clean version entry on re-reconcile", func(ctx SpecContext) {
Expand Down Expand Up @@ -318,5 +338,29 @@ var _ = Describe("ImageUpdater", func() {
Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(1))
Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1877.0.0"))
})

It("in-place update support", func(ctx SpecContext) {
mockSource.images = []cloudprofilesync.SourceImage{{
Version: "1.0.0",
CleanVersion: "1.1",
Architectures: []string{"amd64"},
Capabilities: map[string]gardencorev1beta1.CapabilityValues{"feature": {cloudprofilesync.USIFeature}}},
}
updater := cloudprofilesync.ImageUpdater{
Log: logr.Discard(),
Source: &mockSource,
ImageName: "test",
EnableCapabilities: true,
}
var cpSpec gardencorev1beta1.CloudProfileSpec
Expect(updater.Update(ctx, &cpSpec)).To(Succeed())
Expect(cpSpec.MachineImages[0].Versions).To(HaveLen(2))
Expect(cpSpec.MachineImages[0].Versions[0].Version).To(Equal("1.0.0"))
Expect(cpSpec.MachineImages[0].Versions[0].InPlaceUpdates).NotTo(BeNil())
Expect(cpSpec.MachineImages[0].Versions[0].InPlaceUpdates.Supported).To(BeTrue())
Expect(cpSpec.MachineImages[0].Versions[1].Version).To(Equal("1.1.0"))
Expect(cpSpec.MachineImages[0].Versions[1].InPlaceUpdates).NotTo(BeNil())
Expect(cpSpec.MachineImages[0].Versions[1].InPlaceUpdates.Supported).To(BeTrue())
})
})
})
35 changes: 26 additions & 9 deletions cloudprofilesync/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,32 @@ import (
"oras.land/oras-go/v2/registry/remote/retry"
)

const (
// ChostFeature represent having containerd
ChostFeature = "chost"
// PXEFeature represent pxe boot build
PXEFeature = "_pxe"
SCIFeature = "sci"
SCIBaseFeature = "scibase"
// CAPIFeature includes server, khost, and PXE; excludes SELinux and firewall
CAPIFeature = "capi"
// USIFeature shows UEFI build
USIFeature = "_usi"
USIDevFeature = "_usidev"

Comment thread
adziauho marked this conversation as resolved.
ArchitectureCapability = "architecture"
FeatureCapability = "feature"
)

// validFeatureValues is the allowlist of feature values extracted from the feature_set annotation.
var validFeatureValues = map[string]struct{}{
"chost": {},
"_pxe": {},
"sci": {},
"capi": {},
"scibase": {},
"_usi": {},
"_usidev": {},
ChostFeature: {},
PXEFeature: {},
SCIFeature: {},
SCIBaseFeature: {},
CAPIFeature: {},
USIFeature: {},
USIDevFeature: {},
}

func filterFeatureSet(featureSet string) []string {
Expand Down Expand Up @@ -161,8 +178,8 @@ func (o *OCI) GetVersions(ctx context.Context) ([]SourceImage, error) {
features := filterFeatureSet(featureSet)
if len(features) > 0 {
capabilities = gardencorev1beta1.Capabilities{
"architecture": {arch},
"feature": features,
ArchitectureCapability: {arch},
FeatureCapability: features,
}
cleanVersion = version
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/cobaltcore-dev/cloud-profile-sync

go 1.26
go 1.26.2

require (
github.com/blang/semver/v4 v4.0.0
Expand Down