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

add TLSCert and TLSKey to configoption dep resolution #833

Merged
merged 2 commits into from
Aug 3, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 55 additions & 8 deletions pkg/template/depgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

type depGraph struct {
Dependencies map[string]map[string]struct{}
CertItems map[string]map[string]struct{} // items that use the TLSCert template function. map of certnames to configoptions that provide the certname
KeyItems map[string]map[string]struct{} // items that use the TLSKey template function. map of configoptions to the certnames they use
}

// these config functions are used to add their dependencies to the depGraph
Expand All @@ -21,12 +23,24 @@ func (d *depGraph) funcMap(parent string) template.FuncMap {
return dep
}

addCertFunc := func(certName string, _ ...string) string {
d.AddCert(parent, certName)
return certName
}

addKeyFunc := func(certName string, _ ...string) string {
d.AddKey(parent, certName)
return certName
}

return template.FuncMap{
"ConfigOption": addDepFunc,
"ConfigOptionIndex": addDepFunc,
"ConfigOptionData": addDepFunc,
"ConfigOptionEquals": addDepFunc,
"ConfigOptionNotEquals": addDepFunc,
"TLSCert": addCertFunc,
"TLSKey": addKeyFunc,
}
}

Expand All @@ -46,6 +60,40 @@ func (d *depGraph) AddDep(source, newDependency string) {
d.Dependencies[source][newDependency] = struct{}{}
}

func (d *depGraph) AddCert(source, certName string) {
if d.CertItems == nil {
d.CertItems = make(map[string]map[string]struct{})
}
if _, ok := d.CertItems[certName]; !ok {
d.CertItems[certName] = make(map[string]struct{})
}

d.CertItems[certName][source] = struct{}{}
}

func (d *depGraph) AddKey(source, certName string) {
if d.KeyItems == nil {
d.KeyItems = make(map[string]map[string]struct{})
}
if _, ok := d.KeyItems[source]; !ok {
d.KeyItems[source] = make(map[string]struct{})
}

d.KeyItems[source][certName] = struct{}{}
}

func (d *depGraph) resolveCertKeys() {
for source, certNameMap := range d.KeyItems {
for certName := range certNameMap {
for certProvider := range d.CertItems[certName] {
if certProvider != source {
d.AddDep(source, certProvider)
}
}
}
}
}

