【 Smalltools 】Go编写Helm3 Client实现简易部署工具

⭐️关注我 ,一起探索更多知识!⭐️

helm.sh使用自定义charts部署release

SKD : https://pkg.go.dev/helm.sh/helm/v3@v3.7.2/pkg/action

参考博文 : https://stackoverflow.com/questions/45692719/samples-on-kubernetes-helm-golang-client

package main

import (
    "fmt"
    "log"
    "os"
    "helm.sh/helm/v3/pkg/action"
    "helm.sh/helm/v3/pkg/chart/loader"
    "helm.sh/helm/v3/pkg/cli"
)

func main() {
    chartPath := "./charts.tgz"
    namespace := "default"
    releaseName := "main-sky-beta"

    settings := cli.New()

    actionConfig := new(action.Configuration)
    // You can pass an empty string instead of settings.Namespace() to list
    // all namespaces
    if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
        os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
        log.Printf("%+v", err)
        os.Exit(1)
    }

    // define values
    vals := map[string]interface{}{
        "namespace":    namespace,
        "replicaCount": "1",
        "image": map[string]interface{}{
            "name":       "image",
            "pullPolicy": "IfNotPresent",
        },
        "nameOverride":     releaseName,
        "fullnameOverride": releaseName,
        "service": map[string]interface{}{
            "type": "ClusterIP",
            "port": "8080",
        },
        "hostAliases": map[string]interface{}{
            "hostAliasesSet": false,
            "hostAliasesMap": "",
        },
        "imagePull": map[string]interface{}{
            "secretsSet": true,
            "secrets":    "secret-harbor",
        },
        "envConfig": map[string]interface{}{
            "configSet": false,
            "config":    "",
        },
        "resources": map[string]interface{}{
            "resourcesSet": false,
            "requests": map[string]interface{}{
                "memory": "",
                "cpu":    "",
            },
            "limits": map[string]interface{}{
                "memory": "",
                "cpu":    "",
            },
            "affinity": map[string]interface{}{
                "affinitySet": false,
                "key":         "",
                "operator":    "In",
                "values":      "",
            },
            "tolerations": map[string]interface{}{
                "tolerationsSet": false,
                "key":            "__TOLERATIONS_KEY__",
                "operator":       "Equal",
                "value":          "__TOLERATIONS_VALUE__",
                "effect":         "NoSchedule",
            },
            "livenessProbe": map[string]interface{}{
                "livenessGetSet":     false,
                "livenessGet":        "__LIVENESS_GET__",
                "livenessCommandSet": false,
                "livenessCommand":    "__LIVENESS_COMMAND__",
            },
            "command": map[string]interface{}{
                "commandSet":   false,
                "startCommand": "__COMMAND__",
            },
            "AnnoTations": map[string]interface{}{
                "AnnoTationSet": false,
            },
        },
    }

    // load chart from the path
    chart, err := loader.Load(chartPath)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    client := action.NewInstall(actionConfig)
    client.Namespace = namespace
    client.ReleaseName = releaseName
    // client.DryRun = true - very handy!

    // install the chart here
    rel, err := client.Run(chart, vals)
    if err != nil {
        panic(err)
    }

    log.Printf("Installed Chart from path: %s in namespace: %s\n", rel.Name, rel.Namespace)
    // this will confirm the values set during installation
    log.Println(rel.Config)
}

client-go - 资源获取

SDK : https://pkg.go.dev/k8s.io/api@v0.22.4

参考博文 : https://stackoverflow.com/questions/40975307/how-to-watch-events-on-a-kubernetes-service-using-its-go-client

package main

