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

WIP: lang: core: os: Start virtualization detection #756

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Empty file.
1 change: 1 addition & 0 deletions lang/core/os/resources/aws_sys_class_dmi_id_board_vendor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Amazon EC2
1 change: 1 addition & 0 deletions lang/core/os/resources/aws_sys_class_dmi_id_product_name
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c5.large
1 change: 1 addition & 0 deletions lang/core/os/resources/aws_sys_class_dmi_id_sys_vendor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Amazon EC2
25 changes: 25 additions & 0 deletions lang/core/os/resources/docker_alpine_cgroup2_mountinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
5506 5311 0:128 / / rw,relatime master:1033 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/63JAQQCX4D3NBNCC7SA6BZF2BE:/var/lib/docker/overlay2/l/XPPMIFKZ6ZOPFZ4C5CA3UDPB2L:/var/lib/docker/overlay2/l/OSFZQIGTTGV2QU5LKW2M7WMVA6:/var/lib/docker/overlay2/l/5MHTHXY5TGQ3JKJQH7OJIFJO6M:/var/lib/docker/overlay2/l/K5MF443DO5FWT5PM3HTV5YBOCU:/var/lib/docker/overlay2/l/B2GGQI44SJ4VBZO6PEGHJJJOK6:/var/lib/docker/overlay2/l/LQH7WAAUSIW73MQSKJQTY3BB7R:/var/lib/docker/overlay2/l/574UAOLEE54CNNFP4HENM4E7JB:/var/lib/docker/overlay2/l/7XGVBS2LAAVXUVB6FRJN2KRDRD,upperdir=/var/lib/docker/overlay2/3feeb9390c590acc670a8f71e2a82dbaeb4313bfe93cdff0855cb1e4ed895929/diff,workdir=/var/lib/docker/overlay2/3feeb9390c590acc670a8f71e2a82dbaeb4313bfe93cdff0855cb1e4ed895929/work,nouserxattr
5507 5506 0:154 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
5508 5506 0:155 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5509 5508 0:156 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
5510 5506 0:157 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro
5511 5510 0:28 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw
5512 5508 0:152 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
5513 5508 0:158 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64
5514 5506 259:2 /var/lib/docker/containers/f939857cb4cc282d0a4687249c47d5cd2b92ae827486a7c5b00be3b2cea58a11/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5515 5506 259:2 /var/lib/docker/containers/f939857cb4cc282d0a4687249c47d5cd2b92ae827486a7c5b00be3b2cea58a11/hostname /etc/hostname rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5516 5506 259:2 /var/lib/docker/containers/f939857cb4cc282d0a4687249c47d5cd2b92ae827486a7c5b00be3b2cea58a11/hosts /etc/hosts rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5517 5506 259:2 /var/lib/docker/volumes/ae5c71da1f9b03b586fec23f61f421d0e1e3cc59363d36c8c7eebbd727efa6fd/_data /var/lib/postgresql/data rw,relatime master:1 - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5312 5508 0:156 /0 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
5313 5507 0:154 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw
5314 5507 0:154 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw
5315 5507 0:154 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw
5316 5507 0:154 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw
5317 5507 0:154 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw
5318 5507 0:159 / /proc/asound ro,relatime - tmpfs tmpfs ro,inode64
5319 5507 0:160 / /proc/acpi ro,relatime - tmpfs tmpfs ro,inode64
5320 5507 0:155 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5321 5507 0:155 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5322 5507 0:155 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5323 5507 0:161 / /proc/scsi ro,relatime - tmpfs tmpfs ro,inode64
5324 5510 0:162 / /sys/firmware ro,relatime - tmpfs tmpfs ro,inode64
24 changes: 24 additions & 0 deletions lang/core/os/resources/docker_ubuntu_cgroup2_mountinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
5548 5305 0:128 / / rw,relatime master:1033 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/EJ6MD7X7WZGYTRVU4XOFHOFOH7:/var/lib/docker/overlay2/l/YPTEQOEUARUJLT3442LPJIFTGQ,upperdir=/var/lib/docker/overlay2/9f137cc576eb5e346c32c97c89c59c2131135c0f8f6d3b1a882e506d69b6e0a9/diff,workdir=/var/lib/docker/overlay2/9f137cc576eb5e346c32c97c89c59c2131135c0f8f6d3b1a882e506d69b6e0a9/work,nouserxattr
5549 5548 0:154 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
5550 5548 0:155 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5551 5550 0:156 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
5552 5548 0:157 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro
5553 5552 0:28 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw
5555 5550 0:152 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
5556 5550 0:158 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64
5557 5548 259:2 /var/lib/docker/containers/663379e342690801630c8fc5760d7942e5236b3a4aa0229ad58f182d14f88a9f/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5558 5548 259:2 /var/lib/docker/containers/663379e342690801630c8fc5760d7942e5236b3a4aa0229ad58f182d14f88a9f/hostname /etc/hostname rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5559 5548 259:2 /var/lib/docker/containers/663379e342690801630c8fc5760d7942e5236b3a4aa0229ad58f182d14f88a9f/hosts /etc/hosts rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
5306 5550 0:156 /0 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
5307 5549 0:154 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw
5308 5549 0:154 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw
5309 5549 0:154 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw
5311 5549 0:154 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw
5312 5549 0:154 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw
5313 5549 0:159 / /proc/asound ro,relatime - tmpfs tmpfs ro,inode64
5314 5549 0:160 / /proc/acpi ro,relatime - tmpfs tmpfs ro,inode64
5315 5549 0:155 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5316 5549 0:155 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5317 5549 0:155 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64
5318 5549 0:161 / /proc/scsi ro,relatime - tmpfs tmpfs ro,inode64
5319 5552 0:162 / /sys/firmware ro,relatime - tmpfs tmpfs ro,inode64
1 change: 1 addition & 0 deletions lang/core/os/resources/lxc_proc_1_environ
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
container=lxc
14 changes: 14 additions & 0 deletions lang/core/os/resources/ubuntu_22.04_mountinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
177 29 7:27 / /snap/snapd-desktop-integration/83 ro,nodev,relatime shared:102 - squashfs /dev/loop27 ro,errors=continue,threads=single
180 29 259:1 / /boot/efi rw,relatime shared:104 - vfat /dev/nvme0n1p1 rw,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
183 36 0:36 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime shared:106 - binfmt_misc binfmt_misc rw
2102 27 0:24 /snapd/ns /run/snapd/ns rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,size=3257120k,mode=755,inode64
2143 2102 0:4 mnt:[4026532755] /run/snapd/ns/lxd.mnt rw - nsfs nsfs rw
2488 29 0:62 / /var/snap/lxd/common/ns rw,relatime - tmpfs tmpfs rw,size=1024k,mode=700,inode64
2528 2488 0:4 mnt:[4026532936] /var/snap/lxd/common/ns/shmounts rw - nsfs nsfs rw
2447 2488 0:4 mnt:[4026532755] /var/snap/lxd/common/ns/mntns rw - nsfs nsfs rw
3049 2102 0:4 mnt:[4026533029] /run/snapd/ns/snapd-desktop-integration.mnt rw - nsfs nsfs rw
2623 27 0:56 / /run/user/1000 rw,nosuid,nodev,relatime shared:1025 - tmpfs tmpfs rw,size=3257116k,nr_inodes=814279,mode=700,uid=1000,gid=1000,inode64
3158 2623 0:78 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:1337 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000
3204 2623 0:79 / /run/user/1000/doc rw,nosuid,nodev,relatime shared:1359 - fuse.portal portal rw,user_id=1000,group_id=1000
987 29 8:1 / /media/bstrausser/USB\040DISK rw,nosuid,nodev,relatime shared:946 - vfat /dev/sda1 rw,uid=1000,gid=1000,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,showexec,utf8,flush,errors=remount-ro
5264 29 0:128 / /var/lib/docker/overlay2/3feeb9390c590acc670a8f71e2a82dbaeb4313bfe93cdff0855cb1e4ed895929/merged rw,relatime shared:1033 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/63JAQQCX4D3NBNCC7SA6BZF2BE:/var/lib/docker/overlay2/l/XPPMIFKZ6ZOPFZ4C5CA3UDPB2L:/var/lib/docker/overlay2/l/OSFZQIGTTGV2QU5LKW2M7WMVA6:/var/lib/docker/overlay2/l/5MHTHXY5TGQ3JKJQH7OJIFJO6M:/var/lib/docker/overlay2/l/K5MF443DO5FWT5PM3HTV5YBOCU:/var/lib/docker/overlay2/l/B2GGQI44SJ4VBZO6PEGHJJJOK6:/var/lib/docker/overlay2/l/LQH7WAAUSIW73MQSKJQTY3BB7R:/var/lib/docker/overlay2/l/574UAOLEE54CNNFP4HENM4E7JB:/var/lib/docker/overlay2/l/7XGVBS2LAAVXUVB6FRJN2KRDRD,upperdir=/var/lib/docker/overlay2/3feeb9390c590acc670a8f71e2a82dbaeb4313bfe93cdff0855cb1e4ed895929/diff,workdir=/var/lib/docker/overlay2/3feeb9390c590acc670a8f71e2a82dbaeb4313bfe93cdff0855cb1e4ed895929/work,nouserxattr
221 changes: 221 additions & 0 deletions lang/core/os/virtualization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package coreos

