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

*: support YAML values applier #67

Merged
merged 1 commit into from
Jan 30, 2024
Merged
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
k8s.io/klog/v2 v2.100.1
k8s.io/kubectl v0.28.4
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2
sigs.k8s.io/yaml v1.4.0
)

require (
Expand Down Expand Up @@ -143,5 +144,4 @@ require (
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -529,5 +529,5 @@ sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
42 changes: 42 additions & 0 deletions helmcli/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"time"

"gopkg.in/yaml.v2"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/storage/driver"
Expand Down Expand Up @@ -40,6 +41,47 @@ func StringPathValuesApplier(values ...string) ValuesApplier {
}
}

func YAMLValuesApplier(yamlValues string) (ValuesApplier, error) {
values := make(map[string]interface{})
err := yaml.Unmarshal([]byte(yamlValues), &values)
if err != nil {
return nil, err
}

return func(to map[string]interface{}) error {
return applyValues(to, values)
}, nil
}

func applyValues(to, from map[string]interface{}) error {
for k, v := range from {
// If 'to' doesn't have key 'k'
if _, checkKey := to[k]; !checkKey {
to[k] = v
continue
}

// If 'to' has key 'k'
switch v := v.(type) {
case map[string]interface{}:
// If 'v' is of type map[string]interface{}
if toMap, checkKey := to[k].(map[string]interface{}); checkKey {
if err := applyValues(toMap, v); err != nil {
return err
}
PugDeveloper marked this conversation as resolved.
Show resolved Hide resolved
} else {
to[k] = v

}
default:
// If 'v' is not of type map[string]interface{}
to[k] = v
}

}
return nil
}

// ReleaseCli is a client to deploy helm chart with secret storage.
type ReleaseCli struct {
namespace string
Expand Down
105 changes: 105 additions & 0 deletions helmcli/release_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package helmcli

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestApplyValues(t *testing.T) {
for idx, tc := range []struct {
from map[string]interface{}
to map[string]interface{}
expected map[string]interface{}
}{
{
from: map[string]interface{}{
"foo": "bar1",
"baz": map[string]interface{}{
"name": "alice",
},
},
to: map[string]interface{}{
"foo": "bar2",
"baz": map[string]interface{}{
"name": "bob",
"age": "18",
},
},
expected: map[string]interface{}{
"foo": "bar1",
"baz": map[string]interface{}{
"name": "alice",
"age": "18",
},
},
},
{
from: map[string]interface{}{
"foo": "bar1",
"baz": "profile",
},
to: map[string]interface{}{
"foo": "bar1",
"baz": map[string]interface{}{
"name": "alice",
},
},
expected: map[string]interface{}{
"foo": "bar1",
"baz": "profile",
},
},
{
from: map[string]interface{}{
"foo": "bar1",
"baz": map[string]interface{}{
"name": "alice",
},
},
to: map[string]interface{}{
"version": "alpha",
},
expected: map[string]interface{}{
"foo": "bar1",
"baz": map[string]interface{}{
"name": "alice",
},
"version": "alpha",
},
},
{
from: map[string]interface{}{
"baz": map[string]interface{}{
"name": map[string]interface{}{
"last": "unknown",
"first": "bob",
},
},
"version": "beta",
},
to: map[string]interface{}{
"foo": "bar2",
"baz": map[string]interface{}{
"name": "bob",
"age": "18",
},
},
expected: map[string]interface{}{
"foo": "bar2",
"baz": map[string]interface{}{
"name": map[string]interface{}{
"last": "unknown",
"first": "bob",
},
"age": "18",
},
"version": "beta",
},
},
} {
err := applyValues(tc.to, tc.from)
assert.NoError(t, err, "#%v", idx)
assert.Equal(t, tc.expected, tc.to, "#%v", idx)
}
}
18 changes: 16 additions & 2 deletions virtualcluster/nodes_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/Azure/kperf/helmcli"
"sigs.k8s.io/yaml"
)

var (
Expand Down Expand Up @@ -98,12 +99,25 @@ func WithNodepoolNodeControllerAffinity(nodeSelectors map[string][]string) Nodep
// NOTE: Please align with ../manifests/virtualcluster/nodes/values.yaml
//
// TODO: Add YAML ValuesAppliers to support array type.
func (cfg *nodepoolConfig) toHelmValuesAppliers(nodepoolName string) []helmcli.ValuesApplier {
func (cfg *nodepoolConfig) toHelmValuesAppliers(nodepoolName string) ([]helmcli.ValuesApplier, error) {
res := make([]string, 0, 4)

res = append(res, fmt.Sprintf("name=%s", nodepoolName))
res = append(res, fmt.Sprintf("replicas=%d", cfg.count))
res = append(res, fmt.Sprintf("cpu=%d", cfg.cpu))
res = append(res, fmt.Sprintf("memory=%d", cfg.memory))
return []helmcli.ValuesApplier{helmcli.StringPathValuesApplier(res...)}

stringPathApplier := helmcli.StringPathValuesApplier(res...)

// Marshal nodeSelectors to YAML
nodeSelectorsYaml, err := yaml.Marshal(cfg.nodeSelectors)
if err != nil {
return nil, err
}
// Create YAML ValuesAppliers nodeSelectors
nodeSelectorsApplier, err := helmcli.YAMLValuesApplier(string(nodeSelectorsYaml))
if err != nil {
return nil, err
}
return []helmcli.ValuesApplier{stringPathApplier, nodeSelectorsApplier}, nil
}
6 changes: 5 additions & 1 deletion virtualcluster/nodes_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,17 @@ func CreateNodepool(ctx context.Context, kubeconfigPath string, nodepoolName str
return fmt.Errorf("failed to load virtual node chart: %w", err)
}

cfgValues, err := cfg.toHelmValuesAppliers(nodepoolName)
if err != nil {
return fmt.Errorf("failed to convert to helm values: %w", err)
}
releaseCli, err := helmcli.NewReleaseCli(
kubeconfigPath,
virtualnodeReleaseNamespace,
nodepoolName,
ch,
virtualnodeReleaseLabels,
cfg.toHelmValuesAppliers(nodepoolName)...,
cfgValues...,
)
if err != nil {
return fmt.Errorf("failed to create helm release client: %w", err)
Expand Down
Loading