cli/pkg/kubernetes/kubernetes.go

190 lines
4.0 KiB
Go

// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
package kubernetes
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"time"
"github.com/briandowns/spinner"
"github.com/dapr/cli/pkg/print"
helm "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli"
v1 "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/helm/pkg/strvals"
)
const (
daprReleaseName = "dapr"
daprHelmRepo = "https://dapr.github.io/helm-charts"
daprLatestVersion = "latest"
)
type InitConfiguration struct {
Version string
Namespace string
EnableMTLS bool
EnableHA bool
}
// Init deploys the Dapr operator using the supplied runtime version.
func Init(config InitConfiguration) error {
msg := "Deploying the Dapr control plane to your cluster..."
var s *spinner.Spinner
if runtime.GOOS == "windows" {
print.InfoStatusEvent(os.Stdout, msg)
} else {
s = spinner.New(spinner.CharSets[0], 100*time.Millisecond)
s.Writer = os.Stdout
s.Color("cyan")
s.Suffix = fmt.Sprintf(" %s", msg)
s.Start()
}
err := install(config)
if err != nil {
if s != nil {
s.Stop()
}
return err
}
if s != nil {
s.Stop()
print.SuccessStatusEvent(os.Stdout, msg)
}
return nil
}
func createNamespace(namespace string) error {
_, client, err := GetKubeConfigClient()
if err != nil {
return fmt.Errorf("can't connect to a Kubernetes cluster: %v", err)
}
ns := &v1.Namespace{
ObjectMeta: meta_v1.ObjectMeta{
Name: namespace,
},
}
// try to create the namespace if it doesn't exist. ok to ignore error.
client.CoreV1().Namespaces().Create(context.TODO(), ns, meta_v1.CreateOptions{})
return nil
}
func helmConfig(namespace string) (*helm.Configuration, error) {
ac := helm.Configuration{}
flags := &genericclioptions.ConfigFlags{
Namespace: &namespace,
}
err := ac.Init(flags, namespace, "secret", debugLogf)
return &ac, err
}
func createTempDir() (string, error) {
dir, err := ioutil.TempDir("", "dapr")
if err != nil {
return "", fmt.Errorf("error creating temp dir: %s", err)
}
return dir, nil
}
func locateChartFile(dirPath string) (string, error) {
files, err := ioutil.ReadDir(dirPath)
if err != nil {
return "", err
}
return filepath.Join(dirPath, files[0].Name()), nil
}
func daprChart(version string, config *helm.Configuration) (*chart.Chart, error) {
pull := helm.NewPull()
pull.RepoURL = daprHelmRepo
pull.Settings = &cli.EnvSettings{}
if version != daprLatestVersion {
pull.Version = chartVersion(version)
}
dir, err := createTempDir()
if err != nil {
return nil, err
}
defer os.RemoveAll(dir)
pull.DestDir = dir
_, err = pull.Run(daprReleaseName)
if err != nil {
return nil, err
}
chartPath, err := locateChartFile(dir)
if err != nil {
return nil, err
}
return loader.Load(chartPath)
}
func chartValues(config InitConfiguration) (map[string]interface{}, error) {
chartVals := map[string]interface{}{}
globalVals := []string{
fmt.Sprintf("global.ha.enabled=%t", config.EnableHA),
fmt.Sprintf("global.mtls.enabled=%t", config.EnableMTLS),
}
for _, v := range globalVals {
if err := strvals.ParseInto(v, chartVals); err != nil {
return nil, err
}
}
return chartVals, nil
}
func install(config InitConfiguration) error {
err := createNamespace(config.Namespace)
if err != nil {
return err
}
helmConf, err := helmConfig(config.Namespace)
if err != nil {
return err
}
daprChart, err := daprChart(config.Version, helmConf)
if err != nil {
return err
}
installClient := helm.NewInstall(helmConf)
installClient.ReleaseName = daprReleaseName
installClient.Namespace = config.Namespace
values, err := chartValues(config)
if err != nil {
return err
}
if _, err = installClient.Run(daprChart, values); err != nil {
return err
}
return nil
}
func debugLogf(format string, v ...interface{}) {
}