import (
    "context"
    "fmt"
    "log"
    "time"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

func list() {
    // config 
    configPath := "etc/kube.conf"
    config, err := clientcmd.BuildConfigFromFlags("", configPath)
    if err != nil {
        log.Fatal(err)
    }
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatal(err)
    }

    // 查看Node信息
    fmt.Println("*****************************************************************")
    nodeList, err := clientSet.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }
    for _, node := range nodeList.Items {
        fmt.Printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s,\n",
            node.Name,
            node.Status.Phase,
            node.Status.Addresses,
            node.Status.NodeInfo.OSImage,
            node.Status.NodeInfo.KubeletVersion,
            node.Status.NodeInfo.OperatingSystem,
            node.Status.NodeInfo.Architecture,
            node.CreationTimestamp,
        )
    }

    // 查看Namespace
    fmt.Println("*****************************************************************")
    namespaceList, err := clientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }
    for _, namespace := range namespaceList.Items {
        fmt.Println(namespace.Name, namespace.CreationTimestamp, namespace.Status.Phase)
    }

    // 查看Service
    fmt.Println("*****************************************************************")
    // Services("") 传递指定的namespace
    serviceList, err := clientSet.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }
    for _, service := range serviceList.Items {
        fmt.Println(service.Name, service.Spec.Type, service.CreationTimestamp, service.Spec.Ports)
    }

    // 查看deployment
    fmt.Println("*****************************************************************")
    // Deployments("") 传递指定的namespace
    deploymentList, err := clientSet.AppsV1().Deployments("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }
    for _, deployment := range deploymentList.Items {
        fmt.Println(deployment.Namespace, deployment.Name, deployment.CreationTimestamp, deployment.Spec.Selector.MatchLabels, deployment.Status.Replicas, deployment.Status.AvailableReplicas)
    }

    // Watch deployment 资源变动
    fmt.Println("*****************************************************************")
    deploymentListW, errw := clientSet.AppsV1().Deployments("default").Watch(context.TODO(), metav1.ListOptions{Watch: true, LabelSelector: "app=demoappv10"})
    if errw != nil {
        log.Fatal(err)
    }
    for event := range deploymentListW.ResultChan() {
        fmt.Printf("Type: %v\n", event.Type)
        p, ok := event.Object.(*v1.Pod)
        if !ok {
            log.Fatal("unexpected type")
        }
        fmt.Println(p.Status.ContainerStatuses)
        fmt.Println(p.Status.Phase)
    }

    // Watch Pod 资源变动
    fmt.Println("*****************************************************************")
    label := "app=demoapp"
    podListW, errw := clientSet.CoreV1().Pods("default").Watch(context.TODO(), metav1.ListOptions{LabelSelector: label})
    if errw != nil {
        log.Fatal(err)
    }
    go func() {
        for event := range podListW.ResultChan() {
            fmt.Printf("Type: %v\n", event.Type)
            p, ok := event.Object.(*v1.Pod)
            if !ok {
                log.Fatal("unexpected type")
            }
            fmt.Println(p.Status.ContainerStatuses)
            fmt.Println(p.Status.Phase)
        }
    }()
    time.Sleep(5 * time.Second)
}

Helm3 Client工具

部署功能

  • server

实现 helm upgrade --install 功能的逻辑:

由于helm.sh SDK未直接提供 upgrade --install 的方法,所以需要自行使用 NewHistory 获取release是否存在,若存在则调用 NewUpgrade 方法,若不存在则调用 NewInstall 方法;

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "io/ioutil"
    "net/http"
    "helm.sh/helm/v3/pkg/action"
    "helm.sh/helm/v3/pkg/chart/loader"
    "helm.sh/helm/v3/pkg/cli"
    "helm.sh/helm/v3/pkg/cli/output"
    "helm.sh/helm/v3/pkg/storage/driver"
)

var tmp string
var outfmt output.Format

type Image struct {
    Name       string `json:"name"`
    PullPolicy string `json:"pullPolicy"`
}

type Service struct {
    Type string `json:"type"`
    Port string `json:"port"`
}

type HostAliases struct {
    HostAliasesSet bool `json:"hostAliasesSet"`
    // HostAliasesMap map[string]interface{} `json:"hostAliasesMap"`
    HostAliasesMap string `json:"hostAliasesMap"`
}

type ImagePull struct {
    SecretsSet bool   `json:"secretsSet"`
    Secrets    string `json:"secrets"`
}

type EnvConfig struct {
    ConfigSet bool   `json:"configSet"`
    Config    string `json:"config"`
}

