• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

k8snetworkplumbingwg / sriov-network-operator / 27552282759

15 Jun 2026 02:11PM UTC coverage: 63.754% (+0.3%) from 63.429%
27552282759

Pull #823

github

web-flow
Merge 03b98b616 into 23c5751c8
Pull Request #823: Make ovs-vswitchd service 'other_config' option configurable

118 of 163 new or added lines in 10 files covered. (72.39%)

2 existing lines in 1 file now uncovered.

9595 of 15050 relevant lines covered (63.75%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.26
/pkg/render/render.go
1
package render
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io"
7
        "os"
8
        "path/filepath"
9
        "sort"
10
        "strings"
11
        "text/template"
12

13
        sprig "github.com/Masterminds/sprig/v3"
14
        "github.com/pkg/errors"
15

16
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
17
        "k8s.io/apimachinery/pkg/util/yaml"
18

19
        mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
20
)
21

22
type RenderData struct {
23
        Funcs template.FuncMap
24
        Data  map[string]interface{}
25
}
26

27
type RenderConfig struct {
28
        *mcfgv1.ControllerConfigSpec
29
        PullSecret string
30
}
31

32
type DeviceInfo struct {
33
        PciAddress string
34
        NumVfs     int
35
}
36

37
const (
38
        ovsUnitsDir = "ovs-units"
39
)
40

41
func MakeRenderData() RenderData {
1✔
42
        return RenderData{
1✔
43
                Funcs: template.FuncMap{},
1✔
44
                Data:  map[string]interface{}{},
1✔
45
        }
1✔
46
}
1✔
47

48
// RenderDir will render all manifests in a directory, descending in to subdirectories
49
// It will perform template substitutions based on the data supplied by the RenderData
50
func RenderDir(manifestDir string, d *RenderData) ([]*unstructured.Unstructured, error) {
1✔
51
        out := []*unstructured.Unstructured{}
1✔
52

1✔
53
        if err := filepath.Walk(manifestDir, func(path string, info os.FileInfo, err error) error {
2✔
54
                if err != nil {
1✔
55
                        return err
×
56
                }
×
57
                if info.IsDir() {
2✔
58
                        return nil
1✔
59
                }
1✔
60

61
                // Skip non-manifest files
62
                if !(strings.HasSuffix(path, ".yml") || strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".json")) {
1✔
63
                        return nil
×
64
                }
×
65

66
                objs, err := RenderFileTemplate(path, d)
1✔
67
                if err != nil {
1✔
68
                        return err
×
69
                }
×
70
                out = append(out, objs...)
1✔
71
                return nil
1✔
72
        }); err != nil {
×
73
                return nil, errors.Wrap(err, "error rendering manifests")
×
74
        }
×
75

76
        return out, nil
1✔
77
}
78

79
// RenderTemplate renders provided template to string
80
func RenderTemplate(template string, d *RenderData) (*bytes.Buffer, error) {
1✔
81
        return renderTemplate(template, d)
1✔
82
}
1✔
83

84
// RenderFileTemplate reads, renders, and attempts to parse a yaml or
85
// json file representing one or more k8s api objects
86
func RenderFileTemplate(path string, d *RenderData) ([]*unstructured.Unstructured, error) {
1✔
87
        rendered, err := renderFileTemplate(path, d)
1✔
88
        if err != nil {
2✔
89
                return nil, err
1✔
90
        }
1✔
91

92
        out := []*unstructured.Unstructured{}
1✔
93

1✔
94
        // special case - if the entire file is whitespace, skip
1✔
95
        if len(strings.TrimSpace(rendered.String())) == 0 {
2✔
96
                return out, nil
1✔
97
        }
1✔
98

99
        decoder := yaml.NewYAMLOrJSONDecoder(rendered, 4096)
1✔
100
        for {
2✔
101
                u := unstructured.Unstructured{}
1✔
102
                if err := decoder.Decode(&u); err != nil {
2✔
103
                        if err == io.EOF {
2✔
104
                                break
1✔
105
                        }
106
                        return nil, errors.Wrapf(err, "failed to unmarshal manifest %s", path)
×
107
                }
108

109
                if u.Object == nil {
2✔
110
                        continue
1✔
111
                }
112

113
                out = append(out, &u)
1✔
114
        }
115

116
        return out, nil
1✔
117
}
118

119
func renderTemplate(rawTemplate string, d *RenderData) (*bytes.Buffer, error) {
1✔
120
        tmpl := template.New("template").Option("missingkey=error")
1✔
121
        if d.Funcs != nil {
2✔
122
                tmpl.Funcs(d.Funcs)
1✔
123
        }
1✔
124

125
        // Add universal functions
126
        tmpl.Funcs(template.FuncMap{"getOr": getOr, "isSet": isSet})
1✔
127
        tmpl.Funcs(sprig.TxtFuncMap())
1✔
128

1✔
129
        if _, err := tmpl.Parse(rawTemplate); err != nil {
2✔
130
                return nil, errors.Wrapf(err, "failed to parse manifest %s as template", rawTemplate)
1✔
131
        }
1✔
132

133
        rendered := bytes.Buffer{}
1✔
134
        if err := tmpl.Execute(&rendered, d.Data); err != nil {
2✔
135
                return nil, errors.Wrapf(err, "failed to render manifest %s", rawTemplate)
1✔
136
        }
1✔
137

138
        return &rendered, nil
1✔
139
}
140

