Skip to content

Commit 084810a

Browse files
committed
openstack: dynamically mount the config-drive
When we want to use config-drive in immutable systems, very often the config-drive is only used at boot and then umounted (e.g. ignition does this). Later when we want to fetch Metadata from the config drive, we actually have to mount it. In this PR, I'm adding similar code than coreos/ignition where we dynamically mount the config-drive is the device was found with the right label (config-2 or CONFIG-2 as documented in OpenStack). If the device is found, we mount it, fetch the data and umount it.
1 parent 4bae6ce commit 084810a

File tree

1 file changed

+92
-23
lines changed

1 file changed

+92
-23
lines changed

pkg/platforms/openstack/openstack.go

Lines changed: 92 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"io"
77
"os"
8+
"os/exec"
9+
"path/filepath"
810
"strconv"
911
"strings"
1012

@@ -21,15 +23,18 @@ import (
2123
)
2224

2325
const (
24-
ospHostMetaDataDir = "/host/var/config/openstack/2018-08-27"
25-
ospMetaDataDir = "/var/config/openstack/2018-08-27"
26-
ospMetaDataBaseURL = "http://169.254.169.254/openstack/2018-08-27"
27-
ospNetworkDataJSON = "network_data.json"
28-
ospMetaDataJSON = "meta_data.json"
29-
ospHostNetworkDataFile = ospHostMetaDataDir + "/" + ospNetworkDataJSON
30-
ospHostMetaDataFile = ospHostMetaDataDir + "/" + ospMetaDataJSON
31-
ospNetworkDataURL = ospMetaDataBaseURL + "/" + ospNetworkDataJSON
32-
ospMetaDataURL = ospMetaDataBaseURL + "/" + ospMetaDataJSON
26+
varConfigPath = "/var/config"
27+
ospMetaDataBaseDir = "/openstack/2018-08-27"
28+
ospMetaDataDir = varConfigPath + ospMetaDataBaseDir
29+
ospMetaDataBaseURL = "http://169.254.169.254" + ospMetaDataBaseDir
30+
ospNetworkDataJSON = "network_data.json"
31+
ospMetaDataJSON = "meta_data.json"
32+
ospNetworkDataURL = ospMetaDataBaseURL + "/" + ospNetworkDataJSON
33+
ospMetaDataURL = ospMetaDataBaseURL + "/" + ospMetaDataJSON
34+
// Config drive is defined as an iso9660 or vfat (deprecated) drive
35+
// with the "config-2" label.
36+
//https://docs.openstack.org/nova/latest/user/config-drive.html
37+
configDriveLabel = "config-2"
3338
)
3439