type Requests struct {
    Memory string `json:"memory"`
    Cpu    string `json:"cpu"`
}
type Limits struct {
    Memory string `json:"memory"`
    Cpu    string `json:"cpu"`
}
type Resources struct {
    ResourcesSet bool      `json:"resourcesSet"`
    Requests     *Requests `json:"requests"`
    Limits       *Limits   `json:"limits"`
}

type Affinity struct {
    AffinitySet bool   `json:"affinitySet"`
    Key         string `json:"key"`
    Operator    string `json:"operator"`
    Values      string `json:"values"`
}

type Tolerations struct {
    TolerationsSet bool   `json:"tolerationsSet"`
    Key            string `json:"key"`
    Operator       string `json:"operator"`
    Values         string `json:"values"`
    Effect         string `json:"effect"`
}

type LivenessProbe struct {
    LivenessGetSet     bool   `json:"livenessGetSet"`
    LivenessGet        string `json:"livenessGet"`
    LivenessCommandSet bool   `json:"livenessCommandSet"`
    LivenessCommand    string `json"livenessCommand"`
}

type Command struct {
    CommandSet   bool   `json:"commandSet"`
    StartCommand string `json:"startCommand'`
}

type AnnoTations struct {
    AnnoTationSet     bool   `json:"AnnoTationSet"`
    AnnoTationExplain string `json:"AnnoTationExplain"`
}

type PipeParams struct {
    Namespace    string `json:"namespace"`
    ReplicaCount string `json:"replicaCount"`
    // Image      map[string]interface{} `json:"image"`
    Image            Image         `json:"image"`
    NameOverride     string        `json:"nameOverride"`
    FullnameOverride string        `json:"fullnameOverride"`
    Service          Service       `json:"service"`
    HostAliases      HostAliases   `json:"hostAliases"`
    ImagePull        ImagePull     `json:"imagePull"`
    EnvConfig        EnvConfig     `json:"envConfig"`
    Resources        Resources     `json:"resources"`
    Affinity         Affinity      `json:"affinity"`
    Tolerations      Tolerations   `json:"tolerations"`
    LivenessProbe    LivenessProbe `json:"livenessProbe"`
    Command          Command       `json:"command"`
    AnnoTations      AnnoTations   `json:AnnoTations`
}


func Helm_Upgrade(args map[string]interface{}, namespace string, releaseName string) {
    fmt.Println("args:", args)
    chartPath := "./charts.tgz"

    settings := cli.New()

    actionConfig := new(action.Configuration)
    // You can pass an empty string instead of settings.Namespace() to list
    // all namespaces
    if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
        os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
        log.Printf("%+v", err)
        os.Exit(1)
    }

    // define values
    // load chart from the path
    chart, err := loader.Load(chartPath)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    client := action.NewUpgrade(actionConfig)
    fmt.Println(namespace, releaseName)
    client.Namespace = namespace
    client.Install = true
    // client.DryRun = true - very handy!

    // Support reading values from STDIN for `upgrade` command
    if client.Install {
        // If a release does not exist, install it.
        histClient := action.NewHistory(actionConfig)
        histClient.Max = 1
        if _, err := histClient.Run(releaseName); err == driver.ErrReleaseNotFound {
            fmt.Println("Start Installation ...", releaseName)
            // Only print this to stdout for table output
            fmt.Println("Release does not exist. Installing it now")

            instClient := action.NewInstall(actionConfig)
            instClient.Namespace = namespace
            instClient.ReleaseName = releaseName
            // instClient.DryRun = client.DryRun
            instClient.Timeout = 5000
            instClient.Wait = true
            rel, err := instClient.Run(chart, args)
            if err != nil {
                panic(err)
            }
            fmt.Println(rel.Info)
        } else {
            fmt.Println("Start Upgrate ...", releaseName)
            // install the chart here
            rel, err := client.Run(releaseName, chart, args)
            if err != nil {
                panic(err)

            }
            // fmt.Println(rel.Info.Notes)
            fmt.Println(rel.Info.LastDeployed)
            log.Printf("Installed Chart from path: %s in namespace: %s\n", rel.Name, rel.Namespace)

        }
    }
}