141
func renderFileTemplate(path string, d *RenderData) (*bytes.Buffer, error) {
1✔
142
        source, err := os.ReadFile(path)
1✔
143
        if err != nil {
1✔
NEW
144
                return nil, errors.Wrapf(err, "failed to read manifest %s", path)
×
NEW
145
        }
×
146

147
        return renderTemplate(string(source[:]), d)
1✔
148
}
149

150
func formateDeviceList(devs []DeviceInfo) string {
×
151
        out := ""
×
152
        for _, dev := range devs {
×
153
                out = out + fmt.Sprintln(dev.PciAddress, dev.NumVfs)
×
154
        }
×
155
        return out
×
156
}
157

158
func GenerateMachineConfig(path, name, mcRole string, ovsOffload bool, d *RenderData) (*mcfgv1.MachineConfig, error) {
1✔
159
        d.Funcs["formateDeviceList"] = formateDeviceList
1✔
160

1✔
161
        exists, err := existsDir(path)
1✔
162
        if err != nil {
1✔
163
                return nil, err
×
164
        }
×
165
        if !exists {
1✔
166
                return nil, errors.Errorf("%s is not a directory", path)
×
167
        }
×
168
        units := map[string]string{}
1✔
169

1✔
170
        if ovsOffload {
2✔
171
                p := filepath.Join(path, ovsUnitsDir)
1✔
172
                exists, err = existsDir(p)
1✔
173
                if err != nil {
1✔
174
                        return nil, err
×
175
                }
×
176
                if exists {
2✔
177
                        if err := filterTemplates(units, p, d); err != nil {
1✔
178
                                return nil, err
×
179
                        }
×
180
                }
181
        }
182
        // keySortVals returns a list of values, sorted by key
183
        // we need the lists of files and units to have a stable ordering for the checksum
184
        keySortVals := func(m map[string]string) []string {
2✔
185
                ks := []string{}
1✔
186
                for k := range m {
2✔
187
                        ks = append(ks, k)
1✔
188
                }
1✔
189
                sort.Strings(ks)
1✔
190

1✔
191
                vs := []string{}
1✔
192
                for _, k := range ks {
2✔
193
                        vs = append(vs, m[k])
1✔
194
                }
1✔
195

196
                return vs
1✔
197
        }
198

199
        ignCfg, err := TranspileCoreOSConfigToIgn(nil, keySortVals(units))
1✔
200
        if err != nil {
1✔
201
                return nil, errors.Wrap(err, "error transpiling CoreOS config to Ignition config")
×
202
        }
×
203
        mcfg, err := MachineConfigFromIgnConfig(mcRole, name, ignCfg)
1✔
204
        if err != nil {
1✔
205
                return nil, errors.Wrap(err, "error creating MachineConfig from Ignition config")
×
206
        }
×
207

208
        return mcfg, nil
1✔
209
}
210

211
// existsDir returns true if path exists and is a directory, false if the path
212
// does not exist, and error if there is a runtime error or the path is not a directory
213
func existsDir(path string) (bool, error) {
1✔
214
        info, err := os.Stat(path)
1✔
215
        if err != nil {
1✔
216
                if os.IsNotExist(err) {
×
217
                        return false, nil
×
218
                }
×
219
                return false, errors.Wrapf(err, "failed to open dir %q", path)
×
220
        }
221
        if !info.IsDir() {
1✔
222
                return false, errors.Wrapf(err, "expected template directory, %q is not a directory", path)
×
223
        }
×
224
        return true, nil
1✔
225
}
226

227
func filterTemplates(toFilter map[string]string, path string, d *RenderData) error {
1✔
228
        walkFn := func(path string, info os.FileInfo, err error) error {
2✔
229
                if err != nil {
1✔
230
                        return err
×
231
                }
×
232
                if info.IsDir() {
2✔
233
                        return nil
1✔
234
                }
1✔
235

236
                // empty templates signify don't create
237
                if info.Size() == 0 {
1✔
238
                        delete(toFilter, info.Name())
×
239
                        return nil
×
240
                }
×
241

242
                // Render the template file
243
                renderedData, err := renderFileTemplate(path, d)
1✔
244
                if err != nil {
1✔
245
                        return err
×
246
                }
×
247
                toFilter[info.Name()] = renderedData.String()
1✔
248
                return nil
1✔
249
        }
250

251
        return filepath.Walk(path, walkFn)
1✔
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc