Skip to content

Commit

Permalink
Merge pull request #35 from srl-labs/feat/support-clab-bind-mounts
Browse files Browse the repository at this point in the history
feat: first pass support for bind mounts
  • Loading branch information
carlmontanari authored Sep 24, 2023
2 parents f991755 + 4ee9a0a commit 444c7b4
Show file tree
Hide file tree
Showing 3 changed files with 365 additions and 267 deletions.
282 changes: 15 additions & 267 deletions clabverter/clabverter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,66 +18,6 @@ import (

const specIndentSpaces = 4

type startupConfigConfigMapTemplateVars struct {
Name string
Namespace string
StartupConfig string
}

type extraFilesConfigMapTemplateVars struct {
Name string
Namespace string
ExtraFiles map[string]string
}

type topologyConfigMapTemplateVars struct {
NodeName string
ConfigMapName string
FilePath string
FileName string
}

type containerlabTemplateVars struct {
Name string
Namespace string
ClabConfig string
StartupConfigs []topologyConfigMapTemplateVars
ExtraFiles []topologyConfigMapTemplateVars
InsecureRegistries []string
}

type renderedContent struct {
friendlyName string
fileName string
content []byte
}

func getExtraFilesForNode(
clabConfig *clabernetesutilcontainerlab.Config,
nodeName string,
) ([]string, error) {
var paths []string

nodeConfig, ok := clabConfig.Topology.Nodes[nodeName]
if !ok {
return nil, fmt.Errorf(
"%w: issue fetching extra files for node '%s', this is a bug",
ErrClabvert,
nodeName,
)
}

if nodeConfig.License != "" {
paths = append(paths, nodeConfig.License)
} else if clabConfig.Topology.Defaults != nil && clabConfig.Topology.Defaults.License != "" {
paths = append(paths, clabConfig.Topology.Defaults.License)
}

// if there are other files we need to try to load we can just put them here

return paths, nil
}

// MustNewClabverter returns an instance of Clabverter or panics.
func MustNewClabverter(
topologyFile,
Expand Down Expand Up @@ -164,7 +104,7 @@ func (c *Clabverter) Clabvert() error {
return err
}

err = c.findClabFile()
err = c.findClabTopologyFile()
if err != nil {
return err
}
Expand Down Expand Up @@ -225,11 +165,17 @@ func (c *Clabverter) resolveContentAtPath(path string) ([]byte, error) {
fmt.Sprintf("%s/%s", c.topologyPathParent, path),
)
default:
fullyQualifiedStartupConfigPath := fmt.Sprintf(
"%s/%s",
c.topologyPathParent,
path,
)
fullyQualifiedStartupConfigPath := path

if !strings.HasPrefix(path, c.topologyPathParent) {
// we may have already set this while processing bind mounts, so don't blindly add the
// parent path unless we need to!
fullyQualifiedStartupConfigPath = fmt.Sprintf(
"%s/%s",
c.topologyPathParent,
path,
)
}

content, err = os.ReadFile(fullyQualifiedStartupConfigPath) //nolint:gosec
}
Expand Down Expand Up @@ -335,204 +281,6 @@ func (c *Clabverter) handleAssociatedFiles() error {
return nil
}

func (c *Clabverter) handleStartupConfigs() error {
c.logger.Info("handling containerlab topology startup config(s) if present...")

startupConfigs := map[string][]byte{}

for nodeName, nodeData := range c.clabConfig.Topology.Nodes {
if nodeData.StartupConfig == "" {
c.logger.Debugf("node '%s' does not have a startup-config, skipping....", nodeName)

continue
}

c.logger.Debugf("loading node '%s' startup-config...", nodeName)

startupConfigContents, err := c.resolveContentAtPath(nodeData.StartupConfig)
if err != nil {
c.logger.Criticalf(
"failed loading startup-config contents for node '%s', error: %s",
nodeName,
err,
)

return err
}

startupConfigs[nodeName] = startupConfigContents
}

c.logger.Info("rendering clabernetes startup config outputs...")

// render configmap(s) for startup configs
for nodeName, startupConfigContents := range startupConfigs {
t, err := template.ParseFS(Assets, "assets/startup-config-configmap.yaml.template")
if err != nil {
c.logger.Criticalf(
"failed loading startup-config configmap template from assets: %s",
err,
)

return err
}

configMapName := fmt.Sprintf("%s-%s-startup-config", c.clabConfig.Name, nodeName)

var rendered bytes.Buffer

err = t.Execute(
&rendered,
startupConfigConfigMapTemplateVars{
Name: configMapName,
Namespace: c.destinationNamespace,
// pad w/ a newline so the template can look prettier :)
StartupConfig: "\n" + clabernetesutil.Indent(
string(startupConfigContents),
specIndentSpaces,
),
},
)
if err != nil {
c.logger.Criticalf("failed executing configmap template: %s", err)

return err
}

fileName := fmt.Sprintf("%s/%s-startup-config.yaml", c.outputDirectory, nodeName)

c.renderedFiles = append(
c.renderedFiles,
renderedContent{
friendlyName: fmt.Sprintf("%s-statup-config", nodeName),
fileName: fileName,
content: rendered.Bytes(),
},
)

c.startupConfigConfigMaps[nodeName] = topologyConfigMapTemplateVars{
NodeName: nodeName,
ConfigMapName: configMapName,
FilePath: c.clabConfig.Topology.Nodes[nodeName].StartupConfig,
}
}

c.logger.Debug("handling startup configs complete")

return nil
}

func (c *Clabverter) handleExtraFiles() error {
c.logger.Info("handling containerlab extra file(s) if present...")

extraFiles := make(map[string]map[string][]byte)

for nodeName := range c.clabConfig.Topology.Nodes {
extraFilePaths, err := getExtraFilesForNode(c.clabConfig, nodeName)
if err != nil {
c.logger.Criticalf(
"failed determining extra file paths for node '%s', error: %s",
nodeName,
err,
)

return err
}

if len(extraFilePaths) == 0 {
continue
}

extraFiles[nodeName] = make(map[string][]byte)

for _, extraFilePath := range extraFilePaths {
c.logger.Debugf("loading node '%s' extra file '%s'...", nodeName, extraFilePath)

var extraFileContent []byte

extraFileContent, err = c.resolveContentAtPath(extraFilePath)
if err != nil {
c.logger.Criticalf(
"failed loading extra file '%s' contents for node '%s', error: %s",
extraFilePath,
nodeName,
err,
)

return err
}

extraFiles[nodeName][extraFilePath] = extraFileContent
}
}

c.logger.Info("rendering clabernetes extra file(s) outputs...")

// render "extra" files
for nodeName, nodeExtraFiles := range extraFiles {
t, err := template.ParseFS(Assets, "assets/files-configmap.yaml.template")
if err != nil {
c.logger.Criticalf("failed loading files configmap template from assets: %s", err)

return err
}

configMapName := fmt.Sprintf("%s-%s-files", c.clabConfig.Name, nodeName)

templateVars := extraFilesConfigMapTemplateVars{
Name: configMapName,
Namespace: c.destinationNamespace,
ExtraFiles: make(map[string]string),
}

c.extraFilesConfigMaps[nodeName] = make([]topologyConfigMapTemplateVars, 0)

for extraFilePath, extraFileContent := range nodeExtraFiles {
safeFileName := clabernetesutil.SafeConcatNameKubernetes(
strings.Split(extraFilePath, "/")...)

templateVars.ExtraFiles[safeFileName] = "\n" + clabernetesutil.Indent(
string(extraFileContent),
specIndentSpaces,
)

c.extraFilesConfigMaps[nodeName] = append(
c.extraFilesConfigMaps[nodeName],
topologyConfigMapTemplateVars{
NodeName: nodeName,
ConfigMapName: configMapName,
FilePath: extraFilePath,
FileName: safeFileName,
},
)
}

var rendered bytes.Buffer

err = t.Execute(&rendered, templateVars)
if err != nil {
c.logger.Criticalf("failed executing configmap template: %s", err)

return err
}

fileName := fmt.Sprintf("%s/%s-extra-files.yaml", c.outputDirectory, nodeName)

c.renderedFiles = append(
c.renderedFiles,
renderedContent{
friendlyName: fmt.Sprintf("%s extra files", nodeName),
fileName: fileName,
content: rendered.Bytes(),
},
)
}

c.logger.Debug("handling extra file(s) complete")

return nil
}

func (c *Clabverter) handleManifest() error {
t, err := template.ParseFS(Assets, "assets/containerlab.yaml.template")
if err != nil {
Expand Down Expand Up @@ -623,9 +371,9 @@ func (c *Clabverter) output() error {
return nil
}

// findClabFile attempts to find a clab file in the working directory
// if the path was not provided.
func (c *Clabverter) findClabFile() error {
// findClabTopologyFile attempts to find a clab file in the working directory if the path was not
// provided.
func (c *Clabverter) findClabTopologyFile() error {
if c.topologyFile != "" {
return nil
}
Expand Down
Loading

0 comments on commit 444c7b4

Please sign in to comment.