Skip to content
Draft
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions liquidapi/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

// The following list of regexes is derived from a hardcoded list of valid values
// for an image's "vmware_ostype" attribute in Nova/Glance. This list was copied from
// for an image's "vmware_ostype" and "kvm_ostype" attributes in Nova/Glance. This list was copied from
// https://github.com/openstack/nova/blob/master/nova/virt/vmwareapi/constants.py
// and the comment over there says:
//
Expand All @@ -21,9 +21,9 @@ import (
// OSTypeProber. Therefore, we replaced all obvious version numbers in the valid
// values with placeholders, so that this does not break as easily in the future.
// We do not recommend utilizing this regex list for anything else other than
// validating the "vmware_ostype" attribute on existing images.
// validating the "vmware_ostype" and "kvm_ostype" attributes on existing images.

var isValidVMwareOSTypeRegex = []*regexp.Regexp{
var isValidOSTypeRegex = []*regexp.Regexp{
regexp.MustCompile(`^almalinux_64Guest$`),
regexp.MustCompile(`^amazonlinux(\d+)_64Guest$`),
regexp.MustCompile(`^asianux(\d+)_64Guest$`),
Expand Down
6 changes: 3 additions & 3 deletions liquidapi/constants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// so that we ensure our regexes catch all cases. Version updates should not
// break this, only "net-new" OS types will break the test.

func TestIsValidVMwareOSType(t *testing.T) {
func TestIsValidOSType(t *testing.T) {
var versionsToCheck = []string{
"almalinux_64Guest",
"amazonlinux2_64Guest",
Expand Down Expand Up @@ -211,12 +211,12 @@ func TestIsValidVMwareOSType(t *testing.T) {
}
for _, versionToCheck := range versionsToCheck {
t.Run(versionToCheck, func(t *testing.T) {
for _, regex := range isValidVMwareOSTypeRegex {
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(versionToCheck) {
return
}
}
t.Fatal(`version "` + versionToCheck + `" is not valid according to any of the regexes in isValidVMwareOSTypeRegex, but it should be`)
t.Fatal(`version "` + versionToCheck + `" is not valid according to any of the regexes in isValidOSTypeRegex, but it should be`)
})
}
}
23 changes: 20 additions & 3 deletions liquidapi/ostype_prober.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
// - "image-unknown", if no valid image reference exists in the instance metadata
// - "image-deleted", if the image has been deleted since the instance was booted
// - the value in the "vmware_ostype" attribute on the image metadata, if that field exists and the value is valid
// - the value in the "kvm_ostype" attribute on the image metadata, if that field exists and the value is valid
// - the value in the "properties.os_distro" attribute on the image metadata, if that field exists and the value is valid
// - "$TYPE", if the image metadata contains a tag of the form "ostype:$TYPE"
// - "unknown", if no other rule matches
//
Expand All @@ -37,6 +39,7 @@ import (
// - "rootdisk-missing", if the boot volume has an empty ID
// - "rootdisk-inspect-error", if the boot volume cannot be located or if its metadata cannot be inspected in Glance
// - the value in the "volume_image_metadata.vmware_ostype" attribute on the volume metadata, if that field exists and the value is valid
// - the value in the "volume_image_metadata.kvm_ostype" attribute on the volume metadata, if that field exists and the value is valid
// - "unknown", if no other rule matches
type OSTypeProber struct {
// caches for repeated queries
Expand Down Expand Up @@ -150,25 +153,32 @@ func (p *OSTypeProber) findFromBootVolume(ctx context.Context, instanceID string
var volume struct {
ImageMetadata struct {
VMwareOSType string `json:"vmware_ostype"`
KVMOSType string `json:"kvm_ostype"`
} `json:"volume_image_metadata"`
}
err = volumes.Get(ctx, p.CinderV3, rootVolumeID).ExtractInto(&volume)
if err != nil {
return "", err
}

for _, regex := range isValidVMwareOSTypeRegex {
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(volume.ImageMetadata.VMwareOSType) {
return volume.ImageMetadata.VMwareOSType, nil
}
}
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(volume.ImageMetadata.KVMOSType) {
return volume.ImageMetadata.KVMOSType, nil
}
}
return "unknown", nil
}

func (p *OSTypeProber) findFromImage(ctx context.Context, imageID string) (string, error) {
var result struct {
Tags []string `json:"tags"`
VMwareOSType string `json:"vmware_ostype"`
KVMOSType string `json:"kvm_ostype"`
Properties map[string]any `json:"properties"`
}
err := images.Get(ctx, p.GlanceV2, imageID).ExtractInto(&result)
Expand All @@ -182,15 +192,22 @@ func (p *OSTypeProber) findFromImage(ctx context.Context, imageID string) (strin
}

// prefer vmware_ostype attribute since this is validated by Nova upon booting the VM
for _, regex := range isValidVMwareOSTypeRegex {
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(result.VMwareOSType) {
return result.VMwareOSType, nil
}
}

// fall back to kvm_ostype if vmware_ostype is not set
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(result.KVMOSType) {
return result.KVMOSType, nil
}
}

// on some images, vmware_ostype values are maintained as properties.os_distro instead
if osDistroStr, ok := result.Properties["os_distro"].(string); ok {
for _, regex := range isValidVMwareOSTypeRegex {
for _, regex := range isValidOSTypeRegex {
if regex.MatchString(osDistroStr) {
return osDistroStr, nil
}
Expand Down
Loading