import (
"bufio"
"net/http"
"os"
"strings"
"time"

"github.com/purpleidea/mgmt/lang/types"
)

const (
VIRTUALIZATION_EC2 = "ec2"
VIRTUALIZATION_GCE = "GCE"
VIRTUALIZATION_DOCKER = "docker"
VIRTUALIZATION_PODMAN = "podman"
VIRTUALIZATION_LXC = "lxc"
VIRTUALIZATION_NONE = "none"
)

type (
fileTargetPredicate func(fileTarget) bool
networkTargetPredicate func(networkTarget) bool
)

// TODO fileTarget should probably take a func(string) (bool,error)
type fileTarget struct {
file string
target string
existsOnly bool
}

// TODO networkTarget should probably take a func(response) (bool,error)
type networkTarget struct {
url string
headerVal string
headerKey string
}

type (
fileTargets []fileTarget
networkTargets []networkTarget
)

type VirtualizationPlatform interface {
checkFiles() bool
checkNetwork() bool
evaluate() string
}

type ConcretePlatform struct {
name string
fileTargets fileTargets
networkTargets networkTargets
}

var ec2Platform = ConcretePlatform{
name: VIRTUALIZATION_EC2,
fileTargets: []fileTarget{
{file: "/sys/class/dmi/id/board_vendor", target: "Amazon EC2"},
{file: "/sys/class/dmi/id/sys_vendor", target: "Amazon EC2"},
},
}

