Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
Add LoadConfigFromFile

Move config ops to a seperate file
  • Loading branch information
susesgartner committed Aug 27, 2024
1 parent e0490a2 commit 626cbc1
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
95 changes: 95 additions & 0 deletions extensions/configoperations/configoperations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package configoperations

import (
"errors"
"fmt"

"sigs.k8s.io/yaml"
)

// ReplaceValue iterates through a map to a provided key path and replaces the value.
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 iterates through a map to a provided key path and returns the value.
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
}

// LoadKeyFromMap unmarshals a specific key's value into a map[string]any
func LoadKeyFromMap(key string, config map[string]any) map[string]any {
keyConfig := config[key]
scopedString, err := yaml.Marshal(keyConfig)
if err != nil {
panic(err)
}

var scopedMap map[string]any
err = yaml.Unmarshal(scopedString, &scopedMap)
if err != nil {
panic(err)
}

return scopedMap
}

// 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)
}
}
107 changes: 107 additions & 0 deletions extensions/configoperations/permutations/permutations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package permutations

import (
"encoding/json"

"github.com/rancher/shepherd/extensions/configoperations"
)

// 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 describe permutations
func Permute(permutations []Permutation, baseConfig map[string]any) ([]map[string]any, string, error) {
var configs []map[string]any
var err error
if len(permutations) == 0 {
return configs, "", err
}

for _, keyPathValue := range permutations[0].KeyPathValues {
marshaledConfig, err := json.Marshal(baseConfig)
if err != nil {
return nil, "", err
}

unmarshaledConfig := make(map[string]any)
json.Unmarshal(marshaledConfig, &unmarshaledConfig)

permutedConfig, err := configoperations.ReplaceValue(permutations[0].KeyPath, keyPathValue, unmarshaledConfig)
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 = configoperations.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
}
16 changes: 16 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,19 @@ func WriteConfig(key string, config interface{}) error {

return nil
}

// LoadConfigFromFile loads an entire yaml file into a map[string]any
func LoadConfigFromFile(filePath string) map[string]any {
allString, err := os.ReadFile(filePath)
if err != nil {
panic(err)
}

var all map[string]any
err = yaml.Unmarshal(allString, &all)
if err != nil {
panic(err)
}

return all
}

0 comments on commit 626cbc1

Please sign in to comment.