add ability to store/create encrypted vcenter password
Some checks are pending
CI / Lint (push) Waiting to run
CI / Test (push) Waiting to run
CI / End-to-End (push) Waiting to run
CI / Publish Docker (push) Blocked by required conditions
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-09-27 17:02:02 +10:00
parent 5a00f4a8c7
commit 3501967c9e
13 changed files with 235 additions and 772 deletions

View File

@@ -0,0 +1,80 @@
package secrets
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"io"
"log/slog"
)
type Secrets struct {
Logger *slog.Logger
EncryptionKey []byte
}
func New(logger *slog.Logger, key []byte) *Secrets {
return &Secrets{
Logger: logger,
EncryptionKey: key,
}
}
// Encrypt function that encrypts data using AES256-GCM and returns base64 encoded ciphertext
func (s *Secrets) Encrypt(plainText []byte) (string, error) {
block, err := aes.NewCipher(s.EncryptionKey)
if err != nil {
return "", err
}
// Create a new GCM cipher
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
// Create a nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}
// Encrypt the plaintext using AES256-GCM
cipherText := gcm.Seal(nonce, nonce, plainText, nil)
// Return the base64 encoded ciphertext
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// Decrypt function that decrypts base64 encoded AES256-GCM ciphertext
func (s *Secrets) Decrypt(base64CipherText string) ([]byte, error) {
// Decode the base64 ciphertext
cipherText, err := base64.StdEncoding.DecodeString(base64CipherText)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(s.EncryptionKey)
if err != nil {
return nil, err
}
// Create a new GCM cipher
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
// Extract the nonce from the ciphertext
nonceSize := gcm.NonceSize()
nonce, cipherText := cipherText[:nonceSize], cipherText[nonceSize:]
// Decrypt the ciphertext
plainText, err := gcm.Open(nil, nonce, cipherText, nil)
if err != nil {
return nil, err
}
return plainText, nil
}

View File

@@ -11,17 +11,6 @@ import (
// SettingsYML struct holds various runtime data that is too cumbersome to specify via command line, eg replacement properties // SettingsYML struct holds various runtime data that is too cumbersome to specify via command line, eg replacement properties
type SettingsYML struct { type SettingsYML struct {
Settings struct { Settings struct {
/*
Replacements []struct {
Key string `yaml:"Key"`
Value string `yaml:"Value"`
} `yaml:"replacements"`
Omapi struct {
KeyName string `yaml:"key_name"`
KeySecret string `yaml:"key_secret"`
} `yaml:"omapi"`
*/
TenantsToFilter []string `yaml:"tenants_to_filter"` TenantsToFilter []string `yaml:"tenants_to_filter"`
NodeChargeClusters []string `yaml:"node_charge_clusters"` NodeChargeClusters []string `yaml:"node_charge_clusters"`
SrmActiveActiveVms []string `yaml:"srm_activeactive_vms"` SrmActiveActiveVms []string `yaml:"srm_activeactive_vms"`

View File

@@ -5,21 +5,12 @@ import (
"database/sql" "database/sql"
"log/slog" "log/slog"
"time" "time"
"vctp/db"
"vctp/db/queries" "vctp/db/queries"
"vctp/internal/settings"
"vctp/internal/vcenter" "vctp/internal/vcenter"
"github.com/vmware/govmomi/vim25/types" "github.com/vmware/govmomi/vim25/types"
) )
// Handler handles requests.
type CronTask struct {
Logger *slog.Logger
Database db.Database
Settings settings.SettingsYML
}
// use gocron to check events in the Events table // use gocron to check events in the Events table
func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error {
var ( var (
@@ -42,6 +33,8 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error {
if err != nil { if err != nil {
logger.Error("Unable to query for unprocessed events", "error", err) logger.Error("Unable to query for unprocessed events", "error", err)
return nil // TODO - what to do with this error? return nil // TODO - what to do with this error?
} else {
logger.Debug("Successfully queried for unprocessed events", "count", len(events))
} }
for _, evt := range events { for _, evt := range events {
@@ -51,7 +44,7 @@ func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error {
// to avoid doing unnecessary login/logout of vcenter // to avoid doing unnecessary login/logout of vcenter
c.Logger.Debug("connecting to vcenter") c.Logger.Debug("connecting to vcenter")
vc := vcenter.New(c.Logger) vc := vcenter.New(c.Logger, c.VcCreds)
vc.Login(evt.Source) vc.Login(evt.Source)
//datacenter = evt.DatacenterName.String //datacenter = evt.DatacenterName.String

16
internal/tasks/tasks.go Normal file
View File

@@ -0,0 +1,16 @@
package tasks
import (
"log/slog"
"vctp/db"
"vctp/internal/settings"
"vctp/internal/vcenter"
)
// CronTask stores runtime information to be used by tasks
type CronTask struct {
Logger *slog.Logger
Database db.Database
Settings settings.SettingsYML
VcCreds *vcenter.VcenterLogin
}

View File

@@ -22,6 +22,12 @@ type Vcenter struct {
Logger *slog.Logger Logger *slog.Logger
ctx context.Context ctx context.Context
client *govmomi.Client client *govmomi.Client
credentials *VcenterLogin
}
type VcenterLogin struct {
Username string
Password string
} }
type VmProperties struct { type VmProperties struct {
@@ -30,7 +36,7 @@ type VmProperties struct {
} }
// New creates a new Vcenter with the given logger // New creates a new Vcenter with the given logger
func New(logger *slog.Logger) *Vcenter { func New(logger *slog.Logger, creds *VcenterLogin) *Vcenter {
//ctx, cancel := context.WithCancel(context.Background()) //ctx, cancel := context.WithCancel(context.Background())
//defer cancel() //defer cancel()
@@ -38,15 +44,17 @@ func New(logger *slog.Logger) *Vcenter {
return &Vcenter{ return &Vcenter{
Logger: logger, Logger: logger,
ctx: context.Background(), ctx: context.Background(),
credentials: creds,
} }
} }
func (v *Vcenter) Login(vUrl string) error { func (v *Vcenter) Login(vUrl string) error {
var insecure bool var insecure bool
// TODO - fix this
insecureString := os.Getenv("VCENTER_INSECURE") insecureString := os.Getenv("VCENTER_INSECURE")
username := os.Getenv("VCENTER_USERNAME") //username := os.Getenv("VCENTER_USERNAME")
password := os.Getenv("VCENTER_PASSWORD") //password := os.Getenv("VCENTER_PASSWORD")
// Connect to vCenter // Connect to vCenter
u, err := soap.ParseURL(vUrl) u, err := soap.ParseURL(vUrl)
@@ -54,7 +62,7 @@ func (v *Vcenter) Login(vUrl string) error {
log.Fatalf("Error parsing vCenter URL: %s", err) log.Fatalf("Error parsing vCenter URL: %s", err)
} }
u.User = url.UserPassword(username, password) u.User = url.UserPassword(v.credentials.Username, v.credentials.Password)
/* /*
c, err := govmomi.NewClient(ctx, u, insecure) c, err := govmomi.NewClient(ctx, u, insecure)
@@ -77,7 +85,7 @@ func (v *Vcenter) Login(vUrl string) error {
v.client = c v.client = c
v.Logger.Debug("successfully connected to vCenter", "url", vUrl, "username", username) v.Logger.Debug("successfully connected to vCenter", "url", vUrl, "username", v.credentials.Username)
return nil return nil
} }

26
main.go
View File

@@ -9,9 +9,11 @@ import (
"runtime" "runtime"
"time" "time"
"vctp/db" "vctp/db"
"vctp/internal/secrets"
"vctp/internal/settings" "vctp/internal/settings"
"vctp/internal/tasks" "vctp/internal/tasks"
utils "vctp/internal/utils" utils "vctp/internal/utils"
"vctp/internal/vcenter"
"vctp/log" "vctp/log"
"vctp/server" "vctp/server"
"vctp/server/router" "vctp/server/router"
@@ -26,6 +28,7 @@ var (
buildTime string // when the executable was built buildTime string // when the executable was built
cronFrequency time.Duration cronFrequency time.Duration
cronInvFrequency time.Duration cronInvFrequency time.Duration
encryptionKey = []byte("5L1l3B5KvwOCzUHMAlCgsgUTRAYMfSpa")
) )
func main() { func main() {
@@ -112,6 +115,25 @@ func main() {
utils.GenerateCerts(tlsCertFilename, tlsKeyFilename) utils.GenerateCerts(tlsCertFilename, tlsKeyFilename)
} }
// Load vcenter credentials from .env
a := secrets.New(logger, encryptionKey)
vcEp := os.Getenv("VCENTER_PASSWORD")
if len(vcEp) == 0 {
logger.Error("No vcenter password configured")
os.Exit(1)
}
vcPass, err := a.Decrypt(vcEp)
if err != nil {
logger.Error("failed to decrypt vcenter credentials", "error", err)
//os.Exit(1)
}
creds := vcenter.VcenterLogin{
//insecureString := os.Getenv("VCENTER_INSECURE")
Username: os.Getenv("VCENTER_USERNAME"),
Password: string(vcPass),
}
// Prepare the task scheduler // Prepare the task scheduler
c, err := gocron.NewScheduler() c, err := gocron.NewScheduler()
if err != nil { if err != nil {
@@ -124,6 +146,7 @@ func main() {
Logger: logger, Logger: logger,
Database: database, Database: database,
Settings: s, Settings: s,
VcCreds: &creds,
} }
cronFrequencyString := os.Getenv("VCENTER_EVENT_POLLING_SECONDS") cronFrequencyString := os.Getenv("VCENTER_EVENT_POLLING_SECONDS")
@@ -184,12 +207,13 @@ func main() {
c.Start() c.Start()
// Start server // Start server
r := router.New(logger, database, buildTime, sha1ver, runtime.Version(), &creds, a)
svr := server.New( svr := server.New(
logger, logger,
c, c,
cancel, cancel,
bindAddress, bindAddress,
server.WithRouter(router.New(logger, database, buildTime, sha1ver, runtime.Version())), server.WithRouter(r),
server.SetTls(bindDisableTls), server.SetTls(bindDisableTls),
server.SetCertificate(tlsCertFilename), server.SetCertificate(tlsCertFilename),
server.SetPrivateKey(tlsKeyFilename), server.SetPrivateKey(tlsKeyFilename),

View File

@@ -0,0 +1,61 @@
package handler
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func (h *Handler) EncryptData(w http.ResponseWriter, r *http.Request) {
//ctx := context.Background()
var cipherText string
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "error", err)
fmt.Fprintf(w, "Invalid data received")
w.WriteHeader(http.StatusInternalServerError)
return
} else {
h.Logger.Debug("received input data", "length", len(reqBody))
}
// get the json input
var input map[string]string
if err := json.Unmarshal(reqBody, &input); err != nil {
h.Logger.Error("unable to unmarshal json", "error", err)
prettyPrint(reqBody)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to unmarshal JSON in request body: '%s'", err),
})
return
} else {
h.Logger.Debug("successfully decoded JSON")
prettyPrint(input)
}
//cipher, err := h.Secret.Encrypt()
for k := range input {
//h.Logger.Debug("foo", "key", k, "value", input[k])
cipherText, err = h.Secret.Encrypt([]byte(input[k]))
if err != nil {
h.Logger.Error("Unable to encrypt", "error", err)
} else {
h.Logger.Debug("Encrypted plaintext", "length", len(input[k]), "ciphertext", cipherText)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": cipherText,
})
return
}
}
// return the result
}

View File

@@ -5,6 +5,8 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"vctp/db" "vctp/db"
"vctp/internal/secrets"
"vctp/internal/vcenter"
"github.com/a-h/templ" "github.com/a-h/templ"
) )
@@ -16,6 +18,8 @@ type Handler struct {
BuildTime string BuildTime string
SHA1Ver string SHA1Ver string
GoVersion string GoVersion string
VcCreds *vcenter.VcenterLogin
Secret *secrets.Secrets
} }
func (h *Handler) html(ctx context.Context, w http.ResponseWriter, status int, t templ.Component) { func (h *Handler) html(ctx context.Context, w http.ResponseWriter, status int, t templ.Component) {

View File

@@ -244,7 +244,7 @@ func (h *Handler) calculateNewDiskSize(event models.CloudEventReceived) float64
var diskSize float64 var diskSize float64
var totalDiskBytes int64 var totalDiskBytes int64
h.Logger.Debug("connecting to vcenter") h.Logger.Debug("connecting to vcenter")
vc := vcenter.New(h.Logger) vc := vcenter.New(h.Logger, h.VcCreds)
vc.Login(event.CloudEvent.Source) vc.Login(event.CloudEvent.Source)
vmObject, err := vc.FindVMByIDWithDatacenter(event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Datacenter.Value) vmObject, err := vc.FindVMByIDWithDatacenter(event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Datacenter.Value)

View File

@@ -94,13 +94,22 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
result, err := h.Database.Queries().CreateUpdate(ctx, params) result, err := h.Database.Queries().CreateUpdate(ctx, params)
if err != nil { if err != nil {
h.Logger.Error("unable to perform database insert", "error", err) h.Logger.Error("unable to perform database insert", "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error : %v\n", err) json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to insert move event into database: '%s'", err),
})
return return
} else { } else {
h.Logger.Debug("created database record", "insert_result", result) h.Logger.Debug("created database record", "insert_result", result)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Processed update event: %v\n", result) //fmt.Fprintf(w, "Processed update event: %v\n", result)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": fmt.Sprintf("Successfully processed move event"),
})
return return
} }
} }

View File

@@ -5,17 +5,21 @@ import (
"net/http" "net/http"
"vctp/db" "vctp/db"
"vctp/dist" "vctp/dist"
"vctp/internal/secrets"
"vctp/internal/vcenter"
"vctp/server/handler" "vctp/server/handler"
"vctp/server/middleware" "vctp/server/middleware"
) )
func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver string, goVersion string) http.Handler { func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver string, goVersion string, creds *vcenter.VcenterLogin, secret *secrets.Secrets) http.Handler {
h := &handler.Handler{ h := &handler.Handler{
Logger: logger, Logger: logger,
Database: database, Database: database,
BuildTime: buildTime, BuildTime: buildTime,
SHA1Ver: sha1ver, SHA1Ver: sha1ver,
GoVersion: goVersion, GoVersion: goVersion,
VcCreds: creds,
Secret: secret,
} }
mux := http.NewServeMux() mux := http.NewServeMux()
@@ -35,5 +39,8 @@ func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver st
mux.HandleFunc("/api/report/inventory", h.InventoryReportDownload) mux.HandleFunc("/api/report/inventory", h.InventoryReportDownload)
mux.HandleFunc("/api/report/updates", h.UpdateReportDownload) mux.HandleFunc("/api/report/updates", h.UpdateReportDownload)
// endpoint for encrypting vcenter credential
mux.HandleFunc("/api/encrypt", h.EncryptData)
return middleware.NewLoggingMiddleware(logger, mux) return middleware.NewLoggingMiddleware(logger, mux)
} }

View File

@@ -21,6 +21,7 @@ type Server struct {
disableTls bool disableTls bool
tlsCertFilename string tlsCertFilename string
tlsKeyFilename string tlsKeyFilename string
encryptionKey string
} }
// New creates a new server with the given logger, address and options. // New creates a new server with the given logger, address and options.
@@ -88,6 +89,13 @@ func WithRouter(handler http.Handler) Option {
} }
} }
// SetKey sets the encryption key we use when generating secrets
func SetKey(key string) Option {
return func(s *Server) {
s.encryptionKey = key
}
}
// SetTls sets the disable tls value // SetTls sets the disable tls value
func SetTls(disableTls bool) Option { func SetTls(disableTls bool) Option {
return func(s *Server) { return func(s *Server) {

736
vm.json
View File

@@ -1,736 +0,0 @@
{
"self": {
"type": "VirtualMachine",
"value": "vm-13671"
},
"value": null,
"availableField": null,
"parent": null,
"customValue": null,
"overallStatus": "",
"configStatus": "",
"configIssue": null,
"effectiveRole": null,
"permission": null,
"name": "minecraft",
"disabledMethod": null,
"recentTask": null,
"declaredAlarmState": null,
"triggeredAlarmState": null,
"alarmActionsEnabled": null,
"tag": null,
"capability": {
"snapshotOperationsSupported": false,
"multipleSnapshotsSupported": false,
"snapshotConfigSupported": false,
"poweredOffSnapshotsSupported": false,
"memorySnapshotsSupported": false,
"revertToSnapshotSupported": false,
"quiescedSnapshotsSupported": false,
"disableSnapshotsSupported": false,
"lockSnapshotsSupported": false,
"consolePreferencesSupported": false,
"cpuFeatureMaskSupported": false,
"s1AcpiManagementSupported": false,
"settingScreenResolutionSupported": false,
"toolsAutoUpdateSupported": false,
"vmNpivWwnSupported": false,
"npivWwnOnNonRdmVmSupported": false,
"swapPlacementSupported": false,
"toolsSyncTimeSupported": false,
"virtualMmuUsageSupported": false,
"diskSharesSupported": false,
"bootOptionsSupported": false,
"settingVideoRamSizeSupported": false
},
"config": {
"changeVersion": "2024-05-24T06:41:25.868508Z",
"modified": "1970-01-01T00:00:00Z",
"name": "minecraft",
"guestFullName": "Ubuntu Linux (32-bit)",
"version": "vmx-08",
"uuid": "422598c8-5ab7-63e7-ba34-8111936fea59",
"createDate": "1970-01-01T00:00:00Z",
"instanceUuid": "50251955-6d1b-8954-ae28-50284dd4b44e",
"npivTemporaryDisabled": true,
"locationId": "564d4d65-27af-07d1-d627-70d056c7f233",
"template": false,
"guestId": "ubuntuGuest",
"alternateGuestName": "",
"files": {
"vmPathName": "[freenas] minecraft/minecraft.vmx",
"snapshotDirectory": "[freenas] minecraft/",
"suspendDirectory": "[freenas] minecraft/",
"logDirectory": "[freenas] minecraft/"
},
"tools": {
"toolsVersion": 10362,
"afterPowerOn": true,
"afterResume": true,
"beforeGuestStandby": true,
"beforeGuestShutdown": true,
"toolsUpgradePolicy": "upgradeAtPowerCycle",
"syncTimeWithHostAllowed": true,
"syncTimeWithHost": true,
"lastInstallInfo": {
"counter": 6
}
},
"flags": {
"enableLogging": true,
"useToe": false,
"runWithDebugInfo": false,
"monitorType": "release",
"htSharing": "any",
"snapshotDisabled": false,
"snapshotLocked": false,
"diskUuidEnabled": false,
"snapshotPowerOffBehavior": "powerOff",
"recordReplayEnabled": false,
"faultToleranceType": "unset",
"vvtdEnabled": false,
"vbsEnabled": false
},
"defaultPowerOps": {
"powerOffType": "soft",
"suspendType": "hard",
"resetType": "soft",
"defaultPowerOffType": "soft",
"defaultSuspendType": "hard",
"defaultResetType": "soft",
"standbyAction": "checkpoint"
},
"hardware": {
"numCPU": 1,
"numCoresPerSocket": 1,
"autoCoresPerSocket": false,
"memoryMB": 3072,
"virtualICH7MPresent": false,
"virtualSMCPresent": false,
"device": [
{
"key": 100,
"deviceInfo": {
"label": "PCI controller 0",
"summary": "PCI controller 0"
},
"busNumber": 0,
"device": [
500,
12000,
1000,
4000
]
},
{
"key": 200,
"deviceInfo": {
"label": "IDE 0",
"summary": "IDE 0"
},
"busNumber": 0
},
{
"key": 201,
"deviceInfo": {
"label": "IDE 1",
"summary": "IDE 1"
},
"busNumber": 1,
"device": [
3002
]
},
{
"key": 300,
"deviceInfo": {
"label": "PS2 controller 0",
"summary": "PS2 controller 0"
},
"busNumber": 0,
"device": [
600,
700
]
},
{
"key": 400,
"deviceInfo": {
"label": "SIO controller 0",
"summary": "SIO controller 0"
},
"busNumber": 0,
"device": [
8000
]
},
{
"key": 500,
"deviceInfo": {
"label": "Video card ",
"summary": "Video card"
},
"controllerKey": 100,
"unitNumber": 0,
"videoRamSizeInKB": 4096,
"numDisplays": 1,
"useAutoDetect": false,
"enable3DSupport": false,
"use3dRenderer": "automatic",
"graphicsMemorySizeInKB": 262144
},
{
"key": 600,
"deviceInfo": {
"label": "Keyboard ",
"summary": "Keyboard"
},
"controllerKey": 300,
"unitNumber": 0
},
{
"key": 700,
"deviceInfo": {
"label": "Pointing device",
"summary": "Pointing device; Device"
},
"backing": {
"deviceName": "",
"useAutoDetect": false,
"hostPointingDevice": "autodetect"
},
"controllerKey": 300,
"unitNumber": 1
},
{
"key": 1000,
"deviceInfo": {
"label": "SCSI controller 0",
"summary": "LSI Logic"
},
"slotInfo": {
"pciSlotNumber": 16
},
"controllerKey": 100,
"unitNumber": 3,
"busNumber": 0,
"device": [
2000
],
"hotAddRemove": true,
"sharedBus": "noSharing",
"scsiCtlrUnitNumber": 7
},
{
"key": 2000,
"deviceInfo": {
"label": "Hard disk 1",
"summary": "62,914,560 KB"
},
"backing": {
"fileName": "[freenas] minecraft/minecraft-000002.vmdk",
"datastore": {
"type": "Datastore",
"value": "datastore-6035"
},
"diskMode": "persistent",
"split": false,
"writeThrough": false,
"thinProvisioned": true,
"eagerlyScrub": false,
"uuid": "6000C294-55e8-39b9-1852-00dcfd299398",
"contentId": "b739ed36bfc510b2f1c70000e628ed40",
"parent": {
"fileName": "[freenas] minecraft/minecraft-000001.vmdk",
"datastore": {
"type": "Datastore",
"value": "datastore-6035"
},
"diskMode": "persistent",
"thinProvisioned": true,
"eagerlyScrub": false,
"uuid": "6000C294-55e8-39b9-1852-00dcfd299398",
"contentId": "45ff3b3b3935d631facb7eadbb916797",
"parent": {
"fileName": "[freenas] minecraft/minecraft.vmdk",
"datastore": {
"type": "Datastore",
"value": "datastore-6035"
},
"diskMode": "persistent",
"thinProvisioned": true,
"eagerlyScrub": false,
"uuid": "6000C294-55e8-39b9-1852-00dcfd299398",
"contentId": "8e6ae3c31967c906303f7b3fe1b379f8",
"digestEnabled": false
},
"deltaDiskFormat": "redoLogFormat",
"digestEnabled": false,
"deltaDiskFormatVariant": "vmfsSparseVariant"
},
"deltaDiskFormat": "redoLogFormat",
"digestEnabled": false,
"deltaDiskFormatVariant": "vmfsSparseVariant",
"sharing": "sharingNone"
},
"controllerKey": 1000,
"unitNumber": 0,
"capacityInKB": 62914560,
"capacityInBytes": 64424509440,
"shares": {
"shares": 1000,
"level": "normal"
},
"storageIOAllocation": {
"limit": -1,
"shares": {
"shares": 1000,
"level": "normal"
},
"reservation": 0
},
"diskObjectId": "271-2000",
"vDiskVersion": 1,
"nativeUnmanagedLinkedClone": false,
"guestReadOnly": false
},
{
"key": 3002,
"deviceInfo": {
"label": "CD/DVD drive 1",
"summary": "ISO [] /usr/lib/vmware/isoimages/linux.iso"
},
"backing": {
"fileName": "[] /usr/lib/vmware/isoimages/linux.iso"
},
"connectable": {
"startConnected": false,
"allowGuestControl": true,
"connected": false,
"status": "untried"
},
"controllerKey": 201,
"unitNumber": 0
},
{
"key": 4000,
"deviceInfo": {
"label": "Network adapter 1",
"summary": "DVSwitch: 50 02 bc 27 fa 1b 2c d1-0d 43 fb 29 46 60 c4 0b"
},
"backing": {
"port": {
"switchUuid": "50 02 bc 27 fa 1b 2c d1-0d 43 fb 29 46 60 c4 0b",
"portgroupKey": "dvportgroup-4031",
"portKey": "102",
"connectionCookie": 209430599
}
},
"connectable": {
"migrateConnect": "unset",
"startConnected": true,
"allowGuestControl": true,
"connected": false,
"status": "untried"
},
"slotInfo": {
"pciSlotNumber": 32
},
"controllerKey": 100,
"unitNumber": 7,
"addressType": "assigned",
"macAddress": "00:50:56:a5:16:29",
"wakeOnLanEnabled": true,
"resourceAllocation": {
"reservation": 0,
"share": {
"shares": 50,
"level": "normal"
},
"limit": -1
},
"uptCompatibilityEnabled": false
},
{
"key": 8000,
"deviceInfo": {
"label": "Floppy drive 1",
"summary": "Remote"
},
"backing": {
"deviceName": "",
"useAutoDetect": false
},
"connectable": {
"startConnected": false,
"allowGuestControl": true,
"connected": false,
"status": "untried"
},
"controllerKey": 400,
"unitNumber": 0
},
{
"key": 12000,
"deviceInfo": {
"label": "VMCI device",
"summary": "Device on the virtual machine PCI bus that provides support for the virtual machine communication interface"
},
"slotInfo": {
"pciSlotNumber": 33
},
"controllerKey": 100,
"unitNumber": 17,
"id": -1821382055,
"allowUnrestrictedCommunication": false,
"filterEnable": true
}
],
"motherboardLayout": "i440bxHostBridge",
"simultaneousThreads": 1
},
"cpuAllocation": {
"reservation": 0,
"expandableReservation": false,
"limit": -1,
"shares": {
"shares": 1000,
"level": "normal"
}
},
"memoryAllocation": {
"reservation": 0,
"expandableReservation": false,
"limit": -1,
"shares": {
"shares": 30720,
"level": "normal"
}
},
"latencySensitivity": {
"level": "normal"
},
"memoryHotAddEnabled": false,
"cpuHotAddEnabled": false,
"cpuHotRemoveEnabled": false,
"extraConfig": [
{
"key": "svga.present",
"value": "TRUE"
},
{
"key": "vmci.filter.enable",
"value": "TRUE"
},
{
"key": "tools.guest.desktop.autolock",
"value": "FALSE"
},
{
"key": "pciBridge0.present",
"value": "true"
},
{
"key": "pciBridge4.present",
"value": "true"
},
{
"key": "pciBridge4.virtualDev",
"value": "pcieRootPort"
},
{
"key": "pciBridge4.functions",
"value": "8"
},
{
"key": "pciBridge5.present",
"value": "true"
},
{
"key": "pciBridge5.virtualDev",
"value": "pcieRootPort"
},
{
"key": "pciBridge5.functions",
"value": "8"
},
{
"key": "pciBridge6.present",
"value": "true"
},
{
"key": "pciBridge6.virtualDev",
"value": "pcieRootPort"
},
{
"key": "pciBridge6.functions",
"value": "8"
},
{
"key": "pciBridge7.present",
"value": "true"
},
{
"key": "pciBridge7.virtualDev",
"value": "pcieRootPort"
},
{
"key": "pciBridge7.functions",
"value": "8"
},
{
"key": "hpet0.present",
"value": "TRUE"
},
{
"key": "nvram",
"value": "minecraft.nvram"
},
{
"key": "virtualHW.productCompatibility",
"value": "hosted"
},
{
"key": "scsi0.pciSlotNumber",
"value": "16"
},
{
"key": "ethernet0.pciSlotNumber",
"value": "32"
},
{
"key": "vmci0.pciSlotNumber",
"value": "33"
},
{
"key": "snapshot.action",
"value": "keep"
},
{
"key": "sched.cpu.latencySensitivity",
"value": "normal"
},
{
"key": "replay.supported",
"value": "false"
},
{
"key": "pciBridge0.pciSlotNumber",
"value": "17"
},
{
"key": "pciBridge4.pciSlotNumber",
"value": "21"
},
{
"key": "pciBridge5.pciSlotNumber",
"value": "22"
},
{
"key": "pciBridge6.pciSlotNumber",
"value": "23"
},
{
"key": "pciBridge7.pciSlotNumber",
"value": "24"
},
{
"key": "tools.remindInstall",
"value": "FALSE"
},
{
"key": "hostCPUID.0",
"value": "00000016756e65476c65746e49656e69"
},
{
"key": "hostCPUID.1",
"value": "000906ea001008007ffafbffbfebfbff"
},
{
"key": "hostCPUID.80000001",
"value": "0000000000000000000001212c100800"
},
{
"key": "guestCPUID.0",
"value": "0000000d756e65476c65746e49656e69"
},
{
"key": "guestCPUID.1",
"value": "000406f00001080096d832030f8bfbff"
},
{
"key": "guestCPUID.80000001",
"value": "00000000000000000000010128100800"
},
{
"key": "userCPUID.0",
"value": "0000000d756e65476c65746e49656e69"
},
{
"key": "userCPUID.1",
"value": "000406f00001080096d832030f8bfbff"
},
{
"key": "userCPUID.80000001",
"value": "00000000000000000000010128100800"
},
{
"key": "evcCompatibilityMode",
"value": "TRUE"
},
{
"key": "vmotion.checkpointFBSize",
"value": "4194304"
},
{
"key": "softPowerOff",
"value": "TRUE"
},
{
"key": "toolsInstallManager.updateCounter",
"value": "6"
},
{
"key": "toolsInstallManager.lastInstallError",
"value": "0"
},
{
"key": "numa.autosize.vcpu.maxPerVirtualNode",
"value": "1"
},
{
"key": "numa.autosize.cookie",
"value": "10001"
},
{
"key": "sched.swap.derivedName",
"value": "/vmfs/volumes/a79e4951-d31e6955/minecraft/minecraft-4bfd4f1d.vswp"
},
{
"key": "scsi0:0.redo",
"value": ""
},
{
"key": "monitor.phys_bits_used",
"value": "40"
},
{
"key": "viv.moid",
"value": "91a88fc3-5936-4bfb-a6f8-018e073fcefb:vm-13671:XMmrS0IZV2SrrGL4GiADh//vraEEXaRMaC4vxsNBPOI="
},
{
"key": "vmxstats.filename",
"value": "minecraft.scoreboard"
},
{
"key": "tools.capability.verifiedSamlToken",
"value": "TRUE"
},
{
"key": "vmware.tools.internalversion",
"value": "10362"
},
{
"key": "vmware.tools.requiredversion",
"value": "12389"
},
{
"key": "migrate.hostLogState",
"value": "none"
},
{
"key": "migrate.migrationId",
"value": "0"
},
{
"key": "migrate.hostLog",
"value": "minecraft-662da845.hlog"
}
],
"datastoreUrl": [
{
"name": "freenas",
"url": "/vmfs/volumes/a79e4951-d31e6955"
}
],
"swapPlacement": "inherit",
"bootOptions": {
"enterBIOSSetup": false,
"efiSecureBootEnabled": false,
"bootRetryEnabled": false,
"bootRetryDelay": 10000,
"networkBootProtocol": "ipv4"
},
"changeTrackingEnabled": false,
"firmware": "bios",
"maxMksConnections": 40,
"guestAutoLockEnabled": false,
"memoryReservationLockedToMax": false,
"nestedHVEnabled": false,
"vPMCEnabled": false,
"scheduledHardwareUpgradeInfo": {
"upgradePolicy": "never",
"scheduledHardwareUpgradeStatus": "none"
},
"messageBusTunnelEnabled": false,
"guestIntegrityInfo": {
"enabled": false
},
"migrateEncryption": "opportunistic",
"sgxInfo": {
"epcSize": 0,
"flcMode": "unlocked",
"requireAttestation": false
},
"ftEncryptionMode": "ftEncryptionOpportunistic",
"guestMonitoringModeInfo": {},
"sevEnabled": false,
"numaInfo": {
"coresPerNumaNode": 0,
"autoCoresPerNumaNode": true
},
"vmOpNotificationToAppEnabled": false,
"vmOpNotificationTimeout": -1,
"deviceGroups": {},
"fixedPassthruHotPlugEnabled": false
},
"layout": null,
"layoutEx": null,
"storage": null,
"environmentBrowser": {
"type": "",
"value": ""
},
"resourcePool": null,
"parentVApp": null,
"resourceConfig": null,
"runtime": {
"connectionState": "",
"powerState": "",
"toolsInstallerMounted": false,
"numMksConnections": 0
},
"guest": null,
"summary": {
"runtime": {
"connectionState": "",
"powerState": "",
"toolsInstallerMounted": false,
"numMksConnections": 0
},
"config": {
"name": "",
"template": false,
"vmPathName": ""
},
"quickStats": {
"guestHeartbeatStatus": ""
},
"overallStatus": ""
},
"datastore": null,
"network": null,
"snapshot": null,
"rootSnapshot": null,
"guestHeartbeatStatus": ""
}