Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openstack: dynamically mount the config-drive #773

Merged
merged 1 commit into from
Oct 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 92 additions & 23 deletions pkg/platforms/openstack/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"

Expand All @@ -21,15 +23,18 @@ import (
)

const (
ospHostMetaDataDir = "/host/var/config/openstack/2018-08-27"
ospMetaDataDir = "/var/config/openstack/2018-08-27"
ospMetaDataBaseURL = "http://169.254.169.254/openstack/2018-08-27"
ospNetworkDataJSON = "network_data.json"
ospMetaDataJSON = "meta_data.json"
ospHostNetworkDataFile = ospHostMetaDataDir + "/" + ospNetworkDataJSON
ospHostMetaDataFile = ospHostMetaDataDir + "/" + ospMetaDataJSON
ospNetworkDataURL = ospMetaDataBaseURL + "/" + ospNetworkDataJSON
ospMetaDataURL = ospMetaDataBaseURL + "/" + ospMetaDataJSON
varConfigPath = "/var/config"
ospMetaDataBaseDir = "/openstack/2018-08-27"
ospMetaDataDir = varConfigPath + ospMetaDataBaseDir
ospMetaDataBaseURL = "http://169.254.169.254" + ospMetaDataBaseDir
ospNetworkDataJSON = "network_data.json"
ospMetaDataJSON = "meta_data.json"
ospNetworkDataURL = ospMetaDataBaseURL + "/" + ospNetworkDataJSON
ospMetaDataURL = ospMetaDataBaseURL + "/" + ospMetaDataJSON
// Config drive is defined as an iso9660 or vfat (deprecated) drive
// with the "config-2" label.
//https://docs.openstack.org/nova/latest/user/config-drive.html
configDriveLabel = "config-2"
)

var (
Expand Down Expand Up @@ -109,9 +114,10 @@ func New(hostManager host.HostManagerInterface) OpenstackInterface {
}

// GetOpenstackData gets the metadata and network_data
func getOpenstackData(useHostPath bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
metaData, networkData, err = getOpenstackDataFromConfigDrive(useHostPath)
func getOpenstackData(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
metaData, networkData, err = getOpenstackDataFromConfigDrive(mountConfigDrive)
if err != nil {
log.Log.Error(err, "GetOpenStackData(): non-fatal error getting OpenStack data from config drive")
metaData, networkData, err = getOpenstackDataFromMetadataService()
if err != nil {
return metaData, networkData, fmt.Errorf("GetOpenStackData(): error getting OpenStack data: %w", err)
Expand Down Expand Up @@ -153,46 +159,109 @@ func getOpenstackData(useHostPath bool) (metaData *OSPMetaData, networkData *OSP
return metaData, networkData, err
}

// getConfigDriveDevice returns the config drive device which was found
func getConfigDriveDevice() (string, error) {
dev := "/dev/disk/by-label/" + configDriveLabel
if _, err := os.Stat(dev); os.IsNotExist(err) {
out, err := exec.Command(
"blkid", "-l",
"-t", "LABEL="+configDriveLabel,
"-o", "device",
).CombinedOutput()
if err != nil {
return "", fmt.Errorf("unable to run blkid: %v", err)
}
dev = strings.TrimSpace(string(out))
}
log.Log.Info("found config drive device", "device", dev)
return dev, nil
}

// mountConfigDriveDevice mounts the config drive and return the path
func mountConfigDriveDevice(device string) (string, error) {
if device == "" {
return "", fmt.Errorf("device is empty")
}
tmpDir, err := os.MkdirTemp("", "sriov-configdrive")
if err != nil {
return "", fmt.Errorf("error creating temp directory: %w", err)
}
cmd := exec.Command("mount", "-o", "ro", "-t", "auto", device, tmpDir)
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("error mounting config drive: %w", err)
}
log.Log.V(2).Info("mounted config drive device", "device", device, "path", tmpDir)
return tmpDir, nil
}

// ummountConfigDriveDevice ummounts the config drive device
func ummountConfigDriveDevice(path string) error {
if path == "" {
return fmt.Errorf("path is empty")
}
cmd := exec.Command("umount", path)
if err := cmd.Run(); err != nil {
return fmt.Errorf("error umounting config drive: %w", err)
}
log.Log.V(2).Info("umounted config drive", "path", path)
return nil
}

// getOpenstackDataFromConfigDrive reads the meta_data and network_data files
func getOpenstackDataFromConfigDrive(useHostPath bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
func getOpenstackDataFromConfigDrive(mountConfigDrive bool) (metaData *OSPMetaData, networkData *OSPNetworkData, err error) {
metaData = &OSPMetaData{}
networkData = &OSPNetworkData{}
var configDrivePath string
log.Log.Info("reading OpenStack meta_data from config-drive")
var metadataf *os.File
ospMetaDataFilePath := ospMetaDataFile
if useHostPath {
ospMetaDataFilePath = ospHostMetaDataFile
if mountConfigDrive {
configDriveDevice, err := getConfigDriveDevice()
if err != nil {
return metaData, networkData, fmt.Errorf("error finding config drive device: %w", err)
}
configDrivePath, err = mountConfigDriveDevice(configDriveDevice)
if err != nil {
return metaData, networkData, fmt.Errorf("error mounting config drive device: %w", err)
}
defer func() {
if e := ummountConfigDriveDevice(configDrivePath); err == nil && e != nil {
err = fmt.Errorf("error umounting config drive device: %w", e)
}
if e := os.Remove(configDrivePath); err == nil && e != nil {
err = fmt.Errorf("error removing temp directory %s: %w", configDrivePath, e)
}
}()
ospMetaDataFilePath = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospMetaDataJSON)
ospNetworkDataFile = filepath.Join(configDrivePath, ospMetaDataBaseDir, ospNetworkDataJSON)
}
metadataf, err = os.Open(ospMetaDataFilePath)
if err != nil {
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospHostMetaDataFile, err)
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospMetaDataFilePath, err)
}
defer func() {
if e := metadataf.Close(); err == nil && e != nil {
err = fmt.Errorf("error closing file %s: %w", ospHostMetaDataFile, e)
err = fmt.Errorf("error closing file %s: %w", ospMetaDataFilePath, e)
}
}()
if err = json.NewDecoder(metadataf).Decode(&metaData); err != nil {
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospHostMetaDataFile, err)
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospMetaDataFilePath, err)
}

log.Log.Info("reading OpenStack network_data from config-drive")
var networkDataf *os.File
ospNetworkDataFilePath := ospNetworkDataFile
if useHostPath {
ospNetworkDataFilePath = ospHostNetworkDataFile
}
networkDataf, err = os.Open(ospNetworkDataFilePath)
if err != nil {
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospHostNetworkDataFile, err)
return metaData, networkData, fmt.Errorf("error opening file %s: %w", ospNetworkDataFilePath, err)
}
defer func() {
if e := networkDataf.Close(); err == nil && e != nil {
err = fmt.Errorf("error closing file %s: %w", ospHostNetworkDataFile, e)
err = fmt.Errorf("error closing file %s: %w", ospNetworkDataFilePath, e)
}
}()
if err = json.NewDecoder(networkDataf).Decode(&networkData); err != nil {
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospHostNetworkDataFile, err)
return metaData, networkData, fmt.Errorf("error unmarshalling metadata from file %s: %w", ospNetworkDataFilePath, err)
}
return metaData, networkData, err
}
Expand Down
Loading