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