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

k8snetworkplumbingwg / sriov-network-operator / 19331737185

13 Nov 2025 12:35PM UTC coverage: 62.137% (-0.2%) from 62.366%
19331737185

push

github

web-flow
Merge pull request #902 from SchSeba/create_platform_and_orchestrator_packages

Create platform and orchestrator packages

319 of 659 new or added lines in 25 files covered. (48.41%)

42 existing lines in 10 files now uncovered.

8770 of 14114 relevant lines covered (62.14%)

0.69 hits per line

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

28.92
/pkg/platform/openstack/helpers.go
1
package openstack
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "io"
7
        "os"
8
        "os/exec"
9
        "path/filepath"
10
        "strings"
11

12
        "github.com/hashicorp/go-retryablehttp"
13
        "github.com/jaypipes/ghw"
14
        "github.com/jaypipes/ghw/pkg/net"
15
        "sigs.k8s.io/controller-runtime/pkg/log"
16
)
17

18
// GetOpenstackData gets the metadata and network_data
19
func getOpenstackData(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
1✔
20
        metaData, networkData, err = getOpenstackDataFromConfigDrive(mountConfigDrive)
1✔
21
        if err != nil {
1✔
22
                log.Log.Error(err, "GetOpenStackData(): non-fatal error getting OpenStack data from config drive")
×
23
                metaData, networkData, err = getOpenstackDataFromMetadataService()
×
24
                if err != nil {
×
25
                        return metaData, networkData, fmt.Errorf("GetOpenStackData(): error getting OpenStack data: %w", err)
×
26
                }
×
27
        }
28

29
        // We can't rely on the PCI address from the metadata so we will lookup the real PCI address
30
        // for the NIC that matches the MAC address.
31
        //
32
        // Libvirt/QEMU cannot guarantee that the address specified in the XML will match the address seen by the guest.
33
        // This is a well known limitation: https://libvirt.org/pci-addresses.html
34
        // When using the q35 machine type, it highlights this issue due to the change from using PCI to PCI-E bus for virtual devices.
35
        //
36
        // With that said, the PCI value in Nova Metadata is a best effort hint due to the limitations mentioned above. Therefore
37
        // we will lookup the real PCI address for the NIC that matches the MAC address.
38
        netInfo, err := ghw.Network()
1✔
39
        if err != nil {
1✔
40
                return metaData, networkData, fmt.Errorf("GetOpenStackData(): error getting network info: %w", err)
×
41
        }
×
42
        for i, device := range metaData.Devices {
2✔
43
                realPCIAddr, err := getPCIAddressFromMACAddress(device.Mac, netInfo.NICs)
1✔
44
                if err != nil {
1✔
45
                        // If we can't find the PCI address, we will just print a warning, return the data as is with no error.
×
46
                        // In the future, we'll want to drain the node if sno-initial-node-state.json doesn't exist when daemon is restarted and when we have SR-IOV
×
47
                        // allocated devices already.
×
48
                        log.Log.Error(err, "Warning GetOpenstackData(): error getting PCI address for device",
×
49
                                "device-mac", device.Mac)
×
50
                        return metaData, networkData, nil
×
51
                }
×
52
                if realPCIAddr != device.Address {
2✔
53
                        log.Log.V(2).Info("GetOpenstackData(): PCI address for device does not match Nova metadata value, it'll be overwritten",
1✔
54
                                "device-mac", device.Mac,
1✔
55
                                "current-address", device.Address,
1✔
56
                                "overwrite-address", realPCIAddr)
1✔
57
                        metaData.Devices[i].Address = realPCIAddr
1✔
58
                }
1✔
59
        }
60

61
        return metaData, networkData, err
1✔
62
}
63

