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

k8snetworkplumbingwg / sriov-network-operator / 13677347230

05 Mar 2025 01:40PM UTC coverage: 48.413% (-0.5%) from 48.917%
13677347230

Pull #853

github

web-flow
Merge bbc18ece8 into ab7d36758
Pull Request #853: Move systemd to host package

142 of 318 new or added lines in 6 files covered. (44.65%)

11 existing lines in 4 files now uncovered.

7352 of 15186 relevant lines covered (48.41%)

0.53 hits per line

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

1.44
/pkg/host/internal/systemd/systemd.go
1
/*
2
Copyright 2023.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
        http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
package systemd
17

18
import (
19
        "bytes"
20
        "fmt"
21
        "os"
22
        "strings"
23

24
        "gopkg.in/yaml.v3"
25
        "sigs.k8s.io/controller-runtime/pkg/log"
26

27
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
28
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
29
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
30
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
31
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
32
)
33

34
type systemd struct{}
35

36
func New() types.SystemdInterface {
1✔
37
        return &systemd{}
1✔
38
}
1✔
39

40
// ReadConfFile reads the SR-IOV config file from the host
41
// Unmarshal YAML content into SriovConfig object
NEW
42
func (s *systemd) ReadConfFile() (spec *types.SriovConfig, err error) {
×
NEW
43
        rawConfig, err := os.ReadFile(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
44
        if err != nil {
×
45
                return nil, err
×
46
        }
×
47

48
        err = yaml.Unmarshal(rawConfig, &spec)
×
49

×
50
        return spec, err
×
51
}
52

53
// WriteConfFile generates or updates a SriovNetwork configuration file based on the provided state.
54
// It creates the necessary directory structure if the file doesn't exist,
55
// reads the existing content to check for changes, and writes new content only when needed.
NEW
56
func (s *systemd) WriteConfFile(newState *sriovnetworkv1.SriovNetworkNodeState) (bool, error) {
×
57
        newFile := false
×
NEW
58
        sriovConfig := &types.SriovConfig{
×
59
                newState.Spec,
×
60
                vars.DevMode,
×
61
                vars.PlatformType,
×
62
                vars.ManageSoftwareBridges,
×
63
                vars.OVSDBSocketPath,
×
64
        }
×
65

×
NEW
66
        _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
67
        if err != nil {
×
68
                if os.IsNotExist(err) {
×
69
                        // Create the sriov-operator folder on the host if it doesn't exist
×
70
                        if _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovConfBasePath)); os.IsNotExist(err) {
×
71
                                err = os.Mkdir(utils.GetHostExtensionPath(consts.SriovConfBasePath), os.ModeDir)
×
72
                                if err != nil {
×
73
                                        log.Log.Error(err, "WriteConfFile(): fail to create sriov-operator folder",
×
74
                                                "path", utils.GetHostExtensionPath(consts.SriovConfBasePath))
×
75
                                        return false, err
×
76
                                }
×
77
                        }
78

79
                        log.Log.V(2).Info("WriteConfFile(): file not existed, create it",
×
NEW
80
                                "path", utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
NEW
81
                        _, err = os.Create(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
82
                        if err != nil {
×
83
                                log.Log.Error(err, "WriteConfFile(): fail to create file")
×
84
                                return false, err
×
85
                        }
×
86
                        newFile = true
×
87
                } else {
×
88
                        return false, err
×
89
                }
×
90
        }
91

NEW
92
        oldContent, err := os.ReadFile(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
93
        if err != nil {
×
NEW
94
                log.Log.Error(err, "WriteConfFile(): fail to read file", "path", utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
95
                return false, err
×
96
        }
×
97

NEW
98
        oldContentObj := &types.SriovConfig{}
×
99
        err = yaml.Unmarshal(oldContent, oldContentObj)
×
100
        if err != nil {
×
101
                log.Log.Error(err, "WriteConfFile(): fail to unmarshal old file")
×
102
                return false, err
×
103
        }
×
104

105
        var newContent []byte
×
106
        newContent, err = yaml.Marshal(sriovConfig)
×
107
        if err != nil {
×
108
                log.Log.Error(err, "WriteConfFile(): fail to marshal sriov config")
×
109
                return false, err
×
110
        }
×
111

112
        if bytes.Equal(newContent, oldContent) {
×
113
                log.Log.V(2).Info("WriteConfFile(): no update")
×
114
                return false, nil
×
115
        }
×
116
        log.Log.V(2).Info("WriteConfFile(): old and new configuration are not equal",
×
117
                "old", string(oldContent), "new", string(newContent))
×
118

×
119
        log.Log.V(2).Info("WriteConfFile(): write content to file",
×
NEW
120
                "content", newContent, "path", utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
NEW
121
        err = os.WriteFile(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath), newContent, 0644)
×
122
        if err != nil {
×
123
                log.Log.Error(err, "WriteConfFile(): fail to write file")
×
124
                return false, err
×
125
        }
×
126

127
        // this will be used to mark the first time we create this file.
128
        // this helps to avoid the first reboot after installation
129
        if newFile && len(sriovConfig.Spec.Interfaces) == 0 {
×
130
                log.Log.V(2).Info("WriteConfFile(): first file creation and no interfaces to configure returning reboot false")
×
131
                return false, nil
×
132
        }
×
133

134
        return true, nil
×
135
}
136

137
// WriteSriovResult writes SR-IOV results to the host.
138
// It creates the file if it doesn't exist
NEW
139
func (s *systemd) WriteSriovResult(result *types.SriovResult) error {
×
NEW
140
        _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
141
        if err != nil {
×
142
                if os.IsNotExist(err) {
×
143
                        log.Log.V(2).Info("WriteSriovResult(): file not existed, create it")
×
NEW
144
                        _, err = os.Create(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
145
                        if err != nil {
×
NEW
146
                                log.Log.Error(err, "WriteSriovResult(): failed to create sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
147
                                return err
×
148
                        }
×
149
                } else {
×
NEW
150
                        log.Log.Error(err, "WriteSriovResult(): failed to check sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
151
                        return err
×
152
                }
×
153
        }
154

155
        out, err := yaml.Marshal(result)
×
156
        if err != nil {
×
157
                log.Log.Error(err, "WriteSriovResult(): failed to marshal sriov result")
×
158
                return err
×
159
        }
×
160

161
        log.Log.V(2).Info("WriteSriovResult(): write results",
×
NEW
162
                "content", string(out), "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
NEW
163
        err = os.WriteFile(utils.GetHostExtensionPath(consts.SriovSystemdResultPath), out, 0644)
×
164
        if err != nil {
×
NEW
165
                log.Log.Error(err, "WriteSriovResult(): failed to write sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
166
                return err
×
167
        }
×
168

169
        return nil
×
170
}
171

172
// ReadSriovResult reads and parses the sriov result file from the host.
173
// The function first checks if the result file exists. If it doesn't, it returns nil with a success flag of false and no error.
174
// If the file exists, it reads its contents and attempts to unmarshal the YAML data into the SriovResult struct.
NEW
175
func (s *systemd) ReadSriovResult() (*types.SriovResult, bool, error) {
×
NEW
176
        _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
177
        if err != nil {
×
178
                if os.IsNotExist(err) {
×
179
                        log.Log.V(2).Info("ReadSriovResult(): file does not exist")
×
180
                        return nil, false, nil
×
181
                } else {
×
NEW
182
                        log.Log.Error(err, "ReadSriovResult(): failed to check sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
183
                        return nil, false, err
×
184
                }
×
185
        }
186

NEW
187
        rawConfig, err := os.ReadFile(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
188
        if err != nil {
×
NEW
189
                log.Log.Error(err, "ReadSriovResult(): failed to read sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
190
                return nil, false, err
×
191
        }
×
192

NEW
193
        result := &types.SriovResult{}
×
194
        err = yaml.Unmarshal(rawConfig, &result)
×
195
        if err != nil {
×
NEW
196
                log.Log.Error(err, "ReadSriovResult(): failed to unmarshal sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
197
                return nil, false, err
×
198
        }
×
199
        return result, true, err
×
200
}
201

202
// RemoveSriovResult: Removes the Sriov result file from the host.
NEW
203
func (s *systemd) RemoveSriovResult() error {
×
NEW
204
        err := os.Remove(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
205
        if err != nil {
×
206
                if os.IsNotExist(err) {
×
207
                        log.Log.V(2).Info("RemoveSriovResult(): result file not found")
×
208
                        return nil
×
209
                }
×
NEW
210
                log.Log.Error(err, "RemoveSriovResult(): failed to remove sriov result file", "path", utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
211
                return err
×
212
        }
213
        log.Log.V(2).Info("RemoveSriovResult(): result file removed")
×
214
        return nil
×
215
}
216

217
// WriteSriovSupportedNics() creates or updates a file containing the list of supported SR-IOV NIC IDs
218
// If the file does not exist, it will create it
219
// It reads from sriovnetworkv1.NicIDMap to gather the list of NIC identifiers
NEW
220
func (s *systemd) WriteSriovSupportedNics() error {
×
NEW
221
        _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
222
        if err != nil {
×
223
                if os.IsNotExist(err) {
×
224
                        log.Log.V(2).Info("WriteSriovSupportedNics(): file does not exist, create it")
×
NEW
225
                        _, err = os.Create(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
226
                        if err != nil {
×
227
                                log.Log.Error(err, "WriteSriovSupportedNics(): failed to create sriov supporter nics ids file",
×
NEW
228
                                        "path", utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
229
                                return err
×
230
                        }
×
231
                } else {
×
NEW
232
                        log.Log.Error(err, "WriteSriovSupportedNics(): failed to check sriov supported nics ids file", "path", utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
233
                        return err
×
234
                }
×
235
        }
236

237
        rawNicList := []byte{}
×
238
        for _, line := range sriovnetworkv1.NicIDMap {
×
239
                rawNicList = append(rawNicList, []byte(fmt.Sprintf("%s\n", line))...)
×
240
        }
×
241

NEW
242
        err = os.WriteFile(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath), rawNicList, 0644)
×
243
        if err != nil {
×
244
                log.Log.Error(err, "WriteSriovSupportedNics(): failed to write sriov supported nics ids file",
×
NEW
245
                        "path", utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
246
                return err
×
247
        }
×
248

249
        return nil
×
250
}
251

252
// ReadSriovSupportedNics reads the list of SR-IOV supported network interface cards (NICs) from the host.
253
// It returns a slice of strings where each string represents a line from the file,
254
// with each line corresponding to an SR-IOV supported NIC. If the file does not exist, it returns nil and an error.
255
// If there is an error reading the file, it returns the error along with the file path for debugging purposes.
NEW
256
func (s *systemd) ReadSriovSupportedNics() ([]string, error) {
×
NEW
257
        _, err := os.Stat(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
258
        if err != nil {
×
259
                if os.IsNotExist(err) {
×
260
                        log.Log.V(2).Info("ReadSriovSupportedNics(): file does not exist, return empty result")
×
261
                        return nil, err
×
262
                } else {
×
NEW
263
                        log.Log.Error(err, "ReadSriovSupportedNics(): failed to check sriov supported nics file", "path", utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
264
                        return nil, err
×
265
                }
×
266
        }
267

NEW
268
        rawConfig, err := os.ReadFile(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
269
        if err != nil {
×
NEW
270
                log.Log.Error(err, "ReadSriovSupportedNics(): failed to read sriov supported nics file", "path", utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
271
                return nil, err
×
272
        }
×
273

274
        lines := strings.Split(string(rawConfig), "\n")
×
275
        return lines, nil
×
276
}
277

278
// CleanSriovFilesFromHost removes SR-IOV related configuration and service files from the host system.
279
// It deletes several systemd-related files including configuration paths, result paths, supported NICs path,
280
// and service binary path. If not in an OpenShift environment, it also removes the main SR-IOV
281
// service and post-networking service files.
NEW
282
func (s *systemd) CleanSriovFilesFromHost(isOpenShift bool) error {
×
NEW
283
        err := os.Remove(utils.GetHostExtensionPath(consts.SriovSystemdConfigPath))
×
284
        if err != nil && !os.IsNotExist(err) {
×
285
                return err
×
286
        }
×
287

NEW
288
        err = os.Remove(utils.GetHostExtensionPath(consts.SriovSystemdResultPath))
×
289
        if err != nil && !os.IsNotExist(err) {
×
290
                return err
×
291
        }
×
292

NEW
293
        err = os.Remove(utils.GetHostExtensionPath(consts.SriovSystemdSupportedNicPath))
×
294
        if err != nil && !os.IsNotExist(err) {
×
295
                return err
×
296
        }
×
297

NEW
298
        err = os.Remove(utils.GetHostExtensionPath(consts.SriovSystemdServiceBinaryPath))
×
299
        if err != nil && !os.IsNotExist(err) {
×
300
                return err
×
301
        }
×
302

303
        // in openshift we should not remove the systemd service it will be done by the machine config operator
304
        if !isOpenShift {
×
NEW
305
                err = os.Remove(utils.GetHostExtensionPath(consts.SriovServicePath))
×
306
                if err != nil && !os.IsNotExist(err) {
×
307
                        return err
×
308
                }
×
NEW
309
                err = os.Remove(utils.GetHostExtensionPath(consts.SriovPostNetworkServicePath))
×
310
                if err != nil && !os.IsNotExist(err) {
×
311
                        return err
×
312
                }
×
313
        }
314

315
        return nil
×
316
}
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

© 2025 Coveralls, Inc