forked from rancher/shepherd
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge rancher/shepherd branch 'release/v2.9' into cnrancher release/v…
…2.9-ent
- Loading branch information
Showing
6 changed files
with
282 additions
and
5 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# RAFT Team | ||
* @igomez06 @caliskanugur | ||
* @caliskanugur @bmdepesa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package operations | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"sigs.k8s.io/yaml" | ||
) | ||
|
||
// ReplaceValue recursively traverses keyPath, replacing the specified replaceVal in searchMap. | ||
func ReplaceValue(keyPath []string, replaceVal any, searchMap map[string]any) (map[string]any, error) { | ||
if len(keyPath) <= 1 { | ||
searchMap[keyPath[0]] = replaceVal | ||
|
||
return searchMap, nil | ||
} else { | ||
var err error | ||
|
||
if _, ok := searchMap[keyPath[0]].(map[string]any); ok { | ||
searchMap[keyPath[0]], err = ReplaceValue(keyPath[1:], replaceVal, searchMap[keyPath[0]].(map[string]any)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else if _, ok := searchMap[keyPath[0]].([]any); ok { | ||
for i := range searchMap[keyPath[0]].([]any) { | ||
searchMap[keyPath[0]].([]any)[i], err = ReplaceValue(keyPath[1:], replaceVal, searchMap[keyPath[0]].([]any)[i].(map[string]any)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
} | ||
} | ||
|
||
return searchMap, nil | ||
} | ||
|
||
// GetValue recursively traverses keyPath, returning the value of the specified keyPath in searchMap. | ||
func GetValue(keyPath []string, searchMap map[string]any) (any, error) { | ||
var err error | ||
var keypathvalues any | ||
if len(keyPath) == 1 { | ||
keypathvalues, ok := searchMap[keyPath[0]] | ||
if !ok { | ||
err = errors.New(fmt.Sprintf("expected key does not exist: %s", keyPath[0])) | ||
} | ||
return keypathvalues, err | ||
} else { | ||
if _, ok := searchMap[keyPath[0]].(map[string]any); ok { | ||
keypathvalues, err = GetValue(keyPath[1:], searchMap[keyPath[0]].(map[string]any)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else if _, ok := searchMap[keyPath[0]].([]any); ok { | ||
for i := range searchMap[keyPath[0]].([]any) { | ||
keypathvalues, err = GetValue(keyPath[1:], searchMap[keyPath[0]].([]any)[i].(map[string]any)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
} | ||
} | ||
|
||
return keypathvalues, err | ||
} | ||
|
||
// LoadObjectFromMap unmarshals a specific key's value into an object | ||
func LoadObjectFromMap(key string, config map[string]any, object any) { | ||
keyConfig := config[key] | ||
scopedString, err := yaml.Marshal(keyConfig) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
err = yaml.Unmarshal(scopedString, &object) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
// DeepCopyMap creates a copy of the map that doesn't have any links to the original map | ||
func DeepCopyMap(config map[string]any) (map[string]any, error) { | ||
marshaledConfig, err := json.Marshal(config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
unmarshaledConfig := make(map[string]any) | ||
err = json.Unmarshal(marshaledConfig, &unmarshaledConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return unmarshaledConfig, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package permutations | ||
|
||
import ( | ||
"fmt" | ||
|
||
mapOperations "github.com/rancher/shepherd/pkg/config/operations" | ||
) | ||
|
||
// ExamplePermute is an example of how to use the permutation objects and the permute function. | ||
func ExamplePermute() { | ||
config := map[string]any{ | ||
"foo1": map[string]any{ | ||
"nested-foo1": []any{"bar1", "bar2"}, | ||
}, | ||
"foo2": []any{"bar3", "bar4"}, | ||
} | ||
|
||
nestedFoo1Path := []string{"foo1", "nested-foo1"} | ||
nestedFoo1Value, _ := mapOperations.GetValue(nestedFoo1Path, config) | ||
foo1Permutation := CreatePermutation(nestedFoo1Path, nestedFoo1Value.([]any), []Relationship{}) | ||
|
||
nestedFoo2Path := []string{"foo2"} | ||
nestedFoo2Value, _ := mapOperations.GetValue(nestedFoo2Path, config) | ||
foo2Permutation := CreatePermutation(nestedFoo2Path, nestedFoo2Value.([]any), []Relationship{}) | ||
|
||
permutations := []Permutation{foo1Permutation, foo2Permutation} | ||
permutedConfigs, _ := Permute(permutations, config) | ||
|
||
for _, permutedConfig := range permutedConfigs { | ||
fmt.Println(permutedConfig) | ||
//Output: | ||
//map[foo1:map[nested-foo1:bar1] foo2:bar3] | ||
//map[foo1:map[nested-foo1:bar1] foo2:bar4] | ||
//map[foo1:map[nested-foo1:bar2] foo2:bar3] | ||
//map[foo1:map[nested-foo1:bar2] foo2:bar4] | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package permutations | ||
|
||
import ( | ||
"errors" | ||
|
||
mapOperations "github.com/rancher/shepherd/pkg/config/operations" | ||
) | ||
|
||
// Relationship structs are used to create an association between a parent value and either a set of permutations or the value of a different key | ||
type Relationship struct { | ||
ParentValue any `json:"parentValue" yaml:"parentValue"` | ||
ChildKeyPath []string `json:"childKeyPath" yaml:"childkeyPath"` | ||
ChildKeyPathValue any `json:"childKeyPathValue" yaml:"childkeyPathValue"` | ||
ChildPermutations []Permutation `json:"childPermutations" yaml:"childPermutations"` | ||
} | ||
|
||
// Permutation structs are used to describe a single permutation | ||
type Permutation struct { | ||
KeyPath []string `json:"keyPath" yaml:"keyPath"` | ||
KeyPathValues []any `json:"keyPathValue" yaml:"keyPath"` | ||
KeyPathValueRelationships []Relationship `json:"keyPathValueRelationships" yaml:"KeyPathValueRelationships"` | ||
} | ||
|
||
// CreateRelationship is a constructor for the relationship struct | ||
func CreateRelationship(parentValue any, childKeyPath []string, childKeyPathValue any, childPermutations []Permutation) Relationship { | ||
return Relationship{ | ||
ParentValue: parentValue, | ||
ChildKeyPath: childKeyPath, | ||
ChildKeyPathValue: childKeyPathValue, | ||
ChildPermutations: childPermutations, | ||
} | ||
} | ||
|
||
// CreatePermutation is a constructor for the permutation struct | ||
func CreatePermutation(keyPath []string, keyPathValues []any, keyPathValueRelationships []Relationship) Permutation { | ||
return Permutation{ | ||
KeyPath: keyPath, | ||
KeyPathValues: keyPathValues, | ||
KeyPathValueRelationships: keyPathValueRelationships, | ||
} | ||
} | ||
|
||
// Permute iterates over a list of permutation structs and permutes the base config with each of the permutations | ||
func Permute(permutations []Permutation, baseConfig map[string]any) ([]map[string]any, error) { | ||
var configs []map[string]any | ||
var err error | ||
if len(permutations) == 0 { | ||
err = errors.New("no permutations provided") | ||
return configs, err | ||
} | ||
|
||
for _, keyPathValue := range permutations[0].KeyPathValues { | ||
permutedConfig, err := mapOperations.DeepCopyMap(baseConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
permutedConfig, err = mapOperations.ReplaceValue(permutations[0].KeyPath, keyPathValue, permutedConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
subPermutations := false | ||
for _, relationship := range permutations[0].KeyPathValueRelationships { | ||
if relationship.ParentValue == keyPathValue { | ||
if len(relationship.ChildKeyPath) > 1 && relationship.ChildKeyPathValue != nil { | ||
permutedConfig, err = mapOperations.ReplaceValue(relationship.ChildKeyPath, relationship.ChildKeyPathValue, permutedConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
var relationshipPermutedConfigs []map[string]any | ||
if len(relationship.ChildPermutations) > 0 { | ||
subPermutations = true | ||
relationshipPermutedConfigs, err = Permute(relationship.ChildPermutations, permutedConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
configs = append(configs, relationshipPermutedConfigs...) | ||
} | ||
} | ||
|
||
if !subPermutations { | ||
configs = append(configs, permutedConfig) | ||
} | ||
} | ||
|
||
var finalConfigs []map[string]any | ||
if len(permutations) == 1 { | ||
return configs, nil | ||
} else { | ||
for _, config := range configs { | ||
permutedConfigs, err := Permute(permutations[1:], config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
finalConfigs = append(finalConfigs, permutedConfigs...) | ||
} | ||
} | ||
|
||
return finalConfigs, err | ||
} |