// http
func PipeHook(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close()
    fmt.Println("method:", r.Method)
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        fmt.Printf("read body err, %v\n", err)
        return
    }

    // println("json:", string(body))
    tmp := string(body)

    var struct_tmp PipeParams

    err = json.Unmarshal([]byte(tmp), &struct_tmp)
    if err != nil {
        fmt.Println(err)
    } else {
        var resMap map[string]interface{}

        err := json.Unmarshal([]byte(tmp), &resMap)
        if err != nil {
            fmt.Println(err)
        }

        Helm_Upgrade(resMap, struct_tmp.Namespace, struct_tmp.NameOverride)
        // Get_Release()
    }
}

func main() {
    http.HandleFunc("/pipeline/", PipeHook)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        fmt.Printf("http server failed, err:%v\n", err)
        return
    }
}

  • Client

curl 127.0.0.1:9090/pipeline/ -X POST -d '{
    "namespace": "default",
    "replicaCount": "1",
    "image": {
        "name": "image",
        "pullPolicy": "IfNotPresent"
    },
    "nameOverride": "main-sky-test",
    "fullnameOverride": "main-sky-test",
    "service": {
        "type": "ClusterIP",
        "port": "8080"
    },
    "hostAliases": {
        "hostAliasesSet": false,
        "hostAliasesMap": ""
    },
    "imagePull": {
        "secretsSet": true,
        "secrets": "secret-harbor"
    },
    "envConfig": {
        "configSet": false,
        "config": ""
    },
    "resources": {
        "resourcesSet": false,
        "requests": {
            "memory": "",
            "cpu": ""
        },
        "limits": {
            "memory": "",
            "cpu": ""
        }
    },
    "affinity": {
        "affinitySet": false,
        "key": "",
        "operator": "In",
        "values": ""
    },
    "tolerations": {
        "tolerationsSet": false,
        "key": "__TOLERATIONS_KEY__",
        "operator": "Equal",
        "value": "__TOLERATIONS_VALUE__",
        "effect": "NoSchedule"
    },
    "livenessProbe": {
        "livenessGetSet": false,
        "livenessGet": "__LIVENESS_GET__",
        "livenessCommandSet": false,
        "livenessCommand": "__LIVENESS_COMMAND__"
    },
    "command": {
        "commandSet": false,
        "startCommand": "__COMMAND__"
    },
    "AnnoTations": {
        "AnnoTationSet": false,
        "AnnoTationExplain": ""
    }
}' --header "Content-Type: application/json"

部署及资源Watch功能

出于让客户端可以看到各个资源部署状态,故增加对 Deployment、Pod资源Watch机制;

  • server

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "helm.sh/helm/v3/pkg/action"
    "helm.sh/helm/v3/pkg/chart/loader"
    "helm.sh/helm/v3/pkg/cli"
    "helm.sh/helm/v3/pkg/cli/output"
    "helm.sh/helm/v3/pkg/storage/driver"
    appsV1 "k8s.io/api/apps/v1"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

// 操纵K8S每个方法同一超时时长
// var timeout int = 5

type Image struct {
    Name       string `json:"name"`
    PullPolicy string `json:"pullPolicy"`
}

type Service struct {
    Type string `json:"type"`
    Port string `json:"port"`
}

type HostAliases struct {
    HostAliasesSet bool `json:"hostAliasesSet"`
    HostAliasesMap string `json:"hostAliasesMap"`
}

type ImagePull struct {
    SecretsSet bool   `json:"secretsSet"`
    Secrets    string `json:"secrets"`
}

type EnvConfig struct {
    ConfigSet bool   `json:"configSet"`
    Config    string `json:"config"`
}

type Requests struct {
    Memory string `json:"memory"`
    Cpu    string `json:"cpu"`
}
type Limits struct {
    Memory string `json:"memory"`
    Cpu    string `json:"cpu"`
}
type Resources struct {
    ResourcesSet bool      `json:"resourcesSet"`
    Requests     *Requests `json:"requests"`
    Limits       *Limits   `json:"limits"`
}

