Skip to content

Commit

Permalink
chore: feature from unstructured crd and busola cm
Browse files Browse the repository at this point in the history
  • Loading branch information
tmilos77 committed Jul 12, 2024
1 parent 6ca7f71 commit 2fce6bc
Show file tree
Hide file tree
Showing 7 changed files with 453 additions and 280 deletions.
9 changes: 9 additions & 0 deletions api/cloud-resources/v1beta1/nfsbackupschedule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1beta1

import (
featuretypes "github.com/kyma-project/cloud-manager/pkg/feature/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -106,6 +107,14 @@ type NfsBackupSchedule struct {
Status NfsBackupScheduleStatus `json:"status,omitempty"`
}

func (in *NfsBackupSchedule) SpecificToProviders() []string {
return nil
}

func (in *NfsBackupSchedule) SpecificToFeature() featuretypes.FeatureName {
return featuretypes.FeatureNfsBackup
}

//+kubebuilder:object:root=true

// NfsBackupScheduleList contains a list of NfsBackupSchedule
Expand Down
69 changes: 8 additions & 61 deletions pkg/feature/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ import (
"github.com/kyma-project/cloud-manager/pkg/feature/types"
"github.com/kyma-project/cloud-manager/pkg/util"
"github.com/thomaspoignant/go-feature-flag/ffcontext"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"strings"
)

