Skip to content

Commit

Permalink
Add namespaceLabelsAuthoritative settings option to allow removing un…
Browse files Browse the repository at this point in the history
…defined ns labels
  • Loading branch information
Mateusz Kubaczyk committed Oct 25, 2021
1 parent eaf5a07 commit 0cf91d2
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 27 deletions.
1 change: 1 addition & 0 deletions docs/desired_state_specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ The following options can be skipped if your kubectl context is already created
- **slackWebhook** : a [Slack](http://slack.com) Webhook URL to receive Helmsman notifications. This can be passed directly or in an environment variable.
- **msTeamsWebhook** : a [Microsoft Teams](https://www.microsoft.com/pl-pl/microsoft-teams/group-chat-software) Webhook URL to receive Helmsman notifications. This can be passed directly or in an environment variable.
- **reverseDelete** : if set to `true` it will reverse the priority order whilst deleting.
- **namespaceLabelsAuthoritative** : if set to `true` it will remove all the namespace's labels that are not defined in DSL for particular namespace
- **eyamlEnabled** : if set to `true` it will use [hiera-eyaml](https://github.com/voxpupuli/hiera-eyaml) to decrypt secret files instead of using default helm-secrets based on sops
- **eyamlPrivateKeyPath** : if set with path to the eyaml private key file, it will use it instead of looking for default one in ./keys directory relative to where Helmsman were run. It needs to be defined in conjunction with eyamlPublicKeyPath.
- **eyamlPublicKeyPath** : if set with path to the eyaml public key file, it will use it instead of looking for default one in ./keys directory relative to where Helmsman were run. It needs to be defined in conjunction with eyamlPrivateKeyPath.
Expand Down
6 changes: 3 additions & 3 deletions internal/app/decision_maker.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ func (cs *currentState) decide(r *release, n *namespace, p *plan, c *chartInfo)

if flags.destroy {
if ok := cs.releaseExists(r, ""); ok {
p.addDecision("Release [ "+r.Name+" ] will be DELETED (destroy flag enabled).", r.Priority, delete)
p.addDecision("Release [ "+r.Name+" ] will be DELETED (destroy flag enabled).", r.Priority, remove)
r.uninstall(p)
}
return
}

if !r.Enabled {
if ok := cs.releaseExists(r, ""); ok {
p.addDecision("Release [ "+r.Name+" ] is desired to be DELETED.", r.Priority, delete)
p.addDecision("Release [ "+r.Name+" ] is desired to be DELETED.", r.Priority, remove)
r.uninstall(p)
} else {
p.addDecision("Release [ "+r.Name+" ] disabled", r.Priority, noop)
Expand Down Expand Up @@ -275,7 +275,7 @@ func (cs *currentState) cleanUntrackedReleases(s *state, p *plan) {
if !tracked {
toDelete++
r := cs.releases[name+"-"+ns]
p.addDecision("Untracked release [ "+r.Name+" ] found and it will be deleted", -1000, delete)
p.addDecision("Untracked release [ "+r.Name+" ] found and it will be deleted", -1000, remove)
r.uninstall(p)
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/app/decision_maker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,8 @@ func (dt decisionType) String() string {
return "create"
case change:
return "change"
case delete:
return "delete"
case remove:
return "remove"
case noop:
return "noop"
}
Expand Down
31 changes: 27 additions & 4 deletions internal/app/kube_helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
Expand All @@ -24,7 +25,7 @@ func addNamespaces(s *state) {
go func(name string, cfg *namespace, wg *sync.WaitGroup) {
defer wg.Done()
createNamespace(name)
labelNamespace(name, cfg.Labels)
labelNamespace(name, cfg.Labels, s.Settings.NamespaceLabelsAuthoritative)
annotateNamespace(name, cfg.Annotations)
if !flags.dryRun {
setLimits(name, cfg.Limits)
Expand Down Expand Up @@ -60,12 +61,34 @@ func createNamespace(ns string) {
}

// labelNamespace labels a namespace with provided labels
func labelNamespace(ns string, labels map[string]string) {
if len(labels) == 0 {
func labelNamespace(ns string, labels map[string]string, authoritative bool) {
var nsLabels map[string]string

args := []string{"label", "--overwrite", "namespace/" + ns, flags.getKubeDryRunFlag("label")}

if authoritative {
cmdGetLabels := kubectl([]string{"get", "namespace", ns, "-o", "jsonpath='{.metadata.labels}'"}, "Getting namespace [ "+ns+" ] current labels")
res, err := cmdGetLabels.Exec()
if err != nil {
log.Error(fmt.Sprintf("Could not get namespace [ %s ] labels. Error message: %v", ns, err))
}
if err := json.Unmarshal([]byte(strings.Trim(res.output, `'`)), &nsLabels); err != nil {
log.Fatal(fmt.Sprintf("failed to unmarshal kubectl get namespace labels output: %s, ended with error: %s", res.output, err))
}
// ignore default k8s namespace label from being removed
delete(nsLabels, "kubernetes.io/metadata.name")
// ignore every label defined in DSF for the namespace from being removed
for definedLabelKey, _ := range labels {
delete(nsLabels, definedLabelKey)
}
for label, _ := range nsLabels {
args = append(args, label+"-")
}
}
if len(labels) == 0 && len(nsLabels) == 0 {
return
}

args := []string{"label", "--overwrite", "namespace/" + ns, flags.getKubeDryRunFlag("label")}
for k, v := range labels {
args = append(args, k+"="+v)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/app/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type decisionType int
const (
create decisionType = iota + 1
change
delete
remove
noop
ignored
)
Expand Down Expand Up @@ -219,7 +219,7 @@ func (p *plan) print() {
for _, decision := range p.Decisions {
if decision.Type == ignored || decision.Type == noop {
log.Info(decision.Description + " -- priority: " + strconv.Itoa(decision.Priority))
} else if decision.Type == delete {
} else if decision.Type == remove {
log.Warning(decision.Description + " -- priority: " + strconv.Itoa(decision.Priority))
} else {
log.Notice(decision.Description + " -- priority: " + strconv.Itoa(decision.Priority))
Expand Down
33 changes: 17 additions & 16 deletions internal/app/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,23 @@ import (

// config type represents the settings fields
type config struct {
KubeContext string `yaml:"kubeContext"`
Username string `yaml:"username"`
Password string `yaml:"password"`
ClusterURI string `yaml:"clusterURI"`
ServiceAccount string `yaml:"serviceAccount"`
StorageBackend string `yaml:"storageBackend"`
SlackWebhook string `yaml:"slackWebhook"`
MSTeamsWebhook string `yaml:"msTeamsWebhook"`
ReverseDelete bool `yaml:"reverseDelete"`
BearerToken bool `yaml:"bearerToken"`
BearerTokenPath string `yaml:"bearerTokenPath"`
EyamlEnabled bool `yaml:"eyamlEnabled"`
EyamlPrivateKeyPath string `yaml:"eyamlPrivateKeyPath"`
EyamlPublicKeyPath string `yaml:"eyamlPublicKeyPath"`
GlobalHooks map[string]interface{} `yaml:"globalHooks"`
GlobalMaxHistory int `yaml:"globalMaxHistory"`
KubeContext string `yaml:"kubeContext"`
Username string `yaml:"username"`
Password string `yaml:"password"`
ClusterURI string `yaml:"clusterURI"`
ServiceAccount string `yaml:"serviceAccount"`
StorageBackend string `yaml:"storageBackend"`
SlackWebhook string `yaml:"slackWebhook"`
MSTeamsWebhook string `yaml:"msTeamsWebhook"`
ReverseDelete bool `yaml:"reverseDelete"`
BearerToken bool `yaml:"bearerToken"`
BearerTokenPath string `yaml:"bearerTokenPath"`
NamespaceLabelsAuthoritative bool `yaml:"namespaceLabelsAuthoritative"`
EyamlEnabled bool `yaml:"eyamlEnabled"`
EyamlPrivateKeyPath string `yaml:"eyamlPrivateKeyPath"`
EyamlPublicKeyPath string `yaml:"eyamlPublicKeyPath"`
GlobalHooks map[string]interface{} `yaml:"globalHooks"`
GlobalMaxHistory int `yaml:"globalMaxHistory"`
}

// state type represents the desired state of applications on a k8s cluster.
Expand Down

0 comments on commit 0cf91d2

Please sign in to comment.