You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by ka...@apache.org on 2021/04/29 05:12:47 UTC

[submarine] branch master updated: SUBMARINE-805. Install local traefik chart via helm golang API

This is an automated email from the ASF dual-hosted git repository.

kaihsun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new da51236  SUBMARINE-805. Install local traefik chart via helm golang API
da51236 is described below

commit da51236071a7f30c38c7a05d91a019054d44631f
Author: kevin85421 <b0...@ntu.edu.tw>
AuthorDate: Thu Apr 29 13:12:38 2021 +0800

    SUBMARINE-805. Install local traefik chart via helm golang API
    
    ### What is this PR for?
    Install local traefik chart via Helm golang API.
    
    traefik chart: https://github.com/apache/submarine/tree/master/helm-charts/submarine/charts/traefik
    
    Helm golang API: https://github.com/apache/submarine/blob/master/submarine-cloud-v2/pkg/helm/helm.go
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    * port-forwarding via client-go
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-805?filter=allissues#
    
    ### How should this be tested?
    ```
    # initialization
    # Step1: Register Custom Resource Definition
    kubectl apply -f artifacts/examples/crd.yaml
    
    # Step2: Create a Custom Resource
    kubectl apply -f artifacts/examples/example-submarine.yaml
    
    
    # Step3-1: helm
    cd submarine
    helm install submarine ./helm-charts/submarine
    kubectl port-forward --address 0.0.0.0 service/traefik 32080:80
    
    # Step3-2: in-cluster
    cd submarine/submarine-cloud-v2
    eval $(minikube docker-env)
    make image
    kubectl apply -f artifacts/examples/submarine-operator-service-account.yaml
    kubectl apply -f artifacts/examples/submarine-operator.yaml
    kubectl port-forward --address 0.0.0.0 service/traefik 32080:80
    
    # Step3-3: out-of-cluster
    go build -o submarine-operator
    ./submarine-operator
    kubectl port-forward --address 0.0.0.0 service/traefik 32080:80
    
    # Step4: Check 127.0.0.1:32080 in web browser
    #.            Username: admin / Password: admin
    ```
    
    ### Screenshots (if appropriate)
    
    https://user-images.githubusercontent.com/20109646/116415503-10663480-a86c-11eb-8fff-199cc69d31c7.mov
    
    
    
    
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? No
    * Does this need new documentation? No
---
 .gitignore                                         |   1 +
 submarine-cloud-v2/Dockerfile                      |   4 +
 submarine-cloud-v2/Makefile                        |   7 +-
 .../submarine-operator-service-account.yaml        |  19 +++-
 submarine-cloud-v2/controller.go                   |  29 ++++++
 submarine-cloud-v2/pkg/helm/helm.go                | 113 ++++++++++++++++++++-
 6 files changed, 166 insertions(+), 7 deletions(-)

