Logging & error handling
[ealt-edge.git] / mecm / mepm / applcm / k8shelm / pkg / plugin / helmclient.go
index ec05dd5..eae3c03 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"
+       "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/"
+// Constants to be taken from deployment file
+const (
+       releaseNamespace  = "default"
+       chartPath  = "/go/release/charts/"
+       kubeconfigPath  = "/go/release/kubeconfig/"
+)
+
+// 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.Info("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{}) {
+       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 {
-               panic(err)
-       }
+               }); 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.Info("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{}) {
+       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 {
-               panic(err)
-       }
-       iCli := action.NewUninstall(actionConfig)
-       res, err := iCli.Run(relName);
+               }); err != nil {
+               hc.logger.Errorf("Unable to initialize action config Err: %s", err)
+               return err
+               }
+
+       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.Info("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{}) {
+       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 {
-               panic(err)
+               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(), 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 res.Info.Status.String()
+       return !info.IsDir(), nil
 }