From b818548c1b32629c6af3ea7d3399d0784762a12c Mon Sep 17 00:00:00 2001 From: Anirudh M Date: Wed, 17 Jun 2020 17:42:58 +0530 Subject: [PATCH] Add upgrade chart endpoint --- cmd/service/service.go | 2 + pkg/http/api/install/installcontract.go | 2 +- pkg/http/api/install/installhandler.go | 59 ++++++++----- pkg/http/api/upgrade/upgradecontract.go | 13 +++ pkg/http/api/upgrade/upgradehandler.go | 105 ++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 pkg/http/api/upgrade/upgradecontract.go create mode 100644 pkg/http/api/upgrade/upgradehandler.go diff --git a/cmd/service/service.go b/cmd/service/service.go index c9b9b56be..a7fd57254 100644 --- a/cmd/service/service.go +++ b/cmd/service/service.go @@ -7,6 +7,7 @@ import ( "helm.sh/helm/v3/pkg/http/api/install" "helm.sh/helm/v3/pkg/http/api/list" "helm.sh/helm/v3/pkg/http/api/ping" + "helm.sh/helm/v3/pkg/http/api/upgrade" "helm.sh/helm/v3/pkg/servercontext" ) @@ -20,6 +21,7 @@ func startServer(appconfig *servercontext.Application) { router.Handle("/ping", ping.Handler()) router.Handle("/list", list.Handler()) router.Handle("/install", install.Handler()) + router.Handle("/upgrade", upgrade.Handler()) err := http.ListenAndServe(fmt.Sprintf(":%d", 8080), router) if err != nil { diff --git a/pkg/http/api/install/installcontract.go b/pkg/http/api/install/installcontract.go index 9b5047a0e..c943d4520 100644 --- a/pkg/http/api/install/installcontract.go +++ b/pkg/http/api/install/installcontract.go @@ -7,7 +7,7 @@ type InstallRequest struct { ChartPath string } -type InstallReponse struct { +type InstallResponse struct { Status bool ReleaseStatus string } diff --git a/pkg/http/api/install/installhandler.go b/pkg/http/api/install/installhandler.go index d89a8c5f6..2f4d90bc5 100644 --- a/pkg/http/api/install/installhandler.go +++ b/pkg/http/api/install/installhandler.go @@ -8,12 +8,13 @@ import ( "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/values" + "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/servercontext" ) func Handler() http.Handler { return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-Type", "application/json") defer req.Body.Close() @@ -30,32 +31,15 @@ func Handler() http.Handler { request.ReleaseName = req.Header.Get("Release-Name") request.ReleaseNamespace = req.Header.Get("Release-Namespace") request.ChartPath = req.Header.Get("Chart-Path") + valueOpts := &values.Options{} - install := action.NewInstall(servercontext.App().ActionConfig) - install.ReleaseName = request.ReleaseName - install.Namespace = request.ReleaseNamespace - - cp, err := install.ChartPathOptions.LocateChart(request.ChartPath, servercontext.App().Config) - if err != nil { - fmt.Printf("error in locating chart: %v", err) - return - } - - var requestedChart *chart.Chart - if requestedChart, err = loader.Load(cp); err != nil { - fmt.Printf("error in loading chart: %v", err) - return - } - - var vals map[string]interface{} - release, err := install.Run(requestedChart, vals) + status, releaseStatus, err := InstallChart(request.ReleaseName, request.ReleaseNamespace, request.ChartPath, valueOpts) if err != nil { - fmt.Printf("error in installing chart: %v", err) + fmt.Printf("error in request: %v", err) return } - response := InstallReponse{Status: true, ReleaseStatus: string(release.Info.Status)} - + response := InstallResponse{Status: status, ReleaseStatus: releaseStatus} payload, err := json.Marshal(response) if err != nil { fmt.Printf("error parsing response %v", err) @@ -65,3 +49,34 @@ func Handler() http.Handler { res.Write(payload) }) } + +func InstallChart(releaseName, releaseNamespace, chartPath string, valueOpts *values.Options) (bool, string, error) { + install := action.NewInstall(servercontext.App().ActionConfig) + install.ReleaseName = releaseName + install.Namespace = releaseNamespace + vals, err := valueOpts.MergeValues(getter.All(servercontext.App().Config)) + + cp, err := install.ChartPathOptions.LocateChart(chartPath, servercontext.App().Config) + if err != nil { + fmt.Printf("error in locating chart: %v", err) + return false, "", err + } + + if err != nil { + return false, "", err + } + + var requestedChart *chart.Chart + if requestedChart, err = loader.Load(cp); err != nil { + fmt.Printf("error in loading chart: %v", err) + return false, "", err + } + + release, err := install.Run(requestedChart, vals) + if err != nil { + fmt.Printf("error in installing chart: %v", err) + return false, "", err + } + + return true, release.Info.Status.String(), nil +} diff --git a/pkg/http/api/upgrade/upgradecontract.go b/pkg/http/api/upgrade/upgradecontract.go new file mode 100644 index 000000000..c5557a850 --- /dev/null +++ b/pkg/http/api/upgrade/upgradecontract.go @@ -0,0 +1,13 @@ +package upgrade + +type UpgradeRequest struct { + RequestID string + ReleaseName string + ReleaseNamespace string + ChartPath string +} + +type UpgradeResponse struct { + Status bool + ReleaseStatus string +} diff --git a/pkg/http/api/upgrade/upgradehandler.go b/pkg/http/api/upgrade/upgradehandler.go new file mode 100644 index 000000000..c5e3d3a92 --- /dev/null +++ b/pkg/http/api/upgrade/upgradehandler.go @@ -0,0 +1,105 @@ +package upgrade + +import ( + "encoding/json" + "fmt" + "net/http" + + "helm.sh/helm/v3/cmd/endpoints/install" + "helm.sh/helm/v3/cmd/servercontext" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/storage/driver" +) + +func Handler() http.Handler { + return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + res.Header().Set("Content-Type", "application/json") + defer req.Body.Close() + + var request UpgradeRequest + decoder := json.NewDecoder(req.Body) + decoder.UseNumber() + + if err := decoder.Decode(&request); err != nil { + fmt.Printf("error in request: %v", err) + return + } + + request.RequestID = req.Header.Get("Request-Id") + request.ReleaseName = req.Header.Get("Release-Name") + request.ReleaseNamespace = req.Header.Get("Release-Namespace") + request.ChartPath = req.Header.Get("Chart-Path") + valueOpts := &values.Options{} + + status, releaseStatus, err := UpgradeRelease(request.ReleaseName, request.ReleaseNamespace, request.ChartPath, valueOpts) + if err != nil { + fmt.Printf("error in request: %v", err) + return + } + + response := UpgradeResponse{Status: status, ReleaseStatus: releaseStatus} + payload, err := json.Marshal(response) + if err != nil { + fmt.Printf("error parsing response %v", err) + return + } + + res.Write(payload) + }) +} + +func UpgradeRelease(releaseName, releaseNamespace, chartPath string, valueOpts *values.Options) (bool, string, error) { + upgrade := action.NewUpgrade(servercontext.App().ActionConfig) + upgrade.Namespace = releaseNamespace + + vals, err := valueOpts.MergeValues(getter.All(servercontext.App().Config)) + if err != nil { + return false, "", err + } + + chartPath, err = upgrade.ChartPathOptions.LocateChart(chartPath, servercontext.App().Config) + if err != nil { + return false, "", err + } + if upgrade.Install { + history := action.NewHistory(servercontext.App().ActionConfig) + history.Max = 1 + if _, err := history.Run(releaseName); err == driver.ErrReleaseNotFound { + fmt.Printf("Release %q does not exist. Installing it now.\n", releaseName) + + status, releaseStatus, err := install.InstallChart(releaseName, releaseNamespace, chartPath, valueOpts) + if err != nil { + fmt.Printf("error in request: %v", err) + return false, "", err + } + return status, releaseStatus, nil + } + } + + ch, err := loader.Load(chartPath) + if err != nil { + fmt.Printf("error in loading: %v", err) + return false, "", err + } + if req := ch.Metadata.Dependencies; req != nil { + if err := action.CheckDependencies(ch, req); err != nil { + fmt.Printf("error in dependencies: %v", err) + return false, "", err + } + } + + if ch.Metadata.Deprecated { + fmt.Printf("WARNING: This chart is deprecated") + } + + release, err := upgrade.Run(releaseName, ch, vals) + if err != nil { + fmt.Printf("error in installing chart: %v", err) + return false, "", err + } + + return true, release.Info.Status.String(), nil +}