/
template.go
155 lines (129 loc) · 3.31 KB
/
template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package config
import (
"fmt"
"path/filepath"
"strings"
"text/template"
jT "github.com/kellerza/template"
log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/types"
"gopkg.in/yaml.v2"
)
// templates to execute
var TemplateNames []string
// path to additional templates
var TemplatePaths []string
// debug count
var DebugCount int
type NodeConfig struct {
TargetNode *types.NodeConfig
// All the variables used to render the template
Vars map[string]interface{}
// the Rendered templates
Data []string
Info []string
}
// Load templates from all paths for the specific role/kind
func LoadTemplates(tmpl *template.Template, role string) error {
for _, p := range TemplatePaths {
fn := filepath.Join(p, fmt.Sprintf("*__%s.tmpl", role))
_, err := tmpl.ParseGlob(fn)
if err != nil {
return fmt.Errorf("could not load templates from %s: %s", fn, err)
}
}
return nil
}
func RenderAll(allnodes map[string]*NodeConfig) error {
if len(TemplatePaths) == 0 { // default is the install path
TemplatePaths = []string{"@"}
}
for i, v := range TemplatePaths {
if v == "@" {
TemplatePaths[i] = "/etc/containerlab/templates/"
}
}
if len(TemplateNames) == 0 {
var err error
TemplateNames, err = GetTemplateNamesInDirs(TemplatePaths)
if err != nil {
return err
}
log.Infof("No template names specified (-l) using: %s", strings.Join(TemplateNames, ", "))
}
tmpl := template.New("").Funcs(jT.Funcs)
for _, nc := range allnodes {
for _, baseN := range TemplateNames {
tmplN := fmt.Sprintf("%s__%s.tmpl", baseN, nc.Vars[vkRole])
if tmpl.Lookup(tmplN) == nil {
err := LoadTemplates(tmpl, fmt.Sprintf("%s", nc.Vars[vkRole]))
if err != nil {
return err
}
if tmpl.Lookup(tmplN) == nil {
return fmt.Errorf("template not found %s", tmplN)
}
}
var buf strings.Builder
err := tmpl.ExecuteTemplate(&buf, tmplN, nc.Vars)
if err != nil {
nc.Print(true, true)
return err
}
data := strings.ReplaceAll(strings.Trim(buf.String(), "\n \t\r"), "\n\n\n", "\n\n")
nc.Data = append(nc.Data, data)
nc.Info = append(nc.Info, tmplN)
}
}
return nil
}
// Implement stringer for NodeConfig
func (c *NodeConfig) String() string {
s := fmt.Sprintf("%s: %v", c.TargetNode.ShortName, c.Info)
return s
}
// Print the config
func (c *NodeConfig) Print(vars, rendered bool) {
var s strings.Builder
s.WriteString(c.TargetNode.ShortName)
if vars {
s.WriteString(" vars = ")
var saved_nodes Dict
restore := false
if DebugCount < 3 {
saved_nodes, restore = c.Vars[vkNodes].(Dict)
if restore {
var n strings.Builder
n.WriteRune('{')
for k := range saved_nodes {
fmt.Fprintf(&n, "%s: {...}, ", k)
}
n.WriteRune('}')
c.Vars[vkNodes] = n.String()
}
}
vars, err := yaml.Marshal(c.Vars)
if err != nil {
log.Warnf("error printing vars for node %s: %s", c.TargetNode.ShortName, err)
s.WriteString(err.Error())
}
if restore {
c.Vars[vkNodes] = saved_nodes
}
if len(vars) > 0 {
s.Write(vars)
}
}
if rendered {
for idx, conf := range c.Data {
fmt.Fprintf(&s, "\n Template %s for %s = [[", c.Info[idx], c.TargetNode.ShortName)
cl := strings.Split(conf, "\n")
for _, l := range cl {
s.WriteString("\n ")
s.WriteString(l)
}
s.WriteString("\n ]]")
}
}
log.Infoln(s.String())
}