mirror of https://github.com/helm/helm
parent
929c64261b
commit
2b515a08b6
@ -0,0 +1,47 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"helm.sh/helm/v3/pkg/http/api/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstallRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
Chart string `json:"chart"`
|
||||||
|
Values map[string]interface{} `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InstallResponse struct {
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RODO: we could use interface as well if everything's in same package
|
||||||
|
func Install(svc Service) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req InstallRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
logger.Errorf("[Install] error decoding request: %v", err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
var response InstallResponse
|
||||||
|
res, err := svc.Install(r.Context(), req.Chart, req.Values)
|
||||||
|
if err != nil {
|
||||||
|
response.Error = err.Error()
|
||||||
|
logger.Errorf("[Install] error while installing chart: %v", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Status = res.status
|
||||||
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||||
|
logger.Errorf("[Install] error writing response %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -1,14 +0,0 @@
|
|||||||
package install
|
|
||||||
|
|
||||||
type InstallRequest struct {
|
|
||||||
RequestID string
|
|
||||||
ReleaseName string
|
|
||||||
ReleaseNamespace string
|
|
||||||
ChartPath string
|
|
||||||
Values string
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstallResponse struct {
|
|
||||||
Status bool
|
|
||||||
ReleaseStatus string
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
package install
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"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()
|
|
||||||
|
|
||||||
var request InstallRequest
|
|
||||||
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")
|
|
||||||
request.Values = req.Header.Get("Values")
|
|
||||||
|
|
||||||
valueOpts := &values.Options{}
|
|
||||||
valueOpts.Values = append(valueOpts.Values, request.Values)
|
|
||||||
|
|
||||||
status, releaseStatus, err := InstallChart(request.ReleaseName, request.ReleaseNamespace, request.ChartPath, valueOpts)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error in request: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
response := InstallResponse{Status: status, ReleaseStatus: releaseStatus}
|
|
||||||
payload, err := json.Marshal(response)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error parsing response %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
if err != nil {
|
|
||||||
return false, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
cp, err := install.ChartPathOptions.LocateChart(chartPath, servercontext.App().Config)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error in locating chart: %v", err)
|
|
||||||
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
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log *zap.SugaredLogger
|
||||||
|
|
||||||
|
func Debugf(fmt string, args ...interface{}) {
|
||||||
|
log.Debugf(fmt, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatalf(fmt string, args ...interface{}) {
|
||||||
|
log.Fatalf(fmt, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errorf(fmt string, args ...interface{}) {
|
||||||
|
log.Errorf(fmt, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Infof(fmt string, args ...interface{}) {
|
||||||
|
log.Infof(fmt, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup(level string) {
|
||||||
|
//TODO: map from env config
|
||||||
|
var zlog *zap.Logger
|
||||||
|
switch level {
|
||||||
|
case "debug":
|
||||||
|
zlog, _ = zap.NewDevelopment()
|
||||||
|
case "none":
|
||||||
|
zlog = zap.NewNop()
|
||||||
|
default:
|
||||||
|
zlog, _ = zap.NewProduction()
|
||||||
|
}
|
||||||
|
// This condition is to avoid race conditions in test cases
|
||||||
|
if log == nil {
|
||||||
|
log = zlog.Sugar()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
"helm.sh/helm/v3/pkg/cli/values"
|
||||||
|
"helm.sh/helm/v3/pkg/getter"
|
||||||
|
"helm.sh/helm/v3/pkg/servercontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
config *cli.EnvSettings
|
||||||
|
install *action.Install
|
||||||
|
}
|
||||||
|
|
||||||
|
type chartValues map[string]interface{}
|
||||||
|
|
||||||
|
type installResult struct {
|
||||||
|
status string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) getValues(vals chartValues) (chartValues, error) {
|
||||||
|
valueOpts := &values.Options{}
|
||||||
|
//valueOpts.Values = append(valueOpts.Values, vals)
|
||||||
|
return valueOpts.MergeValues(getter.All(servercontext.App().Config))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) Install(ctx context.Context, chartName string, values chartValues) (installResult, error) {
|
||||||
|
var result installResult
|
||||||
|
chart, err := s.loadChart(chartName)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
vals, err := s.getValues(values)
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("error merging values: %v", err)
|
||||||
|
}
|
||||||
|
release, err := s.install.Run(chart, vals)
|
||||||
|
if err != nil {
|
||||||
|
return result, fmt.Errorf("error in installing chart: %v", err)
|
||||||
|
}
|
||||||
|
if release.Info != nil {
|
||||||
|
result.status = release.Info.Status.String()
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) loadChart(chartName string) (*chart.Chart, error) {
|
||||||
|
cp, err := s.install.ChartPathOptions.LocateChart(chartName, s.config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error in locating chart: %v", err)
|
||||||
|
}
|
||||||
|
var requestedChart *chart.Chart
|
||||||
|
if requestedChart, err = loader.Load(cp); err != nil {
|
||||||
|
return nil, fmt.Errorf("error loading chart: %v", err)
|
||||||
|
}
|
||||||
|
return requestedChart, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(cfg *cli.EnvSettings) Service {
|
||||||
|
return Service{
|
||||||
|
config: cfg,
|
||||||
|
//TODO: not sure why this's needed, but we can refactor later,could be passed as param
|
||||||
|
install: action.NewInstall(servercontext.App().ActionConfig),
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"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/servercontext"
|
||||||
|
"helm.sh/helm/v3/pkg/storage/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpgradeRequest struct {
|
||||||
|
RequestID string
|
||||||
|
ReleaseName string
|
||||||
|
ReleaseNamespace string
|
||||||
|
ChartPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpgradeResponse struct {
|
||||||
|
Status bool
|
||||||
|
ReleaseStatus string
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpgradeHandler struct {
|
||||||
|
service Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func Upgrade(service Service) http.Handler {
|
||||||
|
return UpgradeHandler{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h UpgradeHandler) ServeHTTP(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 := h.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 (h UpgradeHandler) 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)
|
||||||
|
|
||||||
|
//TODO: yet to accomodate namespace and releasename, just refactoring
|
||||||
|
release, err := h.service.Install(context.TODO(), chartPath, vals)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error in request: %v", err)
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
|
return true, release.status, 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
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
package upgrade
|
|
||||||
|
|
||||||
type UpgradeRequest struct {
|
|
||||||
RequestID string
|
|
||||||
ReleaseName string
|
|
||||||
ReleaseNamespace string
|
|
||||||
ChartPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpgradeResponse struct {
|
|
||||||
Status bool
|
|
||||||
ReleaseStatus string
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package upgrade
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"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/http/api/install"
|
|
||||||
"helm.sh/helm/v3/pkg/servercontext"
|
|
||||||
"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
|
|
||||||
}
|
|
Loading…
Reference in new issue