Skip to content

Commit

Permalink
Add Helm template storage backend logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok committed Mar 24, 2022
1 parent 6b60379 commit b409504
Show file tree
Hide file tree
Showing 19 changed files with 837 additions and 471 deletions.
11 changes: 5 additions & 6 deletions cmd/cli/cmd/typeinstance/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@ import (
"strings"
"time"

"capact.io/capact/pkg/hub/client/local"
"github.com/fatih/color"
"github.com/spf13/cobra"

"capact.io/capact/internal/cli"
"capact.io/capact/internal/cli/client"
"capact.io/capact/internal/cli/config"
"capact.io/capact/internal/cli/heredoc"
cliprinter "capact.io/capact/internal/cli/printer"
gqllocalapi "capact.io/capact/pkg/hub/api/graphql/local"

"github.com/spf13/cobra"
"capact.io/capact/pkg/hub/client/local"
)

const (
yamlFileSeparator = "---"
tableRequiredFields = local.TypeInstanceRootFields | local.TypeInstanceTypeRefFields | local.TypeInstanceUsedByIDField | local.TypeInstanceUsesIDField | local.TypeInstanceLatestResourceVersionField
tableRequiredFields = local.TypeInstanceRootFields | local.TypeInstanceTypeRefFields | local.TypeInstanceUsedByIDField | local.TypeInstanceUsesIDField | local.TypeInstanceLatestResourceVersionVersionField
)

// GetOptions is used to store the configuration flags for the Get command.
Expand Down Expand Up @@ -55,8 +54,8 @@ func NewGet() *cobra.Command {
Example: heredoc.WithCLIName(`
# Display TypeInstances with IDs 'c49b' and '4793'
<cli> typeinstance get c49b 4793
# Save TypeInstances with IDs 'c49b' and '4793' to file in the update format which later can be submitted for update by:
# Save TypeInstances with IDs 'c49b' and '4793' to file in the update format which later can be submitted for update by:
# <cli> typeinstance apply --from-file /tmp/typeinstances.yaml
<cli> typeinstance get c49b 4793 -oyaml --export > /tmp/typeinstances.yaml
`, cli.Name),
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/docs/capact_typeinstance_get.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ capact typeinstance get [TYPE_INSTANCE_ID...] [flags]
# Display TypeInstances with IDs 'c49b' and '4793'
capact typeinstance get c49b 4793
# Save TypeInstances with IDs 'c49b' and '4793' to file in the update format which later can be submitted for update by:
# Save TypeInstances with IDs 'c49b' and '4793' to file in the update format which later can be submitted for update by:
# capact typeinstance apply --from-file /tmp/typeinstances.yaml
capact typeinstance get c49b 4793 -oyaml --export > /tmp/typeinstances.yaml
Expand Down
13 changes: 8 additions & 5 deletions cmd/helm-storage-backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import (

helm_storage_backend "capact.io/capact/internal/helm-storage-backend"

"capact.io/capact/internal/healthz"
"capact.io/capact/internal/logger"
"capact.io/capact/pkg/hub/api/grpc/storage_backend"
"github.com/vrischmann/envconfig"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"

"capact.io/capact/internal/healthz"
"capact.io/capact/internal/logger"
"capact.io/capact/pkg/hub/api/grpc/storage_backend"
)

// Mode describes the selected handler for the Helm storage backend gRPC server.
Expand Down Expand Up @@ -67,17 +68,19 @@ func main() {

helmCfgFlags := helmCfgFlagsForK8sCfg(k8sCfg)

relFetcher := helm_storage_backend.NewHelmReleaseFetcher(helmCfgFlags)

// setup servers
parallelServers := new(errgroup.Group)

// create handler
var handler storage_backend.StorageBackendServer
switch cfg.Mode {
case HelmReleaseMode:
handler, err = helm_storage_backend.NewReleaseHandler(logger, helmCfgFlags)
handler, err = helm_storage_backend.NewReleaseHandler(logger, relFetcher)
exitOnError(err, "while creating Helm Release backend storage")
case HelmTemplateMode:
handler = helm_storage_backend.NewTemplateHandler(logger, helmCfgFlags)
handler = helm_storage_backend.NewTemplateHandler(logger, relFetcher)
default:
exitOnError(fmt.Errorf("invalid mode %q", cfg.Mode), "while loading storage backend handler")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ spec:
path: /healthz
port: 8082
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- toYaml .Values.helmReleaseBackend.resources | nindent 12 }}
env:
- name: APP_GRPC_ADDR
value: ":50051"
Expand Down Expand Up @@ -76,8 +76,11 @@ spec:
httpGet:
path: /healthz
port: 8083
volumeMounts:
- mountPath: /tmp
name: cache-volume
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- toYaml .Values.helmTemplateBackend.resources | nindent 12 }}
env:
- name: APP_GRPC_ADDR
value: ":50052"
Expand All @@ -88,6 +91,9 @@ spec:
- name: APP_MODE
value: "template"
{{- end }}
volumes:
- name: cache-volume
emptyDir: { }
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
Expand Down
27 changes: 18 additions & 9 deletions deploy/kubernetes/charts/helm-storage-backend/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,30 @@ helmReleaseBackend:
port: 50051
type: ClusterIP

