Skip to content

Commit

Permalink
Merge rancher/shepherd branch 'release/v2.9' into cnrancher release/v…
Browse files Browse the repository at this point in the history
…2.9-ent
  • Loading branch information
jianghang8421 committed Nov 25, 2024
2 parents 5448651 + 33f9880 commit 6fda2cb
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 5 deletions.
2 changes: 1 addition & 1 deletion CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# RAFT Team
* @igomez06 @caliskanugur
* @caliskanugur @bmdepesa
30 changes: 26 additions & 4 deletions clients/corral/corral.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import (
)

const (
debugFlag = "--trace"
skipCleanupFlag = "--skip-cleanup"
corralPrivateSSHKey = "corral_private_key"
corralPublicSSHKey = "corral_public_key"
debugFlag = "--trace"
skipCleanupFlag = "--skip-cleanup"
corralPrivateSSHKey = "corral_private_key"
corralPublicSSHKey = "corral_public_key"
corralRegistryIP = "registry_ip"
corralRegistryPrivateIP = "registry_private_ip"
)

// GetCorralEnvVar gets corral environment variables
Expand Down Expand Up @@ -345,3 +347,23 @@ func SetCorralSSHKeys(corralName string) error {

return UpdateCorralConfig(corralPublicSSHKey, publicSSHkey)
}

// SetCorralBastion is a helper function that will set the corral bastion private and pulic addresses previously generated by `corralName`
func SetCorralBastion(corralName string) error {
bastion_ip, err := GetCorralEnvVar(corralName, corralRegistryIP)
if err != nil {
return err
}

err = UpdateCorralConfig(corralRegistryIP, bastion_ip)
if err != nil {
return err
}

bastion_internal_ip, err := GetCorralEnvVar(corralName, corralRegistryPrivateIP)
if err != nil {
return err
}

return UpdateCorralConfig(corralRegistryPrivateIP, bastion_internal_ip)
}
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
}
95 changes: 95 additions & 0 deletions pkg/config/operations/operations.go
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
}
38 changes: 38 additions & 0 deletions pkg/config/operations/permutations/example_test.go
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]
}

}
106 changes: 106 additions & 0 deletions pkg/config/operations/permutations/permutations.go
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
}

0 comments on commit 6fda2cb

Please sign in to comment.