From b16f71939dfe28cf380c62faec52fc086c3305a2 Mon Sep 17 00:00:00 2001 From: Oleg Sucharevich Date: Sun, 17 Feb 2019 13:07:54 +0200 Subject: [PATCH] Refactor operator into plugins With better breaking of dependencies --- package.json | 2 +- venonactl/cmd/cmdutils.go | 24 +- venonactl/cmd/delete.go | 54 ++-- venonactl/cmd/install.go | 90 +++--- venonactl/cmd/root.go | 4 +- venonactl/cmd/status.go | 32 ++- venonactl/cmd/upgrade.go | 17 +- venonactl/internal/die.go | 14 - venonactl/internal/table.go | 19 -- venonactl/pkg/operators/operator.go | 33 --- .../pkg/operators/runtime-environment.go | 180 ------------ venonactl/pkg/operators/venona.go | 269 ------------------ venonactl/pkg/operators/volume-provisioner.go | 180 ------------ .../pkg/{operators => plugins}/helper.go | 2 +- venonactl/pkg/plugins/plugin.go | 226 +++++++++++++++ venonactl/pkg/plugins/runtime-environment.go | 127 +++++++++ venonactl/pkg/{operators => plugins}/types.go | 2 +- venonactl/pkg/plugins/venona.go | 168 +++++++++++ venonactl/pkg/plugins/volume-provisioner.go | 92 ++++++ 19 files changed, 718 insertions(+), 817 deletions(-) delete mode 100644 venonactl/internal/die.go delete mode 100644 venonactl/internal/table.go delete mode 100644 venonactl/pkg/operators/operator.go delete mode 100644 venonactl/pkg/operators/runtime-environment.go delete mode 100644 venonactl/pkg/operators/venona.go delete mode 100644 venonactl/pkg/operators/volume-provisioner.go rename venonactl/pkg/{operators => plugins}/helper.go (99%) create mode 100644 venonactl/pkg/plugins/plugin.go create mode 100644 venonactl/pkg/plugins/runtime-environment.go rename venonactl/pkg/{operators => plugins}/types.go (98%) create mode 100644 venonactl/pkg/plugins/venona.go create mode 100644 venonactl/pkg/plugins/volume-provisioner.go diff --git a/package.json b/package.json index dc5f8ac2..8555f54c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "venona", - "version": "0.16.1", + "version": "0.17.0", "description": "Codefresh agent to run on Codefresh's runtime environment and execute pipeline", "main": "index.js", "scripts": { diff --git a/venonactl/cmd/cmdutils.go b/venonactl/cmd/cmdutils.go index 527fd9aa..a2d61ab3 100644 --- a/venonactl/cmd/cmdutils.go +++ b/venonactl/cmd/cmdutils.go @@ -10,8 +10,9 @@ import ( "github.com/codefresh-io/go-sdk/pkg/codefresh" sdkUtils "github.com/codefresh-io/go-sdk/pkg/utils" "github.com/codefresh-io/venona/venonactl/pkg/certs" - runtimectl "github.com/codefresh-io/venona/venonactl/pkg/operators" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" "github.com/codefresh-io/venona/venonactl/pkg/store" + "github.com/olekukonko/tablewriter" "github.com/sirupsen/logrus" ) @@ -148,5 +149,24 @@ func isUsingDefaultStorageClass(sc string) bool { if sc == "" { return true } - return strings.HasPrefix(sc, runtimectl.DefaultStorageClassNamePrefix) + return strings.HasPrefix(sc, plugins.DefaultStorageClassNamePrefix) +} + +func dieOnError(err error) { + if err != nil { + logrus.Error(err) + os.Exit(1) + } +} + +func createTable() *tablewriter.Table { + table := tablewriter.NewWriter(os.Stdout) + table.SetBorder(false) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetRowLine(false) + table.SetHeaderLine(false) + table.SetColumnSeparator(" ") + table.SetColWidth(100) + return table } diff --git a/venonactl/cmd/delete.go b/venonactl/cmd/delete.go index f2b4456f..95bf8380 100644 --- a/venonactl/cmd/delete.go +++ b/venonactl/cmd/delete.go @@ -18,13 +18,12 @@ limitations under the License. import ( "errors" - "fmt" "os" "github.com/codefresh-io/venona/venonactl/pkg/store" "github.com/sirupsen/logrus" - runtimectl "github.com/codefresh-io/venona/venonactl/pkg/operators" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" "github.com/spf13/cobra" ) @@ -61,15 +60,17 @@ var deleteCmd = &cobra.Command{ var errors []DeletionError s.KubernetesAPI.InCluster = deleteCmdOptions.kube.inCluster for _, name := range args { + builder := plugins.NewBuilder() + re, err := s.CodefreshAPI.Client.RuntimeEnvironments().Get(name) - errors = collectError(errors, err, name, "Get Runtime-Environment from Codefresh") + errors = collectError(errors, err, name) if deleteCmdOptions.revertTo != "" { _, err := s.CodefreshAPI.Client.RuntimeEnvironments().Default(deleteCmdOptions.revertTo) - errors = collectError(errors, err, name, fmt.Sprintf("Revert Runtime-Environment to: %s", deleteCmdOptions.revertTo)) + errors = collectError(errors, err, name) } deleted, err := s.CodefreshAPI.Client.RuntimeEnvironments().Delete(name) - errors = collectError(errors, err, name, "Delete Runtime-Environment from Codefresh") + errors = collectError(errors, err, name) if deleted { contextName := re.RuntimeScheduler.Cluster.ClusterProvider.Selector @@ -78,37 +79,19 @@ var deleteCmd = &cobra.Command{ } s.KubernetesAPI.ContextName = contextName s.KubernetesAPI.Namespace = re.RuntimeScheduler.Cluster.Namespace - err = runtimectl.GetOperator(runtimectl.RuntimeEnvironmentOperatorType).Delete() - if err != nil { - errors = append(errors, DeletionError{ - err: err, - name: name, - operation: "Delete Runtime-Environment Kubernetes resoruces", - }) - continue - } + + builder.Add(plugins.RuntimeEnvironmentPluginType) if isUsingDefaultStorageClass(re.RuntimeScheduler.Pvcs.Dind.StorageClassName) { - err = runtimectl.GetOperator(runtimectl.VolumeProvisionerOperatorType).Delete() - if err != nil { - errors = append(errors, DeletionError{ - err: err, - name: name, - operation: "Delete volume provisioner related components", - }) - continue - } + builder.Add(plugins.VolumeProvisionerPluginType) } if re.Metadata.Agent { - err = runtimectl.GetOperator(runtimectl.VenonaOperatorType).Delete() - if err != nil { - errors = append(errors, DeletionError{ - err: err, - name: name, - operation: "Delete Venona's agent Kubernetes resoruces", - }) - continue - } + builder.Add(plugins.VenonaPluginType) + } + + for _, p := range builder.Get() { + err := p.Delete(nil) + collectError(errors, err, name) } logrus.Infof("Deleted %s", name) @@ -135,13 +118,12 @@ func init() { deleteCmd.Flags().BoolVar(&deleteCmdOptions.kube.inCluster, "in-cluster", false, "Set flag if venona is been installed from inside a cluster") } -func collectError(errors []DeletionError, err error, reName string, op string) []DeletionError { +func collectError(errors []DeletionError, err error, reName string) []DeletionError { if err == nil { return errors } return append(errors, DeletionError{ - err: err, - name: reName, - operation: op, + err: err, + name: reName, }) } diff --git a/venonactl/cmd/install.go b/venonactl/cmd/install.go index ae386088..0be4f936 100644 --- a/venonactl/cmd/install.go +++ b/venonactl/cmd/install.go @@ -24,10 +24,7 @@ import ( "github.com/codefresh-io/venona/venonactl/pkg/store" - "github.com/codefresh-io/venona/venonactl/internal" - - "github.com/codefresh-io/venona/venonactl/pkg/codefresh" - runtimectl "github.com/codefresh-io/venona/venonactl/pkg/operators" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -61,6 +58,16 @@ var installCmd = &cobra.Command{ extendStoreWithCodefershClient() extendStoreWithKubeClient() + builder := plugins.NewBuilder() + builderInstallOpt := &plugins.InstallOptions{ + CodefreshHost: s.CodefreshAPI.Host, + CodefreshToken: s.CodefreshAPI.Token, + ClusterNamespace: s.KubernetesAPI.Namespace, + MarkAsDefault: installCmdOptions.setDefaultRuntime, + StorageClass: installCmdOptions.storageClass, + IsDefaultStorageClass: isUsingDefaultStorageClass(installCmdOptions.storageClass), + } + if installCmdOptions.kube.context == "" { config := clientcmd.GetConfigFromFileOrDie(s.KubernetesAPI.ConfigPath) installCmdOptions.kube.context = config.CurrentContext @@ -91,27 +98,40 @@ var installCmd = &cobra.Command{ } s.ClusterInCodefresh = installCmdOptions.clusterNameInCodefresh if installCmdOptions.installOnlyRuntimeEnvironment == true && installCmdOptions.skipRuntimeInstallation == true { - internal.DieOnError(fmt.Errorf("Cannot use both flags skip-runtime-installation and only-runtime-environment")) + dieOnError(fmt.Errorf("Cannot use both flags skip-runtime-installation and only-runtime-environment")) } if installCmdOptions.installOnlyRuntimeEnvironment == true { - registerRuntimeEnvironment() - return + builder.Add(plugins.RuntimeEnvironmentPluginType) } else if installCmdOptions.skipRuntimeInstallation == true { if installCmdOptions.runtimeEnvironmentName == "" { - internal.DieOnError(fmt.Errorf("runtime-environment flag is required when using flag skip-runtime-installation")) + dieOnError(fmt.Errorf("runtime-environment flag is required when using flag skip-runtime-installation")) } s.RuntimeEnvironment = installCmdOptions.runtimeEnvironmentName logrus.Info("Skipping installation of runtime environment, installing venona only") - installvenona() + builder.Add(plugins.VenonaPluginType) } else { - registerRuntimeEnvironment() - installvenona() + builder. + Add(plugins.RuntimeEnvironmentPluginType). + Add(plugins.VenonaPluginType) } if isUsingDefaultStorageClass(installCmdOptions.storageClass) { - configureVolumeProvisioner() + builder.Add(plugins.VolumeProvisionerPluginType) } else { logrus.Info("Non default StorageClass is set, skipping installation of volume provisioner") } + + builderInstallOpt.ClusterName = s.KubernetesAPI.ContextName + builderInstallOpt.RegisterWithAgent = true + if s.ClusterInCodefresh != "" { + builderInstallOpt.ClusterName = s.ClusterInCodefresh + builderInstallOpt.RegisterWithAgent = false + } + + for _, p := range builder.Get() { + if err := p.Install(builderInstallOpt); err != nil { + dieOnError(err) + } + } logrus.Info("Installation completed Successfully\n") }, } @@ -135,49 +155,3 @@ func init() { installCmd.Flags().BoolVar(&installCmdOptions.dryRun, "dry-run", false, "Set to true to simulate installation") installCmd.Flags().BoolVar(&installCmdOptions.setDefaultRuntime, "set-default", false, "Mark the install runtime-environment as default one after installation") } - -func registerRuntimeEnvironment() { - s := store.GetStore() - registerWithAgent := true - name := s.KubernetesAPI.ContextName - if s.ClusterInCodefresh != "" { - registerWithAgent = false - name = s.ClusterInCodefresh - } - opt := &codefresh.APIOptions{ - Logger: logrus.New(), - CodefreshHost: s.CodefreshAPI.Host, - CodefreshToken: s.CodefreshAPI.Token, - ClusterName: name, - ClusterNamespace: s.KubernetesAPI.Namespace, - RegisterWithAgent: registerWithAgent, - MarkAsDefault: installCmdOptions.setDefaultRuntime, - StorageClass: installCmdOptions.storageClass, - IsDefaultStorageClass: isUsingDefaultStorageClass(installCmdOptions.storageClass), - } - cf := codefresh.NewCodefreshAPI(opt) - - cert, err := cf.Sign() - internal.DieOnError(err) - err = cf.Validate() - internal.DieOnError(err) - - err = runtimectl.GetOperator(runtimectl.RuntimeEnvironmentOperatorType).Install() - internal.DieOnError(err) - - re, err := cf.Register() - internal.DieOnError(err) - - s.RuntimeEnvironment = re.Metadata.Name - s.ServerCert = cert -} - -func installvenona() { - err := runtimectl.GetOperator(runtimectl.VenonaOperatorType).Install() - internal.DieOnError(err) -} - -func configureVolumeProvisioner() { - err := runtimectl.GetOperator(runtimectl.VolumeProvisionerOperatorType).Install() - internal.DieOnError(err) -} diff --git a/venonactl/cmd/root.go b/venonactl/cmd/root.go index bb42858f..3d239dab 100644 --- a/venonactl/cmd/root.go +++ b/venonactl/cmd/root.go @@ -19,8 +19,6 @@ limitations under the License. import ( "github.com/spf13/viper" - "github.com/codefresh-io/venona/venonactl/internal" - "github.com/spf13/cobra" ) @@ -32,7 +30,7 @@ var rootCmd = &cobra.Command{ // Execute - execute the root command func Execute() { err := rootCmd.Execute() - internal.DieOnError(err) + dieOnError(err) } func init() { diff --git a/venonactl/cmd/status.go b/venonactl/cmd/status.go index 6744d5ff..b13001c1 100644 --- a/venonactl/cmd/status.go +++ b/venonactl/cmd/status.go @@ -22,8 +22,7 @@ import ( "github.com/sirupsen/logrus" "github.com/codefresh-io/go-sdk/pkg/codefresh" - "github.com/codefresh-io/venona/venonactl/internal" - runtimectl "github.com/codefresh-io/venona/venonactl/pkg/operators" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" "github.com/codefresh-io/venona/venonactl/pkg/store" humanize "github.com/dustin/go-humanize" @@ -49,14 +48,14 @@ var statusCmd = &cobra.Command{ extendStoreWithKubeClient() s := store.GetStore() - table := internal.CreateTable() + table := createTable() // When requested status for specific runtime if len(args) > 0 { name := args[0] re, err := s.CodefreshAPI.Client.RuntimeEnvironments().Get(name) - internal.DieOnError(err) + dieOnError(err) if re == nil { - internal.DieOnError(fmt.Errorf("Runtime-Environment %s not found", name)) + dieOnError(fmt.Errorf("Runtime-Environment %s not found", name)) } if re.Metadata.Agent == true { table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) @@ -78,7 +77,7 @@ var statusCmd = &cobra.Command{ // When requested status for all runtimes res, err := s.CodefreshAPI.Client.RuntimeEnvironments().List() - internal.DieOnError(err) + dieOnError(err) table.SetHeader([]string{"Runtime Name", "Last Message", "Reported"}) for _, re := range res { if re.Metadata.Agent == true { @@ -99,7 +98,9 @@ var statusCmd = &cobra.Command{ } func printTableWithKubernetesRelatedResources(re *codefresh.RuntimeEnvironment, context string) { - table := internal.CreateTable() + builder := plugins.NewBuilder() + + table := createTable() table.SetHeader([]string{"Kind", "Name", "Status"}) s := store.GetStore() if re.RuntimeScheduler.Cluster.Namespace != "" { @@ -108,13 +109,16 @@ func printTableWithKubernetesRelatedResources(re *codefresh.RuntimeEnvironment, } s.KubernetesAPI.ContextName = context s.KubernetesAPI.Namespace = re.RuntimeScheduler.Cluster.Namespace - - rows, err := runtimectl.GetOperator(runtimectl.RuntimeEnvironmentOperatorType).Status() - internal.DieOnError(err) - table.AppendBulk(rows) - rows, err = runtimectl.GetOperator(runtimectl.VenonaOperatorType).Status() - internal.DieOnError(err) - table.AppendBulk(rows) + builder. + Add(plugins.RuntimeEnvironmentPluginType). + Add(plugins.VenonaPluginType). + Add(plugins.VolumeProvisionerPluginType) + + for _, p := range builder.Get() { + rows, err := p.Status(nil) + dieOnError(err) + table.AppendBulk(rows) + } } table.Render() } diff --git a/venonactl/cmd/upgrade.go b/venonactl/cmd/upgrade.go index 3ab6c9c0..243199d4 100644 --- a/venonactl/cmd/upgrade.go +++ b/venonactl/cmd/upgrade.go @@ -19,9 +19,7 @@ limitations under the License. import ( "errors" - "github.com/codefresh-io/venona/venonactl/internal" - "github.com/codefresh-io/venona/venonactl/pkg/operators" - runtimectl "github.com/codefresh-io/venona/venonactl/pkg/operators" + "github.com/codefresh-io/venona/venonactl/pkg/plugins" "github.com/codefresh-io/venona/venonactl/pkg/store" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -55,6 +53,8 @@ var upgradeCmd = &cobra.Command{ extendStoreWithCodefershClient() extendStoreWithKubeClient() + builder := plugins.NewBuilder() + re, _ := s.CodefreshAPI.Client.RuntimeEnvironments().Get(args[0]) contextName := re.RuntimeScheduler.Cluster.ClusterProvider.Selector if upgradeCmdOpt.kube.context != "" { @@ -65,10 +65,15 @@ var upgradeCmd = &cobra.Command{ if upgradeCmdOpt.dryRun { logrus.Info("Running in dry-run mode") } else { - operators.GetOperator(operators.VenonaOperatorType).Upgrade() + builder.Add(plugins.VenonaPluginType) if isUsingDefaultStorageClass(re.RuntimeScheduler.Pvcs.Dind.StorageClassName) { - err := runtimectl.GetOperator(runtimectl.VolumeProvisionerOperatorType).Delete() - internal.DieOnError(err) + builder.Add(plugins.VolumeProvisionerPluginType) + } + builder.Add(plugins.RuntimeEnvironmentPluginType) + } + for _, p := range builder.Get() { + if err := p.Upgrade(nil); err != nil { + dieOnError(err) } } }, diff --git a/venonactl/internal/die.go b/venonactl/internal/die.go deleted file mode 100644 index 75f1d590..00000000 --- a/venonactl/internal/die.go +++ /dev/null @@ -1,14 +0,0 @@ -package internal - -import ( - "os" - - "github.com/sirupsen/logrus" -) - -func DieOnError(err error) { - if err != nil { - logrus.Error(err) - os.Exit(1) - } -} diff --git a/venonactl/internal/table.go b/venonactl/internal/table.go deleted file mode 100644 index 167967b2..00000000 --- a/venonactl/internal/table.go +++ /dev/null @@ -1,19 +0,0 @@ -package internal - -import ( - "os" - - "github.com/olekukonko/tablewriter" -) - -func CreateTable() *tablewriter.Table { - table := tablewriter.NewWriter(os.Stdout) - table.SetBorder(false) - table.SetAlignment(tablewriter.ALIGN_LEFT) - table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - table.SetRowLine(false) - table.SetHeaderLine(false) - table.SetColumnSeparator(" ") - table.SetColWidth(100) - return table -} diff --git a/venonactl/pkg/operators/operator.go b/venonactl/pkg/operators/operator.go deleted file mode 100644 index 10122e62..00000000 --- a/venonactl/pkg/operators/operator.go +++ /dev/null @@ -1,33 +0,0 @@ -package operators - -const ( - RuntimeEnvironmentOperatorType = "runtime-environment" - VenonaOperatorType = "venona" - VolumeProvisionerOperatorType = "volume-provisioner" - DefaultStorageClassNamePrefix = "dind-local-volumes-venona" -) - -type ( - Operator interface { - Install() error - Status() ([][]string, error) - Delete() error - Upgrade() error - } -) - -func GetOperator(t string) Operator { - if t == VenonaOperatorType { - return &venonaOperator{} - } - - if t == RuntimeEnvironmentOperatorType { - return &RuntimeEnvironmentOperator{} - } - - if t == VolumeProvisionerOperatorType { - return &VolumeProvisionerOperator{} - } - - return nil -} diff --git a/venonactl/pkg/operators/runtime-environment.go b/venonactl/pkg/operators/runtime-environment.go deleted file mode 100644 index 7f837df8..00000000 --- a/venonactl/pkg/operators/runtime-environment.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -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 operators - -import ( - "fmt" - "regexp" - - "github.com/codefresh-io/venona/venonactl/internal" - "github.com/sirupsen/logrus" - - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - "github.com/codefresh-io/venona/venonactl/pkg/store" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// RuntimeEnvironmentOperator installs assets on Kubernetes Dind runtimectl Env -type RuntimeEnvironmentOperator struct { -} - -const ( - RuntimeInstallPattern = ".*.re.yaml" -) - -// Install runtimectl environment -func (u *RuntimeEnvironmentOperator) Install() error { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - internal.DieOnError(fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err)) - } - namespace := s.KubernetesAPI.Namespace - var createErr error - var kind, name string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(RuntimeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": RuntimeEnvironmentOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping installation of %s: pattern not match", fileName) - continue - } - if store.GetStore().DryRun == true { - logrus.WithFields(logrus.Fields{ - "File-Name": fileName, - "Operator": RuntimeEnvironmentOperatorType, - }).Debugf("%v", obj) - continue - } - name, kind, createErr = kubeobj.CreateObject(kubeClientset, obj, namespace) - - if createErr == nil { - logrus.Debugf("%s \"%s\" created\n ", kind, name) - } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.Debugf("%s \"%s\" already exists\n", kind, name) - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, statusError) - return statusError - } - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, createErr) - return createErr - } - } - - return nil -} - -func (u *RuntimeEnvironmentOperator) Status() ([][]string, error) { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return nil, err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return nil, err - } - namespace := s.KubernetesAPI.Namespace - var getErr error - var kind, name string - var rows [][]string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(RuntimeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": RuntimeInstallPattern, - "Pattern": RuntimeInstallPattern, - }).Debugf("Skipping status check of %s: pattern not match", fileName) - continue - } - name, kind, getErr = kubeobj.CheckObject(kubeClientset, obj, namespace) - if getErr == nil { - rows = append(rows, []string{kind, name, StatusInstalled}) - } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { - rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, getErr) - return nil, getErr - } - } - - return rows, nil -} - -func (u *RuntimeEnvironmentOperator) Delete() error { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return err - } - namespace := s.KubernetesAPI.Namespace - var kind, name string - var deleteError error - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(RuntimeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": RuntimeEnvironmentOperatorType, - "Pattern": RuntimeInstallPattern, - }).Debugf("Skipping deletion of %s: pattern not match", fileName) - continue - } - kind, name, deleteError = kubeobj.DeleteObject(kubeClientset, obj, namespace) - if deleteError == nil { - logrus.Debugf("%s \"%s\" deleted\n ", kind, name) - } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.Debugf("%s \"%s\" already exists\n", kind, name) - } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - logrus.Debugf("%s \"%s\" not found\n", kind, name) - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, statusError) - return statusError - } - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, deleteError) - return deleteError - } - } - return nil -} - -func (u *RuntimeEnvironmentOperator) Upgrade() error { - return nil -} diff --git a/venonactl/pkg/operators/venona.go b/venonactl/pkg/operators/venona.go deleted file mode 100644 index 893a06e9..00000000 --- a/venonactl/pkg/operators/venona.go +++ /dev/null @@ -1,269 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -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 operators - -import ( - "fmt" - "regexp" - "time" - - "github.com/sirupsen/logrus" - - "github.com/codefresh-io/venona/venonactl/internal" - - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - "github.com/codefresh-io/venona/venonactl/pkg/store" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// venonaOperator installs assets on Kubernetes Dind runtimectl Env -type venonaOperator struct { -} - -const ( - venonaInstallPattern = ".*.venona.yaml" -) - -// Install runtimectl environment -func (u *venonaOperator) Install() error { - s := store.GetStore() - logrus.Debug("Generating token for agent") - tokenName := fmt.Sprintf("generated-%s", time.Now().Format("20060102150405")) - logrus.Debugf("Token candidate name: %s", tokenName) - token, err := s.CodefreshAPI.Client.Tokens().Create(tokenName, s.RuntimeEnvironment) - if err != nil { - logrus.Error(err.Error()) - return err - } - logrus.Debugf(fmt.Sprintf("Created token: %s", token.Value)) - - store.GetStore().AgentToken = token.Value - if err != nil { - return err - } - - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - internal.DieOnError(fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err)) - } - namespace := s.KubernetesAPI.Namespace - var createErr error - var kind, name string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(venonaInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping installation of %s: pattern not match", fileName) - continue - } - if store.GetStore().DryRun == true { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - }).Debugf("Skipping installation of %s due to dry-run flag", fileName) - continue - } - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - "Namespace": namespace, - }).Infof("Installing %s", fileName) - name, kind, createErr = kubeobj.CreateObject(kubeClientset, obj, namespace) - - if createErr == nil { - logrus.WithFields(logrus.Fields{ - "Kind": kind, - "Name": name, - }).Info("Created") - } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.WithFields(logrus.Fields{ - "Kind": kind, - "Name": name, - }).Info("Already exists") - } else { - logrus.WithFields(logrus.Fields{ - "Kind": kind, - "Name": name, - }).Errorf("Failed: %v ", statusError) - return statusError - } - } else { - logrus.WithFields(logrus.Fields{ - "Kind": kind, - "Name": name, - }).Errorf("Failed: %v ", createErr) - return createErr - } - } - - return nil -} - -// Status of runtimectl environment -func (u *venonaOperator) Status() ([][]string, error) { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return nil, err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return nil, err - } - namespace := s.KubernetesAPI.Namespace - var getErr error - var kind, name string - var rows [][]string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(venonaInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping status check of %s: pattern not match", fileName) - continue - } - name, kind, getErr = kubeobj.CheckObject(kubeClientset, obj, namespace) - if getErr == nil { - rows = append(rows, []string{kind, name, StatusInstalled}) - } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { - rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) - } else { - fmt.Printf("%s \"%s\" failed: %v ", kind, name, getErr) - return nil, getErr - } - } - - return rows, nil -} - -func (u *venonaOperator) Delete() error { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return err - } - namespace := s.KubernetesAPI.Namespace - var kind, name string - var deleteError error - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(venonaInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping deletion of %s: pattern not match", fileName) - continue - } - kind, name, deleteError = kubeobj.DeleteObject(kubeClientset, obj, namespace) - if deleteError == nil { - logrus.Debugf("%s \"%s\" deleted\n ", kind, name) - } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.Debugf("%s \"%s\" already exists\n", kind, name) - } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - logrus.Debugf("%s \"%s\" not found\n", kind, name) - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, statusError) - return statusError - } - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, deleteError) - return deleteError - } - } - return nil -} - -func (u *venonaOperator) Upgrade() error { - - // replace of sa creates new secert with sa creds - // avoid it till patch fully implemented - var skipUpgradeFor = map[string]interface{}{ - "service-account.venona.yaml": nil, - } - - var err error - s := store.GetStore() - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return err - } - - namespace := s.KubernetesAPI.Namespace - - // special case when we need to get the token from the remote to no regenrate it - // whole flow should be more like kubectl apply that build a patch - // based on remote object and candidate object - secret, err := kubeClientset.CoreV1().Secrets(namespace).Get(s.AppName, metav1.GetOptions{}) - if err != nil { - return err - } - token := secret.Data["codefresh.token"] - s.AgentToken = string(token) - - kubeObjects, err := getKubeObjectsFromTempalte(s.BuildValues()) - if err != nil { - return err - } - - for fileName, local := range kubeObjects { - match, _ := regexp.MatchString(venonaInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping upgrade of %s: pattern not match", fileName) - continue - } - - if _, ok := skipUpgradeFor[fileName]; ok { - logrus.WithFields(logrus.Fields{ - "Operator": VenonaOperatorType, - }).Debugf("Skipping upgrade of %s: should be ignored", fileName) - continue - } - - _, _, err := kubeobj.ReplaceObject(kubeClientset, local, namespace) - if err != nil { - return err - } - } - - return nil -} diff --git a/venonactl/pkg/operators/volume-provisioner.go b/venonactl/pkg/operators/volume-provisioner.go deleted file mode 100644 index 083455f8..00000000 --- a/venonactl/pkg/operators/volume-provisioner.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright 2019 The Codefresh Authors. - -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 operators - -import ( - "fmt" - "regexp" - - "github.com/codefresh-io/venona/venonactl/internal" - "github.com/sirupsen/logrus" - - "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" - "github.com/codefresh-io/venona/venonactl/pkg/store" - templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// VolumeProvisionerOperator installs assets on Kubernetes Dind runtimectl Env -type VolumeProvisionerOperator struct { -} - -const ( - VolumeInstallPattern = ".*.vp.yaml" -) - -// Install runtimectl environment -func (u *VolumeProvisionerOperator) Install() error { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - internal.DieOnError(fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err)) - } - namespace := s.KubernetesAPI.Namespace - var createErr error - var kind, name string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(VolumeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VolumeProvisionerOperatorType, - "Pattern": venonaInstallPattern, - }).Debugf("Skipping installation of %s: pattern not match", fileName) - continue - } - if store.GetStore().DryRun == true { - logrus.WithFields(logrus.Fields{ - "File-Name": fileName, - "Operator": VolumeProvisionerOperatorType, - }).Debugf("%v", obj) - continue - } - name, kind, createErr = kubeobj.CreateObject(kubeClientset, obj, namespace) - - if createErr == nil { - logrus.Debugf("%s \"%s\" created\n ", kind, name) - } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.Debugf("%s \"%s\" already exists\n", kind, name) - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, statusError) - return statusError - } - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, createErr) - return createErr - } - } - - return nil -} - -func (u *VolumeProvisionerOperator) Status() ([][]string, error) { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return nil, err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return nil, err - } - namespace := s.KubernetesAPI.Namespace - var getErr error - var kind, name string - var rows [][]string - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(VolumeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VolumeProvisionerOperatorType, - "Pattern": VolumeInstallPattern, - }).Debugf("Skipping status check of %s: pattern not match", fileName) - continue - } - name, kind, getErr = kubeobj.CheckObject(kubeClientset, obj, namespace) - if getErr == nil { - rows = append(rows, []string{kind, name, StatusInstalled}) - } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { - rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) - } else { - logrus.Debugf("%s \"%s\" failed: %v ", kind, name, getErr) - return nil, getErr - } - } - - return rows, nil -} - -func (u *VolumeProvisionerOperator) Delete() error { - s := store.GetStore() - templatesMap := templates.TemplatesMap() - kubeObjects, err := KubeObjectsFromTemplates(templatesMap, s.BuildValues()) - if err != nil { - return err - } - - kubeClientset, err := NewKubeClientset(s) - if err != nil { - logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) - return err - } - namespace := s.KubernetesAPI.Namespace - var kind, name string - var deleteError error - for fileName, obj := range kubeObjects { - match, _ := regexp.MatchString(VolumeInstallPattern, fileName) - if match != true { - logrus.WithFields(logrus.Fields{ - "Operator": VolumeProvisionerOperatorType, - "Pattern": VolumeInstallPattern, - }).Debugf("Skipping deletion of %s: pattern not match", fileName) - continue - } - kind, name, deleteError = kubeobj.DeleteObject(kubeClientset, obj, namespace) - if deleteError == nil { - logrus.Debugf("%s \"%s\" deleted\n ", kind, name) - } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { - if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { - logrus.Debugf("%s \"%s\" already exists\n", kind, name) - } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { - logrus.Debugf("%s \"%s\" not found\n", kind, name) - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, statusError) - return statusError - } - } else { - logrus.Errorf("%s \"%s\" failed: %v ", kind, name, deleteError) - return deleteError - } - } - return nil -} - -func (u *VolumeProvisionerOperator) Upgrade() error { - return nil -} diff --git a/venonactl/pkg/operators/helper.go b/venonactl/pkg/plugins/helper.go similarity index 99% rename from venonactl/pkg/operators/helper.go rename to venonactl/pkg/plugins/helper.go index 9ea7ee4a..b2853906 100644 --- a/venonactl/pkg/operators/helper.go +++ b/venonactl/pkg/plugins/helper.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package operators +package plugins import ( "bytes" diff --git a/venonactl/pkg/plugins/plugin.go b/venonactl/pkg/plugins/plugin.go new file mode 100644 index 00000000..105e27cf --- /dev/null +++ b/venonactl/pkg/plugins/plugin.go @@ -0,0 +1,226 @@ +package plugins + +import ( + "regexp" + + "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +const ( + RuntimeEnvironmentPluginType = "runtime-environment" + VenonaPluginType = "venona" + VolumeProvisionerPluginType = "volume-provisioner" + DefaultStorageClassNamePrefix = "dind-local-volumes-venona" +) + +type ( + Plugin interface { + Install(*InstallOptions) error + Status(*StatusOptions) ([][]string, error) + Delete(*DeleteOptions) error + Upgrade(*UpgradeOptions) error + } + + PluginBuilder interface { + Add(string) PluginBuilder + Get() []Plugin + } + + pb struct { + plugins []Plugin + } + + InstallOptions struct { + CodefreshHost string + CodefreshToken string + ClusterName string + ClusterNamespace string + RegisterWithAgent bool + MarkAsDefault bool + StorageClass string + IsDefaultStorageClass bool + } + + DeleteOptions struct { + } + + UpgradeOptions struct { + } + + StatusOptions struct { + } + + installOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + dryRun bool + } + + statusOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + } + + deleteOptions struct { + templates map[string]string + templateValues map[string]interface{} + kubeClientSet *kubernetes.Clientset + namespace string + matchPattern string + operatorType string + } +) + +func NewBuilder() PluginBuilder { + return &pb{ + plugins: []Plugin{}, + } +} + +func (p *pb) Add(name string) PluginBuilder { + p.plugins = append(p.plugins, build(name)) + return p +} + +func (p *pb) Get() []Plugin { + return p.plugins +} + +func build(t string) Plugin { + if t == VenonaPluginType { + return &venonaPlugin{} + } + + if t == RuntimeEnvironmentPluginType { + return &runtimeEnvironmentPlugin{} + } + + if t == VolumeProvisionerPluginType { + return &volumeProvisionerPlugin{} + } + + return nil +} + +func install(opt *installOptions) error { + + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues) + if err != nil { + return err + } + + for fileName, obj := range kubeObjects { + match, _ := regexp.MatchString(opt.matchPattern, fileName) + if match != true { + logrus.WithFields(logrus.Fields{ + "Plugin": opt.operatorType, + "Pattern": opt.matchPattern, + }).Debugf("Skipping installation of %s: pattern not match", fileName) + continue + } + if opt.dryRun == true { + logrus.WithFields(logrus.Fields{ + "File-Name": fileName, + "Plugin": opt.operatorType, + }).Debugf("%v", obj) + continue + } + var createErr error + var kind, name string + name, kind, createErr = kubeobj.CreateObject(opt.kubeClientSet, obj, opt.namespace) + + if createErr == nil { + logrus.Debugf("%s \"%s\" created\n ", kind, name) + } else if statusError, errIsStatusError := createErr.(*errors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { + logrus.Debugf("%s \"%s\" already exists\n", kind, name) + } else { + logrus.Debugf("%s \"%s\" failed: %v ", kind, name, statusError) + return statusError + } + } else { + logrus.Debugf("%s \"%s\" failed: %v ", kind, name, createErr) + return createErr + } + } + + return nil +} + +func status(opt *statusOptions) ([][]string, error) { + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues) + if err != nil { + return nil, err + } + var getErr error + var kind, name string + var rows [][]string + for fileName, obj := range kubeObjects { + match, _ := regexp.MatchString(opt.operatorType, fileName) + if match != true { + logrus.WithFields(logrus.Fields{ + "Plugin": opt.operatorType, + "Pattern": opt.matchPattern, + }).Debugf("Skipping status check of %s: pattern not match", fileName) + continue + } + name, kind, getErr = kubeobj.CheckObject(opt.kubeClientSet, obj, opt.namespace) + if getErr == nil { + rows = append(rows, []string{kind, name, StatusInstalled}) + } else if statusError, errIsStatusError := getErr.(*errors.StatusError); errIsStatusError { + rows = append(rows, []string{kind, name, StatusNotInstalled, statusError.ErrStatus.Message}) + } else { + logrus.Debugf("%s \"%s\" failed: %v ", kind, name, getErr) + return nil, getErr + } + } + return rows, nil +} + +func delete(opt *deleteOptions) error { + kubeObjects, err := KubeObjectsFromTemplates(opt.templates, opt.templateValues) + if err != nil { + return err + } + var kind, name string + var deleteError error + for fileName, obj := range kubeObjects { + match, _ := regexp.MatchString(opt.matchPattern, fileName) + if match != true { + logrus.WithFields(logrus.Fields{ + "Plugin": opt.operatorType, + "Pattern": opt.matchPattern, + }).Debugf("Skipping deletion of %s: pattern not match", fileName) + continue + } + kind, name, deleteError = kubeobj.DeleteObject(opt.kubeClientSet, obj, opt.namespace) + if deleteError == nil { + logrus.Debugf("%s \"%s\" deleted\n ", kind, name) + } else if statusError, errIsStatusError := deleteError.(*errors.StatusError); errIsStatusError { + if statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists { + logrus.Debugf("%s \"%s\" already exists\n", kind, name) + } else if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound { + logrus.Debugf("%s \"%s\" not found\n", kind, name) + } else { + logrus.Errorf("%s \"%s\" failed: %v ", kind, name, statusError) + return statusError + } + } else { + logrus.Errorf("%s \"%s\" failed: %v ", kind, name, deleteError) + return deleteError + } + } + return nil +} diff --git a/venonactl/pkg/plugins/runtime-environment.go b/venonactl/pkg/plugins/runtime-environment.go new file mode 100644 index 00000000..64aa34b6 --- /dev/null +++ b/venonactl/pkg/plugins/runtime-environment.go @@ -0,0 +1,127 @@ +/* +Copyright 2019 The Codefresh Authors. + +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 plugins + +import ( + "fmt" + + "github.com/sirupsen/logrus" + + "github.com/codefresh-io/venona/venonactl/pkg/codefresh" + "github.com/codefresh-io/venona/venonactl/pkg/store" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// runtimeEnvironmentPlugin installs assets on Kubernetes Dind runtimectl Env +type runtimeEnvironmentPlugin struct { +} + +const ( + runtimeEnvironmentFilesPattern = ".*.re.yaml" +) + +// Install runtimectl environment +func (u *runtimeEnvironmentPlugin) Install(opt *InstallOptions) error { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + return fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err) + } + + cfOpt := &codefresh.APIOptions{ + Logger: logrus.New(), + CodefreshHost: opt.CodefreshHost, + CodefreshToken: opt.CodefreshToken, + ClusterName: opt.ClusterName, + RegisterWithAgent: opt.RegisterWithAgent, + ClusterNamespace: s.KubernetesAPI.Namespace, + MarkAsDefault: opt.MarkAsDefault, + StorageClass: opt.StorageClass, + IsDefaultStorageClass: opt.IsDefaultStorageClass, + } + cf := codefresh.NewCodefreshAPI(cfOpt) + cert, err := cf.Sign() + if err != nil { + return err + } + s.ServerCert = cert + + if err := cf.Validate(); err != nil { + return err + } + + err = install(&installOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + dryRun: s.DryRun, + }) + if err != nil { + return nil + } + + re, err := cf.Register() + if err != nil { + return err + } + s.RuntimeEnvironment = re.Metadata.Name + + return nil +} + +func (u *runtimeEnvironmentPlugin) Status(_ *StatusOptions) ([][]string, error) { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + } + return status(opt) +} + +func (u *runtimeEnvironmentPlugin) Delete(_ *DeleteOptions) error { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: runtimeEnvironmentFilesPattern, + operatorType: RuntimeEnvironmentPluginType, + } + return delete(opt) +} + +func (u *runtimeEnvironmentPlugin) Upgrade(_ *UpgradeOptions) error { + return nil +} diff --git a/venonactl/pkg/operators/types.go b/venonactl/pkg/plugins/types.go similarity index 98% rename from venonactl/pkg/operators/types.go rename to venonactl/pkg/plugins/types.go index 71054ff5..266f2b64 100644 --- a/venonactl/pkg/operators/types.go +++ b/venonactl/pkg/plugins/types.go @@ -13,7 +13,7 @@ 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 operators +package plugins const ( // AppName - app name for config diff --git a/venonactl/pkg/plugins/venona.go b/venonactl/pkg/plugins/venona.go new file mode 100644 index 00000000..a1b4364a --- /dev/null +++ b/venonactl/pkg/plugins/venona.go @@ -0,0 +1,168 @@ +/* +Copyright 2019 The Codefresh Authors. + +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 plugins + +import ( + "fmt" + "regexp" + "time" + + "github.com/sirupsen/logrus" + + "github.com/codefresh-io/venona/venonactl/pkg/obj/kubeobj" + "github.com/codefresh-io/venona/venonactl/pkg/store" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// venonaPlugin installs assets on Kubernetes Dind runtimectl Env +type venonaPlugin struct { +} + +const ( + venonaFilesPattern = ".*.venona.yaml" +) + +// Install runtimectl environment +func (u *venonaPlugin) Install(_ *InstallOptions) error { + s := store.GetStore() + logrus.Debug("Generating token for agent") + tokenName := fmt.Sprintf("generated-%s", time.Now().Format("20060102150405")) + logrus.Debugf("Token candidate name: %s", tokenName) + token, err := s.CodefreshAPI.Client.Tokens().Create(tokenName, s.RuntimeEnvironment) + if err != nil { + logrus.Error(err.Error()) + return err + } + logrus.Debugf(fmt.Sprintf("Created token: %s", token.Value)) + + store.GetStore().AgentToken = token.Value + if err != nil { + return err + } + + cs, err := NewKubeClientset(s) + if err != nil { + return fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err) + } + return install(&installOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: venonaFilesPattern, + dryRun: s.DryRun, + operatorType: VolumeProvisionerPluginType, + }) +} + +// Status of runtimectl environment +func (u *venonaPlugin) Status(_ *StatusOptions) ([][]string, error) { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: venonaFilesPattern, + operatorType: VenonaPluginType, + } + return status(opt) +} + +func (u *venonaPlugin) Delete(_ *DeleteOptions) error { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: venonaFilesPattern, + operatorType: VolumeProvisionerPluginType, + } + return delete(opt) +} + +func (u *venonaPlugin) Upgrade(_ *UpgradeOptions) error { + + // replace of sa creates new secert with sa creds + // avoid it till patch fully implemented + var skipUpgradeFor = map[string]interface{}{ + "service-account.venona.yaml": nil, + } + + var err error + s := store.GetStore() + + kubeClientset, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return err + } + + namespace := s.KubernetesAPI.Namespace + + // special case when we need to get the token from the remote to no regenrate it + // whole flow should be more like kubectl apply that build a patch + // based on remote object and candidate object + secret, err := kubeClientset.CoreV1().Secrets(namespace).Get(s.AppName, metav1.GetOptions{}) + if err != nil { + return err + } + token := secret.Data["codefresh.token"] + s.AgentToken = string(token) + + kubeObjects, err := getKubeObjectsFromTempalte(s.BuildValues()) + if err != nil { + return err + } + + for fileName, local := range kubeObjects { + match, _ := regexp.MatchString(venonaFilesPattern, fileName) + if match != true { + logrus.WithFields(logrus.Fields{ + "Operator": VenonaPluginType, + "Pattern": venonaFilesPattern, + }).Debugf("Skipping upgrade of %s: pattern not match", fileName) + continue + } + + if _, ok := skipUpgradeFor[fileName]; ok { + logrus.WithFields(logrus.Fields{ + "Operator": VenonaPluginType, + }).Debugf("Skipping upgrade of %s: should be ignored", fileName) + continue + } + + _, _, err := kubeobj.ReplaceObject(kubeClientset, local, namespace) + if err != nil { + return err + } + } + + return nil +} diff --git a/venonactl/pkg/plugins/volume-provisioner.go b/venonactl/pkg/plugins/volume-provisioner.go new file mode 100644 index 00000000..030588ce --- /dev/null +++ b/venonactl/pkg/plugins/volume-provisioner.go @@ -0,0 +1,92 @@ +/* +Copyright 2019 The Codefresh Authors. + +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 plugins + +import ( + "fmt" + + "github.com/sirupsen/logrus" + + "github.com/codefresh-io/venona/venonactl/pkg/store" + templates "github.com/codefresh-io/venona/venonactl/pkg/templates/kubernetes" +) + +// volumeProvisionerPlugin installs assets on Kubernetes Dind runtimectl Env +type volumeProvisionerPlugin struct { +} + +const ( + volumeProvisionerFilesPattern = ".*.vp.yaml" +) + +// Install runtimectl environment +func (u *volumeProvisionerPlugin) Install(_ *InstallOptions) error { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + return fmt.Errorf("Cannot create kubernetes clientset: %v\n ", err) + } + return install(&installOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: volumeProvisionerFilesPattern, + dryRun: s.DryRun, + operatorType: VolumeProvisionerPluginType, + }) +} + +func (u *volumeProvisionerPlugin) Status(_ *StatusOptions) ([][]string, error) { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil, err + } + opt := &statusOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: volumeProvisionerFilesPattern, + operatorType: VolumeProvisionerPluginType, + } + return status(opt) +} + +func (u *volumeProvisionerPlugin) Delete(_ *DeleteOptions) error { + s := store.GetStore() + cs, err := NewKubeClientset(s) + if err != nil { + logrus.Errorf("Cannot create kubernetes clientset: %v\n ", err) + return nil + } + opt := &deleteOptions{ + templates: templates.TemplatesMap(), + templateValues: s.BuildValues(), + kubeClientSet: cs, + namespace: s.KubernetesAPI.Namespace, + matchPattern: volumeProvisionerFilesPattern, + operatorType: VolumeProvisionerPluginType, + } + return delete(opt) +} + +func (u *volumeProvisionerPlugin) Upgrade(_ *UpgradeOptions) error { + return nil +}