Skip to content

Commit

Permalink
Merge branch 'main' into feature/kyma-project#1507-no-downtime-runtim…
Browse files Browse the repository at this point in the history
…e-tls-configuration
  • Loading branch information
LeelaChacha authored Sep 29, 2024
2 parents 9e385c7 + adce201 commit 7846c8e
Show file tree
Hide file tree
Showing 58 changed files with 2,009 additions and 262 deletions.
8 changes: 8 additions & 0 deletions .github/actions/deploy-template-operator/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ runs:
run: |
kubectl apply -f tests/moduletemplates/moduletemplate_template_operator_v2_fast.yaml
kubectl apply -f tests/moduletemplates/moduletemplate_template_operator_v1_regular.yaml
- name: Create Template Operator Module for installation by version
working-directory: lifecycle-manager
if: ${{ matrix.e2e-test == 'module-install-by-version' }}
shell: bash
run: |
kubectl apply -f tests/moduletemplates/moduletemplate_template_operator_v2_fast.yaml
kubectl apply -f tests/moduletemplates/moduletemplate_template_operator_v1_regular.yaml
kubectl apply -f tests/moduletemplates/moduletemplate_template_operator_v2_direct_version.yaml
- name: Create Template Operator Module as Mandatory Module
working-directory: lifecycle-manager
if: ${{ matrix.e2e-test == 'mandatory-module' ||
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
- module-upgrade-channel-switch
- module-upgrade-new-version
- unmanage-module
- module-install-by-version
- skip-manifest-reconciliation
- ca-certificate-rotation
- self-signed-certificate-rotation
Expand Down
2 changes: 2 additions & 0 deletions api-version-compatibility-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ operator.kyma-project.io_moduletemplates.yaml:
- .spec.properties.target
- .spec.required[]|select(.=="target")
v1beta2:
- .spec.properties.version
- .spec.properties.moduleName
- .spec.properties.customStateCheck.description
2 changes: 1 addition & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.6
require (
github.com/Masterminds/semver/v3 v3.3.0
github.com/open-component-model/ocm v0.13.0
k8s.io/apimachinery v0.31.0
k8s.io/apimachinery v0.31.1
sigs.k8s.io/controller-runtime v0.19.0
)

Expand Down
4 changes: 2 additions & 2 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1142,8 +1142,8 @@ k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo=
k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE=
k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk=
k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk=
k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k=
k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30=
k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8=
Expand Down
14 changes: 14 additions & 0 deletions api/shared/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package shared

import "strings"

type Channel string

const (
// NoneChannel when this value is defined for the ModuleTemplate, it means that the ModuleTemplate is not assigned to any channel.
NoneChannel Channel = "none"
)

func (c Channel) Equals(value string) bool {
return string(c) == strings.ToLower(value)
}
3 changes: 2 additions & 1 deletion api/shared/operator_labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const (
OperatorName = "lifecycle-manager"
// WatchedByLabel defines a redirect to a controller that should be getting a notification
// if this resource is changed.
WatchedByLabel = OperatorGroup + Separator + "watched-by"
WatchedByLabel = OperatorGroup + Separator + "watched-by"
WatchedByLabelValue = "kyma"
// PurposeLabel defines the purpose of the resource, i.e. Secrets which will be used to certificate management.
PurposeLabel = OperatorGroup + Separator + "purpose"
CertManager = "klm-watcher-cert-manager"
Expand Down
46 changes: 8 additions & 38 deletions api/v1beta2/kyma_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ type Module struct {
// +kubebuilder:validation:MinLength:=3
Channel string `json:"channel,omitempty"`

// Version is the desired version of the Module. If this changes or is set, it will be used to resolve a new
// ModuleTemplate based on this specific version.
// The Version and Channel are mutually exclusive options.
// The regular expression come from here: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
// json:"-" to disable installation of specific versions until decided to roll this out
// see https://github.com/kyma-project/lifecycle-manager/issues/1847
Version string `json:"-"`

// RemoteModuleTemplateRef is deprecated and will no longer have any functionality.
// It will be removed in the upcoming API version.
RemoteModuleTemplateRef string `json:"remoteModuleTemplateRef,omitempty"`
Expand Down Expand Up @@ -211,14 +219,6 @@ type PartialMeta struct {

const DefaultChannel = "regular"

func PartialMetaFromObject(object apimetav1.Object) PartialMeta {
return PartialMeta{
Name: object.GetName(),
Namespace: object.GetNamespace(),
Generation: object.GetGeneration(),
}
}

func (m PartialMeta) GetName() string {
return m.Name
}
Expand Down Expand Up @@ -389,36 +389,6 @@ func (kyma *Kyma) IsBeta() bool {
return found && shared.IsEnabled(beta)
}

type AvailableModule struct {
Module
Enabled bool
Unmanaged bool
}

func (kyma *Kyma) GetAvailableModules() []AvailableModule {
moduleMap := make(map[string]bool)
modules := make([]AvailableModule, 0)
for _, module := range kyma.Spec.Modules {
moduleMap[module.Name] = true
modules = append(modules, AvailableModule{Module: module, Enabled: true, Unmanaged: !module.Managed})
}

for _, module := range kyma.Status.Modules {
_, exist := moduleMap[module.Name]
if exist {
continue
}
modules = append(modules, AvailableModule{
Module: Module{
Name: module.Name,
Channel: module.Channel,
},
Enabled: false,
})
}
return modules
}

func (kyma *Kyma) EnsureLabelsAndFinalizers() bool {
if controllerutil.ContainsFinalizer(kyma, "foregroundDeletion") {
return false
Expand Down
51 changes: 51 additions & 0 deletions api/v1beta2/moduletemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ limitations under the License.
package v1beta2

import (
"errors"
"fmt"
"strings"

"github.com/Masterminds/semver/v3"
"github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc"
apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -78,6 +81,18 @@ type ModuleTemplateSpec struct {
// +kubebuilder:validation:MinLength:=3
Channel string `json:"channel"`

// Version identifies the version of the Module. Can be empty, or a semantic version.
// +optional
// +kubebuilder:validation:Pattern:=`^((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-[a-zA-Z-][0-9a-zA-Z-]*)?)?$`
// +kubebuilder:validation:MaxLength:=32
Version string `json:"version"`

// ModuleName is the name of the Module. Can be empty.
// +optional
// +kubebuilder:validation:Pattern:=`^([a-z]{3,}(-[a-z]{3,})*)?$`
// +kubebuilder:validation:MaxLength:=64
ModuleName string `json:"moduleName"`

// Mandatory indicates whether the module is mandatory. It is used to enforce the installation of the module with
// its configuration in all runtime clusters.
// +optional
Expand Down Expand Up @@ -172,6 +187,42 @@ func (m *ModuleTemplate) IsInternal() bool {
return false
}

var ErrInvalidVersion = errors.New("can't find valid semantic version")

// getVersionLegacy() returns the version of the ModuleTemplate from the annotation on the object.
// Remove once shared.ModuleVersionAnnotation is removed
func (m *ModuleTemplate) getVersionLegacy() (string, error) {
if m.Annotations != nil {
moduleVersion, found := m.Annotations[shared.ModuleVersionAnnotation]
if found {
return moduleVersion, nil
}
}
return "", ErrInvalidVersion
}

// GetVersion returns the declared version of the ModuleTemplate from it's Spec.
func (m *ModuleTemplate) GetVersion() (*semver.Version, error) {
var versionValue string
var err error

if m.Spec.Version == "" {
versionValue, err = m.getVersionLegacy()
if err != nil {
return nil, err
}
} else {
versionValue = m.Spec.Version

}

version, err := semver.NewVersion(versionValue)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrInvalidVersion, err.Error())
}
return version, nil
}

func (m *ModuleTemplate) IsBeta() bool {
if isBeta, found := m.Labels[shared.BetaLabel]; found {
return strings.ToLower(isBeta) == shared.EnableLabelValue
Expand Down
105 changes: 105 additions & 0 deletions api/v1beta2/moduletemplate_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package v1beta2

import (
"strings"
"testing"

"github.com/kyma-project/lifecycle-manager/api/shared"
apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func Test_GetVersion(t *testing.T) {
const testVersion = "1.0.1"
const otherVersion = "0.0.1"
tests := []struct {
name string
m *ModuleTemplate
expectedVersion string
expectedErr string
}{
{
name: "Test GetVersion() by annotation (legacy)",
m: &ModuleTemplate{
ObjectMeta: apimetav1.ObjectMeta{
Annotations: map[string]string{
shared.ModuleVersionAnnotation: testVersion,
},
},
},
expectedVersion: testVersion,
},
{
name: "Test GetVersion() by explicit version in Spec",
m: &ModuleTemplate{
Spec: ModuleTemplateSpec{
Version: testVersion,
},
},
expectedVersion: testVersion,
},
{
name: "Test GetVersion() with both version in Spec and annotation",
m: &ModuleTemplate{
ObjectMeta: apimetav1.ObjectMeta{
Annotations: map[string]string{
shared.ModuleVersionAnnotation: otherVersion,
},
},
Spec: ModuleTemplateSpec{
Version: testVersion,
},
},
expectedVersion: testVersion,
},
{
name: "Test GetVersion without any version info",
m: &ModuleTemplate{
ObjectMeta: apimetav1.ObjectMeta{
Annotations: map[string]string{},
},
Spec: ModuleTemplateSpec{},
},
expectedErr: ErrInvalidVersion.Error(),
},
{
name: "Test GetVersion with invalid version",
m: &ModuleTemplate{
Spec: ModuleTemplateSpec{
Version: "invalid",
},
},
expectedErr: "Invalid Semantic Version",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt := tt
actualVersion, err := tt.m.GetVersion()
if err != nil {
if actualVersion != nil {
t.Errorf("GetVersion(): Returned version should be nil when error is not nil")
}
if tt.expectedErr == "" {
t.Errorf("GetVersion(): Unexpected error: %v", err)
}
if !strings.Contains(err.Error(), tt.expectedErr) {
t.Errorf("GetVersion(): Actual error = %v, expected error: %v", err, tt.expectedErr)
}
return
}

if actualVersion == nil {
t.Errorf("GetVersion(): Returned version should not be nil when error is nil")
}

if tt.expectedVersion == "" {
t.Errorf("GetVersion(): Expected version is empty but non-nil version is returned")
}

if actualVersion.String() != tt.expectedVersion {
t.Errorf("GetVersion(): actual version = %v, expected version: %v", actualVersion.String(), tt.expectedVersion)
}
})
}
}
16 changes: 0 additions & 16 deletions api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 1 addition & 13 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func createSkrWebhookManager(mgr ctrl.Manager, skrContextFactory remote.SkrConte
caCertificateCache := watcher.NewCACertificateCache(flagVar.CaCertCacheTTL)
config := watcher.SkrWebhookManagerConfig{
SKRWatcherPath: flagVar.WatcherResourcesPath,
SkrWatcherImage: getWatcherImg(flagVar),
SkrWatcherImage: flagVar.GetWatcherImage(),
SkrWebhookCPULimits: flagVar.WatcherResourceLimitsCPU,
SkrWebhookMemoryLimits: flagVar.WatcherResourceLimitsMemory,
RemoteSyncNamespace: flagVar.RemoteSyncNamespace,
Expand Down Expand Up @@ -357,18 +357,6 @@ func createSkrWebhookManager(mgr ctrl.Manager, skrContextFactory remote.SkrConte
resolvedKcpAddr)
}

const (
watcherRegProd = "europe-docker.pkg.dev/kyma-project/prod/runtime-watcher-skr"
watcherRegDev = "europe-docker.pkg.dev/kyma-project/dev/runtime-watcher"
)

func getWatcherImg(flagVar *flags.FlagVar) string {
if flagVar.UseWatcherDevRegistry {
return fmt.Sprintf("%s:%s", watcherRegDev, flagVar.WatcherImageTag)
}
return fmt.Sprintf("%s:%s", watcherRegProd, flagVar.WatcherImageTag)
}

func setupPurgeReconciler(mgr ctrl.Manager,
skrContextProvider remote.SkrContextProvider,
event event.Event,
Expand Down
11 changes: 11 additions & 0 deletions config/crd/bases/operator.kyma-project.io_moduletemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,17 @@ spec:
Mandatory indicates whether the module is mandatory. It is used to enforce the installation of the module with
its configuration in all runtime clusters.
type: boolean
moduleName:
description: ModuleName is the name of the Module. Can be empty.
maxLength: 64
pattern: ^([a-z]{3,}(-[a-z]{3,})*)?$
type: string
version:
description: Version identifies the version of the Module. Can be
empty, or a semantic version.
maxLength: 32
pattern: ^((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-[a-zA-Z-][0-9a-zA-Z-]*)?)?$
type: string
required:
- channel
- descriptor
Expand Down
Loading

0 comments on commit 7846c8e

Please sign in to comment.