Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WiP] Fixes to make KIM produce the same output as Provisioner #341

Closed
wants to merge 12 commits into from
22 changes: 11 additions & 11 deletions api/v1/runtime_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@ type RuntimeStatus struct {
}

type RuntimeShoot struct {
Name string `json:"name"`
Purpose gardener.ShootPurpose `json:"purpose"`
PlatformRegion string `json:"platformRegion"`
Region string `json:"region"`
LicenceType *string `json:"licenceType,omitempty"`
SecretBindingName string `json:"secretBindingName"`
EnforceSeedLocation *bool `json:"enforceSeedLocation,omitempty"`
Kubernetes Kubernetes `json:"kubernetes,omitempty"`
Provider Provider `json:"provider"`
Networking Networking `json:"networking"`
ControlPlane gardener.ControlPlane `json:"controlPlane"`
Name string `json:"name"`
Purpose gardener.ShootPurpose `json:"purpose"`
PlatformRegion string `json:"platformRegion"`
Region string `json:"region"`
LicenceType *string `json:"licenceType,omitempty"`
SecretBindingName string `json:"secretBindingName"`
EnforceSeedLocation *bool `json:"enforceSeedLocation,omitempty"`
Kubernetes Kubernetes `json:"kubernetes,omitempty"`
Provider Provider `json:"provider"`
Networking Networking `json:"networking"`
ControlPlane *gardener.ControlPlane `json:"controlPlane,omitempty"`
}

