Skip to content

Commit

Permalink
support kapp config within configmap
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitriy Kalinin committed Sep 1, 2020
1 parent 8af57be commit e62d79a
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 19 deletions.
29 changes: 29 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,32 @@ Path specifies location within a resource (as used `rebaseRules` and `ownershipL
```
[spec, volumeClaimTemplates, {index: 0}, metadata, labels]
```
---
### Config wrapped in ConfigMap
Available of v0.34.0+.
Config resource could be wrapped in a ConfigMap to support same deployment configuration by tools that do not understand kapp's `Config` resource directly. ConfigMap carrying kapp config must to be labeled with `kapp.k14s.io/config` and have `config.yml` data key. Such config maps will be applied to the cluster, unlike config given as `Config` resource.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-kapp-config
labels:
kapp.k14s.io/config: ""
data:
config.yml: |
apiVersion: kapp.k14s.io/v1alpha1
kind: Config
rebaseRules:
- path: [rules]
type: copy
sources: [existing, new]
resourceMatchers:
- notMatcher:
matcher:
emptyFieldMatcher:
path: [aggregationRule]
```
67 changes: 56 additions & 11 deletions pkg/kapp/config/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import (
"fmt"

ctlres "github.com/k14s/kapp/pkg/kapp/resources"
corev1 "k8s.io/api/core/v1"
)

const (
configLabelKey = "kapp.k14s.io/config"
configMapConfigKey = "config.yml"
)

type Conf struct {
Expand All @@ -18,25 +24,64 @@ func NewConfFromResources(resources []ctlres.Resource) ([]ctlres.Resource, Conf,
var configs []Config

for _, res := range resources {
if res.APIVersion() == configAPIVersion {
if res.Kind() == configKind {
config, err := NewConfigFromResource(res)
if err != nil {
return nil, Conf{}, err
}
configs = append(configs, config)
} else {
errMsg := "Unexpected kind in resource '%s', wanted '%s'"
return nil, Conf{}, fmt.Errorf(errMsg, res.Description(), configKind)
_, isLabeledAsConfig := res.Labels()[configLabelKey]

switch {
case res.APIVersion() == configAPIVersion:
config, err := NewConfigFromResource(res)
if err != nil {
return nil, Conf{}, fmt.Errorf(
"Parsing resource '%s' as kapp config: %s", res.Description(), err)
}
} else {
configs = append(configs, config)

case isLabeledAsConfig:
config, err := newConfigFromConfigMapRes(res)
if err != nil {
return nil, Conf{}, fmt.Errorf(
"Parsing resource '%s' labeled as kapp config: %s", res.Description(), err)
}
// Make sure to add ConfigMap resource to regular resources list
// (our goal of allowing kapp config in ConfigMaps is to allow
// both kubectl and kapp to work against exactly same configuration;
// hence want to preserve same behaviour)
rsWithoutConfigs = append(rsWithoutConfigs, res)
configs = append(configs, config)

default:
rsWithoutConfigs = append(rsWithoutConfigs, res)
}
}

return rsWithoutConfigs, Conf{configs}, nil
}

func newConfigFromConfigMapRes(res ctlres.Resource) (Config, error) {
if res.APIVersion() != "v1" || res.Kind() != "ConfigMap" {
errMsg := "Expected kapp config to be within v1/ConfigMap but apiVersion or kind do not match"
return Config{}, fmt.Errorf(errMsg, res.Description())
}

configCM := corev1.ConfigMap{}

err := res.AsTypedObj(&configCM)
if err != nil {
return Config{}, fmt.Errorf("Converting resource to ConfigMap: %s", err)
}

configStr, found := configCM.Data[configMapConfigKey]
if !found {
return Config{}, fmt.Errorf("Expected to find field 'data.\"%s\"', but did not", configMapConfigKey)
}

configRes, err := ctlres.NewResourceFromBytes([]byte(configStr))
if err != nil {
return Config{}, fmt.Errorf("Parsing kapp config as resource: %s", err)
}

return NewConfigFromResource(configRes)
}

func (c Conf) RebaseMods() []ctlres.ResourceModWithMultiple {
var mods []ctlres.ResourceModWithMultiple
for _, config := range c.configs {
Expand Down
12 changes: 12 additions & 0 deletions pkg/kapp/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ type ChangeRuleBinding struct {
}

func NewConfigFromResource(res ctlres.Resource) (Config, error) {
if res.APIVersion() != configAPIVersion {
return Config{}, fmt.Errorf(
"Expected kapp config to have apiVersion '%s', but was '%s'",
configAPIVersion, res.APIVersion())
}

if res.Kind() != configKind {
return Config{}, fmt.Errorf(
"Expected kapp config to have kind '%s', but was '%s'",
configKind, res.Kind())
}

bs, err := res.AsYAMLBytes()
if err != nil {
return Config{}, err
Expand Down
28 changes: 20 additions & 8 deletions test/e2e/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,26 @@ rebaseRules:
kind: ConfigMap
namespace: kapp-test
name: first
- path: [data, keep]
type: copy
sources: [existing, new]
resourceMatchers:
- kindNamespaceNameMatcher:
kind: ConfigMap
namespace: kapp-test
name: second
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kapp-config
labels:
kapp.k14s.io/config: ""
data:
config.yml: |
apiVersion: kapp.k14s.io/v1alpha1
kind: Config
rebaseRules:
- path: [data, keep]
type: copy
sources: [existing, new]
resourceMatchers:
- kindNamespaceNameMatcher:
kind: ConfigMap
namespace: kapp-test
name: second
`

yaml1 := `
Expand Down

0 comments on commit e62d79a

Please sign in to comment.