From c146cd5563f7765996f2105f59f9bd002ee63256 Mon Sep 17 00:00:00 2001 From: Nikita Vanyasin Date: Wed, 15 Jun 2022 10:06:36 +0400 Subject: [PATCH] Add 'crd install' subcommand to new 'ops' binary --- CHANGELOG.md | 1 + cmd/cmd.go | 2 +- cmd/crd.go | 67 ++++++++++++++++++++++++++ pkg/crd/apply.go | 108 +++++++++++++++++++++++------------------- pkg/crd/apply_test.go | 2 +- 5 files changed, 128 insertions(+), 52 deletions(-) create mode 100644 cmd/crd.go diff --git a/CHANGELOG.md b/CHANGELOG.md index e06e4441a..f7008316e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - (Bugfix) Infinite loop fix in ArangoD AsyncClient - (Bugfix) Add Panic Handler - (Bugfix) Unify yaml packages +- (Feature) Add 'crd install' subcommand ## [1.2.13](https://github.com/arangodb/kube-arangodb/tree/1.2.13) (2022-06-07) - (Bugfix) Fix arangosync members state inspection diff --git a/cmd/cmd.go b/cmd/cmd.go index e312ee8ed..8070ecba5 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -289,7 +289,7 @@ func executeMain(cmd *cobra.Command, args []string) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - crd.EnsureCRD(ctx, client) + _ = crd.EnsureCRD(ctx, client, true) } secrets := client.Kubernetes().CoreV1().Secrets(namespace) diff --git a/cmd/crd.go b/cmd/crd.go new file mode 100644 index 000000000..4a26cc863 --- /dev/null +++ b/cmd/crd.go @@ -0,0 +1,67 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package cmd + +import ( + "context" + "os" + "time" + + "github.com/spf13/cobra" + + "github.com/arangodb/kube-arangodb/pkg/crd" + "github.com/arangodb/kube-arangodb/pkg/util/kclient" +) + +var ( + cmdCRD = &cobra.Command{ + Use: "crd", + Run: executeUsage, + Short: "CRD operations", + } + cmdCRDInstall = &cobra.Command{ + Use: "install", + Run: cmdCRDInstallRun, + Short: "Install and update all required CRDs", + } +) + +func init() { + cmdMain.AddCommand(cmdCRD) + cmdOps.AddCommand(cmdCRD) + + cmdCRD.AddCommand(cmdCRDInstall) +} + +func cmdCRDInstallRun(cmd *cobra.Command, args []string) { + client, ok := kclient.GetDefaultFactory().Client() + if !ok { + logger.Fatal("Failed to get client") + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + err := crd.EnsureCRD(ctx, client, false) + if err != nil { + os.Exit(1) + } +} diff --git a/pkg/crd/apply.go b/pkg/crd/apply.go index e61fb5586..aef6379cd 100644 --- a/pkg/crd/apply.go +++ b/pkg/crd/apply.go @@ -37,81 +37,89 @@ import ( var logger = logging.Global().RegisterAndGetLogger("crd", logging.Info) -func EnsureCRD(ctx context.Context, client kclient.Client) { +func EnsureCRD(ctx context.Context, client kclient.Client, ignoreErrors bool) error { crdsLock.Lock() defer crdsLock.Unlock() for crd, spec := range crds { getAccess := verifyCRDAccess(ctx, client, crd, "get") - if !getAccess.Allowed { logger.Str("crd", crd).Info("Get Operations is not allowed. Continue") continue } - c, err := client.KubernetesExtensions().ApiextensionsV1().CustomResourceDefinitions().Get(ctx, crd, meta.GetOptions{}) - if err != nil { - if !errors.IsNotFound(err) { - logger.Err(err).Str("crd", crd).Warn("Get Operations is not allowed due to error. Continue") - continue - } - - createAccess := verifyCRDAccess(ctx, client, crd, "create") - - if !createAccess.Allowed { - logger.Str("crd", crd).Info("Create Operations is not allowed but CRD is missing. Continue") - continue - } - - c = &apiextensions.CustomResourceDefinition{ - ObjectMeta: meta.ObjectMeta{ - Name: crd, - Labels: map[string]string{ - Version: string(spec.version), - }, - }, - Spec: spec.spec, - } + err := tryApplyCRD(ctx, client, crd, spec) + if !ignoreErrors && err != nil { + return err + } + } + return nil +} - if _, err := client.KubernetesExtensions().ApiextensionsV1().CustomResourceDefinitions().Create(ctx, c, meta.CreateOptions{}); err != nil { - logger.Err(err).Str("crd", crd).Warn("Create Operations is not allowed due to error. Continue") - continue - } +func tryApplyCRD(ctx context.Context, client kclient.Client, crd string, spec crd) error { + crdDefinitions := client.KubernetesExtensions().ApiextensionsV1().CustomResourceDefinitions() - logger.Str("crd", crd).Info("CRD Created") - continue + c, err := crdDefinitions.Get(ctx, crd, meta.GetOptions{}) + if err != nil { + if !errors.IsNotFound(err) { + logger.Err(err).Str("crd", crd).Warn("Get Operations is not allowed due to error") + return err } - updateAccess := verifyCRDAccess(ctx, client, crd, "update") + createAccess := verifyCRDAccess(ctx, client, crd, "create") - if !updateAccess.Allowed { - logger.Str("crd", crd).Info("Update Operations is not allowed. Continue") - continue + if !createAccess.Allowed { + logger.Str("crd", crd).Info("Create Operations is not allowed but CRD is missing. Continue") + return nil } - if c.ObjectMeta.Labels == nil { - c.ObjectMeta.Labels = map[string]string{} + c = &apiextensions.CustomResourceDefinition{ + ObjectMeta: meta.ObjectMeta{ + Name: crd, + Labels: map[string]string{ + Version: string(spec.version), + }, + }, + Spec: spec.spec, } - if v, ok := c.ObjectMeta.Labels[Version]; ok { - if v != "" { - if !isUpdateRequired(spec.version, driver.Version(v)) { - logger.Str("crd", crd).Info("CRD Update not required") - continue - } - } + if _, err := crdDefinitions.Create(ctx, c, meta.CreateOptions{}); err != nil { + logger.Err(err).Str("crd", crd).Warn("Create Operations is not allowed due to error") + return err } - c.ObjectMeta.Labels[Version] = string(spec.version) + logger.Str("crd", crd).Info("CRD Created") + return nil + } - c.Spec = spec.spec + updateAccess := verifyCRDAccess(ctx, client, crd, "update") + if !updateAccess.Allowed { + logger.Str("crd", crd).Info("Update Operations is not allowed. Continue") + return nil + } - if _, err := client.KubernetesExtensions().ApiextensionsV1().CustomResourceDefinitions().Update(ctx, c, meta.UpdateOptions{}); err != nil { - logger.Err(err).Str("crd", crd).Warn("Create Operations is not allowed due to error. Continue") - continue + if c.ObjectMeta.Labels == nil { + c.ObjectMeta.Labels = map[string]string{} + } + + if v, ok := c.ObjectMeta.Labels[Version]; ok { + if v != "" { + if !isUpdateRequired(spec.version, driver.Version(v)) { + logger.Str("crd", crd).Info("CRD Update not required") + return nil + } } - logger.Str("crd", crd).Info("CRD Updated") } + + c.ObjectMeta.Labels[Version] = string(spec.version) + c.Spec = spec.spec + + if _, err := crdDefinitions.Update(ctx, c, meta.UpdateOptions{}); err != nil { + logger.Err(err).Str("crd", crd).Warn("Create Operations is not allowed due to error") + return err + } + logger.Str("crd", crd).Info("CRD Updated") + return nil } func verifyCRDAccess(ctx context.Context, client kclient.Client, crd string, verb string) authorization.SubjectAccessReviewStatus { diff --git a/pkg/crd/apply_test.go b/pkg/crd/apply_test.go index bed95f435..21b1ee551 100644 --- a/pkg/crd/apply_test.go +++ b/pkg/crd/apply_test.go @@ -34,6 +34,6 @@ func Test_Apply(t *testing.T) { c, ok := kclient.GetDefaultFactory().Client() require.True(t, ok) - EnsureCRD(context.Background(), c) + _ = EnsureCRD(context.Background(), c, true) }) }