type Affinity struct {
    AffinitySet bool   `json:"affinitySet"`
    Key         string `json:"key"`
    Operator    string `json:"operator"`
    Values      string `json:"values"`
}

type Tolerations struct {
    TolerationsSet bool   `json:"tolerationsSet"`
    Key            string `json:"key"`
    Operator       string `json:"operator"`
    Values         string `json:"values"`
    Effect         string `json:"effect"`
}

type LivenessProbe struct {
    LivenessGetSet     bool   `json:"livenessGetSet"`
    LivenessGet        string `json:"livenessGet"`
    LivenessCommandSet bool   `json:"livenessCommandSet"`
    LivenessCommand    string `json:"livenessCommand"`
}

type Command struct {
    CommandSet   bool   `json:"commandSet"`
    StartCommand string `json:"startCommand"`
}

type AnnoTations struct {
    AnnoTationSet     bool   `json:"AnnoTationSet"`
    AnnoTationExplain string `json:"AnnoTationExplain"`
}

type PipeParams struct {
    Namespace    string `json:"namespace"`
    ReplicaCount string `json:"replicaCount"`
    // Image      map[string]interface{} `json:"image"`
    Image            Image         `json:"image"`
    NameOverride     string        `json:"nameOverride"`
    FullnameOverride string        `json:"fullnameOverride"`
    Service          Service       `json:"service"`
    HostAliases      HostAliases   `json:"hostAliases"`
    ImagePull        ImagePull     `json:"imagePull"`
    EnvConfig        EnvConfig     `json:"envConfig"`
    Resources        Resources     `json:"resources"`
    Affinity         Affinity      `json:"affinity"`
    Tolerations      Tolerations   `json:"tolerations"`
    LivenessProbe    LivenessProbe `json:"livenessProbe"`
    Command          Command       `json:"command"`
    AnnoTations      AnnoTations   `json:"AnnoTations"`
}

//

type Deployment struct {
    // Resources string      `json:"Resources"`
    Name      string      `json:"Name"`
    Ready     string      `json:"Ready"`
    Avatlable string      `json:"Avatlable"`
    Age       metav1.Time `json:"Age"`
    Image     string      `json:"Image"`
}

type JsonResponse struct {
    Deployment Deployment    `json:"Deployment"`
    Pod        []interface{} `json:"Pod"`
}

// TODO
/*
    Helm 状态返回
    Helm 状态回滚
*/

type JsonResult struct {
    Code       int          `json:"code"`
    Msg        string       `json:"msg"`
    Deployment JsonResponse `json:"deployment"`
}

// 加载配置文件
func K8s_Conf() (*kubernetes.Clientset, error) {
    configPath := "etc/kube.conf"
    config, err := clientcmd.BuildConfigFromFlags("", configPath)
    if err != nil {
        log.Fatal(err)
    }
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatal(err)
    }
    return clientSet, err
}

func Pod_Watch(name, namespace string) []interface{} {
    // var podstatus Pod
    var test []interface{}
    label := "app.kubernetes.io/name=" + name
    // label := "app=demoapp"
    timeout := new(int64)
    *timeout = 8

    clientSet, err := K8s_Conf()
    if err != nil {
        log.Fatal(err)
    }
    // fmt.Println("*****************************************************************")

    podListW, errw := clientSet.CoreV1().Pods(namespace).Watch(context.TODO(), metav1.ListOptions{LabelSelector: label, TimeoutSeconds: timeout})
    if errw != nil {
        log.Fatal(err)
    }
    // go func() {
    for event := range podListW.ResultChan() {
        // fmt.Printf("Type: %v\n", event.Type)
        p, ok := event.Object.(*v1.Pod)
        if !ok {
            log.Fatal("unexpected type")
        }
        pname := p.Name           // demoappv10-6ff964cbff-hmsb8
        pstatus := p.Status.Phase // Running
        reason := p.Status.StartTime
        fmt.Printf("==> v1/Pod(related)\nNAME\t\t\t\t\tSTATUS\t\t\tAGE\n%s\t\t%s\t\t\t%v\t\n", pname, pstatus, reason)

        reasonstring := fmt.Sprintf("%v", p.Status.StartTime)
        pod := map[string]interface{}{
            pname: []string{
                string(pstatus), reasonstring,
            },
        }
        // fmt.Println(pod)
        test = append(test, pod)
    }
    return test
}