diff --git a/.gitignore b/.gitignore
index 25e6577..7629275 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,7 @@ submarine-security/spark-security/derby.log
 # submarine-cloud-v2
 submarine-cloud-v2/vendor/*
 submarine-cloud-v2/submarine-operator
+submarine-cloud-v2/charts/*
 
 # vscode file
 .project
diff --git a/submarine-cloud-v2/Dockerfile b/submarine-cloud-v2/Dockerfile
index cb67e2c..a4097aa 100644
--- a/submarine-cloud-v2/Dockerfile
+++ b/submarine-cloud-v2/Dockerfile
@@ -16,6 +16,8 @@
 FROM ubuntu:18.04
 MAINTAINER Apache Software Foundation <de...@submarine.apache.org>
 
+WORKDIR /usr/src
+
 RUN apt-get update &&\
     apt-get install -y wget vim git
 
@@ -27,5 +29,7 @@ ENV PATH=$PATH:$GOPATH:$GOBIN:$GOROOT/bin
 RUN wget https://dl.google.com/go/go1.16.2.linux-amd64.tar.gz &&\
     tar -C /usr/local -xzf go1.16.2.linux-amd64.tar.gz
 
+ADD charts/ /usr/src/charts
+
 ADD submarine-operator /usr/src
 CMD ["/usr/src/submarine-operator", "-incluster=true"] 
diff --git a/submarine-cloud-v2/Makefile b/submarine-cloud-v2/Makefile
index d9db13a..d6e4a4c 100644
--- a/submarine-cloud-v2/Makefile
+++ b/submarine-cloud-v2/Makefile
@@ -17,8 +17,11 @@
 
 all: # The default target
 
+charts:
+	cp -r ../helm-charts/submarine/charts  .
+
 .PHONY: all
-all:
+all: charts
 	go build -o submarine-operator
 
 .PHONY: api
@@ -27,7 +30,7 @@ api:
 		echo "Verifying API..."; ./verify-codegen.sh
 
 .PHONY: image
-image:
+image: charts
 	GOOS=linux go build -o submarine-operator
 	docker build -t submarine-operator .
 	go build -o submarine-operator
diff --git a/submarine-cloud-v2/artifacts/examples/submarine-operator-service-account.yaml b/submarine-cloud-v2/artifacts/examples/submarine-operator-service-account.yaml
index cf73d2a..08d047e 100644
--- a/submarine-cloud-v2/artifacts/examples/submarine-operator-service-account.yaml
+++ b/submarine-cloud-v2/artifacts/examples/submarine-operator-service-account.yaml
@@ -27,6 +27,18 @@ rules:
     verbs:
       - "*"
   - apiGroups:
+      - traefik.containo.us
+    resources:
+      - ingressroutes
+      - ingressroutetcps
+      - ingressrouteudps
+      - middlewares
+      - tlsoptions
+      - tlsstores
+      - traefikservices
+    verbs:
+      - "*"
+  - apiGroups:
       - ""
     resources:
       - pods
@@ -60,6 +72,12 @@ rules:
       - clusterrolebindings
     verbs:
       - "*"
+  - apiGroups:
+      - apiextensions.k8s.io
+    resources:
+      - customresourcedefinitions
+    verbs:
+      - "*"
 ---
 apiVersion: v1
 kind: ServiceAccount
@@ -79,4 +97,3 @@ subjects:
   - kind: ServiceAccount
     name: submarine-operator
     namespace: default
-
diff --git a/submarine-cloud-v2/controller.go b/submarine-cloud-v2/controller.go
index 316cf56..96fdac2 100644
--- a/submarine-cloud-v2/controller.go
+++ b/submarine-cloud-v2/controller.go
@@ -53,6 +53,7 @@ import (
 	"k8s.io/client-go/tools/record"
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
+	"submarine-cloud-v2/pkg/helm"
 )
 
 const controllerAgentName = "submarine-controller"
@@ -707,6 +708,31 @@ func (c *Controller) newSubmarineDatabase(namespace string, spec *v1alpha1.Subma
 	return nil
 }
 
+// subcharts: https://github.com/apache/submarine/tree/master/helm-charts/submarine/charts
+
+func (c *Controller) newSubCharts(namespace string) error {
+	// Install traefik
+	// Reference: https://github.com/apache/submarine/tree/master/helm-charts/submarine/charts/traefik
+
+	if !helm.CheckRelease("traefik", namespace) {
+		klog.Info("[Helm] Install Traefik")
+		helm.HelmInstallLocalChart(
+			"traefik",
+			"charts/traefik",
+			"traefik",
+			namespace,
+			map[string]string{},
+		)
+	}
+
+	// TODO: maintain "error"
+	// TODO: (sample-controller) controller.go:287 ~ 293
+	// TODO: port-forward
+	// 		kubectl port-forward --address 0.0.0.0 service/traefik 32080:80
+
+	return nil
+}
+
 // syncHandler compares the actual state with the desired, and attempts to
 // converge the two. It then updates the Status block of the Foo resource
 // with the current status of the resource.
@@ -766,6 +792,9 @@ func (c *Controller) syncHandler(key string) error {
 		return err
 	}
 
+	// Install subcharts
+	c.newSubCharts(namespace)
+
 	return nil
 }
 
diff --git a/submarine-cloud-v2/pkg/helm/helm.go b/submarine-cloud-v2/pkg/helm/helm.go
index 4c14ff8..3961e00 100644
--- a/submarine-cloud-v2/pkg/helm/helm.go
+++ b/submarine-cloud-v2/pkg/helm/helm.go
@@ -41,10 +41,11 @@ import (
 	"helm.sh/helm/v3/pkg/downloader"
 	"helm.sh/helm/v3/pkg/getter"
 	"helm.sh/helm/v3/pkg/repo"
+	"helm.sh/helm/v3/pkg/storage/driver"
 	"helm.sh/helm/v3/pkg/strvals"
 )
 
-func HelmInstall(url string, repoName string, chartName string, releaseName string, namespace string, args map[string]string) (*action.Configuration){
+func HelmInstall(url string, repoName string, chartName string, releaseName string, namespace string, args map[string]string) *action.Configuration {
 	var settings *cli.EnvSettings
 	os.Setenv("HELM_NAMESPACE", namespace)
 	settings = cli.New()
@@ -57,6 +58,15 @@ func HelmInstall(url string, repoName string, chartName string, releaseName stri
 	return cfg
 }
 
+func HelmInstallLocalChart(chartName string, chartPath string, releaseName string, namespace string, args map[string]string) *action.Configuration {
+	var settings *cli.EnvSettings
+	os.Setenv("HELM_NAMESPACE", namespace)
+	settings = cli.New()
+	// Install charts
+	cfg := InstallLocalChart(releaseName, chartName, chartPath, args, settings)
+	return cfg
+}
+
 func HelmUninstall(releaseName string, cfg *action.Configuration) error {
 	uninstall := action.NewUninstall(cfg)
 	_, err := uninstall.Run(releaseName)
@@ -158,19 +168,20 @@ func RepoUpdate(settings *cli.EnvSettings) {
 }
 
 // InstallChart
-func InstallChart(name, repo, chart string, args map[string]string, settings *cli.EnvSettings) (*action.Configuration) {
+func InstallChart(releaseName string, repo string, chart string, args map[string]string, settings *cli.EnvSettings) *action.Configuration {
 	actionConfig := new(action.Configuration)
 	debug("KUBECONFIG: %s", settings.KubeConfig)
 	if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil {
 		log.Fatal(err)
 	}
+
 	client := action.NewInstall(actionConfig)
 
 	if client.Version == "" && client.Devel {
 		client.Version = ">0.0.0-0"
 	}
-	//name, chart, err := client.NameAndChart(args)
-	client.ReleaseName = name
+
+	client.ReleaseName = releaseName
 	cp, err := client.ChartPathOptions.LocateChart(fmt.Sprintf("%s/%s", repo, chart), settings)
 	if err != nil {
 		log.Fatal(err)
@@ -234,6 +245,100 @@ func InstallChart(name, repo, chart string, args map[string]string, settings *cl
 	return actionConfig
 }
 
+// InstallChart
+func InstallLocalChart(releaseName string, chart string, chartPath string, args map[string]string, settings *cli.EnvSettings) *action.Configuration {
+	actionConfig := new(action.Configuration)
+	if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil {
+		log.Fatal(err)
+	}
+
+	client := action.NewInstall(actionConfig)
+
+	if client.Version == "" && client.Devel {
+		client.Version = ">0.0.0-0"
+	}
+
+	client.ReleaseName = releaseName
+
+	debug("CHART PATH: %s\n", chartPath)
+
+	p := getter.All(settings)
+	valueOpts := &values.Options{}
+	vals, err := valueOpts.MergeValues(p)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Add args
+	if err := strvals.ParseInto(args["set"], vals); err != nil {
+		log.Fatal(errors.Wrap(err, "failed parsing --set data"))
+	}
+
+	// Check chart dependencies to make sure all are present in /charts
+	chartRequested, err := loader.Load(chartPath)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	validInstallableChart, err := isChartInstallable(chartRequested)
+	if !validInstallableChart {
+		log.Fatal(err)
+	}
+
+	if req := chartRequested.Metadata.Dependencies; req != nil {
+		// If CheckDependencies returns an error, we have unfulfilled dependencies.
+		// As of Helm 2.4.0, this is treated as a stopping condition:
+		// https://github.com/helm/helm/issues/2209
+		if err := action.CheckDependencies(chartRequested, req); err != nil {
+			if client.DependencyUpdate {
+				man := &downloader.Manager{
+					Out:              os.Stdout,
+					ChartPath:        chartPath,
+					Keyring:          client.ChartPathOptions.Keyring,
+					SkipUpdate:       false,
+					Getters:          p,
+					RepositoryConfig: settings.RepositoryConfig,
+					RepositoryCache:  settings.RepositoryCache,
+				}
+				if err := man.Update(); err != nil {
+					log.Fatal(err)
+				}
+			} else {
+				log.Fatal(err)
+			}
+		}
+	}
+
+	client.Namespace = settings.Namespace()
+	release, err := client.Run(chartRequested, vals)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(release.Manifest)
+	return actionConfig
+}
+
+func CheckRelease(releaseName string, namespace string) bool {
+	debug("[CheckRelease] %s %s\n", releaseName, namespace)
+	var settings *cli.EnvSettings
+	os.Setenv("HELM_NAMESPACE", namespace)
+	settings = cli.New()
+
+	actionConfig := new(action.Configuration)
+	if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil {
+		log.Fatal(err)
+	}
+
+	histClient := action.NewHistory(actionConfig)
+	if _, err := histClient.Run(releaseName); err == driver.ErrReleaseNotFound {
+		debug("		The release %s does not exist.\n", releaseName)
+		return false
+	}
+
+	debug("		The release %s exists.\n", releaseName)
+	return true
+}
+
 func isChartInstallable(ch *chart.Chart) (bool, error) {
 	switch ch.Metadata.Type {
 	case "", "application":

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org