forked from linuxkit/linuxkit
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds the openstack config-drive provider
https://github.com/canonical/cloud-init/blob/main/doc/rtd/reference/datasources/configdrive.rst As this shares so much stuff with the cdrom provider, I reconfigured things around to have shared methods between them for ease of use. Signed-off-by: Itxaka <[email protected]>
- Loading branch information
1 parent
541cb6a
commit fa64b2f
Showing
3 changed files
with
206 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package providers | ||
|
||
import ( | ||
"fmt" | ||
"github.com/diskfs/go-diskfs" | ||
log "github.com/sirupsen/logrus" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
"syscall" | ||
) | ||
|
||
const ( | ||
cdromDevs = "/dev/sr[0-9]*" | ||
blockDevs = "/sys/class/block/*" | ||
) | ||
|
||
// ProviderCDROM is the type implementing the Provider interface for CDROMs (nocloud/config-drive) | ||
type ProviderCDROM struct { | ||
providerType string | ||
device string | ||
mountPoint string | ||
err error | ||
userdata []byte | ||
} | ||
|
||
func (p *ProviderCDROM) String() string { | ||
return fmt.Sprintf("%s(%s)", p.providerType, p.device) | ||
} | ||
|
||
// Probe checks if the CD has the right file | ||
func (p *ProviderCDROM) Probe() bool { | ||
if p.err != nil { | ||
log.Errorf("there were errors probing %s: %v", p.device, p.err) | ||
} | ||
return len(p.userdata) != 0 | ||
} | ||
|
||
// Extract gets both the CDROM specific and generic userdata | ||
func (p *ProviderCDROM) Extract() ([]byte, error) { | ||
return p.userdata, p.err | ||
} | ||
|
||
// mount mounts a CDROM/DVD device under mountPoint | ||
func (p *ProviderCDROM) mount() error { | ||
var err error | ||
// We may need to poll a little for device ready | ||
errISO := syscall.Mount(p.device, p.mountPoint, "iso9660", syscall.MS_RDONLY, "") | ||
if errISO != nil { | ||
errFat := syscall.Mount(p.device, p.mountPoint, "vfat", syscall.MS_RDONLY, "") | ||
if errFat != nil { | ||
err = fmt.Errorf("failed mounting %s: %v %v", p.device, errISO, errFat) | ||
p.err = err | ||
} | ||
} | ||
return err | ||
} | ||
|
||
// unmount removes the mount | ||
func (p *ProviderCDROM) unmount() { | ||
_ = syscall.Unmount(p.mountPoint, 0) | ||
} | ||
|
||
// uniqueString returns a unique subset of the string slice provided. | ||
func uniqueString(input []string) []string { | ||
u := make([]string, 0, len(input)) | ||
m := make(map[string]bool) | ||
|
||
for _, val := range input { | ||
if _, ok := m[val]; !ok { | ||
m[val] = true | ||
u = append(u, val) | ||
} | ||
} | ||
|
||
return u | ||
} | ||
|
||
func NewProviderCDROM(device string, datafiles []string, providerType string) *ProviderCDROM { | ||
mountPoint, err := os.MkdirTemp("", "cd") | ||
p := ProviderCDROM{providerType, device, mountPoint, err, []byte{}} | ||
if err == nil { | ||
if p.err = p.mount(); p.err == nil { | ||
defer p.unmount() | ||
// read the userdata - we read the spec file and the fallback, but eventually | ||
// will remove the fallback | ||
for _, f := range datafiles { | ||
userdata, err := os.ReadFile(path.Join(p.mountPoint, f)) | ||
// did we find a file? | ||
if err == nil && userdata != nil { | ||
p.userdata = userdata | ||
break | ||
} | ||
} | ||
if p.userdata == nil { | ||
log.Debugf("no userdata file found at any of %v", datafiles) | ||
} | ||
} | ||
} | ||
return &p | ||
} | ||
|
||
// FindCIs goes through all known devices and checks for the given label | ||
// https://github.com/canonical/cloud-init/blob/main/doc/rtd/reference/datasources/configdrive.rst | ||
// https://github.com/canonical/cloud-init/blob/master/doc/rtd/topics/datasources/nocloud.rst | ||
func FindCIs(findLabel string) []string { | ||
devs, err := filepath.Glob(blockDevs) | ||
log.Debugf("block devices found: %v", devs) | ||
if err != nil { | ||
// Glob can only error on invalid pattern | ||
panic(fmt.Sprintf("Invalid glob pattern: %s", blockDevs)) | ||
} | ||
foundDevices := []string{} | ||
for _, device := range devs { | ||
// get the base device name | ||
dev := filepath.Base(device) | ||
// ignore loop and ram devices | ||
if strings.HasPrefix(dev, "loop") || strings.HasPrefix(dev, "ram") { | ||
log.Debugf("ignoring loop or ram device: %s", dev) | ||
continue | ||
} | ||
dev = fmt.Sprintf("/dev/%s", dev) | ||
log.Debugf("checking device: %s", dev) | ||
// open readonly, ignore errors | ||
disk, err := diskfs.Open(dev, diskfs.WithOpenMode(diskfs.ReadOnly)) | ||
if err != nil { | ||
log.Debugf("failed to open device read-only: %s: %v", dev, err) | ||
continue | ||
} | ||
disk.DefaultBlocks = true | ||
fs, err := disk.GetFilesystem(0) | ||
if err != nil { | ||
log.Debugf("failed to get filesystem on partition 0 for device: %s: %v", dev, err) | ||
_ = disk.File.Close() | ||
continue | ||
} | ||
// get the label | ||
label := strings.TrimSpace(fs.Label()) | ||
log.Debugf("found trimmed filesystem label for device: %s: '%s'", dev, label) | ||
if label == strings.ToUpper(findLabel) || label == strings.ToLower(findLabel) { | ||
log.Debugf("adding device: %s", dev) | ||
foundDevices = append(foundDevices, dev) | ||
} | ||
err = disk.File.Close() | ||
if err != nil { | ||
log.Debugf("failed closing device %s", dev) | ||
} | ||
} | ||
return foundDevices | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
Copyright © 2022 - 2023 SUSE LLC | ||
Copyright © 2015-2017 Docker, Inc. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package providers | ||
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
// ListConfigDrives lists all the cdroms in the system the fill the config-drive standard | ||
func ListConfigDrives() []Provider { | ||
// UserdataFiles is where to find the user data | ||
var userdataFiles = []string{"/openstack/latest/user_data"} | ||
cdroms, err := filepath.Glob(cdromDevs) | ||
if err != nil { | ||
// Glob can only error on invalid pattern | ||
panic(fmt.Sprintf("Invalid glob pattern: %s", cdromDevs)) | ||
} | ||
log.Debugf("cdrom devices to be checked: %v", cdroms) | ||
// get the devices that match the cloud-init spec | ||
cidevs := FindCIs("config-2") | ||
log.Debugf("CONFIG-2 devices to be checked: %v", cidevs) | ||
// merge the two, ensuring that the list is unique | ||
cdroms = append(cidevs, cdroms...) | ||
cdroms = uniqueString(cdroms) | ||
log.Debugf("unique devices to be checked: %v", cdroms) | ||
var providers []Provider | ||
for _, device := range cdroms { | ||
providers = append(providers, NewProviderCDROM(device, userdataFiles, "CONFIG_DRIVE")) | ||
} | ||
return providers | ||
} |