Skip to content

Commit

Permalink
refactor: do yaml merge nightmare to merge optional base spec setup i…
Browse files Browse the repository at this point in the history
…nto rendered topo
  • Loading branch information
carlmontanari committed Jun 7, 2024
1 parent 5116d62 commit 64d92d0
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 289 deletions.
3 changes: 0 additions & 3 deletions clabverter/assets/topology-clab.yaml.template

This file was deleted.

3 changes: 3 additions & 0 deletions clabverter/assets/topology.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ spec:
naming: {{ .Naming }}
{{- end }}
connectivity: vxlan
definition:
containerlab: |-
{{- .ClabConfig }}
167 changes: 76 additions & 91 deletions clabverter/clabverter.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (
"strings"
"text/template"

clabernetesapisv1alpha1 "github.com/srl-labs/clabernetes/apis/v1alpha1"
clabernetesconstants "github.com/srl-labs/clabernetes/constants"
claberneteslogging "github.com/srl-labs/clabernetes/logging"
clabernetesutil "github.com/srl-labs/clabernetes/util"
clabernetesutilcontainerlab "github.com/srl-labs/clabernetes/util/containerlab"
clabernetesutilkubernetes "github.com/srl-labs/clabernetes/util/kubernetes"
yamlConfig "go.uber.org/config"
"gopkg.in/yaml.v3"
sigsyaml "sigs.k8s.io/yaml"
)

