From 44d1f43bc6dd9ad7be880601d0abbc94e785a309 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Wed, 11 Nov 2020 12:40:19 -0800 Subject: [PATCH] Add MariaDB patch util Signed-off-by: Tamal Saha --- .../typed/kubedb/v1alpha2/util/mariadb.go | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 client/clientset/versioned/typed/kubedb/v1alpha2/util/mariadb.go diff --git a/client/clientset/versioned/typed/kubedb/v1alpha2/util/mariadb.go b/client/clientset/versioned/typed/kubedb/v1alpha2/util/mariadb.go new file mode 100644 index 0000000000..b1cf02fabd --- /dev/null +++ b/client/clientset/versioned/typed/kubedb/v1alpha2/util/mariadb.go @@ -0,0 +1,156 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + + api "kubedb.dev/apimachinery/apis/kubedb/v1alpha2" + cs "kubedb.dev/apimachinery/client/clientset/versioned/typed/kubedb/v1alpha2" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/golang/glog" + kerr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + kutil "kmodules.xyz/client-go" +) + +func CreateOrPatchMariaDB(ctx context.Context, c cs.KubedbV1alpha2Interface, meta metav1.ObjectMeta, transform func(*api.MariaDB) *api.MariaDB, opts metav1.PatchOptions) (*api.MariaDB, kutil.VerbType, error) { + cur, err := c.MariaDBs(meta.Namespace).Get(ctx, meta.Name, metav1.GetOptions{}) + if kerr.IsNotFound(err) { + glog.V(3).Infof("Creating MariaDB %s/%s.", meta.Namespace, meta.Name) + out, err := c.MariaDBs(meta.Namespace).Create(ctx, transform(&api.MariaDB{ + TypeMeta: metav1.TypeMeta{ + Kind: "MariaDB", + APIVersion: api.SchemeGroupVersion.String(), + }, + ObjectMeta: meta, + }), metav1.CreateOptions{ + DryRun: opts.DryRun, + FieldManager: opts.FieldManager, + }) + return out, kutil.VerbCreated, err + } else if err != nil { + return nil, kutil.VerbUnchanged, err + } + return PatchMariaDB(ctx, c, cur, transform, opts) +} + +func PatchMariaDB(ctx context.Context, c cs.KubedbV1alpha2Interface, cur *api.MariaDB, transform func(*api.MariaDB) *api.MariaDB, opts metav1.PatchOptions) (*api.MariaDB, kutil.VerbType, error) { + return PatchMariaDBObject(ctx, c, cur, transform(cur.DeepCopy()), opts) +} + +func PatchMariaDBObject(ctx context.Context, c cs.KubedbV1alpha2Interface, cur, mod *api.MariaDB, opts metav1.PatchOptions) (*api.MariaDB, kutil.VerbType, error) { + curJson, err := json.Marshal(cur) + if err != nil { + return nil, kutil.VerbUnchanged, err + } + + modJson, err := json.Marshal(mod) + if err != nil { + return nil, kutil.VerbUnchanged, err + } + + patch, err := jsonpatch.CreateMergePatch(curJson, modJson) + if err != nil { + return nil, kutil.VerbUnchanged, err + } + if len(patch) == 0 || string(patch) == "{}" { + return cur, kutil.VerbUnchanged, nil + } + glog.V(3).Infof("Patching MariaDB %s/%s with %s.", cur.Namespace, cur.Name, string(patch)) + out, err := c.MariaDBs(cur.Namespace).Patch(ctx, cur.Name, types.MergePatchType, patch, opts) + return out, kutil.VerbPatched, err +} + +func TryUpdateMariaDB(ctx context.Context, c cs.KubedbV1alpha2Interface, meta metav1.ObjectMeta, transform func(*api.MariaDB) *api.MariaDB, opts metav1.UpdateOptions) (result *api.MariaDB, err error) { + attempt := 0 + err = wait.PollImmediate(kutil.RetryInterval, kutil.RetryTimeout, func() (bool, error) { + attempt++ + cur, e2 := c.MariaDBs(meta.Namespace).Get(ctx, meta.Name, metav1.GetOptions{}) + if kerr.IsNotFound(e2) { + return false, e2 + } else if e2 == nil { + + result, e2 = c.MariaDBs(cur.Namespace).Update(ctx, transform(cur.DeepCopy()), opts) + return e2 == nil, nil + } + glog.Errorf("Attempt %d failed to update MariaDB %s/%s due to %v.", attempt, cur.Namespace, cur.Name, e2) + return false, nil + }) + + if err != nil { + err = fmt.Errorf("failed to update MariaDB %s/%s after %d attempts due to %v", meta.Namespace, meta.Name, attempt, err) + } + return +} + +func UpdateMariaDBStatus( + ctx context.Context, + c cs.KubedbV1alpha2Interface, + meta metav1.ObjectMeta, + transform func(*api.MariaDBStatus) (types.UID, *api.MariaDBStatus), + opts metav1.UpdateOptions, +) (result *api.MariaDB, err error) { + apply := func(x *api.MariaDB) *api.MariaDB { + uid, updatedStatus := transform(x.Status.DeepCopy()) + // Ignore status update when uid does not match + if uid != "" && uid != x.UID { + return x + } + return &api.MariaDB{ + TypeMeta: x.TypeMeta, + ObjectMeta: x.ObjectMeta, + Spec: x.Spec, + Status: *updatedStatus, + } + } + + attempt := 0 + cur, err := c.MariaDBs(meta.Namespace).Get(ctx, meta.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + err = wait.PollImmediate(kutil.RetryInterval, kutil.RetryTimeout, func() (bool, error) { + attempt++ + var e2 error + result, e2 = c.MariaDBs(meta.Namespace).UpdateStatus(ctx, apply(cur), opts) + if kerr.IsConflict(e2) { + latest, e3 := c.MariaDBs(meta.Namespace).Get(ctx, meta.Name, metav1.GetOptions{}) + switch { + case e3 == nil: + cur = latest + return false, nil + case kutil.IsRequestRetryable(e3): + return false, nil + default: + return false, e3 + } + } else if err != nil && !kutil.IsRequestRetryable(e2) { + return false, e2 + } + return e2 == nil, nil + }) + + if err != nil { + err = fmt.Errorf("failed to update status of MariaDB %s/%s after %d attempts due to %v", meta.Namespace, meta.Name, attempt, err) + } + return +}