mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-25 16:07:24 +00:00
feat: upstream enterprise preview (#1841)
feat: upstream enterprise preview --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net> Co-authored-by: CorentinPtrl <pitrel.corentin@gmail.com>
This commit is contained in:
co-authored by
CorentinPtrl
parent
7a65ab7afc
commit
cc4fb45d70
+19
-2
@@ -4,7 +4,8 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
gherrors "github.com/pkg/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/discovery"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
@@ -13,5 +14,21 @@ import (
|
||||
func IsUnsupportedAPI(err error) bool {
|
||||
missingAPIError, discoveryGropuError, discoveryResourceError := &meta.NoKindMatchError{}, &discovery.ErrGroupDiscoveryFailed{}, &apiutil.ErrResourceDiscoveryFailed{}
|
||||
|
||||
return errors.As(err, &missingAPIError) || errors.As(err, &discoveryGropuError) || errors.As(err, &discoveryResourceError)
|
||||
return gherrors.As(err, &missingAPIError) || gherrors.As(err, &discoveryGropuError) || gherrors.As(err, &discoveryResourceError)
|
||||
}
|
||||
|
||||
func IgnoreWrappedNotFound(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if apierrors.IsNotFound(gherrors.Cause(err)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,10 +7,10 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/projectcapsule/capsule/pkg/api"
|
||||
"github.com/projectcapsule/capsule/pkg/api/rbac"
|
||||
)
|
||||
|
||||
func RoleBindingHashFunc(binding api.AdditionalRoleBindingsSpec) string {
|
||||
func RoleBindingHashFunc(binding rbac.AdditionalRoleBindingsSpec) string {
|
||||
h := fnv.New64a()
|
||||
|
||||
_, _ = h.Write([]byte(binding.ClusterRoleName))
|
||||
|
||||
+11
-11
@@ -8,12 +8,12 @@ import (
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
"github.com/projectcapsule/capsule/pkg/api"
|
||||
"github.com/projectcapsule/capsule/pkg/api/rbac"
|
||||
"github.com/projectcapsule/capsule/pkg/utils"
|
||||
)
|
||||
|
||||
func TestRoleBindingHashFunc_Deterministic(t *testing.T) {
|
||||
b := api.AdditionalRoleBindingsSpec{
|
||||
b := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{
|
||||
{Kind: "User", Name: "alice"},
|
||||
@@ -33,11 +33,11 @@ func TestRoleBindingHashFunc_Deterministic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoleBindingHashFunc_ChangesWhenClusterRoleChanges(t *testing.T) {
|
||||
b1 := api.AdditionalRoleBindingsSpec{
|
||||
b1 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
|
||||
}
|
||||
b2 := api.AdditionalRoleBindingsSpec{
|
||||
b2 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "view",
|
||||
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
|
||||
}
|
||||
@@ -51,11 +51,11 @@ func TestRoleBindingHashFunc_ChangesWhenClusterRoleChanges(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoleBindingHashFunc_ChangesWhenSubjectKindChanges(t *testing.T) {
|
||||
b1 := api.AdditionalRoleBindingsSpec{
|
||||
b1 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
|
||||
}
|
||||
b2 := api.AdditionalRoleBindingsSpec{
|
||||
b2 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{{Kind: "Group", Name: "alice"}},
|
||||
}
|
||||
@@ -69,11 +69,11 @@ func TestRoleBindingHashFunc_ChangesWhenSubjectKindChanges(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoleBindingHashFunc_ChangesWhenSubjectNameChanges(t *testing.T) {
|
||||
b1 := api.AdditionalRoleBindingsSpec{
|
||||
b1 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{{Kind: "User", Name: "alice"}},
|
||||
}
|
||||
b2 := api.AdditionalRoleBindingsSpec{
|
||||
b2 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{{Kind: "User", Name: "bob"}},
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func TestRoleBindingHashFunc_ChangesWhenSubjectNameChanges(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoleBindingHashFunc_EmptyInputsStillProduceHash(t *testing.T) {
|
||||
b := api.AdditionalRoleBindingsSpec{
|
||||
b := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "",
|
||||
Subjects: nil,
|
||||
}
|
||||
@@ -101,14 +101,14 @@ func TestRoleBindingHashFunc_EmptyInputsStillProduceHash(t *testing.T) {
|
||||
func TestRoleBindingHashFunc_SubjectOrderMatters_CurrentBehavior(t *testing.T) {
|
||||
// This test documents the CURRENT behavior:
|
||||
// the hash is order-dependent because subjects are written in slice order.
|
||||
b1 := api.AdditionalRoleBindingsSpec{
|
||||
b1 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{
|
||||
{Kind: "User", Name: "alice"},
|
||||
{Kind: "Group", Name: "devops"},
|
||||
},
|
||||
}
|
||||
b2 := api.AdditionalRoleBindingsSpec{
|
||||
b2 := rbac.AdditionalRoleBindingsSpec{
|
||||
ClusterRoleName: "admin",
|
||||
Subjects: []rbacv1.Subject{
|
||||
{Kind: "Group", Name: "devops"},
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2020-2026 Project Capsule Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
var versionsWithNodeFix = []string{"v1.18.18", "v1.19.10", "v1.20.6", "v1.21.0"}
|
||||
|
||||
func NodeWebhookSupported(currentVersion *version.Version) (bool, error) {
|
||||
versions := make([]*version.Version, 0, len(versionsWithNodeFix))
|
||||
|
||||
for _, v := range versionsWithNodeFix {
|
||||
ver, err := version.ParseGeneric(v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
versions = append(versions, ver)
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
if currentVersion.Major() == v.Major() {
|
||||
if currentVersion.Minor() < v.Minor() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if currentVersion.Minor() == v.Minor() && currentVersion.Patch() < v.Patch() {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func GetK8sVersionFromConfig(dc discovery.DiscoveryInterface) (*version.Version, error) {
|
||||
sv, err := dc.ServerVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return version.ParseGeneric(sv.String())
|
||||
}
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func MapMergeNoOverrite(dst, src map[string]string) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
@@ -28,3 +35,75 @@ func MapEqual(a, b map[string]string) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func ToUnstructuredMap(obj any) (map[string]any, error) {
|
||||
m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func Mapify(data any) map[string]any {
|
||||
result := make(map[string]any)
|
||||
v := reflect.ValueOf(data)
|
||||
|
||||
// If the provided data is a pointer, resolve to the underlying value
|
||||
if v.Kind() == reflect.Pointer {
|
||||
if v.IsNil() {
|
||||
return result // Return empty map for nil pointers
|
||||
}
|
||||
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
// Ensure we're working with a struct
|
||||
if v.Kind() == reflect.Struct {
|
||||
for i := range v.NumField() {
|
||||
field := v.Type().Field(i)
|
||||
|
||||
// Skip unexported fields
|
||||
if field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
value := v.Field(i)
|
||||
|
||||
// Handle different types with recursive or base handling
|
||||
//nolint:exhaustive
|
||||
switch value.Kind() {
|
||||
case reflect.Pointer:
|
||||
if !value.IsNil() {
|
||||
result[field.Name] = Mapify(value.Interface())
|
||||
}
|
||||
case reflect.Struct:
|
||||
result[field.Name] = Mapify(value.Interface())
|
||||
case reflect.Slice:
|
||||
var slice []any
|
||||
|
||||
for j := range value.Len() {
|
||||
item := value.Index(j)
|
||||
if item.Kind() == reflect.Struct {
|
||||
slice = append(slice, Mapify(item.Interface()))
|
||||
} else {
|
||||
slice = append(slice, item.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
result[field.Name] = slice
|
||||
case reflect.Map:
|
||||
mapResult := make(map[string]any)
|
||||
for _, key := range value.MapKeys() {
|
||||
mapResult[fmt.Sprint(key)] = value.MapIndex(key).Interface()
|
||||
}
|
||||
|
||||
result[field.Name] = mapResult
|
||||
default:
|
||||
result[field.Name] = value.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user