Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added support for target namespaces #475

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pkg/addon-operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package addon_operator
import (
"context"
"fmt"
"github.com/flant/shell-operator/pkg/debug"
"path"
"runtime/trace"
"strings"
Expand Down Expand Up @@ -30,7 +31,6 @@ import (
"github.com/flant/kube-client/client"
sh_app "github.com/flant/shell-operator/pkg/app"
runtimeConfig "github.com/flant/shell-operator/pkg/config"
"github.com/flant/shell-operator/pkg/debug"
bc "github.com/flant/shell-operator/pkg/hook/binding_context"
"github.com/flant/shell-operator/pkg/hook/controller"
htypes "github.com/flant/shell-operator/pkg/hook/types"
Expand Down Expand Up @@ -1291,7 +1291,8 @@ func (op *AddonOperator) HandleModulePurge(t sh_task.Task, labels map[string]str
logEntry.Debugf("Module purge start")

hm := task.HookMetadataAccessor(t)
err := op.Helm.NewClient(t.GetLogLabels()).DeleteRelease(hm.ModuleName)
namespace, _ := op.ModuleManager.GetModule(hm.ModuleName).GetDefaultOrDefinedNamespace()
err := op.Helm.NewClient(t.GetLogLabels()).DeleteRelease(namespace, hm.ModuleName)
if err != nil {
// Purge is for unknown modules, just print warning.
logEntry.Warnf("Module purge failed, no retry. Error: %s", err)
Expand Down
10 changes: 5 additions & 5 deletions pkg/helm/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package client
import "github.com/flant/addon-operator/pkg/utils"

type HelmClient interface {
LastReleaseStatus(releaseName string) (string, string, error)
LastReleaseStatus(releaseNamespace string, releaseName string) (string, string, error)
UpgradeRelease(releaseName string, chart string, valuesPaths []string, setValues []string, namespace string) error
Render(releaseName string, chart string, valuesPaths []string, setValues []string, namespace string, debug bool) (string, error)
GetReleaseValues(releaseName string) (utils.Values, error)
DeleteRelease(releaseName string) error
ListReleasesNames() ([]string, error)
IsReleaseExists(releaseName string) (bool, error)
GetReleaseValues(releaseNamespace string, releaseName string) (utils.Values, error)
DeleteRelease(releaseNamespace string, releaseName string) error
ListReleasesNames(releaseNamespace string) ([]string, error)
IsReleaseExists(releaseNamespace string, releaseName string) (bool, error)
}
62 changes: 38 additions & 24 deletions pkg/helm/helm3/helm3.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package helm3
import (
"bytes"
"fmt"
"github.com/flant/addon-operator/pkg/app"
"os/exec"
"sort"
"strings"
Expand All @@ -11,7 +12,6 @@ import (
log "github.com/sirupsen/logrus"
k8syaml "sigs.k8s.io/yaml"

"github.com/flant/addon-operator/pkg/app"
"github.com/flant/addon-operator/pkg/helm/client"
"github.com/flant/addon-operator/pkg/utils"
"github.com/flant/shell-operator/pkg/executor"
Expand Down Expand Up @@ -93,10 +93,10 @@ func (h *Helm3Client) initAndVersion() error {
// Example helm history output:
// REVISION UPDATED STATUS CHART DESCRIPTION
// 1 Fri Jul 14 18:25:00 2017 SUPERSEDED symfony-demo-0.1.0 Install complete
func (h *Helm3Client) LastReleaseStatus(releaseName string) (revision string, status string, err error) {
func (h *Helm3Client) LastReleaseStatus(releaseNamespace string, releaseName string) (revision string, status string, err error) {
stdout, stderr, err := h.cmd(
"history", releaseName,
"--namespace", h.Namespace,
"--namespace", releaseNamespace,
"--max", "1",
"--output", "yaml",
)
Expand Down Expand Up @@ -134,18 +134,17 @@ func (h *Helm3Client) LastReleaseStatus(releaseName string) (revision string, st
}

func (h *Helm3Client) UpgradeRelease(releaseName string, chart string, valuesPaths []string, setValues []string, namespace string) error {
if namespace == "" {
namespace = h.Namespace
}
args := []string{
"upgrade", releaseName, chart,
"--install",
"--namespace", namespace,
"--history-max", fmt.Sprintf("%d", Options.HistoryMax),
"--timeout", Options.Timeout.String(),
}

if namespace != "" {
args = append(args, "--namespace")
args = append(args, namespace)
}

for _, valuesPath := range valuesPaths {
args = append(args, "--values")
args = append(args, valuesPath)
Expand All @@ -166,12 +165,18 @@ func (h *Helm3Client) UpgradeRelease(releaseName string, chart string, valuesPat
return nil
}

func (h *Helm3Client) GetReleaseValues(releaseName string) (utils.Values, error) {
func (h *Helm3Client) GetReleaseValues(releaseNamespace string, releaseName string) (utils.Values, error) {
namespace := h.Namespace
if releaseNamespace != "" {
namespace = releaseNamespace
}

args := []string{
"get", "values", releaseName,
"--namespace", h.Namespace,
"--namespace", namespace,
"--output", "yaml",
}

stdout, stderr, err := h.cmd(args...)
if err != nil {
return nil, fmt.Errorf("cannot get values of helm release %s: %s\n%s %s", releaseName, err, stdout, stderr)
Expand All @@ -185,13 +190,19 @@ func (h *Helm3Client) GetReleaseValues(releaseName string) (utils.Values, error)
return values, nil
}

func (h *Helm3Client) DeleteRelease(releaseName string) (err error) {
func (h *Helm3Client) DeleteRelease(releaseNamespace string, releaseName string) (err error) {
h.LogEntry.Debugf("helm release '%s': execute helm uninstall", releaseName)

namespace := h.Namespace
if releaseNamespace != "" {
namespace = releaseNamespace
}

args := []string{
"uninstall", releaseName,
"--namespace", h.Namespace,
"--namespace", namespace,
}

stdout, stderr, err := h.cmd(args...)
if err != nil {
return fmt.Errorf("helm uninstall %s invocation error: %v\n%v %v", releaseName, err, stdout, stderr)
Expand All @@ -200,8 +211,8 @@ func (h *Helm3Client) DeleteRelease(releaseName string) (err error) {
return
}

func (h *Helm3Client) IsReleaseExists(releaseName string) (bool, error) {
revision, _, err := h.LastReleaseStatus(releaseName)
func (h *Helm3Client) IsReleaseExists(releaseNamespace string, releaseName string) (bool, error) {
revision, _, err := h.LastReleaseStatus(releaseNamespace, releaseName)
if err != nil && revision == "0" {
return false, nil
} else if err != nil {
Expand All @@ -212,10 +223,15 @@ func (h *Helm3Client) IsReleaseExists(releaseName string) (bool, error) {
}

// ListReleasesNames returns list of release names.
func (h *Helm3Client) ListReleasesNames() ([]string, error) {
func (h *Helm3Client) ListReleasesNames(releaseNamespace string) ([]string, error) {
namespace := h.Namespace
if releaseNamespace != "" {
namespace = releaseNamespace
}

args := []string{
"list", "--all",
"--namespace", h.Namespace,
"--namespace", namespace,
"--output", "yaml",
}

Expand All @@ -231,14 +247,12 @@ func (h *Helm3Client) ListReleasesNames() ([]string, error) {
if err := k8syaml.Unmarshal([]byte(stdout), &list); err != nil {
return nil, fmt.Errorf("helm list returned invalid json: %v", err)
}

releases := make([]string, 0, len(list))
for _, release := range list {
// Do not return ignored release or empty string.
if release.Name == app.HelmIgnoreRelease || release.Name == "" {
continue
}

releases = append(releases, release.Name)
}

Expand All @@ -248,17 +262,17 @@ func (h *Helm3Client) ListReleasesNames() ([]string, error) {

// Render renders helm templates for chart
func (h *Helm3Client) Render(releaseName string, chart string, valuesPaths []string, setValues []string, namespace string, debug bool) (string, error) {
args := []string{"template", releaseName, chart}
helmNamespace := h.Namespace
if namespace != "" {
helmNamespace = namespace
}

args := []string{"template", releaseName, chart, "--namespace", helmNamespace}

if debug {
args = append(args, "--debug")
}

if namespace != "" {
args = append(args, "--namespace")
args = append(args, namespace)
}

for _, valuesPath := range valuesPaths {
args = append(args, "--values")
args = append(args, valuesPath)
Expand Down
21 changes: 21 additions & 0 deletions pkg/module_manager/models/modules/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package modules
import (
"context"
"fmt"
"github.com/flant/addon-operator/pkg/app"
"os"
"path/filepath"
"sort"
Expand Down Expand Up @@ -862,6 +863,26 @@ func (bm *BasicModule) GetModuleError() error {
return bm.state.lastModuleErr
}

// Read namespace from .namespace file in module dir
// Return addon-operator namespace by default
func (bm *BasicModule) GetDefaultOrDefinedNamespace() (string, error) {
content, err := os.ReadFile(filepath.Join(bm.Path, ".namespace"))
if err != nil {
if err != os.ErrNotExist {
return app.Namespace, fmt.Errorf("%s: %s", bm.Name, err)
} else {
log.Warnf("%s: .namespace not found, ignoring", bm.Name)
return app.Namespace, nil
}
}
namespace := strings.TrimRight(string(content), " \t\n")
if namespace != "" {
return namespace, nil
} else {
return app.Namespace, nil
}
}

type ModuleRunPhase string

const (
Expand Down
31 changes: 21 additions & 10 deletions pkg/module_manager/models/modules/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/kennygrant/sanitize"
log "github.com/sirupsen/logrus"

"github.com/flant/addon-operator/pkg/app"
"github.com/flant/addon-operator/pkg/helm"
"github.com/flant/addon-operator/pkg/helm/client"
"github.com/flant/addon-operator/pkg/utils"
Expand All @@ -25,6 +24,8 @@ import (
type HelmModule struct {
// Name of the module
name string
// Name of the kubernetes namespace where helm module will be installed
namespace string
// Path of the module on the fs
path string

Expand Down Expand Up @@ -66,8 +67,14 @@ func NewHelmModule(bm *BasicModule, tmpDir string, deps *HelmModuleDependencies,
utils.ModuleNameToValuesKey(bm.GetName()): moduleValues,
}

chartNamespace, err := bm.GetDefaultOrDefinedNamespace()
if err != nil {
log.Warnf("module %q has error on reading namespace, using default: %s", bm.Name, err)
}

hm := &HelmModule{
name: bm.Name,
namespace: chartNamespace,
path: bm.Path,
values: chartValues,
tmpDir: tmpDir,
Expand Down Expand Up @@ -177,7 +184,7 @@ func (hm *HelmModule) RunHelmInstall(logLabels map[string]string) error {
hm.path,
[]string{valuesPath},
[]string{},
app.Namespace,
hm.namespace,
false,
)
}()
Expand Down Expand Up @@ -206,7 +213,7 @@ func (hm *HelmModule) RunHelmInstall(logLabels map[string]string) error {
hm.dependencies.MetricsStorage.HistogramObserve("{PREFIX}helm_operation_seconds", d.Seconds(), metricLabels, nil)
})()

runUpgradeRelease, err = hm.shouldRunHelmUpgrade(helmClient, helmReleaseName, checksum, manifests, logLabels)
runUpgradeRelease, err = hm.shouldRunHelmUpgrade(helmClient, helmReleaseName, hm.namespace, checksum, manifests, logLabels)
}()
if err != nil {
return err
Expand All @@ -215,7 +222,7 @@ func (hm *HelmModule) RunHelmInstall(logLabels map[string]string) error {
if !runUpgradeRelease {
// Start resources monitor if release is not changed
if !hm.dependencies.HelmResourceManager.HasMonitor(hm.name) {
hm.dependencies.HelmResourceManager.StartMonitor(hm.name, manifests, app.Namespace)
hm.dependencies.HelmResourceManager.StartMonitor(hm.name, manifests, hm.namespace)
}
return nil
}
Expand All @@ -238,7 +245,7 @@ func (hm *HelmModule) RunHelmInstall(logLabels map[string]string) error {
hm.path,
[]string{valuesPath},
[]string{fmt.Sprintf("_addonOperatorModuleChecksum=%s", checksum)},
app.Namespace,
hm.namespace,
)
}()

Expand All @@ -247,16 +254,16 @@ func (hm *HelmModule) RunHelmInstall(logLabels map[string]string) error {
}

// Start monitor resources if release was successful
hm.dependencies.HelmResourceManager.StartMonitor(hm.name, manifests, app.Namespace)
hm.dependencies.HelmResourceManager.StartMonitor(hm.name, manifests, hm.namespace)

return nil
}

// If all these conditions aren't met, helm upgrade can be skipped.
func (hm *HelmModule) shouldRunHelmUpgrade(helmClient client.HelmClient, releaseName string, checksum string, manifests []manifest.Manifest, logLabels map[string]string) (bool, error) {
func (hm *HelmModule) shouldRunHelmUpgrade(helmClient client.HelmClient, releaseName string, releaseNamespace string, checksum string, manifests []manifest.Manifest, logLabels map[string]string) (bool, error) {
logEntry := log.WithFields(utils.LabelsToLogFields(logLabels))

revision, status, err := helmClient.LastReleaseStatus(releaseName)
revision, status, err := helmClient.LastReleaseStatus(releaseNamespace, releaseName)

if revision == "0" {
logEntry.Debugf("helm release '%s' not exists: should run upgrade", releaseName)
Expand All @@ -274,7 +281,7 @@ func (hm *HelmModule) shouldRunHelmUpgrade(helmClient client.HelmClient, release
}

// Get values for a non-failed release.
releaseValues, err := helmClient.GetReleaseValues(releaseName)
releaseValues, err := helmClient.GetReleaseValues(releaseNamespace, releaseName)
if err != nil {
logEntry.Debugf("helm release '%s' get values error, no upgrade: %v", releaseName, err)
return false, err
Expand All @@ -297,7 +304,7 @@ func (hm *HelmModule) shouldRunHelmUpgrade(helmClient client.HelmClient, release
}

// Check if there are absent resources
absent, err := hm.dependencies.HelmResourceManager.GetAbsentResources(manifests, app.Namespace)
absent, err := hm.dependencies.HelmResourceManager.GetAbsentResources(manifests, hm.namespace)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -333,6 +340,10 @@ func (hm *HelmModule) safeName() string {
return sanitize.BaseName(hm.name)
}

func (hm *HelmModule) GetNamespace() string {
return hm.namespace
}

func (hm *HelmModule) Render(namespace string, debug bool) (string, error) {
if namespace == "" {
namespace = "default"
Expand Down
1 change: 1 addition & 0 deletions pkg/module_manager/models/modules/values_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type ValuesStorage struct {
// /modules/001-module/values.yaml
// are set only on module init phase
staticConfigValues utils.Values

// configValues are user defined values from KubeConfigManager (ConfigMap or ModuleConfig)
// without merge with static and openapi values
configValues utils.Values
Expand Down
6 changes: 3 additions & 3 deletions pkg/module_manager/module_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ func (mm *ModuleManager) RefreshStateFromHelmReleases(logLabels map[string]strin
if mm.dependencies.Helm == nil {
return &ModulesState{}, nil
}
releasedModules, err := mm.dependencies.Helm.NewClient(logLabels).ListReleasesNames()
releasedModules, err := mm.dependencies.Helm.NewClient(logLabels).ListReleasesNames("", nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -728,7 +728,7 @@ func (mm *ModuleManager) DeleteModule(moduleName string, logLabels map[string]st
}
helmModule, _ := modules.NewHelmModule(ml, mm.TempDir, &hmdeps, mm.ValuesValidator)
if helmModule != nil {
releaseExists, err := mm.dependencies.Helm.NewClient(deleteLogLabels).IsReleaseExists(ml.GetName())
releaseExists, err := mm.dependencies.Helm.NewClient(deleteLogLabels).IsReleaseExists(helmModule.GetNamespace(), ml.GetName())
if !releaseExists {
if err != nil {
logEntry.Warnf("Cannot find helm release '%s' for module '%s'. Helm error: %s", ml.GetName(), ml.GetName(), err)
Expand All @@ -737,7 +737,7 @@ func (mm *ModuleManager) DeleteModule(moduleName string, logLabels map[string]st
}
} else {
// Chart and release are existed, so run helm delete command
err := mm.dependencies.Helm.NewClient(deleteLogLabels).DeleteRelease(ml.GetName())
err := mm.dependencies.Helm.NewClient(deleteLogLabels).DeleteRelease(helmModule.GetNamespace(), ml.GetName())
if err != nil {
return err
}
Expand Down