func (d *depGraph) ResolveDep(resolvedDependency string) {
for _, depMap := range d.Dependencies {
delete(depMap, resolvedDependency)
Expand All @@ -66,7 +114,7 @@ func (d *depGraph) GetHeadNodes() ([]string, error) {
waitList := []string{}
for k, v := range d.Dependencies {
depsList := []string{}
for dep, _ := range v {
for dep := range v {
depsList = append(depsList, fmt.Sprintf("%q", dep))
}
waitItem := fmt.Sprintf(`%q depends on %s`, k, strings.Join(depsList, `, `))
Expand All @@ -87,31 +135,28 @@ func (d *depGraph) Copy() (depGraph, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
dec := json.NewDecoder(&buf)
err := enc.Encode(d.Dependencies)
err := enc.Encode(d)
if err != nil {
return depGraph{}, err
}
var depCopy map[string]map[string]struct{}
depCopy := depGraph{}
err = dec.Decode(&depCopy)
if err != nil {
return depGraph{}, err
}

return depGraph{
Dependencies: depCopy,
}, nil
return depCopy, nil

}

func (d *depGraph) ParseConfigGroup(configGroups []kotsv1beta1.ConfigGroup) error {
staticCtx := &StaticCtx{}
for _, configGroup := range configGroups {
for _, configItem := range configGroup.Items {
// add this to the dependency graph
d.AddNode(configItem.Name)

depBuilder := Builder{
Ctx: []Ctx{staticCtx},
Ctx: []Ctx{},
Functs: d.funcMap(configItem.Name),
}

Expand All @@ -122,5 +167,7 @@ func (d *depGraph) ParseConfigGroup(configGroups []kotsv1beta1.ConfigGroup) erro
}
}

d.resolveCertKeys()

return nil
}
75 changes: 70 additions & 5 deletions pkg/template/depgraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

type depGraphTestCase struct {
dependencies map[string][]string
testCerts map[string][]string
testKeys map[string][]string
resolveOrder []string
expectError bool //expect an error fetching head nodes
expectNotFound string //expect this dependency not to be part of the head nodes
Expand Down Expand Up @@ -113,6 +115,41 @@ func TestDepGraph(t *testing.T) {
expectError: true,
name: "does_not_exist",
},
{
dependencies: map[string][]string{
"alpha": {},
"bravo": {"alpha"},
"charlie": {"bravo"},
"delta": {"alpha", "charlie"},
"echo": {},
},
testCerts: map[string][]string{
"echo": {"certA"},
},
testKeys: map[string][]string{
"delta": {"certA"},
},
resolveOrder: []string{"alpha", "bravo", "charlie", "echo", "delta"},
name: "basic_certs",
},
{
dependencies: map[string][]string{
"alpha": {},
"bravo": {"alpha"},
"charlie": {"bravo"},
"delta": {"alpha", "charlie"},
"echo": {},
},
testCerts: map[string][]string{
"echo": {"certA"},
},
testKeys: map[string][]string{
"delta": {"certA"},
},
resolveOrder: []string{"alpha", "bravo", "charlie", "delta", "echo"},
name: "basic_certs_original_order",
expectNotFound: "delta",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand All @@ -126,6 +163,18 @@ func TestDepGraph(t *testing.T) {
graph.AddDep(source, dep)
}
}
for source, certNames := range test.testCerts {
for _, certName := range certNames {
graph.AddCert(source, certName)
}
}
for source, keys := range test.testKeys {
for _, key := range keys {
graph.AddKey(source, key)
}
}
graph.resolveCertKeys()

runGraphTests(t, test, graph)
})

Expand All @@ -135,7 +184,7 @@ func TestDepGraph(t *testing.T) {

graph := depGraph{}

groups := buildTestConfigGroups(test.dependencies, "templateStringStart", "templateStringEnd", true)
groups := buildTestConfigGroups(test.dependencies, test.testCerts, test.testKeys, "templateStringStart", "templateStringEnd", true)

err := graph.ParseConfigGroup(groups)
require.NoError(t, err)
Expand All @@ -146,7 +195,7 @@ func TestDepGraph(t *testing.T) {
}

// this makes sure that we test with each of the configOption types, in both Value and Default
func buildTestConfigGroups(dependencies map[string][]string, prefix string, suffix string, rotate bool) []kotsv1beta1.ConfigGroup {
func buildTestConfigGroups(dependencies, certs, keys map[string][]string, prefix string, suffix string, rotate bool) []kotsv1beta1.ConfigGroup {
group := kotsv1beta1.ConfigGroup{}
group.Items = make([]kotsv1beta1.ConfigItem, 0)
counter := 0
Expand All @@ -156,7 +205,7 @@ func buildTestConfigGroups(dependencies map[string][]string, prefix string, suff
"{{repl ConfigOptionIndex \"%s\" }}",
"{{repl ConfigOptionData \"%s\" }}",
"repl{{ ConfigOptionEquals \"%s\" \"abc\" }}",
"{{repl ConfigOptionNotEquals \"%s\" \"xyz\" }}{{repl DoesNotExistFunc }}",
"{{repl ConfigOptionNotEquals \"%s\" \"xyz\" }}",
}

if !rotate {
Expand All @@ -166,12 +215,28 @@ func buildTestConfigGroups(dependencies map[string][]string, prefix string, suff
}
}

totalDepItems := 0

for source, deps := range dependencies {
newItem := kotsv1beta1.ConfigItem{Type: "text", Name: source}
depString := prefix
for i, dep := range deps {
depString += fmt.Sprintf(templateFuncs[i%len(templateFuncs)], dep)
for _, dep := range deps {
depString += fmt.Sprintf(templateFuncs[totalDepItems%len(templateFuncs)], dep)
totalDepItems++
}

if certNames, ok := certs[source]; ok {
for _, certName := range certNames {
depString += fmt.Sprintf("{{repl TLSCert \"%s\" }}", certName)
}
}

if certNames, ok := keys[source]; ok {
for _, certName := range certNames {
depString += fmt.Sprintf("{{repl TLSKey \"%s\" }}", certName)
}
}

depString += suffix

if counter%2 == 0 {
Expand Down