Merge "mecm-mepm uninstall playbook added"
[ealt-edge.git] / mecm / mepm / applcm / k8shelm / pkg / plugin / helmclient.go
index ec05dd5..d756ef9 100644 (file)
+/*
+ * Copyright 2020 Huawei Technologies Co., Ltd.
+ *
+ * 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 plugin
 
 import (
        "bytes"
        "fmt"
+       "os"
+
+       "github.com/sirupsen/logrus"
        "helm.sh/helm/v3/pkg/action"
        "helm.sh/helm/v3/pkg/chart/loader"
        "helm.sh/helm/v3/pkg/kube"
-       "log"
-       "os"
 )
 
-const releaseNamespace  = "default"
-const chartPath  = "/go/release/charts/"
-const kubeconfigPath  = "/go/release/kubeconfig/"
+// Variables to be defined in deployment file
+var (
+       chartPath        = os.Getenv("CHART_PATH")
+       kubeconfigPath   = os.Getenv("KUBECONFIG_DIR_PATH")
+       releaseNamespace = os.Getenv("RELEASE_NAMESPACE")
+)
+
+// Helm client
+type HelmClient struct {
+       hostIP     string
+       kubeconfig string
+       logger     *logrus.Logger
+}
 
-//const chartPath  = "/home/root1/code/mecm/mepm/applcm/k8shelm/pkg/plugin/"
-//const kubeconfigPath  = "/home/root1/"
+// Constructor of helm client for a given host IP
+func NewHelmClient(hostIP string, logger *logrus.Logger) (*HelmClient, error) {
+       // Kubeconfig file will be picked based on host IP and will be check for existence
+       exists, err := fileExists(kubeconfigPath + hostIP)
+       if exists {
+               return &HelmClient{hostIP: hostIP, kubeconfig: kubeconfigPath + hostIP, logger: logger}, nil
+       } else {
+               logger.Errorf("No file exist with name: %s. Err: %s", kubeconfigPath+hostIP)
+               return nil, err
+       }
+}
 
-func installChart(helmPkg bytes.Buffer, hostIP string) string {
-       logger := log.New(os.Stdout, "helmplugin ", log.LstdFlags|log.Lshortfile)
-       logger.Println("Inside helm client")
+// Install a given helm chart
+func (hc *HelmClient) installChart(helmPkg bytes.Buffer) (string, error) {
+       hc.logger.Debug("Inside helm client")
 
+       // Create temporary file to hold helm chart
        file, err := os.Create(chartPath + "temp.tar.gz")
        if err != nil {
-               logger.Printf("unable to create file")
+               hc.logger.Errorf("Unable to create file: %s. Err: %s", chartPath+"temp.tar.gz", err)
+               return "", err
        }
+       defer os.Remove(chartPath + "temp.tar.gz")
 
+       // Write input bytes to temp file
        _, err = helmPkg.WriteTo(file)
        if err != nil {
-               logger.Printf("uanble to write to file")
+               hc.logger.Errorf("Unable to write to file: %s. Err: %s", chartPath+"temp.tar.gz", err)
+               return "", err
        }
 
+       // Load the file to chart
        chart, err := loader.Load(chartPath + "temp.tar.gz")
        if err != nil {
-
-               panic(err)
+               hc.logger.Errorf("Unable to load chart from file: %s. Err: %s", chartPath+"temp.tar.gz", err)
+               return "", err
        }
 
-       releaseName := chart.Metadata.Name
-
-       kubeconfig := kubeconfigPath + hostIP
+       // Release name will be taken from the name in chart's metadata
+       relName := chart.Metadata.Name
 
+       // Initialize action config
        actionConfig := new(action.Configuration)
-       if err := actionConfig.Init(kube.GetConfig(kubeconfig, "", releaseNamespace), releaseNamespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
-               fmt.Sprintf(format, v)
-       }); err != nil {
-               panic(err)
+       if err := actionConfig.Init(kube.GetConfig(hc.kubeconfig, "", releaseNamespace), releaseNamespace,
+               os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
+                       fmt.Sprintf(format, v)
+               }); err != nil {
+               hc.logger.Errorf("Unable to initialize action config Err: %s", err)
+               return "", err
        }
 
-       iCli := action.NewInstall(actionConfig)
-       iCli.Namespace = releaseNamespace
-       iCli.ReleaseName = releaseName
-       rel, err := iCli.Run(chart, nil)
+       // Prepare chart install action and install chart
+       installer := action.NewInstall(actionConfig)
+       installer.Namespace = releaseNamespace
+       installer.ReleaseName = relName
+       rel, err := installer.Run(chart, nil)
        if err != nil {
-               panic(err)
+               hc.logger.Errorf("Unable to install chart with release name: %s. Err: %s", relName, err)
+               return "", err
        }
-       fmt.Println("Successfully installed release: ", rel.Name)
-       return rel.Name
+       hc.logger.Infof("Successfully create chart with release name: %s", relName)
+       return rel.Name, err
 }
 
-func uninstallChart(relName string, hostIP string) {
-       kubeconfig := kubeconfigPath + hostIP
+// Un-Install a given helm chart
+func (hc *HelmClient) uninstallChart(relName string) error {
+       // Prepare action config and uninstall chart
        actionConfig := new(action.Configuration)
-       if err := actionConfig.Init(kube.GetConfig(kubeconfig, "", releaseNamespace), releaseNamespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
-               fmt.Sprintf(format, v)
-       }); err != nil {
-               panic(err)
+       if err := actionConfig.Init(kube.GetConfig(hc.kubeconfig, "", releaseNamespace), releaseNamespace,
+               os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
+                       fmt.Sprintf(format, v)
+               }); err != nil {
+               hc.logger.Errorf("Unable to initialize action config Err: %s", err)
+               return err
        }
-       iCli := action.NewUninstall(actionConfig)
-       res, err := iCli.Run(relName);
+
+       ui := action.NewUninstall(actionConfig)
+       res, err := ui.Run(relName)
        if err != nil {
-               panic(err)
+               hc.logger.Errorf("Unable to uninstall chart with release name: %s. Err: %s", relName, err)
+               return err
        }
-       fmt.Println("Successfully uninstalled release: ", res.Info)
+       hc.logger.Infof("Successfully uninstalled chart with release name: %s. Response Info: %s", res.Release.Name, res.Info)
+       return nil
 }
 
-func queryChart(relName string, hostIP string) string  {
-       kubeconfig := kubeconfigPath + hostIP
+// Query a given chart
+func (hc *HelmClient) queryChart(relName string) (string, error) {
        actionConfig := new(action.Configuration)
-       if err := actionConfig.Init(kube.GetConfig(kubeconfig, "", releaseNamespace), releaseNamespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
-               fmt.Sprintf(format, v)
-       }); err != nil {
-               panic(err)
+       if err := actionConfig.Init(kube.GetConfig(hc.kubeconfig, "", releaseNamespace), releaseNamespace,
+               os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
+                       fmt.Sprintf(format, v)
+               }); err != nil {
+               hc.logger.Errorf("Unable to initialize action config Err: %s", err)
+               return "", err
        }
-       iCli := action.NewStatus(actionConfig)
-       res, err := iCli.Run(relName)
+       s := action.NewStatus(actionConfig)
+       res, err := s.Run(relName)
        if err != nil {
-               panic(err)
+               hc.logger.Errorf("Unable to query chart with release name: %s. Err: %s", relName, err)
+               return "", err
        }
-       return res.Info.Status.String()
+       return res.Info.Status.String(), nil
 }
 
+// fileExists checks if a file exists and is not a directory before we
+// try using it to prevent further errors.
+func fileExists(filename string) (bool, error) {
+       info, err := os.Stat(filename)
+       if os.IsNotExist(err) {
+               return false, err
+       }
+       return !info.IsDir(), nil
+}