64
// getConfigDriveDevice returns the config drive device which was found
65
func getConfigDriveDevice() (string, error) {
×
66
        dev := "/dev/disk/by-label/" + configDriveLabel
×
67
        if _, err := os.Stat(dev); os.IsNotExist(err) {
×
68
                out, err := exec.Command(
×
69
                        "blkid", "-l",
×
70
                        "-t", "LABEL="+configDriveLabel,
×
71
                        "-o", "device",
×
72
                ).CombinedOutput()
×
73
                if err != nil {
×
74
                        return "", fmt.Errorf("unable to run blkid: %v", err)
×
75
                }
×
76
                dev = strings.TrimSpace(string(out))
×
77
        }
78
        log.Log.Info("found config drive device", "device", dev)
×
79
        return dev, nil
×
80
}
81

82
// mountConfigDriveDevice mounts the config drive and return the path
83
func mountConfigDriveDevice(device string) (string, error) {
×
84
        if device == "" {
×
85
                return "", fmt.Errorf("device is empty")
×
86
        }
×
87
        tmpDir, err := os.MkdirTemp("", "sriov-configdrive")
×
88
        if err != nil {
×
89
                return "", fmt.Errorf("error creating temp directory: %w", err)
×
90
        }
×
91
        cmd := exec.Command("mount", "-o", "ro", "-t", "auto", device, tmpDir)
×
92
        if err := cmd.Run(); err != nil {
×
93
                return "", fmt.Errorf("error mounting config drive: %w", err)
×
94
        }
×
95
        log.Log.V(2).Info("mounted config drive device", "device", device, "path", tmpDir)
×
96
        return tmpDir, nil
×
97
}
98

99
// ummountConfigDriveDevice ummounts the config drive device
100
func ummountConfigDriveDevice(path string) error {
×
101
        if path == "" {
×
102
                return fmt.Errorf("path is empty")
×
103
        }
×
104
        cmd := exec.Command("umount", path)
×
105
        if err := cmd.Run(); err != nil {
×
106
                return fmt.Errorf("error umounting config drive: %w", err)
×
107
        }
×
108
        log.Log.V(2).Info("umounted config drive", "path", path)
×
109
        return nil
×
110
}
111

112
// getOpenstackDataFromConfigDrive reads the meta_data and network_data files
113
func getOpenstackDataFromConfigDrive(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
1✔
114
        metaData = &OSPMetaData{}
1✔
115
        networkData = &OSPNetworkData{}
1✔
116
        var configDrivePath string
1✔
117
        log.Log.Info("reading OpenStack meta_data from config-drive")
1✔
118
        var metadataf *os.File
1✔
119
        ospMetaDataFilePath := ospMetaDataFile
1✔
120
        if mountConfigDrive {
1✔
121
                configDriveDevice, err := getConfigDriveDevice()
×
122
                if err != nil {
×
123
                        return metaData, networkData, fmt.Errorf("error finding config drive device: %w", err)
×
124
                }
×
125
                configDrivePath, err = mountConfigDriveDevice(configDriveDevice)
×
126
                if err != nil {
×
127
                        return metaData, networkData, fmt.Errorf("error mounting config drive device: %w", err)
×
128
                }
×
129
                defer func() {
×
130
                        if e := ummountConfigDriveDevice(configDrivePath); err == nil && e != nil {
×
131
                                err = fmt.Errorf("error umounting config drive device: %w", e)
×
132
                        }
×
133
                        if e := os.Remove(configDrivePath); err == nil && e != nil {
×
134
                                err = fmt.Errorf("error removing temp directory %s: %w", configDrivePath, e)
×
135
                        }
×
136
                }()
137
                ospMetaDataFilePath = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospMetaDataJSON)
×
138
                ospNetworkDataFile = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospNetworkDataJSON)
×
139
        }
140
        metadataf, err = os.Open(ospMetaDataFilePath)
1✔
141
        if err != nil {
1✔
142
                return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospMetaDataFilePath, err)
×
143
        }
×
144
        defer func() {
2✔
145
                if e := metadataf.Close(); err == nil && e != nil {
1✔
146
                        err = fmt.Errorf("error closing file %s: %w", ospMetaDataFilePath, e)
×
147
                }
×
148
        }()