type Kubernetes struct {
Expand Down
6 changes: 5 additions & 1 deletion api/v1/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,6 @@ spec:
secretBindingName:
type: string
required:
- controlPlane
- name
- networking
- platformRegion
Expand Down
3 changes: 1 addition & 2 deletions hack/runtime-migrator/input/runtimeids_sample.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
c65d5c9b-b321-4481-b567-d331d769ff1c,
61e18f65-6c82-4fdd-97dc-cf51bfbbbeb2
7c6b4bd3-09d3-462f-b27c-992727b62eec,
}
44 changes: 26 additions & 18 deletions hack/runtime-migrator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ func saveRuntime(ctx context.Context, cfg migrator.Config, runtime v1.Runtime, g
func createRuntime(ctx context.Context, shoot v1beta1.Shoot, cfg migrator.Config, provider kubeconfig.Provider) (v1.Runtime, error) {
var subjects = getAdministratorsList(ctx, provider, shoot.Name)
var oidcConfig = getOidcConfig(shoot)
var hAFailureToleranceType = getFailureToleranceType(shoot)
var licenceType = shoot.Annotations["kcp.provisioner.kyma-project.io/licence-type"]
labels, err := getAllRuntimeLabels(ctx, shoot, cfg.Client)
if err != nil {
Expand Down Expand Up @@ -210,17 +209,12 @@ func createRuntime(ctx context.Context, shoot v1beta1.Shoot, cfg migrator.Config
Workers: shoot.Spec.Provider.Workers,
},
Networking: v1.Networking{
Type: shoot.Spec.Networking.Type,
Pods: *shoot.Spec.Networking.Pods,
Nodes: *shoot.Spec.Networking.Nodes,
Services: *shoot.Spec.Networking.Services,
},
ControlPlane: v1beta1.ControlPlane{
HighAvailability: &v1beta1.HighAvailability{
FailureTolerance: v1beta1.FailureTolerance{
Type: hAFailureToleranceType,
},
},
},
ControlPlane: getControlPlane(shoot),
},
Security: v1.Security{
Administrators: subjects,
Expand Down Expand Up @@ -280,23 +274,29 @@ func getShootList(ctx context.Context, cfg migrator.Config, gardenerNamespace st
return list
}

func getFailureToleranceType(shoot v1beta1.Shoot) v1beta1.FailureToleranceType {
func getControlPlane(shoot v1beta1.Shoot) *v1beta1.ControlPlane {
if shoot.Spec.ControlPlane != nil {
if shoot.Spec.ControlPlane.HighAvailability != nil {
return shoot.Spec.ControlPlane.HighAvailability.FailureTolerance.Type
return &v1beta1.ControlPlane{HighAvailability: &v1beta1.HighAvailability{
FailureTolerance: v1beta1.FailureTolerance{
Type: shoot.Spec.ControlPlane.HighAvailability.FailureTolerance.Type,
},
},
}
}
}
return ""

return nil
}

func getAdministratorsList(ctx context.Context, provider kubeconfig.Provider, shootName string) []string {
var kubeconfig, err = provider.Fetch(ctx, shootName)
if kubeconfig == "" {
var clusterKubeconfig, err = provider.Fetch(ctx, shootName)
if clusterKubeconfig == "" {
log.Printf("Failed to get dynamic kubeconfig for shoot %s, %s\n", shootName, err.Error())
return []string{}
}

restClientConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeconfig))
restClientConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(clusterKubeconfig))
if err != nil {
log.Printf("Failed to create REST client from kubeconfig - %s\n", err)
return []string{}
Expand All @@ -311,7 +311,8 @@ func getAdministratorsList(ctx context.Context, provider kubeconfig.Provider, sh
LabelSelector: "reconciler.kyma-project.io/managed-by=reconciler,app=kyma",
})

var subjects = []string{}
subjects := make([]string, 0)

for _, clusterRoleBinding := range clusterRoleBindings.Items {
for _, subject := range clusterRoleBinding.Subjects {
subjects = append(subjects, subject.Name)
Expand Down Expand Up @@ -395,8 +396,14 @@ func getAllRuntimeLabels(ctx context.Context, shoot v1beta1.Shoot, getClient mig
return map[string]string{}, errors.Wrap(clientErr, fmt.Sprintf("Failed to get GardenerClient for shoot %s - %s\n", shoot.Name, clientErr))
}
gardenerCluster := v1.GardenerCluster{}
shootKey := types.NamespacedName{Name: shoot.Name, Namespace: "kcp-system"}
getGardenerCRerr := k8sClient.Get(ctx, shootKey, &gardenerCluster)

kymaID, found := shoot.Annotations["kcp.provisioner.kyma-project.io/runtime-id"]
if !found {
return nil, errors.New("Runtime ID not found in shoot annotations")
}

gardenerCRKey := types.NamespacedName{Name: kymaID, Namespace: "kcp-system"}
getGardenerCRerr := k8sClient.Get(ctx, gardenerCRKey, &gardenerCluster)
if getGardenerCRerr != nil {
var errMsg = fmt.Sprintf("Failed to retrieve GardenerCluster CR for shoot %s\n", shoot.Name)
return map[string]string{}, errors.Wrap(getGardenerCRerr, errMsg)
Expand All @@ -410,7 +417,8 @@ func getAllRuntimeLabels(ctx context.Context, shoot v1beta1.Shoot, getClient mig
enrichedRuntimeLabels["kyma-project.io/region"] = gardenerCluster.Labels["kyma-project.io/region"]
enrichedRuntimeLabels["kyma-project.io/shoot-name"] = gardenerCluster.Labels["kyma-project.io/shoot-name"]
enrichedRuntimeLabels["operator.kyma-project.io/kyma-name"] = gardenerCluster.Labels["operator.kyma-project.io/kyma-name"]

// The runtime CR should be controlled by the KIM
enrichedRuntimeLabels["kyma-project.io/controlled-by-provisioner"] = "false"
// add custom label for the migrator
enrichedRuntimeLabels[migratorLabel] = "true"

Expand Down
5 changes: 3 additions & 2 deletions hack/shoot-comparator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ require (
github.com/gardener/gardener v1.98.0
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.29.6
sigs.k8s.io/yaml v1.4.0
)

Expand All @@ -31,10 +34,8 @@ require (
golang.org/x/tools v0.22.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.29.6 // indirect
k8s.io/apiextensions-apiserver v0.29.6 // indirect
k8s.io/apimachinery v0.29.6 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
71 changes: 71 additions & 0 deletions hack/shoot-comparator/pkg/shoot/extensionmatcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package shoot

import (
"fmt"
"github.com/gardener/gardener/pkg/apis/core/v1beta1"
"github.com/onsi/gomega"
"github.com/onsi/gomega/types"
"reflect"
"sort"
"strings"
)

type ExtensionMatcher struct {
toMatch interface{}
fails []string
}

func NewExtensionMatcher(i interface{}) types.GomegaMatcher {
return &ExtensionMatcher{
toMatch: i,
}
}

func (m *ExtensionMatcher) Match(actual interface{}) (success bool, err error) {
aExtensions, err := getExtension(actual)
if err != nil {
return false, err
}

eExtensions, err := getExtension(m.toMatch)
if err != nil {
return false, err
}

sort.Sort(Extensions(aExtensions))
sort.Sort(Extensions(eExtensions))

return gomega.BeComparableTo(eExtensions).Match(aExtensions)
}

func getExtension(i interface{}) ([]v1beta1.Extension, error) {
switch v := i.(type) {
case []v1beta1.Extension:
return v, nil

default:
return []v1beta1.Extension{}, fmt.Errorf(`%w: %s`, errInvalidType, reflect.TypeOf(v))
}
}

type Extensions []v1beta1.Extension

func (e Extensions) Len() int {
return len(e)
}

func (e Extensions) Less(i, j int) bool {
return e[i].Type < e[j].Type
}

func (e Extensions) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}

func (m *ExtensionMatcher) NegatedFailureMessage(_ interface{}) string {
return "expected should not equal actual"
}

func (m *ExtensionMatcher) FailureMessage(_ interface{}) string {
return strings.Join(m.fails, "\n")
}
106 changes: 106 additions & 0 deletions hack/shoot-comparator/pkg/shoot/extensionmatcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package shoot

import (
"fmt"
"github.com/gardener/gardener/pkg/apis/core/v1beta1"
. "github.com/onsi/ginkgo/v2" //nolint:revive
. "github.com/onsi/gomega" //nolint:revive
"k8s.io/apimachinery/pkg/runtime"
)

var _ = Describe(":: extension matcher :: ", func() {
emptyExt := make([]v1beta1.Extension, 0)

DescribeTable(
"checking invalid args :: ",
testExtensionInvalidArgs,
Entry("when actual is not of Extension type", v1beta1.Shoot{}, emptyExt),
Entry("when expected is not of Extension type", emptyExt, v1beta1.Shoot{}),
Entry("when actual is nil", nil, emptyExt),
Entry("when expected is nil", emptyExt, nil),
)

dnsExtEnabled := getDNSExtension(false, true)
dnsExtDisabled := getDNSExtension(true, false)
networkingExtDisabled := getNetworkingExtension(true)
certificateExtEnabled := getCertificateExtension(false, true)

DescribeTable(
"checking results :: ",
testExtensionResults,
Entry(
"should match empty values",
emptyExt,
emptyExt,
true,
),
Entry(
"should match identical tables",
[]v1beta1.Extension{dnsExtEnabled, networkingExtDisabled, certificateExtEnabled},
[]v1beta1.Extension{networkingExtDisabled, certificateExtEnabled, dnsExtEnabled},
true,
),
Entry(
"should detect extension differs",
[]v1beta1.Extension{dnsExtEnabled, networkingExtDisabled, certificateExtEnabled},
[]v1beta1.Extension{dnsExtDisabled, networkingExtDisabled, certificateExtEnabled},
false,
),
Entry(
"should detect redundant extension",
[]v1beta1.Extension{dnsExtEnabled, networkingExtDisabled, certificateExtEnabled},
[]v1beta1.Extension{networkingExtDisabled, certificateExtEnabled},
false,
),
Entry(
"should detect missing extension",
[]v1beta1.Extension{networkingExtDisabled, certificateExtEnabled},
[]v1beta1.Extension{dnsExtEnabled, networkingExtDisabled, certificateExtEnabled},
false,
),
)
})

func testExtensionInvalidArgs(actual, expected interface{}) {
matcher := NewExtensionMatcher(expected)
_, err := matcher.Match(actual)
Expect(err).To(HaveOccurred())
}

func testExtensionResults(actual, expected interface{}, expectedMatch bool) {
matcher := NewExtensionMatcher(expected)
actualMatch, err := matcher.Match(actual)
Expect(err).ShouldNot(HaveOccurred())
Expect(actualMatch).Should(Equal(expectedMatch), matcher.FailureMessage(actual))
}

func getDNSExtension(disabled bool, replicationEnabled bool) v1beta1.Extension {
json := fmt.Sprintf(`{apiVersion: "service.dns.extensions.gardener.cloud/v1alpha1", kind: "DNSConfig", dnsProviderReplication: {enabled: %v}}`, replicationEnabled)

return v1beta1.Extension{
Type: "shoot-dns-service",
Disabled: &disabled,
ProviderConfig: &runtime.RawExtension{
Raw: []byte(json),
},
}
}

func getNetworkingExtension(disabled bool) v1beta1.Extension {
return v1beta1.Extension{
Type: "shoot-networking-service",
Disabled: &disabled,
}
}

func getCertificateExtension(disabled bool, shootIssuersEnabled bool) v1beta1.Extension {
json := fmt.Sprintf(`{apiVersion: "service.cert.extensions.gardener.cloud/v1alpha1", kind: "CertConfig", shootIssuers: {enabled: %v}}`, shootIssuersEnabled)

return v1beta1.Extension{
Type: "shoot-cert-service",
Disabled: &disabled,
ProviderConfig: &runtime.RawExtension{
Raw: []byte(json),
},
}
}
Loading
Loading