Skip to content

Commit

Permalink
Update VM API spec.bootstrap.sysprep fields
Browse files Browse the repository at this point in the history
This patch includes several changes to the VirtualMachine
API's sysprep bootstrap provider, including:

* The field `spec.bootstrap.sysprep.userData` is now
  required. This is only true if `spec.bootstrap.sysprep` is
  set, so it does not prevent someone from omitting a bootstrap
  provider. This is aligned witht the VMODL used by VM Operator
  to customize the guest.

* The sysprep bootstrap provider now defaults to the UTC
  timezone by setting the default value of the field
  `spec.bootstrap.sysprep.guiUnattended.timeZone` to be 85.
  85.

* The linuxprep bootstrap provider now defaults to the UTC
  timezone by setting the default value of the field
  `spec.bootstrap.linuxPrep.timeZone` to be "Etc/UTC".
  • Loading branch information
akutz committed Nov 1, 2024
1 parent 2840635 commit 27553ae
Show file tree
Hide file tree
Showing 14 changed files with 64 additions and 33 deletions.
2 changes: 1 addition & 1 deletion api/v1alpha1/virtualmachine_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func TestVirtualMachineConversion(t *testing.T) {
Identification: &vmopv1sysprep.Identification{
DomainAdmin: "my-admin",
},
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
FullName: "vmware",
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ func Convert_sysprep_Sysprep_To_sysprep_Sysprep(
}
out.GUIUnattended = (*vmopv1sysprep.GUIUnattended)(unsafe.Pointer(in.GUIUnattended))
out.LicenseFilePrintData = (*vmopv1sysprep.LicenseFilePrintData)(unsafe.Pointer(in.LicenseFilePrintData))
out.UserData = (*vmopv1sysprep.UserData)(unsafe.Pointer(in.UserData))
if in.UserData != nil {
out.UserData.FullName = in.UserData.FullName
out.UserData.OrgName = in.UserData.OrgName
out.UserData.ProductID = (*vmopv1sysprep.ProductIDSecretKeySelector)(unsafe.Pointer(in.UserData.ProductID))
}
if id := in.Identification; id != nil {
out.Identification = &vmopv1sysprep.Identification{
DomainAdmin: id.DomainAdmin,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ func Convert_sysprep_Sysprep_To_sysprep_Sysprep(
}
out.GUIUnattended = (*vmopv1a2sysprep.GUIUnattended)(unsafe.Pointer(in.GUIUnattended))
out.LicenseFilePrintData = (*vmopv1a2sysprep.LicenseFilePrintData)(unsafe.Pointer(in.LicenseFilePrintData))
out.UserData = (*vmopv1a2sysprep.UserData)(unsafe.Pointer(in.UserData))
out.UserData = &vmopv1a2sysprep.UserData{
FullName: in.UserData.FullName,
OrgName: in.UserData.OrgName,
ProductID: (*vmopv1a2sysprep.ProductIDSecretKeySelector)(unsafe.Pointer(in.UserData.ProductID)),
}
if id := in.Identification; id != nil {
out.Identification = &vmopv1a2sysprep.Identification{
DomainAdmin: id.DomainAdmin,
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha2/virtualmachine_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestVirtualMachineConversion(t *testing.T) {
Identification: &vmopv1sysprep.Identification{
DomainAdmin: "my-admin",
},
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
FullName: "vmware",
},
},
Expand Down Expand Up @@ -591,7 +591,7 @@ func TestVirtualMachineConversion(t *testing.T) {
Bootstrap: &vmopv1.VirtualMachineBootstrapSpec{
Sysprep: &vmopv1.VirtualMachineBootstrapSysprepSpec{
Sysprep: &vmopv1sysprep.Sysprep{
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
FullName: "test-user",
OrgName: "test-org",
ProductID: &vmopv1sysprep.ProductIDSecretKeySelector{
Expand Down
8 changes: 5 additions & 3 deletions api/v1alpha3/sysprep/sysprep.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ type Sysprep struct {
// Server 2003.
LicenseFilePrintData *LicenseFilePrintData `json:"licenseFilePrintData,omitempty"`

// +optional

// UserData is a representation of the Sysprep UserData key.
UserData *UserData `json:"userData,omitempty"`
UserData UserData `json:"userData"`
}

// GUIRunOnce maps to the GuiRunOnce key in the sysprep.xml answer file.
Expand Down Expand Up @@ -99,11 +97,15 @@ type GUIUnattended struct {
Password *PasswordSecretKeySelector `json:"password,omitempty"`

// +optional
// +kubebuilder:default=85
// +kubebuilder:validation:Minimum=13

// TimeZone is the time zone index for the virtual machine.
//
// Please note that numbers correspond to time zones listed at
// https://bit.ly/3Rzv8oL.
//
// Defaults to UTC.
TimeZone int32 `json:"timeZone,omitempty"`
}

Expand Down
6 changes: 1 addition & 5 deletions api/v1alpha3/sysprep/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions api/v1alpha3/virtualmachine_bootstrap_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ type VirtualMachineBootstrapLinuxPrepSpec struct {
HardwareClockIsUTC *bool `json:"hardwareClockIsUTC,omitempty"`

// +optional
// +kubebuilder:default=Etc/UTC

// TimeZone is a case-sensitive timezone, such as Europe/Sofia.
//
Expand All @@ -137,6 +138,8 @@ type VirtualMachineBootstrapLinuxPrepSpec struct {
//
// Please see https://kb.vmware.com/s/article/2145518 for a list of valid
// time zones for Linux systems.
//
// Defaults to UTC.
TimeZone string `json:"timeZone,omitempty"`
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ spec:
local time.
type: boolean
timeZone:
default: Etc/UTC
description: |-
TimeZone is a case-sensitive timezone, such as Europe/Sofia.
Expand All @@ -600,6 +601,8 @@ spec:
Please see https://kb.vmware.com/s/article/2145518 for a list of valid
time zones for Linux systems.
Defaults to UTC.
type: string
type: object
sysprep:
Expand Down Expand Up @@ -717,12 +720,16 @@ spec:
- name
type: object
timeZone:
default: 85
description: |-
TimeZone is the time zone index for the virtual machine.
Please note that numbers correspond to time zones listed at
https://bit.ly/3Rzv8oL.
Defaults to UTC.
format: int32
minimum: 13
type: integer
type: object
identification:
Expand Down Expand Up @@ -827,6 +834,8 @@ spec:
- fullName
- orgName
type: object
required:
- userData
type: object
type: object
vAppConfig:
Expand Down
9 changes: 9 additions & 0 deletions config/crd/bases/vmoperator.vmware.com_virtualmachines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3377,6 +3377,7 @@ spec:
local time.
type: boolean
timeZone:
default: Etc/UTC
description: |-
TimeZone is a case-sensitive timezone, such as Europe/Sofia.
Expand All @@ -3387,6 +3388,8 @@ spec:
Please see https://kb.vmware.com/s/article/2145518 for a list of valid
time zones for Linux systems.
Defaults to UTC.
type: string
type: object
sysprep:
Expand Down Expand Up @@ -3504,12 +3507,16 @@ spec:
- name
type: object
timeZone:
default: 85
description: |-
TimeZone is the time zone index for the virtual machine.
Please note that numbers correspond to time zones listed at
https://bit.ly/3Rzv8oL.
Defaults to UTC.
format: int32
minimum: 13
type: integer
type: object
identification:
Expand Down Expand Up @@ -3613,6 +3620,8 @@ spec:
- fullName
- orgName
type: object
required:
- userData
type: object
type: object
vAppConfig:
Expand Down
18 changes: 12 additions & 6 deletions pkg/providers/vsphere/sysprep/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ func GetSysprepSecretData(
productID, password, domainPwd string
)

if userData := in.UserData; userData != nil && userData.ProductID != nil {
if in.UserData.ProductID != nil {
// this is an optional secret key selector even when FullName or OrgName are set.
err := util.GetSecretData(ctx, k8sClient, secretNamespace, userData.ProductID.Name, userData.ProductID.Key, &productID)
if err != nil {
if err := util.GetSecretData(
ctx,
k8sClient,
secretNamespace,
in.UserData.ProductID.Name,
in.UserData.ProductID.Key,
&productID); err != nil {

return SecretData{}, err
}
}
Expand Down Expand Up @@ -84,16 +90,16 @@ func GetSecretResources(
}
}

if userData := in.UserData; userData != nil && userData.ProductID != nil {
if in.UserData.ProductID != nil {
s, err := util.GetSecretResource(
ctx,
k8sClient,
secretNamespace,
userData.ProductID.Name)
in.UserData.ProductID.Name)
if err != nil {
return nil, err
}
captureSecret(s, userData.ProductID.Name)
captureSecret(s, in.UserData.ProductID.Name)
}

if guiUnattended := in.GUIUnattended; guiUnattended != nil && guiUnattended.AutoLogon {
Expand Down
6 changes: 3 additions & 3 deletions pkg/providers/vsphere/sysprep/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var _ = Describe("GetSysprepSecretData", func() {
productIDSecretName := "product_id_secret"
BeforeEach(func() {
inlineSysprep = vmopv1sysprep.Sysprep{
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
ProductID: &vmopv1sysprep.ProductIDSecretKeySelector{
Name: productIDSecretName,
Key: "product_id",
Expand Down Expand Up @@ -249,7 +249,7 @@ var _ = Describe("Sysprep GetSecretResources", func() {
productIDSecretName := "product_id_secret"
BeforeEach(func() {
inlineSysprep = vmopv1sysprep.Sysprep{
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
ProductID: &vmopv1sysprep.ProductIDSecretKeySelector{
Name: productIDSecretName,
Key: "product_id",
Expand Down Expand Up @@ -375,7 +375,7 @@ var _ = Describe("Sysprep GetSecretResources", func() {
secretName := "same-secret"
BeforeEach(func() {
inlineSysprep = vmopv1sysprep.Sysprep{
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
ProductID: &vmopv1sysprep.ProductIDSecretKeySelector{
Name: secretName,
Key: "product_id",
Expand Down
14 changes: 6 additions & 8 deletions pkg/providers/vsphere/vmlifecycle/bootstrap_sysprep.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,12 @@ func convertTo(from *vmopv1sysprep.Sysprep, bsArgs *BootstrapArgs) *vimtypes.Cus
Name: bsArgs.HostName,
},
}
if from.UserData != nil {
sysprepCustomization.UserData.FullName = from.UserData.FullName
sysprepCustomization.UserData.OrgName = from.UserData.OrgName
// In the case of a VMI with volume license key, this might not be set.
// Hence, add a check to see if the productID is set to empty.
if bootstrapData.Sysprep != nil && bootstrapData.Sysprep.ProductID != "" {
sysprepCustomization.UserData.ProductId = bootstrapData.Sysprep.ProductID
}
sysprepCustomization.UserData.FullName = from.UserData.FullName
sysprepCustomization.UserData.OrgName = from.UserData.OrgName
// In the case of a VMI with volume license key, this might not be set.
// Hence, add a check to see if the productID is set to empty.
if bootstrapData.Sysprep != nil && bootstrapData.Sysprep.ProductID != "" {
sysprepCustomization.UserData.ProductId = bootstrapData.Sysprep.ProductID
}

if from.GUIRunOnce != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ var _ = Describe("SysPrep Bootstrap", func() {
},
TimeZone: 4,
},
UserData: &vmopv1sysprep.UserData{
UserData: vmopv1sysprep.UserData{
FullName: "foo-bar",
OrgName: "foo-org",
ProductID: &vmopv1sysprep.ProductIDSecretKeySelector{Key: "product_id_key"},
Expand Down
4 changes: 2 additions & 2 deletions pkg/providers/vsphere/vmprovider_vm_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ func vmUtilTests() {
productIDSecretName := "product_id_secret"
BeforeEach(func() {
vmCtx.VM.Spec.Bootstrap.Sysprep.Sysprep = &sysprep.Sysprep{
UserData: &sysprep.UserData{
UserData: sysprep.UserData{
ProductID: &sysprep.ProductIDSecretKeySelector{
Name: productIDSecretName,
Key: "product_id",
Expand Down Expand Up @@ -1186,7 +1186,7 @@ func vmUtilTests() {
vmCtx.VM.Spec.Bootstrap = &vmopv1.VirtualMachineBootstrapSpec{
Sysprep: &vmopv1.VirtualMachineBootstrapSysprepSpec{
Sysprep: &sysprep.Sysprep{
UserData: &sysprep.UserData{
UserData: sysprep.UserData{
ProductID: &sysprep.ProductIDSecretKeySelector{
Name: "dummy-sysprep-secret",
},
Expand Down

0 comments on commit 27553ae

Please sign in to comment.