const (
Expand All @@ -29,7 +29,7 @@ const (
// MustNewClabverter returns an instance of Clabverter or panics.
func MustNewClabverter(
topologyFile,
specsFile,
topologySpecFile,
outputDirectory,
destinationNamespace,
naming,
Expand Down Expand Up @@ -93,7 +93,7 @@ func MustNewClabverter(
return &Clabverter{
logger: clabverterLogger,
topologyFile: topologyFile,
specsFile: specsFile,
topologySpecFile: topologySpecFile,
githubToken: githubToken,
outputDirectory: outputDirectory,
stdout: stdout,
Expand All @@ -117,7 +117,6 @@ type Clabverter struct {
logger claberneteslogging.Instance

topologyFile string
specsFile string
outputDirectory string
stdout bool

Expand All @@ -128,10 +127,13 @@ type Clabverter struct {

disableExpose bool

topologyPath string
topologyPathParent string
isRemotePath bool
valuesPath string
topologyPath string
topologyPathParent string
isRemotePath bool

topologySpecFile string
topologySpecFilePath string

githubGroup string
githubRepo string
githubToken string
Expand All @@ -141,8 +143,6 @@ type Clabverter struct {
rawClabConfig string
clabConfig *clabernetesutilcontainerlab.Config

rawSpecValues string

// mapping of nodeName -> startup-config info for the templating process; this is its own thing
// because configurations may be huge and configmaps have a 1M char limit, so while keeping them
// by themselves may not "solve" for ginormous configs, it can certainly give us a little extra
Expand Down Expand Up @@ -313,6 +313,19 @@ func (c *Clabverter) load() error {
c.topologyPathParent = filepath.Dir(c.topologyPath)
}

if c.topologySpecFile != "" {
c.topologySpecFilePath, err = filepath.Abs(c.topologySpecFile)
if err != nil {
c.logger.Criticalf("failed determining absolute path of values file, error: %s", err)

return err
}
}

c.logger.Debugf(
"determined fully qualified topology spec values file path as: %s", c.topologySpecFilePath,
)

c.logger.Debug("attempting to load containerlab topology....")

var rawClabConfigBytes []byte
Expand Down Expand Up @@ -370,37 +383,6 @@ func (c *Clabverter) load() error {

c.logger.Debug("loading and validating containerlab topology file complete!")

if c.specsFile != "" {
c.valuesPath, err = filepath.Abs(c.specsFile)
if err != nil {
c.logger.Criticalf("failed determining absolute path of values file, error: %s", err)

return err
}

c.logger.Debugf(
"determined fully qualified spec values file path as: %s", c.valuesPath,
)

c.logger.Debug("attempting to load spec values....")

rawSpecValuesBytes, err := os.ReadFile(c.valuesPath)
if err != nil {
c.logger.Criticalf(
"failed reading spec values file at '%s' from disk, error: %s",
c.valuesPath, err,
)

return err
}

// specs file content is non-indented, need to make it match spec indent
c.rawSpecValues = "spec:\n" + clabernetesutil.Indent(
string(rawSpecValuesBytes),
specIndentSpaces,
)
}

return nil
}

Expand Down Expand Up @@ -492,8 +474,13 @@ func (c *Clabverter) handleManifest() error {
err = t.Execute(
&rendered,
containerlabTemplateVars{
Name: c.clabConfig.Name,
Namespace: c.destinationNamespace,
Name: c.clabConfig.Name,
Namespace: c.destinationNamespace,
// pad w/ a newline so the template can look prettier :)
ClabConfig: "\n" + clabernetesutil.Indent(
c.rawClabConfig,
specDefinitionIndentSpaces,
),
Files: files,
FilesFromURL: c.extraFilesFromURL,
InsecureRegistries: c.insecureRegistries,
Expand All @@ -504,80 +491,78 @@ func (c *Clabverter) handleManifest() error {
},
)
if err != nil {
c.logger.Criticalf("failed executing topology template: %s", err)
c.logger.Criticalf("failed executing topology template, error: %s", err)

return err
}

fileName := fmt.Sprintf("%s/%s.yaml", c.outputDirectory, c.clabConfig.Name)

// merge yamls
// spec values override rendered values
rendered_yaml := yamlConfig.Source(strings.NewReader(rendered.String()))
spec_yaml := yamlConfig.Source(strings.NewReader(c.rawSpecValues))

merged_yaml, err := yamlConfig.NewYAML(rendered_yaml, spec_yaml)
finalRendered, err := c.mergeConfigSpecWithRenderedTopology(rendered.Bytes())
if err != nil {
c.logger.Criticalf("failed merging topology spec values: %s", err)
c.logger.Criticalf("failed merging spec config with rendered topology, error: %s", err)

return err
}

var target interface{}
fileName := fmt.Sprintf("%s/%s.yaml", c.outputDirectory, c.clabConfig.Name)

err = merged_yaml.Get(yamlConfig.Root).Populate(&target)
if err != nil {
c.logger.Criticalf("failed extracting spec values: %s", err)
c.renderedFiles = append(
c.renderedFiles,
renderedContent{
friendlyName: "clabernetes manifest",
fileName: fileName,
content: finalRendered,
},
)

return err
return nil
}

func (c *Clabverter) mergeConfigSpecWithRenderedTopology(
renderedTopologySpecBytes []byte,
) ([]byte, error) {
finalTopology := &clabernetesapisv1alpha1.Topology{}

if c.topologySpecFilePath == "" {
return renderedTopologySpecBytes, nil
}

rendered_bytes, err := yaml.Marshal(target)
content, err := os.ReadFile(c.topologySpecFilePath)
if err != nil {
c.logger.Criticalf("error marshalling topology YAML: %s", err)

return err
return nil, err
}

// marshalling removes the yaml start document chars, adding them back
rendered_bytes = append([]byte("---\n"), rendered_bytes...)
topologySpecFromSpecsFile := &clabernetesapisv1alpha1.TopologySpec{}

// marshalling uglifies multilne clab topo, appending separate template render to keep it pretty
t_clab, err := template.ParseFS(Assets, "assets/topology-clab.yaml.template")
err = sigsyaml.Unmarshal(content, topologySpecFromSpecsFile)
if err != nil {
c.logger.Criticalf("failed loading containerlab definition manifest from assets: %s", err)
return nil, err
}

return err
topologyFromSpecsFile := &clabernetesapisv1alpha1.Topology{
Spec: *topologySpecFromSpecsFile,
}

var rendered_clab bytes.Buffer
topologyFromSpecsFileBytes, err := sigsyaml.Marshal(topologyFromSpecsFile)
if err != nil {
return nil, err
}

err = t_clab.Execute(
&rendered_clab,
containerlabDefinitionTemplateVars{
// pad w/ a newline so the template can look prettier :)
ClabConfig: "\n" + clabernetesutil.Indent(
c.rawClabConfig,
specDefinitionIndentSpaces,
),
},
)
err = sigsyaml.Unmarshal(topologyFromSpecsFileBytes, finalTopology)
if err != nil {
c.logger.Criticalf("failed executing configmap template: %s", err)
return nil, err
}

return err
err = sigsyaml.Unmarshal(renderedTopologySpecBytes, finalTopology)
if err != nil {
return nil, err
}

c.renderedFiles = append(
c.renderedFiles,
renderedContent{
friendlyName: "clabernetes manifest",
fileName: fileName,
content: append(rendered_bytes, rendered_clab.Bytes()...),
},
)
finalTopologyBytes, err := sigsyaml.Marshal(finalTopology)
if err != nil {
return nil, err
}

return nil
return finalTopologyBytes, nil
}

func (c *Clabverter) output() error {
Expand Down
3 changes: 2 additions & 1 deletion clabverter/test-fixtures/clabversiontest/specs.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
statusProbes:
enabled: true
excludedNodes:
- baguette
probeConfiguration:
tcpProbeConfiguration:
port: 22
port: 22
5 changes: 1 addition & 4 deletions clabverter/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type topologyFileFromURLTemplateVars struct {
type containerlabTemplateVars struct {
Name string
Namespace string
ClabConfig string
Files map[string][]topologyConfigMapTemplateVars
FilesFromURL map[string][]topologyFileFromURLTemplateVars
InsecureRegistries []string
Expand All @@ -37,10 +38,6 @@ type containerlabTemplateVars struct {
ContainerlabVersion string
}

type containerlabDefinitionTemplateVars struct {
ClabConfig string
}

type renderedContent struct {
friendlyName string
fileName string
Expand Down
Loading

0 comments on commit 64d92d0

Please sign in to comment.