3540
var (
@@ -109,9 +114,10 @@ func New(hostManager host.HostManagerInterface) OpenstackInterface {
109114
}
110115

111116
// GetOpenstackData gets the metadata and network_data
112-
func getOpenstackData(useHostPath bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
113-
metaData, networkData, err = getOpenstackDataFromConfigDrive(useHostPath)
117+
func getOpenstackData(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
118+
metaData, networkData, err = getOpenstackDataFromConfigDrive(mountConfigDrive)
114119
if err != nil {
120+
log.Log.Error(err, "GetOpenStackData(): non-fatal error getting OpenStack data from config drive")
115121
metaData, networkData, err = getOpenstackDataFromMetadataService()
116122
if err != nil {
117123
return metaData, networkData, fmt.Errorf("GetOpenStackData(): error getting OpenStack data: %w", err)
@@ -153,46 +159,109 @@ func getOpenstackData(useHostPath bool) (metaData *OSPMetaData, networkData *OSP
153159
return metaData, networkData, err
154160
}
155161

162+
// getConfigDriveDevice returns the config drive device which was found
163+
func getConfigDriveDevice() (string, error) {
164+
dev := "/dev/disk/by-label/" + configDriveLabel
165+
if _, err := os.Stat(dev); os.IsNotExist(err) {
166+
out, err := exec.Command(
167+
"blkid", "-l",
168+
"-t", "LABEL="+configDriveLabel,
169+
"-o", "device",
170+
).CombinedOutput()
171+
if err != nil {
172+
return "", fmt.Errorf("unable to run blkid: %v", err)
173+
}
174+
dev = strings.TrimSpace(string(out))
175+
}
176+
log.Log.Info("found config drive device", "device", dev)
177+
return dev, nil
178+
}
179+
180+
// mountConfigDriveDevice mounts the config drive and return the path
181+
func mountConfigDriveDevice(device string) (string, error) {
182+
if device == "" {
183+
return "", fmt.Errorf("device is empty")
184+
}
185+
tmpDir, err := os.MkdirTemp("", "sriov-configdrive")
186+
if err != nil {
187+
return "", fmt.Errorf("error creating temp directory: %w", err)
188+
}
189+
cmd := exec.Command("mount", "-o", "ro", "-t", "auto", device, tmpDir)
190+
if err := cmd.Run(); err != nil {
191+
return "", fmt.Errorf("error mounting config drive: %w", err)
192+
}
193+
log.Log.V(2).Info("mounted config drive device", "device", device, "path", tmpDir)
194+
return tmpDir, nil
195+
}
196+
197+
// ummountConfigDriveDevice ummounts the config drive device
198+
func ummountConfigDriveDevice(path string) error {
199+
if path == "" {
200+
return fmt.Errorf("path is empty")
201+
}
202+
cmd := exec.Command("umount", path)
203+
if err := cmd.Run(); err != nil {
204+
return fmt.Errorf("error umounting config drive: %w", err)
205+
}
206+
log.Log.V(2).Info("umounted config drive", "path", path)
207+
return nil
208+
}
209+
156210
// getOpenstackDataFromConfigDrive reads the meta_data and network_data files
157-
func getOpenstackDataFromConfigDrive(useHostPath bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
211+
func getOpenstackDataFromConfigDrive(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
158212
metaData = &OSPMetaData{}
159213
networkData = &OSPNetworkData{}
214+
var configDrivePath string
160215
log.Log.Info("reading OpenStack meta_data from config-drive")
161216
var metadataf *os.File
162217
ospMetaDataFilePath := ospMetaDataFile
163-
if useHostPath {
164-
ospMetaDataFilePath = ospHostMetaDataFile
218+
if mountConfigDrive {
219+
configDriveDevice, err := getConfigDriveDevice()
220+
if err != nil {
221+
return metaData, networkData, fmt.Errorf("error finding config drive device: %w", err)
222+
}
223+
configDrivePath, err = mountConfigDriveDevice(configDriveDevice)
224+
if err != nil {
225+
return metaData, networkData, fmt.Errorf("error mounting config drive device: %w", err)
226+
}
227+
defer func() {
228+
if e := ummountConfigDriveDevice(configDrivePath); err == nil && e != nil {
229+
err = fmt.Errorf("error umounting config drive device: %w", e)
230+
}
231+
if e := os.Remove(configDrivePath); err == nil && e != nil {
232+
err = fmt.Errorf("error removing temp directory %s: %w", configDrivePath, e)
233+
}
234+
}()
235+
ospMetaDataFilePath = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospMetaDataJSON)
236+
ospNetworkDataFile = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospNetworkDataJSON)
165237
}
166238
metadataf, err = os.Open(ospMetaDataFilePath)
167239
if err != nil {
168-
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospHostMetaDataFile, err)
240+
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospMetaDataFilePath, err)
169241
}
170242
defer func() {
171243
if e := metadataf.Close(); err == nil && e != nil {
172-
err = fmt.Errorf("error closing file %s: %w", ospHostMetaDataFile, e)
244+
err = fmt.Errorf("error closing file %s: %w", ospMetaDataFilePath, e)
173245
}
174246
}()
175247
if err = json.NewDecoder(metadataf).Decode(&metaData); err != nil {
176-
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospHostMetaDataFile, err)
248+
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospMetaDataFilePath, err)
177249
}
178250

179251
log.Log.Info("reading OpenStack network_data from config-drive")
180252
var networkDataf *os.File
181253
ospNetworkDataFilePath := ospNetworkDataFile
182-
if useHostPath {
183-
ospNetworkDataFilePath = ospHostNetworkDataFile
184-
}
185254
networkDataf, err = os.Open(ospNetworkDataFilePath)
186255
if err != nil {
187-
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospHostNetworkDataFile, err)
256+
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospNetworkDataFilePath, err)
188257
}
189258
defer func() {
190259
if e := networkDataf.Close(); err == nil && e != nil {
191-
err = fmt.Errorf("error closing file %s: %w", ospHostNetworkDataFile, e)
260+
err = fmt.Errorf("error closing file %s: %w", ospNetworkDataFilePath, e)
192261
}
193262
}()
194263
if err = json.NewDecoder(networkDataf).Decode(&networkData); err != nil {
195-
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospHostNetworkDataFile, err)
264+
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospNetworkDataFilePath, err)
196265
}
197266
return metaData, networkData, err
198267
}

0 commit comments

Comments
 (0)