Expand Down Expand Up @@ -225,66 +221,17 @@ func (b *contextBuilderImpl) KindsFromObject(obj client.Object, scheme *runtime.
b.CrdKindGroup("")
b.BusolaKindGroup("")

var err error
gvk := obj.GetObjectKind().GroupVersionKind()
if gvk.Kind == "" {
gvk, err = apiutil.GVKForObject(obj, scheme)
if err != nil {
return b
}
kindInfo := ObjectKinds(obj, scheme)
if !kindInfo.ObjOK {
return b
}

kg := strings.ToLower(gvk.Kind)
if gvk.Group != "" {
kg = fmt.Sprintf("%s.%s", strings.ToLower(gvk.Kind), strings.ToLower(gvk.Group))
b.ObjKindGroup(strings.ToLower(kindInfo.ObjGK.String()))
if kindInfo.CrdOK {
b.CrdKindGroup(strings.ToLower(kindInfo.CrdGK.String()))
}
b.ObjKindGroup(kg)

if kg == "customresourcedefinition.apiextensions.k8s.io" {
if u, ok := obj.(*unstructured.Unstructured); ok {
crdGroup, groupFound, groupErr := unstructured.NestedString(u.Object, "spec", "group")
crdKind, kindFound, kindErr := unstructured.NestedString(u.Object, "spec", "names", "kind")
if groupFound && kindFound && groupErr == nil && kindErr == nil {
crdKg := fmt.Sprintf("%s.%s", strings.ToLower(crdKind), strings.ToLower(crdGroup))
b.CrdKindGroup(crdKg)
}
}
if crd, ok := obj.(*apiextensions.CustomResourceDefinition); ok {
crdGroup := crd.Spec.Group
crdKind := crd.Spec.Names.Kind
crdKg := fmt.Sprintf("%s.%s", strings.ToLower(crdKind), strings.ToLower(crdGroup))
b.CrdKindGroup(crdKg)
}
}

if kg == "configmap" &&
obj.GetLabels() != nil && obj.GetLabels()["busola.io/extension"] != "" {

var general string
if cm, ok := obj.(*unstructured.Unstructured); ok {
gen, found, err := unstructured.NestedString(cm.Object, "data", "general")
if found && err == nil {
general = gen
}
}
if cm, ok := obj.(*corev1.ConfigMap); ok {
gen, found := cm.Data["general"]
if found {
general = gen
}
}

if len(general) > 0 {
obj := map[string]interface{}{}
if err := yaml.Unmarshal([]byte(general), &obj); err == nil {
cmGroup, groupFound, groupErr := unstructured.NestedString(obj, "resource", "group")
cmKind, kindFound, kindErr := unstructured.NestedString(obj, "resource", "kind")
if groupFound && kindFound && groupErr == nil && kindErr == nil {
busolaKg := fmt.Sprintf("%s.%s", strings.ToLower(cmKind), strings.ToLower(cmGroup))
b.BusolaKindGroup(busolaKg)
}
}
}
if kindInfo.BusolaOK {
b.BusolaKindGroup(strings.ToLower(kindInfo.BusolaGK.String()))
}

return b
Expand Down
123 changes: 35 additions & 88 deletions pkg/feature/object2feature.go
Original file line number Diff line number Diff line change
@@ -1,75 +1,31 @@
package feature

import (
"context"
"github.com/kyma-project/cloud-manager/pkg/feature/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
)

/*
All feature determination implementation in this file is used only in case
object does not implement types.FeatureAwareObject interface
*/

type featureDeterminator func(mi *manifestInfo) (bool, types.FeatureName)

type manifestInfo struct {
obj client.Object
name string
namespace string
objKindGroup string
labels map[string]string
annotations map[string]string
crdKindGroup string
busolaKindGroup string
}

var featureDeterminators = []featureDeterminator{
featureDeterminatorByKindGroup,
featureDeterminatorByCrdKindGroup,
featureDeterminatorByBusolaKindGroup,
}

var featuresByKindGroup = map[string]types.FeatureName{
// Please respect the order of the filenames in config/crd/bases
// and list items here in the same order as files in that dir are.

// KCP ==============================================================
// scope has no feature defined
"scope.cloud-control.kyma-project.io": "",
// iprange atm is for nfs feature only, but in the future other features might include it as well,
// so we will define iprange feature from start as undefined
"iprange.cloud-control.kyma-project.io": "",
"nfsinstance.cloud-control.kyma-project.io": types.FeatureNfs,
"vpcpeering.cloud-control.kyma-project.io": types.FeaturePeering,

// SKR ==============================================================

"awsnfsvolumebackup.cloud-resources.kyma-project.io": types.FeatureNfsBackup,
"awsnfsvolume.cloud-resources.kyma-project.io": types.FeatureNfs,
// cloudresouces module CR has no feature
"cloudresouces.cloud-control.kyma-project.io": "",
"gcpnfsvolumebackup.cloud-resources.kyma-project.io": types.FeatureNfsBackup,
"gcpnfsvolumerestore.cloud-resources.kyma-project.io": types.FeatureNfsBackup,
"gcpnfsvolume.cloud-resources.kyma-project.io": types.FeatureNfs,
// iprange has no feature, see comment from KCP about it
"iprange.cloud-resources.kyma-project.io": "",
}

func featureDeterminatorByKindGroup(mi *manifestInfo) (bool, types.FeatureName) {
f, ok := featuresByKindGroup[mi.objKindGroup]
return ok, f
}

func featureDeterminatorByCrdKindGroup(mi *manifestInfo) (bool, types.FeatureName) {
f, ok := featuresByKindGroup[mi.crdKindGroup]
return ok, f
}

func featureDeterminatorByBusolaKindGroup(mi *manifestInfo) (bool, types.FeatureName) {
f, ok := featuresByKindGroup[mi.busolaKindGroup]
return ok, f
func tryFeatureAwareOnGK(gk schema.GroupKind, scheme *runtime.Scheme) (types.FeatureName, bool) {
versions := scheme.VersionsForGroupKind(schema.GroupKind{
Group: gk.Group,
Kind: gk.Kind,
})
for _, version := range versions {
x, err := scheme.New(schema.GroupVersionKind{
Group: version.Group,
Version: version.Version,
Kind: gk.Kind,
})
if err == nil {
if fa, ok := x.(types.FeatureAwareObject); ok {
return fa.SpecificToFeature(), true
}
}
}
return "", false
}

// ObjectToFeature returns FeatureName specific to the object. It can return empty string
Expand All @@ -81,38 +37,29 @@ func ObjectToFeature(obj client.Object, scheme *runtime.Scheme) types.FeatureNam
if fa, ok := obj.(types.FeatureAwareObject); ok {
return fa.SpecificToFeature()
}
return objectToFeaturePredetermined(obj, scheme)
}

func objectToFeaturePredetermined(obj client.Object, scheme *runtime.Scheme) types.FeatureName {
ffCtx := ContextBuilderFromCtx(context.Background()).
KindsFromObject(obj, scheme).
FFCtx()

intfToString := func(x interface{}) string {
if x == nil {
return ""
if u, ok := obj.(*unstructured.Unstructured); ok {
x, err := scheme.New(u.GroupVersionKind())
if err == nil {
if ufa, ok := x.(types.FeatureAwareObject); ok {
return ufa.SpecificToFeature()
}
}
return x.(string)
}

mi := &manifestInfo{
obj: obj,
name: obj.GetName(),
namespace: obj.GetNamespace(),
objKindGroup: intfToString(ffCtx.GetCustom()[types.KeyObjKindGroup]),
labels: obj.GetLabels(),
annotations: obj.GetAnnotations(),
crdKindGroup: intfToString(ffCtx.GetCustom()[types.KeyCrdKindGroup]),
busolaKindGroup: intfToString(ffCtx.GetCustom()[types.KeyBusolaKindGroup]),
kindInfo := ObjectKinds(obj, scheme)

if kindInfo.CrdOK {
if f, ok := tryFeatureAwareOnGK(kindInfo.CrdGK, scheme); ok {
return f
}
}

for _, det := range featureDeterminators {
ok, f := det(mi)
if ok {
if kindInfo.BusolaOK {
if f, ok := tryFeatureAwareOnGK(kindInfo.BusolaGK, scheme); ok {
return f
}
}

return ""
return types.FeatureUnknown
}
Loading

0 comments on commit 2fce6bc

Please sign in to comment.