var gcePlatform = ConcretePlatform{
name: VIRTUALIZATION_GCE,
networkTargets: []networkTarget{
{url: "metadata.google.internal", headerKey: "Metadata-Flavor", headerVal: "Google"},
},
}

var dockerPlatform = ConcretePlatform{
name: VIRTUALIZATION_DOCKER,
fileTargets: []fileTarget{
{file: "/.dockerenv", existsOnly: true},
{file: "/proc/self/mountinfo", target: "docker/containers"},
},
}

var podmanPlatform = ConcretePlatform{
name: VIRTUALIZATION_PODMAN,
fileTargets: []fileTarget{
{file: "/.dockerenv", existsOnly: true},
{file: "/proc/self/mountinfo", target: "docker/containers"},
},
}

var lxcPlatform = ConcretePlatform{
name: VIRTUALIZATION_LXC,
fileTargets: []fileTarget{
{file: "/proc/1/environ", target: "container=lxc"},
},
}

func checkInNetwork(networkTarget networkTarget) bool {
tr := &http.Transport{
MaxIdleConns: 5,
ResponseHeaderTimeout: 10 * time.Second,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}

client := &http.Client{Transport: tr}

resp, err := client.Get(networkTarget.url)
if err != nil {
return false
}
actualHeader := resp.Header.Get(networkTarget.headerKey)
if actualHeader == networkTarget.headerVal {
return true
}
return false
}

func scanFile(fileTarget fileTarget) bool {
f, err := os.OpenFile(fileTarget.file, os.O_RDONLY, os.ModePerm)
if err != nil {
return false
}
defer f.Close()

if fileTarget.existsOnly {
return true
}

sc := bufio.NewScanner(f)
for sc.Scan() {
line := sc.Text() // GET the line string
if strings.Contains(line, fileTarget.target) {
return true
}
}
if err := sc.Err(); err != nil {
return false
}
return false
}

func (plat *ConcretePlatform) checkFiles() bool {
for _, targetFile := range plat.fileTargets {
result := scanFile(targetFile)
if result {
return result
}
}

return false
}

func (plat *ConcretePlatform) checkNetwork() bool {
for _, targetFile := range plat.networkTargets {
result := checkInNetwork(targetFile)
if result {
return result
}
}

return false
}

func (plat *ConcretePlatform) evaluate() string {
switch true {
case plat.checkNetwork():
return plat.name
case plat.checkFiles():
return plat.name
case false:

}
return VIRTUALIZATION_NONE
}

func isEc2Instance() string {
return ec2Platform.evaluate()
}

func isGCEInstance() string {
return gcePlatform.evaluate()
}

func isDockerContainer() string {
return dockerPlatform.evaluate()
}

func isLxcContainer() string {
return lxcPlatform.evaluate()
}

func isPodManContainer() string {
return lxcPlatform.evaluate()
}

func isContainer() string {
isContainerFuncs := []func() string{isDockerContainer, isPodManContainer, isLxcContainer}
for _, isContainerFunc := range isContainerFuncs {

containerPlatform := isContainerFunc()
if containerPlatform != VIRTUALIZATION_NONE {
return containerPlatform
}

}

return VIRTUALIZATION_NONE
}

func IsVirtualized(input []types.Value) (types.Value, error) {
platform := isContainer()

virtualizationDetected := platform != VIRTUALIZATION_NONE

return &types.StructValue{
T: types.NewType("struct{isVirtualized bool; platform str}"),
V: map[string]types.Value{
"isVirtualized": &types.BoolValue{V: virtualizationDetected},
"platformName": &types.StrValue{V: platform},
},
}, nil
}
Loading