func K8s_Client(name, namespace string) JsonResponse {
    var result JsonResponse

    clientSet, err := K8s_Conf()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("*****************************************************************")
    label := "app.kubernetes.io/name=" + name
    timeout := new(int64)
    *timeout = 2
    deploymentListW, errw := clientSet.AppsV1().Deployments(namespace).Watch(context.TODO(), metav1.ListOptions{LabelSelector: label, TimeoutSeconds: timeout})
    if errw != nil {
        log.Fatal(err)
    }

    for event := range deploymentListW.ResultChan() {
        fmt.Printf("Type: %v\n", event.Type)
        p, ok := event.Object.(*appsV1.Deployment)
        if !ok {
            log.Fatal("unexpected type")
        }
        // dns := p.Namespace
        dna := p.Name
        dreplicas := p.Status.Replicas
        dreadyreplicas := p.Status.ReadyReplicas
        davailablereplicas := p.Status.AvailableReplicas
        dcreationtimestamp := p.CreationTimestamp
        dgetimage := p.Spec.Template.Spec.Containers[0].Image
        client_result := fmt.Sprintf("*****************************************************************\nRESOURCES:\n===> v1/Deployment\nNAME\t\tREADY\tAVAILABLE\tAGE\t\t\t\t\tIMAGE\n%s\t%v/%v\t%v\t\t%v\t\t%v\n", dna, dreplicas, dreadyreplicas, davailablereplicas, dcreationtimestamp, dgetimage)
        fmt.Println(client_result)
        result.Deployment.Name = p.Name
        result.Deployment.Ready = fmt.Sprintf("%v/%v", p.Status.ReadyReplicas, p.Status.AvailableReplicas)
        result.Deployment.Avatlable = fmt.Sprintf("%v", p.Status.AvailableReplicas)
        result.Deployment.Age = p.CreationTimestamp
        result.Deployment.Image = p.Spec.Template.Spec.Containers[0].Image
        fmt.Println(result)

        fmt.Println(name)
        result.Pod = Pod_Watch(name, namespace)

        if dreadyreplicas != dreplicas {
            // 监视 Pod资源变动
            fmt.Println("Pod_Watch")
            result.Pod = Pod_Watch(name, namespace)
        }

    }

    return result
}

var tmp string
var outfmt output.Format

func Helm_Upgrade(args map[string]interface{}, namespace string, releaseName string) JsonResult {
    var result JsonResult

    fmt.Println("args:", args)
    chartPath := "./charts.tgz"

    settings := cli.New()

    actionConfig := new(action.Configuration)
    // You can pass an empty string instead of settings.Namespace() to list
    // all namespaces
    if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
        os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
        log.Printf("%+v", err)
        os.Exit(1)
    }

    // define values
    // load chart from the path
    chart, err := loader.Load(chartPath)
    if err != nil {
        fmt.Println(err)
        panic(err)
    }

    client := action.NewUpgrade(actionConfig)
    fmt.Println(namespace, releaseName)
    client.Namespace = namespace
    client.Install = true
    client.Timeout = 30
    // client.DryRun = true - very handy!

    // Fixes #7002 - Support reading values from STDIN for `upgrade` command
    // Must load values AFTER determining if we have to call install so that values loaded from stdin are are not read twice

    if client.Install {
        // If a release does not exist, install it.
        histClient := action.NewHistory(actionConfig)
        histClient.Max = 1
        if _, err := histClient.Run(releaseName); err == driver.ErrReleaseNotFound {
            fmt.Println("Start Installation ...", releaseName)
            // Only print this to stdout for table output
            fmt.Println("Release does not exist. Installing it now")

            instClient := action.NewInstall(actionConfig)
            instClient.Namespace = namespace
            instClient.ReleaseName = releaseName
            // instClient.DryRun = client.DryRun
            instClient.Timeout = 30
            // instClient.Wait = true
            rel, err := instClient.Run(chart, args)
            if err != nil {
                panic(err)
            }
            fmt.Println(rel.Info)

            msg := "Install success" + releaseName + "in" + namespace
            result.Code = 200
            result.Msg = msg
            result.Deployment = K8s_Client(releaseName, namespace)
            return result

        } else {
            fmt.Println("Start Upgrate ...", releaseName)
            rel, err := client.Run(releaseName, chart, args)
            if err != nil {
                panic(err)

            }

            fmt.Println(rel.Info.LastDeployed)

            log.Printf("Installed Chart from path: %s in namespace: %s\n", rel.Name, rel.Namespace)

            // this will confirm the values set during installation
            // log.Println(rel.Config)
            msg := "Upgrate success " + releaseName + " in " + namespace
            result.Code = 200
            result.Msg = msg
            result.Deployment = K8s_Client(releaseName, namespace)
            return result
        }
    }
    msg := "Install filed" + releaseName + "in" + namespace
    result.Code = 500
    result.Msg = msg
    return result
}

