mirror of
https://github.com/paralus/paralus.git
synced 2026-05-06 00:17:19 +00:00
initial commit for sentry related changes (#16)
This commit is contained in:
350
components/common/pkg/controller/apply/apply.go
Normal file
350
components/common/pkg/controller/apply/apply.go
Normal file
@@ -0,0 +1,350 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/client"
|
||||
scheme "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/scheme"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/util"
|
||||
clusterv2 "github.com/RafaySystems/rcloud-base/components/common/proto/types/controller"
|
||||
apixv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/util/retry"
|
||||
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
applyLog = logf.Log.WithName("cluster-v2-apply")
|
||||
)
|
||||
|
||||
var (
|
||||
crdv1beta1GVK = schema.GroupVersionKind{
|
||||
Group: apixv1beta1.SchemeGroupVersion.Group,
|
||||
Version: apixv1beta1.SchemeGroupVersion.Version,
|
||||
Kind: "CustomResourceDefinition",
|
||||
}
|
||||
)
|
||||
|
||||
var knownApplyUpdateGroups = func() map[string]struct{} {
|
||||
return map[string]struct{}{
|
||||
clusterv2.GroupVersion.Group: {},
|
||||
}
|
||||
}()
|
||||
|
||||
// isApplyUpdate checks if object should be updated for apply operation
|
||||
func isApplyUpdate(o runtime.Object) bool {
|
||||
group := o.GetObjectKind().GroupVersionKind().Group
|
||||
if _, ok := knownApplyUpdateGroups[group]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Options are the options for apply operation
|
||||
type Options struct {
|
||||
// if UseUpdate is set, then update is used instead of patch
|
||||
UseUpdate bool
|
||||
// if DontCreate is set, then object is not created if it is not present;
|
||||
// it is only updated/patched when present
|
||||
DontCreate bool
|
||||
}
|
||||
|
||||
// Option is the functional apply options
|
||||
type Option func(*Options)
|
||||
|
||||
// WithUseUpdate sets if update should be used instead of patch for apply
|
||||
// operation
|
||||
func WithUseUpdate(o runtime.Object) Option {
|
||||
return func(opts *Options) {
|
||||
opts.UseUpdate = isApplyUpdate(o)
|
||||
}
|
||||
}
|
||||
|
||||
// WithForceUseUpdate sets if update should be used instead of patch for apply
|
||||
// operation, irrespective of whether the object is of rafay domain or not
|
||||
func WithForceUseUpdate() Option {
|
||||
return func(opts *Options) {
|
||||
opts.UseUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithDontCreate sets DontCreate flag
|
||||
func WithDontCreate() Option {
|
||||
return func(opts *Options) {
|
||||
opts.DontCreate = true
|
||||
}
|
||||
}
|
||||
|
||||
// Applier is the interface for applying patch to runtime objects
|
||||
type Applier interface {
|
||||
Apply(ctx context.Context, obj ctrlclient.Object, opts ...Option) error
|
||||
ApplyStatus(ctx context.Context, obj ctrlclient.Object, statusObj interface{}) error
|
||||
ctrlclient.Client
|
||||
}
|
||||
|
||||
type applier struct {
|
||||
dynamic bool
|
||||
ctrlclient.Client
|
||||
}
|
||||
|
||||
// NewApplier returns new applier
|
||||
func NewApplier(client ctrlclient.Client) Applier {
|
||||
return &applier{false, client}
|
||||
}
|
||||
|
||||
// NewDynamicApplier returns a new applier whose client is dynamically refreshed
|
||||
// when new CRDs are installed
|
||||
func NewDynamicApplier() (Applier, error) {
|
||||
c, err := client.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &applier{true, c}, nil
|
||||
}
|
||||
|
||||
func isCRD(gvk schema.GroupVersionKind) bool {
|
||||
//applyLog.Info("is crd", "gvk", gvk)
|
||||
switch gvk {
|
||||
case crdv1beta1GVK:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *applier) Apply(ctx context.Context, obj ctrlclient.Object, opts ...Option) error {
|
||||
var applyOpts = new(Options)
|
||||
for _, f := range opts {
|
||||
f(applyOpts)
|
||||
}
|
||||
|
||||
// added to preserve backward compatability with other code
|
||||
if !applyOpts.UseUpdate {
|
||||
applyOpts.UseUpdate = isApplyUpdate(obj)
|
||||
}
|
||||
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
log := applyLog.WithValues("gvk", gvk)
|
||||
|
||||
var objectKey ctrlclient.ObjectKey
|
||||
var current ctrlclient.Object
|
||||
var err error
|
||||
|
||||
if mo, ok := obj.(metav1.Object); ok {
|
||||
|
||||
objectKey = ctrlclient.ObjectKey{
|
||||
Name: mo.GetName(),
|
||||
Namespace: mo.GetNamespace(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gvk, err = GetGVK(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
current, err = util.NewObject(gvk)
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to create new object %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
//refresh client before applying a unknow object
|
||||
if !util.KnownObject(gvk) && a.dynamic {
|
||||
c, err := client.New()
|
||||
if err != nil {
|
||||
log.Info("error in creating the refreshed client ", "err", err)
|
||||
err = fmt.Errorf("unable to create new client for dynamic applier %s", err.Error())
|
||||
return err
|
||||
}
|
||||
a.Client = c
|
||||
}
|
||||
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
err := a.Get(ctx, objectKey, current)
|
||||
if err != nil {
|
||||
if apierrs.IsNotFound(err) {
|
||||
// if don't create flag is set and object is not found
|
||||
if applyOpts.DontCreate {
|
||||
return err
|
||||
}
|
||||
|
||||
err = a.Create(ctx, obj)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to create step object %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if a.dynamic && isCRD(gvk) {
|
||||
|
||||
// wait until the crds are sync
|
||||
// TODO : what happens when you get an error ???
|
||||
err = a.pollCRDUntilEstablished(ctx, 180*time.Second, obj, objectKey)
|
||||
if err != nil {
|
||||
log.Info("error in polling ", "err", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info("crd created, refreshing client")
|
||||
a.Client, err = client.New()
|
||||
if err != nil {
|
||||
log.Info("error in creating the refreshed client ", "err", err)
|
||||
return err
|
||||
}
|
||||
log.Info("crd created, refreshed client")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = fmt.Errorf("unable to get step object %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
current.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
|
||||
if applyOpts.UseUpdate {
|
||||
err = updateObject(current, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = a.Update(ctx, current)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = a.Patch(ctx, obj, NewPatch(current))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to patch step object %s", err.Error())
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
obj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (a *applier) pollCRDUntilEstablished(ctx context.Context, timeout time.Duration, obj ctrlclient.Object, objectKey types.NamespacedName) error {
|
||||
return wait.PollImmediate(time.Second, timeout, func() (bool, error) {
|
||||
|
||||
crd := &apixv1beta1.CustomResourceDefinition{}
|
||||
err := scheme.Scheme.Convert(obj, crd, nil)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("unable to convert to CRD type: %v", err)
|
||||
}
|
||||
|
||||
err = a.Get(ctx, objectKey, obj)
|
||||
if err != nil {
|
||||
applyLog.Info("error in getting the object", "err", err)
|
||||
}
|
||||
|
||||
applyLog.Info("checking crd status ", "name", crd.Spec.Names, "crd status", crd.Status)
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
switch cond.Type {
|
||||
case apixv1beta1.Established:
|
||||
if cond.Status == apixv1beta1.ConditionTrue {
|
||||
return true, nil
|
||||
}
|
||||
case apixv1beta1.NamesAccepted:
|
||||
if cond.Status == apixv1beta1.ConditionFalse {
|
||||
return false, fmt.Errorf("naming conflict detected for CRD %s", crd.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
|
||||
func getGVKIfNotFound(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||
currentGVK := obj.GetObjectKind().GroupVersionKind()
|
||||
formedGVK := schema.GroupVersionKind{}
|
||||
|
||||
kind := currentGVK.Kind
|
||||
if len(kind) == 0 {
|
||||
gvks, _, err := scheme.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return formedGVK, err
|
||||
}
|
||||
kind = gvks[0].Kind
|
||||
}
|
||||
|
||||
var listMeta metav1.Common
|
||||
objectMeta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
listMeta, err = meta.CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return formedGVK, err
|
||||
}
|
||||
} else {
|
||||
listMeta = objectMeta
|
||||
}
|
||||
|
||||
version := currentGVK.GroupVersion().String()
|
||||
if len(version) == 0 {
|
||||
selfLink := listMeta.GetSelfLink()
|
||||
if len(selfLink) == 0 {
|
||||
return formedGVK, ErrNoSelfLink
|
||||
}
|
||||
selfLinkURL, err := url.Parse(selfLink)
|
||||
if err != nil {
|
||||
return formedGVK, err
|
||||
}
|
||||
// example paths: /<prefix>/<version>/*
|
||||
parts := strings.Split(selfLinkURL.Path, "/")
|
||||
if len(parts) < 3 {
|
||||
return formedGVK, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version)
|
||||
}
|
||||
version = parts[2]
|
||||
}
|
||||
|
||||
formedGVK.Kind = kind
|
||||
formedGVK.Version = version
|
||||
|
||||
return formedGVK, nil
|
||||
}
|
||||
|
||||
func (a *applier) ApplyStatus(ctx context.Context, obj ctrlclient.Object, statusObj interface{}) error {
|
||||
var objectKey ctrlclient.ObjectKey
|
||||
var original ctrlclient.Object
|
||||
var err error
|
||||
if mo, ok := obj.(metav1.Object); ok {
|
||||
objectKey = ctrlclient.ObjectKey{
|
||||
Name: mo.GetName(),
|
||||
Namespace: mo.GetNamespace(),
|
||||
}
|
||||
}
|
||||
|
||||
gvk, err := GetGVK(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
original, err = util.NewObject(gvk)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
err := a.Get(ctx, objectKey, original)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.Status().Patch(ctx, obj, NewStatus(original, statusObj))
|
||||
})
|
||||
}
|
||||
305
components/common/pkg/controller/apply/apply_test.go
Normal file
305
components/common/pkg/controller/apply/apply_test.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
cruntime "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/runtime"
|
||||
clusterv2 "github.com/RafaySystems/rcloud-base/components/common/proto/types/controller"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func getObject(name string) ctrlclient.Object {
|
||||
f, err := os.Open(fmt.Sprintf("testdata/%s", name))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
yb, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
jb, err := yaml.YAMLToJSON(yb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var so clusterv2.StepObject
|
||||
err = json.Unmarshal(jb, &so)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
o, _, err := cruntime.ToUnstructuredObject(&so)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func TestCRDNSApply(t *testing.T) {
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o3 := getObject("rafay-system-ns.yaml")
|
||||
err = applier.Apply(context.TODO(), o3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplier(t *testing.T) {
|
||||
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cm1 := corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test-cm",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"test1": "test1",
|
||||
},
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), &cm1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cm1 = corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test-cm",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"test2": "test2",
|
||||
},
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), &cm1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
s1 := corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test-s-1",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"test1": []byte("test1"),
|
||||
},
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), &s1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
s1 = corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test-s-1",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"test2": []byte("test2"),
|
||||
},
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), &s1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o1 := getObject("crd1.yaml")
|
||||
|
||||
err = applier.Apply(context.TODO(), o1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o2 := getObject("crd1-modified.yaml")
|
||||
err = applier.Apply(context.TODO(), o2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o3 := getObject("cr1.yaml")
|
||||
err = applier.Apply(context.TODO(), o3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o4 := getObject("statefulset.yaml")
|
||||
err = applier.Apply(context.TODO(), o4)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o5 := getObject("statefulset-patch.yaml")
|
||||
err = applier.Apply(context.TODO(), o5)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// jb, _ := GetPreviousConfig(o4)
|
||||
|
||||
// t.Log(string(jb))
|
||||
|
||||
}
|
||||
|
||||
func TestApplyForPod(t *testing.T) {
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o1 := getObject("pod1.yaml")
|
||||
|
||||
err = applier.Apply(context.TODO(), o1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o2 := getObject("pod2.yaml")
|
||||
err = applier.Apply(context.TODO(), o2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestApplyDeployment(t *testing.T) {
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o1 := getObject("deployment.yaml")
|
||||
|
||||
err = applier.Apply(context.TODO(), o1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o2 := getObject("deployment-patch.yaml")
|
||||
err = applier.Apply(context.TODO(), o2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestServiceApply(t *testing.T) {
|
||||
// applier, err := NewDynamicApplier()
|
||||
// // if err != nil {
|
||||
// // t.Error(err)
|
||||
// // return
|
||||
// // }
|
||||
|
||||
// // o1 := getObject("service1.yaml")
|
||||
|
||||
// // err = applier.Apply(context.TODO(), o1)
|
||||
// // if err != nil {
|
||||
// // t.Error(err)
|
||||
// // return
|
||||
// // }
|
||||
|
||||
// o2 := getObject("service2-current.yaml")
|
||||
// err = applier.Apply(context.TODO(), o2)
|
||||
// if err != nil {
|
||||
// t.Error(err)
|
||||
// return
|
||||
// }
|
||||
}
|
||||
|
||||
func TestCRDApply(t *testing.T) {
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o1 := getObject("crd1.yaml")
|
||||
|
||||
err = applier.Apply(context.TODO(), o1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o2 := getObject("cr1.yaml")
|
||||
err = applier.Apply(context.TODO(), o2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidApply(t *testing.T) {
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
o1 := getObject("invalid-deployment.yaml")
|
||||
|
||||
err = applier.Apply(context.TODO(), o1)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
return
|
||||
}
|
||||
t.Log(err.Error())
|
||||
}
|
||||
46
components/common/pkg/controller/apply/appy_bench_test.go
Normal file
46
components/common/pkg/controller/apply/appy_bench_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkLargeApply(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
largeApply()
|
||||
}
|
||||
}
|
||||
|
||||
func largeApply() {
|
||||
obj := getObject("prometheus.yaml")
|
||||
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), obj)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestLargeApply(t *testing.T) {
|
||||
obj := getObject("prometheus.yaml")
|
||||
|
||||
applier, err := NewDynamicApplier()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = applier.Apply(context.TODO(), obj)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
127
components/common/pkg/controller/apply/patch.go
Normal file
127
components/common/pkg/controller/apply/patch.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/scheme"
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/util"
|
||||
sp "k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
var (
|
||||
patchLog = logf.Log.WithName("cluster-v2-patch")
|
||||
)
|
||||
|
||||
type patch struct {
|
||||
current client.Object
|
||||
}
|
||||
|
||||
var _ client.Patch = (*patch)(nil)
|
||||
|
||||
func (p *patch) Data(o client.Object) ([]byte, error) {
|
||||
var err error
|
||||
var ret []byte
|
||||
var current, modified, original []byte
|
||||
|
||||
current, err = getBytes(p.current, false)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to serialize current object %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gvk, err := util.GetGVK(current)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get gvk of current object %s", err.Error())
|
||||
}
|
||||
|
||||
original, err = GetOriginalConfig(p.current)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to serialize original object %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modified, err = getBytes(o, false)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to serialize modified object %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if util.IsStrategicMergePatch(*gvk) {
|
||||
ret, err = util.CreateStrategicMergePatch(*gvk, original, current, modified)
|
||||
} else {
|
||||
ret, err = util.CreateJSONMergePatch(original, current, modified)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to create patch %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (p *patch) Type() types.PatchType {
|
||||
current, _ := getBytes(p.current, false)
|
||||
|
||||
gvk, _ := util.GetGVK(current)
|
||||
if util.IsStrategicMergePatch(*gvk) {
|
||||
return types.StrategicMergePatchType
|
||||
}
|
||||
return types.MergePatchType
|
||||
}
|
||||
|
||||
// NewPatch prepres patch for current runtime Object
|
||||
func NewPatch(current client.Object) client.Patch {
|
||||
|
||||
return &patch{
|
||||
current: current,
|
||||
}
|
||||
}
|
||||
|
||||
type patchStatus struct {
|
||||
o client.Object
|
||||
statusObj interface{}
|
||||
}
|
||||
|
||||
var _ client.Patch = (*patchStatus)(nil)
|
||||
|
||||
func (p *patchStatus) Data(current client.Object) ([]byte, error) {
|
||||
oBuf := new(bytes.Buffer)
|
||||
err := scheme.Serializer.Encode(p.o, oBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cBuf := new(bytes.Buffer)
|
||||
err = scheme.Serializer.Encode(current, cBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pb, err := sp.CreateTwoWayMergePatch(oBuf.Bytes(), cBuf.Bytes(), p.statusObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sp.StrategicMergePatch(oBuf.Bytes(), pb, p.statusObj)
|
||||
|
||||
}
|
||||
|
||||
func (p *patchStatus) Type() types.PatchType {
|
||||
return types.MergePatchType
|
||||
}
|
||||
|
||||
// NewStatus returns new path for status objects
|
||||
func NewStatus(original client.Object, statusObj interface{}) client.Patch {
|
||||
return &patchStatus{
|
||||
o: original,
|
||||
statusObj: statusObj,
|
||||
}
|
||||
}
|
||||
19
components/common/pkg/controller/apply/patch_large_test.go
Normal file
19
components/common/pkg/controller/apply/patch_large_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package apply
|
||||
|
||||
import "testing"
|
||||
|
||||
func largePatch() error {
|
||||
obj := getObject("prometheus.yaml")
|
||||
|
||||
_, err := NewPatch(obj).Data(obj)
|
||||
return err
|
||||
}
|
||||
|
||||
func BenchmarkLargePatch(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
err := largePatch()
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
32
components/common/pkg/controller/apply/patch_test.go
Normal file
32
components/common/pkg/controller/apply/patch_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServicePatch(t *testing.T) {
|
||||
s1 := getObject("service2-current.yaml")
|
||||
s2 := getObject(("service2-modified.yaml"))
|
||||
|
||||
p := NewPatch(s1)
|
||||
b, err := p.Data(s2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(string(b))
|
||||
|
||||
}
|
||||
|
||||
func TestServicePatch1(t *testing.T) {
|
||||
current := getObject("service1-current.yaml")
|
||||
modified := getObject(("service1-modified.yaml"))
|
||||
|
||||
p := NewPatch(current)
|
||||
b, err := p.Data(modified)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(string(b))
|
||||
}
|
||||
8
components/common/pkg/controller/apply/testdata/cr1.yaml
vendored
Normal file
8
components/common/pkg/controller/apply/testdata/cr1.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: "stable.example.com/v1"
|
||||
kind: CronTab
|
||||
metadata:
|
||||
name: my-new-cron-object
|
||||
namespace: default
|
||||
spec:
|
||||
cronSpec: "* * * * */5"
|
||||
image: my-awesome-cron-image
|
||||
43
components/common/pkg/controller/apply/testdata/crd1-modified.yaml
vendored
Normal file
43
components/common/pkg/controller/apply/testdata/crd1-modified.yaml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.stable.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: stable.example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: crontabs
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: crontab
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: CronTab
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- ct
|
||||
- ct4
|
||||
preserveUnknownFields: false
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
cronSpec:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
42
components/common/pkg/controller/apply/testdata/crd1.yaml
vendored
Normal file
42
components/common/pkg/controller/apply/testdata/crd1.yaml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.stable.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: stable.example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: crontabs
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: crontab
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: CronTab
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- ct
|
||||
preserveUnknownFields: false
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
cronSpec:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
24
components/common/pkg/controller/apply/testdata/deployment-patch.yaml
vendored
Normal file
24
components/common/pkg/controller/apply/testdata/deployment-patch.yaml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: default
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
rafay.dev/original: '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"namespace":"default","name":"nginx-deployment","labels":{"app":"nginx"}},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.7.9","ports":[{"containerPort":80}]}]}}}}'
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
ports:
|
||||
- containerPort: 80
|
||||
31
components/common/pkg/controller/apply/testdata/deployment.yaml
vendored
Normal file
31
components/common/pkg/controller/apply/testdata/deployment.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: default
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
rafay.dev/original: '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"namespace":"default","name":"nginx-deployment","labels":{"app":"nginx"}},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.7.9","ports":[{"containerPort":80}],"readinessProbe":{"httpGet":{"path":"/healthz","port":8080,"httpHeaders":[{"name":"X-Custom-Header","value":"Awesome"}]}}}]}}}}'
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
ports:
|
||||
- containerPort: 80
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
httpHeaders:
|
||||
- name: X-Custom-Header
|
||||
value: Awesome
|
||||
31
components/common/pkg/controller/apply/testdata/invalid-deployment.yaml
vendored
Normal file
31
components/common/pkg/controller/apply/testdata/invalid-deployment.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment11
|
||||
metadata:
|
||||
namespace: default
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
annotations:
|
||||
rafay.dev/original: '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"namespace":"default","name":"nginx-deployment","labels":{"app":"nginx"}},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.7.9","ports":[{"containerPort":80}],"readinessProbe":{"httpGet":{"path":"/healthz","port":8080,"httpHeaders":[{"name":"X-Custom-Header","value":"Awesome"}]}}}]}}}}'
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
ports:
|
||||
- containerPort: 80
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
httpHeaders:
|
||||
- name: X-Custom-Header
|
||||
value: Awesome
|
||||
30
components/common/pkg/controller/apply/testdata/pod1.yaml
vendored
Normal file
30
components/common/pkg/controller/apply/testdata/pod1.yaml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
app: web
|
||||
name: rss-site
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: front-end
|
||||
ports:
|
||||
- containerPort: 80
|
||||
protocol: TCP
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
- image: nickchase/rss-php-nginx:v1
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: rss-reader
|
||||
ports:
|
||||
- containerPort: 88
|
||||
protocol: TCP
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
enableServiceLinks: true
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
terminationGracePeriodSeconds: 30
|
||||
30
components/common/pkg/controller/apply/testdata/pod2.yaml
vendored
Normal file
30
components/common/pkg/controller/apply/testdata/pod2.yaml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
app: web
|
||||
name: rss-site
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.17
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: front-end
|
||||
ports:
|
||||
- containerPort: 80
|
||||
protocol: TCP
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
- image: nickchase/rss-php-nginx:v1
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: rss-reader
|
||||
ports:
|
||||
- containerPort: 88
|
||||
protocol: TCP
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
dnsPolicy: ClusterFirst
|
||||
enableServiceLinks: true
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
terminationGracePeriodSeconds: 30
|
||||
9132
components/common/pkg/controller/apply/testdata/prometheus.yaml
vendored
Normal file
9132
components/common/pkg/controller/apply/testdata/prometheus.yaml
vendored
Normal file
File diff suppressed because one or more lines are too long
499
components/common/pkg/controller/apply/testdata/rafay-system-ns.yaml
vendored
Normal file
499
components/common/pkg/controller/apply/testdata/rafay-system-ns.yaml
vendored
Normal file
@@ -0,0 +1,499 @@
|
||||
apiVersion: cluster.rafay.dev/v2
|
||||
kind: Namespace
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/object-hash: avinash-test
|
||||
label-1: test
|
||||
rafay.dev/pruned: "null"
|
||||
rafay.dev/random: jcoVQsZEXH
|
||||
rafay.dev/resource-hash: 4fc5c12346ea0fb4ac19cca416fbaffb3c77a0ace763c2ad37510c0cca274af1
|
||||
rep-drift-action: deny
|
||||
creationTimestamp: "2021-09-15T05:00:18Z"
|
||||
finalizers:
|
||||
- cluster.rafay.dev.v2.predelete
|
||||
generation: 1
|
||||
labels:
|
||||
rafay.dev/global: "true"
|
||||
rafay.dev/modified-sa: "true"
|
||||
rafay.dev/psp: rafay-privileged-psp
|
||||
rafay.dev/system: "true"
|
||||
rep-drift-reconcillation: enabled
|
||||
managedFields:
|
||||
- apiVersion: cluster.rafay.dev/v2
|
||||
fieldsType: FieldsV1
|
||||
fieldsV1:
|
||||
f:spec:
|
||||
f:init: {}
|
||||
f:namespaceMeta: {}
|
||||
f:status:
|
||||
.: {}
|
||||
f:conditions: {}
|
||||
f:init: {}
|
||||
f:namespaceRef: {}
|
||||
f:observedGeneration: {}
|
||||
f:postCreate: {}
|
||||
manager: manager
|
||||
operation: Update
|
||||
time: "2021-09-15T05:00:18Z"
|
||||
- apiVersion: cluster.rafay.dev/v2
|
||||
fieldsType: FieldsV1
|
||||
fieldsV1:
|
||||
f:metadata:
|
||||
f:annotations:
|
||||
.: {}
|
||||
f:rafay.dev/object-hash: {}
|
||||
f:rafay.dev/pruned: {}
|
||||
f:rafay.dev/random: {}
|
||||
f:rafay.dev/resource-hash: {}
|
||||
f:rep-drift-action: {}
|
||||
f:finalizers:
|
||||
.: {}
|
||||
v:"cluster.rafay.dev.v2.predelete": {}
|
||||
f:labels:
|
||||
.: {}
|
||||
f:rafay.dev/global: {}
|
||||
f:rafay.dev/modified-sa: {}
|
||||
f:rafay.dev/psp: {}
|
||||
f:rafay.dev/system: {}
|
||||
f:rep-drift-reconcillation: {}
|
||||
f:spec:
|
||||
.: {}
|
||||
f:postCreate: {}
|
||||
manager: rafay-connector
|
||||
operation: Update
|
||||
time: "2021-09-15T05:00:18Z"
|
||||
name: rafay-system
|
||||
namespace: default
|
||||
resourceVersion: "1272"
|
||||
uid: e4550a5c-a2ef-4277-8283-0f4e3478970c
|
||||
spec:
|
||||
init:
|
||||
- name: create-manager-cluster-role
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"ClusterRole","rules":[{"verbs":["*"],"apiGroups":["*"],"resources":["*"]},{"verbs":["*"],"nonResourceURLs":["*"]},{"verbs":["create","delete","get","list","patch","update","watch"],"apiGroups":["cluster.rafay.dev"],"resources":["namespaces"]},{"verbs":["get","patch","update"],"apiGroups":["cluster.rafay.dev"],"resources":["namespaces/status"]},{"verbs":["create","delete","get","list","patch","update","watch"],"apiGroups":["cluster.rafay.dev"],"resources":["tasklets"]},{"verbs":["get","patch","update"],"apiGroups":["cluster.rafay.dev"],"resources":["tasklets/status"]},{"verbs":["create","delete","get","list","patch","update","watch"],"apiGroups":["cluster.rafay.dev"],"resources":["tasks"]},{"verbs":["get","patch","update"],"apiGroups":["cluster.rafay.dev"],"resources":["tasks/status"]}],"metadata":{"name":"rafay:manager","creationTimestamp":null,"labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:manager
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- namespaces
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- namespaces/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- tasklets
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- tasklets/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- tasks
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- cluster.rafay.dev
|
||||
resources:
|
||||
- tasks/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- name: create-proxy-cluster-role
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"ClusterRole","rules":[{"verbs":["create"],"apiGroups":["authentication.k8s.io"],"resources":["tokenreviews"]},{"verbs":["create"],"apiGroups":["authorization.k8s.io"],"resources":["subjectaccessreviews"]}],"metadata":{"name":"rafay:proxy-role","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
namespaceMeta:
|
||||
annotations:
|
||||
rep-drift-action: deny
|
||||
role: rafay-system
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
rafay.dev/global: "true"
|
||||
rafay.dev/modified-sa: "true"
|
||||
rafay.dev/psp: rafay-privileged-psp
|
||||
rafay.dev/system: "true"
|
||||
rep-drift-reconcillation: enabled
|
||||
role: rafay-system
|
||||
name: rafay-system
|
||||
postCreate:
|
||||
- name: create-system-sa-serviceaccount
|
||||
object:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"ServiceAccount","metadata":{"name":"system-sa","namespace":"rafay-system","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"apiVersion":"v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: system-sa
|
||||
namespace: rafay-system
|
||||
- name: create-leader-election-role
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"Role","rules":[{"verbs":["get","list","watch","create","update","patch","delete"],"apiGroups":[""],"resources":["configmaps"]},{"verbs":["get","update","patch"],"apiGroups":[""],"resources":["configmaps/status"]},{"verbs":["create"],"apiGroups":[""],"resources":["events"]}],"metadata":{"name":"rafay:leader-election-role","namespace":"rafay-system","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:leader-election-role
|
||||
namespace: rafay-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- name: create-leaderelection-role-binding
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"RoleBinding","roleRef":{"kind":"Role","name":"rafay:leader-election-role","apiGroup":"rbac.authorization.k8s.io"},"metadata":{"name":"rafay:leader-election-rolebinding","namespace":"rafay-system","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"subjects":[{"kind":"ServiceAccount","name":"system-sa","namespace":"rafay-system"},{"kind":"ServiceAccount","name":"default","namespace":"rafay-system"}],"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:leader-election-rolebinding
|
||||
namespace: rafay-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: rafay:leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: system-sa
|
||||
namespace: rafay-system
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: rafay-system
|
||||
- name: create-manager-role-binding
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"ClusterRoleBinding","roleRef":{"kind":"ClusterRole","name":"rafay:manager","apiGroup":"rbac.authorization.k8s.io"},"metadata":{"name":"rafay:rafay-system:manager-rolebinding","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"subjects":[{"kind":"ServiceAccount","name":"system-sa","namespace":"rafay-system"},{"kind":"ServiceAccount","name":"default","namespace":"rafay-system"}],"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:rafay-system:manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: rafay:manager
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: system-sa
|
||||
namespace: rafay-system
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: rafay-system
|
||||
- name: create-proxy-role-binding
|
||||
object:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind":"ClusterRoleBinding","roleRef":{"kind":"ClusterRole","name":"rafay:proxy-role","apiGroup":"rbac.authorization.k8s.io"},"metadata":{"name":"rafay:rafay-system:proxy-rolebinding","labels":{"rep-drift-reconcillation":"enabled"},"annotations":{"rep-drift-action":"deny"}},"subjects":[{"kind":"ServiceAccount","name":"system-sa","namespace":"rafay-system"},{"kind":"ServiceAccount","name":"default","namespace":"rafay-system"}],"apiVersion":"rbac.authorization.k8s.io/v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay:rafay-system:proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: rafay:proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: system-sa
|
||||
namespace: rafay-system
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: rafay-system
|
||||
- name: create-access-log-configmap_v2_1
|
||||
object:
|
||||
apiVersion: v1
|
||||
data:
|
||||
fluent.conf: |
|
||||
<match kube.rafay-system.ingress-nginx-controller**>
|
||||
@type forward
|
||||
require_ack_response true
|
||||
ack_response_timeout 190
|
||||
<buffer>
|
||||
@type memory
|
||||
flush_mode interval
|
||||
retry_type exponential_backoff
|
||||
flush_thread_count 2
|
||||
flush_interval 60s
|
||||
retry_forever false
|
||||
retry_max_interval 1h
|
||||
retry_timeout 32h
|
||||
retry_max_times 17
|
||||
retry_randomize true
|
||||
chunk_limit_size 5M
|
||||
queue_limit_length 8
|
||||
overflow_action block
|
||||
</buffer>
|
||||
<server>
|
||||
host log-aggregator.rafay-infra.svc.cluster.local
|
||||
port 24224
|
||||
</server>
|
||||
</match>
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"data":{"fluent.conf":"<match kube.rafay-system.ingress-nginx-controller**>\n @type
|
||||
forward\n require_ack_response true\n ack_response_timeout 190\n <buffer>\n @type
|
||||
memory\n flush_mode interval\n retry_type exponential_backoff\n flush_thread_count
|
||||
2\n flush_interval 60s\n retry_forever false\n retry_max_interval
|
||||
1h\n retry_timeout 32h\n retry_max_times 17\n retry_randomize
|
||||
true\n chunk_limit_size 5M\n queue_limit_length 8\n overflow_action
|
||||
block\n </buffer>\n <server>\n host log-aggregator.rafay-infra.svc.cluster.local\n port
|
||||
24224\n </server>\n</match>\n"},"kind":"ConfigMap","metadata":{"name":"rafay-ingress-log-config","labels":{"logger":"rafay-logger","rep-drift-reconcillation":"enabled"},"namespace":"rafay-system","annotations":{"rep-drift-action":"deny"}},"apiVersion":"v1"}'
|
||||
rep-drift-action: deny
|
||||
labels:
|
||||
logger: rafay-logger
|
||||
rep-drift-reconcillation: enabled
|
||||
name: rafay-ingress-log-config
|
||||
namespace: rafay-system
|
||||
status:
|
||||
conditions:
|
||||
- lastUpdateTime: "2021-09-15T05:00:18Z"
|
||||
reason: all steps complete
|
||||
status: Complete
|
||||
type: NamespaceInit
|
||||
- lastUpdateTime: "2021-09-15T05:00:18Z"
|
||||
reason: namespace created
|
||||
status: Complete
|
||||
type: NamespaceCreate
|
||||
- lastUpdateTime: "2021-09-15T05:00:18Z"
|
||||
reason: all steps complete
|
||||
status: Complete
|
||||
type: NamespacePostCreate
|
||||
- lastUpdateTime: "2021-09-15T05:00:18Z"
|
||||
reason: all steps complete
|
||||
status: Complete
|
||||
type: NamespaceReady
|
||||
init:
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-manager-cluster-role
|
||||
objectReason: object type *v1.ClusterRole not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
name: rafay:manager
|
||||
resourceVersion: "1258"
|
||||
uid: 855e1d07-8a75-47be-9e98-d03810f634a6
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-proxy-cluster-role
|
||||
objectReason: object type *v1.ClusterRole not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
name: rafay:proxy-role
|
||||
resourceVersion: "1259"
|
||||
uid: abf1cc60-8f9a-4fad-be5d-5551fc6c236a
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
namespaceRef:
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
name: rafay-system
|
||||
resourceVersion: "1262"
|
||||
uid: 574a3611-2ab8-436f-999a-f463360e5d3d
|
||||
observedGeneration: 1
|
||||
postCreate:
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-system-sa-serviceaccount
|
||||
objectReason: object type *v1.ServiceAccount not handled
|
||||
objectRef:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
name: system-sa
|
||||
namespace: rafay-system
|
||||
resourceVersion: "1265"
|
||||
uid: f1981c17-775d-4138-8633-776ad49fb586
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-leader-election-role
|
||||
objectReason: object type *v1.Role not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
name: rafay:leader-election-role
|
||||
namespace: rafay-system
|
||||
resourceVersion: "1266"
|
||||
uid: 3afaf464-0b94-4116-9bcc-93a4978174c6
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-leaderelection-role-binding
|
||||
objectReason: object type *v1.RoleBinding not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
name: rafay:leader-election-rolebinding
|
||||
namespace: rafay-system
|
||||
resourceVersion: "1267"
|
||||
uid: 12551dfd-7143-4e83-a0a6-0c4ab1e1d4fe
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-manager-role-binding
|
||||
objectReason: object type *v1.ClusterRoleBinding not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
name: rafay:rafay-system:manager-rolebinding
|
||||
resourceVersion: "1268"
|
||||
uid: 2fe8a87a-d571-4997-b22e-a6da5bdcbe49
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-proxy-role-binding
|
||||
objectReason: object type *v1.ClusterRoleBinding not handled
|
||||
objectRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
name: rafay:rafay-system:proxy-rolebinding
|
||||
resourceVersion: "1269"
|
||||
uid: 7f3c4c02-cd90-40c0-8663-5f156c50e6c3
|
||||
objectSpecHash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
- jobReason: not configured
|
||||
jobState: StepJobComplete
|
||||
name: create-access-log-configmap_v2_1
|
||||
objectReason: object type *v1.ConfigMap not handled
|
||||
objectRef:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: rafay-ingress-log-config
|
||||
namespace: rafay-system
|
||||
resourceVersion: "1270"
|
||||
uid: e86e3ea0-a3b2-4187-b552-c18e5f6ca30f
|
||||
objectSpecHash: d26d566c010b3b8a7dde8ef1a406a961c8839d60951b08cbd8d34c1c885c6cd2
|
||||
objectState: StepObjectComplete
|
||||
reason: complete
|
||||
state: StepComplete
|
||||
55
components/common/pkg/controller/apply/testdata/service1-current.yaml
vendored
Normal file
55
components/common/pkg/controller/apply/testdata/service1-current.yaml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: '{"kind": "Service", "spec": {"type": "ClusterIP", "ports":
|
||||
[{"name": "log-aggregator-tcp", "port": 8888, "nodePort": null, "protocol":
|
||||
"TCP", "targetPort": 8888}, {"name": "log-aggregator-udp", "port": 5140, "nodePort":
|
||||
null, "protocol": "UDP", "targetPort": 5140}, {"name": "log-aggregator-fwd",
|
||||
"port": 24224, "nodePort": null, "protocol": "TCP", "targetPort": 24224}, {"name":
|
||||
"prometheus", "port": 24231, "nodePort": null, "protocol": "TCP", "targetPort":
|
||||
24231}], "selector": {"app": "log-aggregator"}}, "metadata": {"name": "log-aggregator",
|
||||
"namespace": "rafay-infra", "annotations": {"rafay.dev/previous": "{\"kind\":
|
||||
\"Service\", \"spec\": {\"type\": \"ClusterIP\", \"ports\": [{\"name\": \"log-aggregator-tcp\",
|
||||
\"port\": 8888, \"protocol\": \"TCP\", \"targetPort\": 8888}, {\"name\": \"log-aggregator-udp\",
|
||||
\"port\": 5140, \"protocol\": \"UDP\", \"targetPort\": 5140}, {\"name\": \"log-aggregator-fwd\",
|
||||
\"port\": 24224, \"protocol\": \"TCP\", \"targetPort\": 24224}, {\"name\": \"prometheus\",
|
||||
\"port\": 24231, \"protocol\": \"TCP\", \"targetPort\": 24231}], \"selector\":
|
||||
{\"app\": \"log-aggregator\"}}, \"metadata\": {\"name\": \"log-aggregator\",
|
||||
\"namespace\": \"rafay-infra\"}, \"apiVersion\": \"v1\"}"}}, "apiVersion": "v1"}'
|
||||
creationTimestamp: "2020-02-12T21:49:41Z"
|
||||
name: log-aggregator
|
||||
namespace: default
|
||||
resourceVersion: "341295"
|
||||
selfLink: /api/v1/namespaces/default/services/log-aggregator
|
||||
uid: 0c1409f9-eed0-4f1d-9c29-128540ee6db4
|
||||
spec:
|
||||
clusterIP: 10.43.88.175
|
||||
externalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- name: log-aggregator-tcp
|
||||
nodePort: 31285
|
||||
port: 8888
|
||||
protocol: TCP
|
||||
targetPort: 8888
|
||||
- name: log-aggregator-udp
|
||||
nodePort: 32198
|
||||
port: 5140
|
||||
protocol: UDP
|
||||
targetPort: 5140
|
||||
- name: log-aggregator-fwd
|
||||
nodePort: 30669
|
||||
port: 24224
|
||||
protocol: TCP
|
||||
targetPort: 24224
|
||||
- name: prometheus
|
||||
nodePort: 30320
|
||||
port: 24231
|
||||
protocol: TCP
|
||||
targetPort: 24231
|
||||
selector:
|
||||
app: log-aggregator
|
||||
sessionAffinity: None
|
||||
type: NodePort
|
||||
status:
|
||||
loadBalancer: {}
|
||||
48
components/common/pkg/controller/apply/testdata/service1-modified.yaml
vendored
Normal file
48
components/common/pkg/controller/apply/testdata/service1-modified.yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: log-aggregator
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: log-aggregator-tcp
|
||||
nodePort: 0
|
||||
port: 8888
|
||||
protocol: TCP
|
||||
targetPort: 8888
|
||||
- name: log-aggregator-udp
|
||||
nodePort: 0
|
||||
port: 5140
|
||||
protocol: UDP
|
||||
targetPort: 5140
|
||||
- name: log-aggregator-fwd
|
||||
nodePort: 0
|
||||
port: 24224
|
||||
protocol: TCP
|
||||
targetPort: 24224
|
||||
- name: prometheus
|
||||
nodePort: 0
|
||||
port: 24231
|
||||
protocol: TCP
|
||||
targetPort: 24231
|
||||
selector:
|
||||
app: log-aggregator
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
30
components/common/pkg/controller/apply/testdata/service2-current.yaml
vendored
Normal file
30
components/common/pkg/controller/apply/testdata/service2-current.yaml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/original: |
|
||||
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"service.beta.kubernetes.io/aws-load-balancer-internal":"0.0.0.0/0"},"name":"device-manager-service","namespace":"default"},"spec":{"ports":[{"name":"grpc","port":55050}],"selector":{"app":"device-manager-service"},"type":"LoadBalancer"}}
|
||||
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
|
||||
creationTimestamp: "2020-02-12T23:52:46Z"
|
||||
name: device-manager-service
|
||||
namespace: default
|
||||
resourceVersion: "346679"
|
||||
selfLink: /api/v1/namespaces/default/services/device-manager-service
|
||||
uid: a8125b03-c881-4940-95be-fa3fd1e9555b
|
||||
spec:
|
||||
clusterIP: 10.43.163.228
|
||||
externalTrafficPolicy: Cluster
|
||||
ports:
|
||||
- name: grpc
|
||||
nodePort: 31963
|
||||
port: 55050
|
||||
protocol: TCP
|
||||
targetPort: 55050
|
||||
selector:
|
||||
app: device-manager-service
|
||||
sessionAffinity: None
|
||||
type: LoadBalancer
|
||||
status:
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- ip: 172.18.0.2
|
||||
14
components/common/pkg/controller/apply/testdata/service2-modified.yaml
vendored
Normal file
14
components/common/pkg/controller/apply/testdata/service2-modified.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: device-manager-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 55050
|
||||
nodePort: 0
|
||||
selector:
|
||||
app: device-manager-service
|
||||
#type: ClusterIP
|
||||
|
||||
34
components/common/pkg/controller/apply/testdata/statefulset-patch.yaml
vendored
Normal file
34
components/common/pkg/controller/apply/testdata/statefulset-patch.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
annotations:
|
||||
rafay.dev/overridedBy: global/global-override
|
||||
name: rafay-connector
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rafay-connector
|
||||
serviceName: "connector"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rafay-connector
|
||||
spec:
|
||||
containers:
|
||||
- image: rafaysystems/rafay-connector:latest
|
||||
imagePullPolicy: Always
|
||||
name: connector
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /etc/config
|
||||
name: connector-config
|
||||
priorityClassName: rafay-cluster-critical
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- configMap:
|
||||
name: connector-config
|
||||
name: connector-config
|
||||
status:
|
||||
replicas: 0
|
||||
56
components/common/pkg/controller/apply/testdata/statefulset.yaml
vendored
Normal file
56
components/common/pkg/controller/apply/testdata/statefulset.yaml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"annotations":{},"name":"rafay-connector","namespace":"rafay-system"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"rafay-connector"}},"serviceName":"connector","template":{"metadata":{"labels":{"app":"rafay-connector"}},"spec":{"containers":[{"image":"rafaysystems/rafay-connector:latest","name":"connector","volumeMounts":[{"mountPath":"/etc/config","name":"connector-config"}]}],"priorityClassName":"rafay-cluster-critical","terminationGracePeriodSeconds":10,"volumes":[{"configMap":{"name":"connector-config"},"name":"connector-config"}]}}}}
|
||||
name: rafay-connector
|
||||
namespace: default
|
||||
spec:
|
||||
podManagementPolicy: OrderedReady
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rafay-connector
|
||||
serviceName: connector
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: rafay-connector
|
||||
spec:
|
||||
containers:
|
||||
- image: rafaysystems/rafay-connector:latest
|
||||
imagePullPolicy: Always
|
||||
name: connector
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /etc/config
|
||||
name: connector-config
|
||||
dnsPolicy: ClusterFirst
|
||||
priorityClassName: rafay-cluster-critical
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
name: connector-config
|
||||
name: connector-config
|
||||
updateStrategy:
|
||||
rollingUpdate:
|
||||
partition: 0
|
||||
type: RollingUpdate
|
||||
status:
|
||||
collisionCount: 0
|
||||
currentReplicas: 1
|
||||
currentRevision: rafay-connector-568bcd85cb
|
||||
observedGeneration: 1
|
||||
readyReplicas: 1
|
||||
replicas: 1
|
||||
updateRevision: rafay-connector-568bcd85cb
|
||||
updatedReplicas: 1
|
||||
117
components/common/pkg/controller/apply/util.go
Normal file
117
components/common/pkg/controller/apply/util.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/components/common/pkg/controller/scheme"
|
||||
clusterv2 "github.com/RafaySystems/rcloud-base/components/common/proto/types/controller"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
cruntime "github.com/RafaySystems/rcloud-base/components/common/pkg/controller/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Errors that could be returned by Apply.
|
||||
var (
|
||||
ErrNilObject = errors.New("can't reference a nil object")
|
||||
ErrNoSelfLink = errors.New("selfLink was empty, can't make reference")
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoPreviousConfig is returned when no previous configuration is found in the annotations
|
||||
ErrNoPreviousConfig = errors.New("last applied configuration not found")
|
||||
)
|
||||
|
||||
var (
|
||||
emptyGVK = schema.GroupVersionKind{}
|
||||
)
|
||||
|
||||
func getBytes(o runtime.Object, withOriginal bool) ([]byte, error) {
|
||||
do := o.DeepCopyObject()
|
||||
if !withOriginal {
|
||||
if mo, ok := do.(metav1.Object); ok {
|
||||
annotations := mo.GetAnnotations()
|
||||
if annotations != nil {
|
||||
delete(annotations, clusterv2.OrignalConfig)
|
||||
}
|
||||
mo.SetAnnotations(annotations)
|
||||
}
|
||||
}
|
||||
return runtime.Encode(unstructured.UnstructuredJSONScheme, o)
|
||||
|
||||
}
|
||||
|
||||
// GetOriginalConfig returns previous config of the object
|
||||
func GetOriginalConfig(o runtime.Object) ([]byte, error) {
|
||||
if mo, ok := o.(metav1.Object); ok {
|
||||
annotations := mo.GetAnnotations()
|
||||
if annotations != nil {
|
||||
if v, ok := annotations[clusterv2.OrignalConfig]; ok {
|
||||
return []byte(v), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetGVK returns group version kind of a runtime object
|
||||
func GetGVK(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||
gvks, _, err := scheme.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return emptyGVK, err
|
||||
}
|
||||
return gvks[0], nil
|
||||
}
|
||||
|
||||
// updateObject updates current object with modified object
|
||||
func updateObject(current, modified runtime.Object) error {
|
||||
if reflect.TypeOf(current) != reflect.TypeOf(modified) {
|
||||
current = cruntime.ToStructuredObject(current)
|
||||
modified = cruntime.ToStructuredObject(modified)
|
||||
|
||||
//return fmt.Errorf("current %T and modified %T of different types", current, modified)
|
||||
}
|
||||
|
||||
switch current.(type) {
|
||||
case *clusterv2.Task:
|
||||
c := current.(*clusterv2.Task)
|
||||
m := modified.(*clusterv2.Task)
|
||||
c.ObjectMeta.Labels = m.ObjectMeta.Labels
|
||||
c.ObjectMeta.Annotations = m.ObjectMeta.Annotations
|
||||
c.ObjectMeta.Finalizers = m.ObjectMeta.Finalizers
|
||||
c.Spec = m.Spec
|
||||
|
||||
case *clusterv2.Tasklet:
|
||||
c := current.(*clusterv2.Tasklet)
|
||||
m := modified.(*clusterv2.Tasklet)
|
||||
c.ObjectMeta.Labels = m.ObjectMeta.Labels
|
||||
c.ObjectMeta.Annotations = m.ObjectMeta.Annotations
|
||||
c.ObjectMeta.Finalizers = m.ObjectMeta.Finalizers
|
||||
c.Spec = m.Spec
|
||||
case *clusterv2.Namespace:
|
||||
c := current.(*clusterv2.Namespace)
|
||||
m := modified.(*clusterv2.Namespace)
|
||||
c.ObjectMeta.Labels = m.ObjectMeta.Labels
|
||||
c.ObjectMeta.Annotations = m.ObjectMeta.Annotations
|
||||
c.ObjectMeta.Finalizers = m.ObjectMeta.Finalizers
|
||||
c.Spec = m.Spec
|
||||
case *v1.Node:
|
||||
c := current.(*v1.Node)
|
||||
m := modified.(*v1.Node)
|
||||
c.Labels = m.Labels
|
||||
c.Annotations = m.Annotations
|
||||
c.Finalizers = m.Finalizers
|
||||
c.Spec.Unschedulable = m.Spec.Unschedulable
|
||||
c.Spec.Taints = m.Spec.Taints
|
||||
default:
|
||||
return fmt.Errorf("unhandled type for update %T", current)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
18
components/common/pkg/controller/apply/util_test.go
Normal file
18
components/common/pkg/controller/apply/util_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
clusterv2 "github.com/RafaySystems/rcloud-base/components/common/proto/types/controller"
|
||||
)
|
||||
|
||||
func TestGetGVK(t *testing.T) {
|
||||
ns := clusterv2.Namespace{}
|
||||
|
||||
gvk, err := GetGVK(&ns)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(gvk)
|
||||
}
|
||||
Reference in New Issue
Block a user