resources:
limits:
cpu: 100m
memory: 32Mi
requests:
cpu: 30m
memory: 16Mi


helmTemplateBackend:
enabled: true
service:
port: 50052
type: ClusterIP

resources:
limits:
cpu: 1
memory: 512Mi
requests:
cpu: 30m
memory: 16Mi


replicaCount: 1

imagePullSecrets: []
Expand All @@ -37,15 +55,6 @@ securityContext: {}
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000

resources:
limits:
cpu: 100m
memory: 32Mi
requests:
cpu: 30m
memory: 16Mi

autoscaling:
enabled: false
minReplicas: 1
Expand Down
13 changes: 13 additions & 0 deletions internal/helm-storage-backend/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package helmstoragebackend

import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func gRPCInternalError(err error) error {
if err == nil {
return nil
}
return status.Error(codes.Internal, err.Error())
}
36 changes: 0 additions & 36 deletions internal/helm-storage-backend/helm.go

This file was deleted.

90 changes: 90 additions & 0 deletions internal/helm-storage-backend/helm_rel_fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package helmstoragebackend

import (
"fmt"

"github.com/pkg/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver"
"k8s.io/cli-runtime/pkg/genericclioptions"

"capact.io/capact/internal/ptr"
)

const defaultHelmDriver = "secrets"

type (
// HelmRelease holds details about Helm release.
HelmRelease struct {
// Name specifies Helm release name for a given request.
Name string `json:"name"`
// Namespace specifies in which Kubernetes Namespace Helm release is located.
Namespace string `json:"namespace"`
// Driver specifies drivers used for storing the Helm release.
Driver *string `json:"driver,omitempty"`
}

actionConfigurationProducerFn func(flags *genericclioptions.ConfigFlags, driver string, ns string) (*action.Configuration, error)
)

// HelmReleaseFetcher provides functionality to fetch Helm release.
type HelmReleaseFetcher struct {
helmCfgFlags *genericclioptions.ConfigFlags
actionConfigurationProducer actionConfigurationProducerFn
}

// NewHelmReleaseFetcher returns a new HelmReleaseFetcher instance.
func NewHelmReleaseFetcher(flags *genericclioptions.ConfigFlags) *HelmReleaseFetcher {
return &HelmReleaseFetcher{helmCfgFlags: flags, actionConfigurationProducer: actionConfigurationProducer}
}

// FetchHelmRelease returns a given Helm release. It already handles the gRPC errors properly.
func (f *HelmReleaseFetcher) FetchHelmRelease(tiID string, helmRelease HelmRelease) (*release.Release, error) {
cfg, err := f.actionConfigurationProducer(f.helmCfgFlags, *helmRelease.Driver, helmRelease.Namespace)
if err != nil {
return nil, gRPCInternalError(errors.Wrap(err, "while creating Helm get release client"))
}

helmGet := action.NewGet(cfg)

// NOTE: req.resourceVersion is ignored on purpose.
// Based on our contract we always return the latest Helm release revision.
helmGet.Version = latestRevisionIndicator

rel, err := helmGet.Run(helmRelease.Name)
switch {
case err == nil:
case errors.Is(err, driver.ErrReleaseNotFound):
return nil, status.Error(codes.NotFound, fmt.Sprintf("Helm release '%s/%s' for TypeInstance '%s' was not found", helmRelease.Namespace, helmRelease.Name, tiID))
default:
return nil, gRPCInternalError(errors.Wrap(err, "while fetching Helm release"))
}

return rel, nil
}

// actionConfigurationProducer returns Configuration with a given input settings.
func actionConfigurationProducer(flags *genericclioptions.ConfigFlags, driver, ns string) (*action.Configuration, error) {
actionConfig := new(action.Configuration)
helmCfg := &genericclioptions.ConfigFlags{
APIServer: flags.APIServer,
Insecure: flags.Insecure,
CAFile: flags.CAFile,
BearerToken: flags.BearerToken,
Namespace: ptr.String(ns),
}

debugLog := func(format string, v ...interface{}) {
// noop
}

err := actionConfig.Init(helmCfg, ns, driver, debugLog)
if err != nil {
return nil, errors.Wrap(err, "while initializing Helm configuration")
}

return actionConfig, nil
}
Loading

0 comments on commit b409504

Please sign in to comment.