// http
func PipeHook(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close()
    fmt.Println("method:", r.Method)
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        fmt.Printf("read body err, %v\n", err)
        return
    }

    tmp := string(body)
    var struct_tmp PipeParams

    err = json.Unmarshal([]byte(tmp), &struct_tmp)
    if err != nil {
        fmt.Println(err)
    } else {
        // fmt.Println("STRUCT:", struct_tmp.Resources.Requests.Cpu)
        var resMap map[string]interface{}
        err := json.Unmarshal([]byte(tmp), &resMap)
        if err != nil {
            fmt.Println(err)
        }

        response := Helm_Upgrade(resMap, struct_tmp.Namespace, struct_tmp.NameOverride)
        w.Header().Set("content-type", "text/json")
        msg, _ := json.Marshal(response)
        w.Write(msg)
    }
}

func main() {
    fmt.Println("The service listens on port 9090....")
    http.HandleFunc("/pipeline/", PipeHook)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        fmt.Printf("http server failed, err:%v\n", err)
        return
    }
}

  • client

#!/bin/bash
curl 127.0.0.1:9090/pipeline/ --connect-timeout 15 -m 20 -X POST -d '{
    "namespace": "default",
    "replicaCount": "1",
    "image": {
    "name": "image_name",
    "pullPolicy": "IfNotPresent"
    },
    "nameOverride": "gaea-test",
    "fullnameOverride": "gaea-test",
    "service": {
    "type": "ClusterIP",
    "port": "8080"
    },
    "hostAliases": {
    "hostAliasesSet": false,
    "hostAliasesMap": ""
    },
    "imagePull": {
    "secretsSet": true,
    "secrets": "secret-harbor"
    },
    "envConfig": {
    "configSet": true,
    "config": "configmap"
    },
    "resources": {
    "resourcesSet": false,
    "requests": {
    "memory": "",
    "cpu": ""
    },
    "limits": {
    "memory": "",
    "cpu": ""
    }
    },
    "affinity": {
    "affinitySet": false,
    "key": "",
    "operator": "In",
    "values": ""
    },
    "tolerations": {
    "tolerationsSet": false,
    "key": "__TOLERATIONS_KEY__",
    "operator": "Equal",
    "value": "__TOLERATIONS_VALUE__",
    "effect": "NoSchedule"
    },
    "livenessProbe": {
    "livenessGetSet": false,
    "livenessGet": "__LIVENESS_GET__",
    "livenessCommandSet": false,
    "livenessCommand": "__LIVENESS_COMMAND__"
    },
    "command": {
    "commandSet": true,
    "startCommand": "['bash','./start.sh']"
    },
    "AnnoTations": {
    "AnnoTationSet": false,
    "AnnoTationExplain": ""
    }
    }' --header "Content-Type: application/json"

image.png

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值