149
        if err = json.NewDecoder(metadataf).Decode(&metaData); err != nil {
1✔
150
                return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospMetaDataFilePath, err)
×
151
        }
×
152

153
        log.Log.Info("reading OpenStack network_data from config-drive")
1✔
154
        var networkDataf *os.File
1✔
155
        ospNetworkDataFilePath := ospNetworkDataFile
1✔
156
        networkDataf, err = os.Open(ospNetworkDataFilePath)
1✔
157
        if err != nil {
1✔
158
                return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospNetworkDataFilePath, err)
×
159
        }
×
160
        defer func() {
2✔
161
                if e := networkDataf.Close(); err == nil && e != nil {
1✔
162
                        err = fmt.Errorf("error closing file %s: %w", ospNetworkDataFilePath, e)
×
163
                }
×
164
        }()
165
        if err = json.NewDecoder(networkDataf).Decode(&networkData); err != nil {
1✔
166
                return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospNetworkDataFilePath, err)
×
167
        }
×
168
        return metaData, networkData, err
1✔
169
}
170

171
func getBodyFromURL(url string) ([]byte, error) {
×
172
        log.Log.V(2).Info("Getting body from", "url", url)
×
173
        resp, err := retryablehttp.Get(url)
×
174
        if err != nil {
×
175
                return nil, err
×
176
        }
×
NEW
177
        defer resp.Body.Close()
×
178
        rawBytes, err := io.ReadAll(resp.Body)
×
179
        if err != nil {
×
180
                return nil, err
×
181
        }
×
182
        return rawBytes, nil
×
183
}
184

185
// getOpenstackDataFromMetadataService fetchs the metadata and network_data from the metadata service
186
func getOpenstackDataFromMetadataService() (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
×
187
        metaData = &OSPMetaData{}
×
188
        networkData = &OSPNetworkData{}
×
189
        log.Log.Info("getting OpenStack meta_data from metadata server")
×
190
        metaDataRawBytes, err := getBodyFromURL(ospMetaDataURL)
×
191
        if err != nil {
×
192
                return metaData, networkData, fmt.Errorf("error getting OpenStack meta_data from %s: %v", ospMetaDataURL, err)
×
193
        }
×
194
        err = json.Unmarshal(metaDataRawBytes, metaData)
×
195
        if err != nil {
×
196
                return metaData, networkData, fmt.Errorf("error unmarshalling raw bytes %v from %s", err, ospMetaDataURL)
×
197
        }
×
198

199
        log.Log.Info("getting OpenStack network_data from metadata server")
×
200
        networkDataRawBytes, err := getBodyFromURL(ospNetworkDataURL)
×
201
        if err != nil {
×
202
                return metaData, networkData, fmt.Errorf("error getting OpenStack network_data from %s: %v", ospNetworkDataURL, err)
×
203
        }
×
204
        err = json.Unmarshal(networkDataRawBytes, networkData)
×
205
        if err != nil {
×
206
                return metaData, networkData, fmt.Errorf("error unmarshalling raw bytes %v from %s", err, ospNetworkDataURL)
×
207
        }
×
208
        return metaData, networkData, nil
×
209
}
210

211
// getPCIAddressFromMACAddress returns the PCI address of a device given its MAC address
212
func getPCIAddressFromMACAddress(macAddress string, nics []*net.NIC) (string, error) {
1✔
213
        var pciAddress string
1✔
214
        for _, nic := range nics {
2✔
215
                if strings.EqualFold(nic.MacAddress, macAddress) {
2✔
216
                        if pciAddress == "" {
2✔
217
                                pciAddress = *nic.PCIAddress
1✔
218
                        } else {
1✔
219
                                return "", fmt.Errorf("more than one device found with MAC address %s is unsupported", macAddress)
×
220
                        }
×
221
                }
222
        }
223

224
        if pciAddress != "" {
2✔
225
                return pciAddress, nil
1✔
226
        }
1✔
227

228
        return "", fmt.Errorf("no device found with MAC address %s", macAddress)
×
229
}
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