-
Notifications
You must be signed in to change notification settings - Fork 706
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic Helm 3 support (with ListReleases only) (#1359)
- Loading branch information
1 parent
a12eeb2
commit f6cd36c
Showing
18 changed files
with
1,144 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
{{- if .Values.useHelm3 -}} | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: {{ template "kubeapps.kubeops.fullname" . }} | ||
labels: | ||
app: {{ template "kubeapps.kubeops.fullname" . }} | ||
chart: {{ template "kubeapps.chart" . }} | ||
release: {{ .Release.Name }} | ||
heritage: {{ .Release.Service }} | ||
spec: | ||
replicas: {{ .Values.kubeops.replicaCount }} | ||
selector: | ||
matchLabels: | ||
app: {{ template "kubeapps.kubeops.fullname" . }} | ||
release: {{ .Release.Name }} | ||
template: | ||
metadata: | ||
labels: | ||
app: {{ template "kubeapps.kubeops.fullname" . }} | ||
release: {{ .Release.Name }} | ||
spec: | ||
serviceAccountName: {{ template "kubeapps.kubeops.fullname" . }} | ||
# Increase termination timeout to let remaining operations to finish before killing the pods | ||
# This is because new releases/upgrades/deletions are synchronous operations | ||
terminationGracePeriodSeconds: 300 | ||
{{- include "kubeapps.imagePullSecrets" . | indent 6 }} | ||
containers: | ||
- name: kubeops | ||
image: {{ template "kubeapps.image" (list .Values.kubeops.image .Values.global) }} | ||
command: | ||
- /kubeops | ||
args: | ||
- --user-agent-comment=kubeapps/{{ .Chart.AppVersion }} | ||
- --chartsvc-url=http://{{ template "kubeapps.chartsvc.fullname" . }}:{{ .Values.chartsvc.service.port }} | ||
ports: | ||
- name: http | ||
containerPort: {{ .Values.kubeops.service.port }} | ||
env: | ||
- name: POD_NAMESPACE | ||
valueFrom: | ||
fieldRef: | ||
fieldPath: metadata.namespace | ||
resources: | ||
{{ toYaml .Values.kubeops.resources | indent 12 }} | ||
{{- with .Values.kubeops.nodeSelector }} | ||
nodeSelector: | ||
{{ toYaml . | indent 8 }} | ||
{{- end }} | ||
{{- if .Values.securityContext.enabled }} | ||
securityContext: | ||
fsGroup: {{ .Values.securityContext.fsGroup }} | ||
runAsUser: {{ .Values.securityContext.runAsUser }} | ||
{{- end }} | ||
{{- with .Values.kubeops.affinity }} | ||
affinity: | ||
{{ toYaml . | indent 8 }} | ||
{{- end }} | ||
{{- with .Values.kubeops.tolerations }} | ||
tolerations: | ||
{{ toYaml . | indent 8 }} | ||
{{- end }} | ||
{{- end }}{{/* matches useHelm3 */}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{{- if .Values.useHelm3 -}} | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: {{ template "kubeapps.kubeops.fullname" . }} | ||
labels: | ||
app: {{ template "kubeapps.name" . }} | ||
chart: {{ template "kubeapps.chart" . }} | ||
release: {{ .Release.Name }} | ||
heritage: {{ .Release.Service }} | ||
spec: | ||
type: ClusterIP | ||
ports: | ||
- port: {{ .Values.kubeops.service.port }} | ||
targetPort: http | ||
protocol: TCP | ||
name: http | ||
selector: | ||
app: {{ template "kubeapps.kubeops.fullname" . }} | ||
release: {{ .Release.Name }} | ||
{{- end }}{{/* matches useHelm3 */}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{{- if .Values.useHelm3 -}} | ||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: {{ template "kubeapps.kubeops.fullname" . }} | ||
labels: | ||
app: {{ template "kubeapps.kubeops.fullname" . }} | ||
chart: {{ template "kubeapps.chart" . }} | ||
release: {{ .Release.Name }} | ||
heritage: {{ .Release.Service }} | ||
{{- end }}{{/* matches useHelm3 */}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 1 addition & 2 deletions
3
...oller/pkg/client/clientset/versioned/typed/apprepository/v1alpha1/apprepository_client.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
...er/pkg/client/clientset/versioned/typed/apprepository/v1alpha1/fake/fake_apprepository.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# syntax = docker/dockerfile:experimental | ||
|
||
FROM golang:1.13 as builder | ||
WORKDIR /go/src/github.com/kubeapps/kubeapps | ||
COPY go.mod go.sum ./ | ||
COPY vendor vendor | ||
COPY pkg pkg | ||
COPY cmd cmd | ||
ARG VERSION | ||
# With the trick below, Go's build cache is kept between builds. | ||
# https://github.com/golang/go/issues/27719#issuecomment-514747274 | ||
RUN --mount=type=cache,target=/go/pkg/mod \ | ||
--mount=type=cache,target=/root/.cache/go-build \ | ||
CGO_ENABLED=0 go build -installsuffix cgo -ldflags "-X main.version=$VERSION" ./cmd/kubeops | ||
|
||
FROM scratch | ||
COPY --from=builder /go/src/github.com/kubeapps/kubeapps/kubeops /kubeops | ||
EXPOSE 8080 | ||
CMD ["/kubeops"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package handler | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/kubeapps/common/response" | ||
"github.com/kubeapps/kubeapps/pkg/agent" | ||
"github.com/kubeapps/kubeapps/pkg/auth" | ||
"github.com/kubeapps/kubeapps/pkg/handlerutil" | ||
) | ||
|
||
const ( | ||
authHeader = "Authorization" | ||
namespaceParam = "namespace" | ||
) | ||
|
||
// This type represents the fact that a regular handler cannot actually be created until we have access to the request, | ||
// because a valid action config (and hence agent config) cannot be created until then. | ||
// If the agent config were a "this" argument instead of an explicit argument, it would be easy to create a handler with a "zero" config. | ||
// This approach practically eliminates that risk; it is much easier to use WithAgentConfig to create a handler guaranteed to use a valid agent config. | ||
type dependentHandler func(cfg agent.Config, w http.ResponseWriter, req *http.Request, params handlerutil.Params) | ||
|
||
// WithAgentConfig takes a dependentHandler and creates a regular (WithParams) handler that, | ||
// for every request, will create an agent config for itself. | ||
// Written in a curried fashion for convenient usage; see cmd/kubeops/main.go. | ||
func WithAgentConfig(driverType agent.DriverType, options agent.Options) func(f dependentHandler) handlerutil.WithParams { | ||
return func(f dependentHandler) handlerutil.WithParams { | ||
return func(w http.ResponseWriter, req *http.Request, params handlerutil.Params) { | ||
namespace := params[namespaceParam] | ||
token := auth.ExtractToken(req.Header.Get(authHeader)) | ||
cfg := agent.Config{ | ||
AgentOptions: options, | ||
ActionConfig: agent.NewActionConfig(driverType, token, namespace), | ||
} | ||
f(cfg, w, req, params) | ||
} | ||
} | ||
} | ||
|
||
func ListReleases(cfg agent.Config, w http.ResponseWriter, req *http.Request, params handlerutil.Params) { | ||
apps, err := agent.ListReleases(cfg.ActionConfig, params[namespaceParam], cfg.AgentOptions.ListLimit, req.URL.Query().Get("statuses")) | ||
if err != nil { | ||
response.NewErrorResponse(handlerutil.ErrorCode(err), err.Error()).Write(w) | ||
return | ||
} | ||
response.NewDataResponse(apps).Write(w) | ||
} | ||
|
||
func ListAllReleases(cfg agent.Config, w http.ResponseWriter, req *http.Request, _ handlerutil.Params) { | ||
ListReleases(cfg, w, req, make(map[string]string)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/gorilla/mux" | ||
"github.com/kubeapps/kubeapps/cmd/kubeops/internal/handler" | ||
"github.com/kubeapps/kubeapps/pkg/agent" | ||
"github.com/kubeapps/kubeapps/pkg/auth" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/pflag" | ||
"github.com/urfave/negroni" | ||
"k8s.io/helm/pkg/helm/environment" | ||
) | ||
|
||
const defaultHelmDriver agent.DriverType = agent.Secret | ||
|
||
var ( | ||
settings environment.EnvSettings | ||
chartsvcURL string | ||
helmDriverArg string | ||
userAgentComment string | ||
listLimit int | ||
timeout int64 | ||
) | ||
|
||
func init() { | ||
settings.AddFlags(pflag.CommandLine) | ||
pflag.StringVar(&chartsvcURL, "chartsvc-url", "https://kubeapps-internal-chartsvc:8080", "URL to the internal chartsvc") | ||
pflag.StringVar(&helmDriverArg, "helm-driver", "", "which Helm driver type to use") | ||
pflag.IntVar(&listLimit, "list-max", 256, "maximum number of releases to fetch") | ||
pflag.StringVar(&userAgentComment, "user-agent-comment", "", "UserAgent comment used during outbound requests") | ||
// Default timeout from https://github.com/helm/helm/blob/b0b0accdfc84e154b3d48ec334cd5b4f9b345667/cmd/helm/install.go#L216 | ||
pflag.Int64Var(&timeout, "timeout", 300, "Timeout to perform release operations (install, upgrade, rollback, delete)") | ||
} | ||
|
||
func main() { | ||
pflag.Parse() | ||
settings.Init(pflag.CommandLine) | ||
|
||
options := agent.Options{ | ||
ListLimit: listLimit, | ||
Timeout: timeout, | ||
} | ||
|
||
// Will panic below if an invalid driver type is provided. | ||
driverType := defaultHelmDriver | ||
if helmDriverArg != "" { | ||
driverType = agent.ParseDriverType(helmDriverArg) | ||
} | ||
withAgentConfig := handler.WithAgentConfig(driverType, options) | ||
r := mux.NewRouter() | ||
|
||
// Routes | ||
// Auth not necessary here with Helm 3 because it's done by Kubernetes. | ||
apiv1 := r.PathPrefix("/v1").Subrouter() | ||
apiv1.Methods("GET").Path("/releases").Handler(negroni.New( | ||
negroni.Wrap(withAgentConfig(handler.ListAllReleases)), | ||
)) | ||
apiv1.Methods("GET").Path("/namespaces/{namespace}/releases").Handler(negroni.New( | ||
negroni.Wrap(withAgentConfig(handler.ListReleases)), | ||
)) | ||
|
||
// Chartsvc reverse proxy | ||
authGate := auth.AuthGate() | ||
parsedChartsvcURL, err := url.Parse(chartsvcURL) | ||
if err != nil { | ||
log.Fatalf("Unable to parse the chartsvc URL: %v", err) | ||
} | ||
chartsvcProxy := httputil.NewSingleHostReverseProxy(parsedChartsvcURL) | ||
chartsvcPrefix := "/chartsvc" | ||
chartsvcRouter := r.PathPrefix(chartsvcPrefix).Subrouter() | ||
// Logos don't require authentication so bypass that step | ||
chartsvcRouter.Methods("GET").Path("/v1/assets/{repo}/{id}/logo").Handler(negroni.New( | ||
negroni.Wrap(http.StripPrefix(chartsvcPrefix, chartsvcProxy)), | ||
)) | ||
chartsvcRouter.Methods("GET").Handler(negroni.New( | ||
authGate, | ||
negroni.Wrap(http.StripPrefix(chartsvcPrefix, chartsvcProxy)), | ||
)) | ||
|
||
n := negroni.Classic() | ||
n.UseHandler(r) | ||
|
||
port := os.Getenv("PORT") | ||
if port == "" { | ||
port = "8080" | ||
} | ||
addr := ":" + port | ||
|
||
srv := &http.Server{ | ||
Addr: addr, | ||
Handler: n, | ||
} | ||
|
||
go func() { | ||
log.WithFields(log.Fields{"addr": addr}).Info("Started Kubeops") | ||
err := srv.ListenAndServe() | ||
if err != nil { | ||
log.Info(err) | ||
} | ||
}() | ||
|
||
// Catch SIGINT and SIGTERM | ||
// Set up channel on which to send signal notifications. | ||
c := make(chan os.Signal, 1) | ||
signal.Notify(c, os.Interrupt, syscall.SIGTERM) | ||
log.Debug("Set system to get notified on signals") | ||
s := <-c | ||
log.Infof("Received signal: %v. Waiting for existing requests to finish", s) | ||
// Set a timeout value high enough to let k8s terminationGracePeriodSeconds to act | ||
// accordingly and send a SIGKILL if needed | ||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3600) | ||
defer cancel() | ||
// Doesn't block if no connections, but will otherwise wait | ||
// until the timeout deadline. | ||
srv.Shutdown(ctx) | ||
log.Info("All requests have been served. Exiting") | ||
os.Exit(0) | ||
} |
Oops, something went wrong.