Skip to content

Commit 183ef5e

Browse files
committed
HIVE-2391: VSphere zonal part deux
Followon addressing review from #2731. MachinePool: - Removed `Topology` override - Restored ResourcePool and TagIDs overrides - Removed `osImage` detected from arbitrary master; using whatever's passed through from FD Topology (which defaults sanely if unset). Deprovision: - Changed `--vsphere-vcenter` StringVar to `--vsphere-vcenters` StringSliceVar Platform Creds: - Redesigned to take `vcenters`, a list of vcenter server/username/password, matching (and unmarshaling into) the corresponding chunk of metadata.json. Docs: - Updated install-config sample to zonal shape. - Documented new creds shape.
1 parent 4723de6 commit 183ef5e

30 files changed

Lines changed: 630 additions & 567 deletions

apis/hive/v1/clusterdeprovision_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,11 @@ type VSphereClusterDeprovision struct {
133133
// necessary for communicating with the VCenter.
134134
CertificatesSecretRef corev1.LocalObjectReference `json:"certificatesSecretRef"`
135135
// DeprecatedVCenter is the vSphere vCenter hostname.
136-
// Deprecated: use VCenters instead
136+
// Deprecated: use VCenters instead.
137+
// +optional
137138
DeprecatedVCenter string `json:"vCenter"`
138139
// VCenters are potentially multiple vCenter hostnames. Prefer this field over VCenter.
140+
// +optional
139141
VCenters []string `json:"vCenters"`
140142
}
141143

apis/hive/v1/vsphere/machinepools.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,10 @@ type MachinePool struct {
99

1010
// ResourcePool is the name of the resource pool that will be used for virtual machines.
1111
// If it is not present, a default value will be used.
12-
// Deprecated: use Topology instead
1312
// +optional
14-
DeprecatedResourcePool string `json:"resourcePool,omitempty"`
13+
ResourcePool string `json:"resourcePool,omitempty"`
1514

1615
// TagIDs is a list of up to 10 tags to add to the VMs that this machine set provisions in vSphere.
17-
// Deprecated: use Topology instead
1816
// +kubebuilder:validation:MaxItems:=10
19-
DeprecatedTagIDs []string `json:"tagIDs,omitempty"`
20-
21-
// Topology is the vSphere topology that will be used for virtual machines.
22-
// If it is not present, a default value will be used.
23-
// +optional
24-
Topology *vsphere.Topology `json:"topology,omitempty"`
17+
TagIDs []string `json:"tagIDs,omitempty"`
2518
}

apis/hive/v1/vsphere/zz_generated.deepcopy.go

Lines changed: 2 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crds/hive.openshift.io_clusterdeprovisions.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ spec:
355355
vCenter:
356356
description: |-
357357
DeprecatedVCenter is the vSphere vCenter hostname.
358-
Deprecated: use VCenters instead
358+
Deprecated: use VCenters instead.
359359
type: string
360360
vCenters:
361361
description: VCenters are potentially multiple vCenter hostnames. Prefer this field over VCenter.
@@ -365,8 +365,6 @@ spec:
365365
required:
366366
- certificatesSecretRef
367367
- credentialsSecretRef
368-
- vCenter
369-
- vCenters
370368
type: object
371369
type: object
372370
required:

config/crds/hive.openshift.io_machinepools.yaml

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -844,94 +844,13 @@ spec:
844844
description: |-
845845
ResourcePool is the name of the resource pool that will be used for virtual machines.
846846
If it is not present, a default value will be used.
847-
Deprecated: use Topology instead
848847
type: string
849848
tagIDs:
850-
description: |-
851-
TagIDs is a list of up to 10 tags to add to the VMs that this machine set provisions in vSphere.
852-
Deprecated: use Topology instead
849+
description: TagIDs is a list of up to 10 tags to add to the VMs that this machine set provisions in vSphere.
853850
items:
854851
type: string
855852
maxItems: 10
856853
type: array
857-
topology:
858-
description: |-
859-
Topology is the vSphere topology that will be used for virtual machines.
860-
If it is not present, a default value will be used.
861-
properties:
862-
computeCluster:
863-
description: |-
864-
computeCluster as the failure domain
865-
This is required to be a path
866-
maxLength: 2048
867-
minLength: 1
868-
type: string
869-
datacenter:
870-
description: |-
871-
datacenter is the vCenter datacenter in which virtual machines will be located
872-
and defined as the failure domain.
873-
maxLength: 80
874-
minLength: 1
875-
type: string
876-
datastore:
877-
description: |-
878-
datastore is the name or inventory path of the datastore in which the
879-
virtual machine is created/located.
880-
maxLength: 2048
881-
minLength: 1
882-
type: string
883-
folder:
884-
description: |-
885-
folder is the inventory path of the folder in which the
886-
virtual machine is created/located.
887-
maxLength: 2048
888-
minLength: 1
889-
pattern: ^/.*?/vm/.*?
890-
type: string
891-
hostGroup:
892-
description: |-
893-
hostGroup is the name of the vm-host group of type host within vCenter for this failure domain.
894-
hostGroup is limited to 80 characters.
895-
This field is required when the ZoneType is HostGroup
896-
maxLength: 80
897-
type: string
898-
networks:
899-
description: networks is the list of networks within this failure domain
900-
items:
901-
type: string
902-
maxItems: 10
903-
minItems: 1
904-
type: array
905-
resourcePool:
906-
description: |-
907-
resourcePool is the absolute path of the resource pool where virtual machines will be
908-
created. The absolute path is of the form /<datacenter>/host/<cluster>/Resources/<resourcepool>.
909-
maxLength: 2048
910-
minLength: 1
911-
pattern: ^/.*?/host/.*?/Resources.*
912-
type: string
913-
tagIDs:
914-
description: |-
915-
tagIDs is an optional set of tags to add to an instance. Specified tagIDs
916-
must use URN-notation instead of display names. A maximum of 10 tag IDs may be specified.
917-
example: urn:vmomi:InventoryServiceTag:5736bf56-49f5-4667-b38c-b97e09dc9578:GLOBAL
918-
items:
919-
type: string
920-
type: array
921-
template:
922-
description: |-
923-
template is the inventory path of the virtual machine or template
924-
that will be used for cloning.
925-
maxLength: 2048
926-
minLength: 1
927-
pattern: ^/.*?/vm/.*?
928-
type: string
929-
required:
930-
- computeCluster
931-
- datacenter
932-
- datastore
933-
- networks
934-
type: object
935854
zones:
936855
description: |-
937856
Zones defines available zones

contrib/pkg/createcluster/create.go

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ import (
3131
openstackcreds "github.com/openshift/hive/pkg/creds/openstack"
3232
"github.com/openshift/hive/pkg/gcpclient"
3333
"github.com/openshift/hive/pkg/util/scheme"
34+
3435
installertypes "github.com/openshift/installer/pkg/types"
3536
installervsphere "github.com/openshift/installer/pkg/types/vsphere"
37+
"github.com/openshift/installer/pkg/types/vsphere/conversion"
3638
"github.com/openshift/installer/pkg/validate"
3739
)
3840

@@ -346,6 +348,7 @@ OpenShift Installer publishes all the services of the cluster like API server an
346348
flags.StringVar(&opt.OpenStackIngressFloatingIP, "openstack-ingress-floating-ip", "", "Floating IP address to use for cluster's Ingress service")
347349

348350
// vSphere flags
351+
// TODO: This needs a full rewrite for zonal.
349352
flags.StringVar(&opt.VSphereVCenter, "vsphere-vcenter", "", "Domain name or IP address of the vCenter")
350353
flags.StringVar(&opt.VSphereDatacenter, "vsphere-datacenter", "", "Datacenter to use in the vCenter")
351354
flags.StringVar(&opt.VSphereDefaultDataStore, "vsphere-default-datastore", "", "Default datastore to use for provisioning volumes")
@@ -731,15 +734,23 @@ func (o *Options) GenerateObjects() ([]runtime.Object, error) {
731734
}
732735
builder.CloudBuilder = openStackProvider
733736
case constants.PlatformVSphere:
734-
vsphereUsername := os.Getenv(constants.VSphereUsernameEnvVar)
735-
if vsphereUsername == "" {
736-
return nil, fmt.Errorf("no %s env var set, cannot proceed", constants.VSphereUsernameEnvVar)
737+
// Little DRYer to set a username or password string (which one should be indicated via `label`)
738+
// to `value` iff not already set in `receiver`.
739+
// If the `receiver` and `value` are both unset, generate an error.
740+
// This is for convenience as various paths need to do this conditionally, and the values could
741+
// come from multiple places (env vars, json blob).
742+
setCredValue := func(label string, receiver *string, value string) error {
743+
if *receiver != "" {
744+
return nil
745+
}
746+
if value == "" {
747+
return fmt.Errorf("Missing VSphere %s: must be provided either via env var or platform spec.", label)
748+
}
749+
*receiver = value
750+
return nil
737751
}
738-
752+
vsphereUsername := os.Getenv(constants.VSphereUsernameEnvVar)
739753
vspherePassword := os.Getenv(constants.VSpherePasswordEnvVar)
740-
if vspherePassword == "" {
741-
return nil, fmt.Errorf("no %s env var set, cannot proceed", constants.VSpherePasswordEnvVar)
742-
}
743754

744755
vsphereCACerts := os.Getenv(constants.VSphereTLSCACertsEnvVar)
745756
if o.VSphereCACerts != "" {
@@ -767,16 +778,7 @@ func (o *Options) GenerateObjects() ([]runtime.Object, error) {
767778
if err != nil {
768779
return nil, fmt.Errorf("error decoding platform %s: %w", o.VSpherePlatformSpecJSON, err)
769780
}
770-
771-
// Set credentials on VCenters if using new structure
772-
for i := range platform.VCenters {
773-
if platform.VCenters[i].Username == "" {
774-
platform.VCenters[i].Username = vsphereUsername
775-
}
776-
if platform.VCenters[i].Password == "" {
777-
platform.VCenters[i].Password = vspherePassword
778-
}
779-
}
781+
// We'll inject credentials from env vars later, if unset in the json blob
780782
} else {
781783
o.log.Info("Platform spec not provided, trying legacy flags")
782784
// Try legacy flags
@@ -810,39 +812,74 @@ func (o *Options) GenerateObjects() ([]runtime.Object, error) {
810812
return nil, fmt.Errorf("must provide --vsphere-vcenter or set %s env var", constants.VSphereVCenterEnvVar)
811813
}
812814

813-
platform.DeprecatedUsername = vsphereUsername
814-
platform.DeprecatedPassword = vspherePassword
815+
if err := setCredValue("username", &platform.DeprecatedUsername, vsphereUsername); err != nil {
816+
return nil, err
817+
}
818+
if err := setCredValue("password", &platform.DeprecatedPassword, vspherePassword); err != nil {
819+
return nil, err
820+
}
815821
platform.DeprecatedNetwork = vSphereNetwork
816822
platform.DeprecatedDatacenter = vSphereDatacenter
817823
platform.DeprecatedDefaultDatastore = vSphereDatastore
818824
platform.DeprecatedVCenter = vSphereVCenter
819825
platform.DeprecatedFolder = o.VSphereFolder
820826
platform.DeprecatedCluster = o.VSphereCluster
827+
dummyInstallConfig := &installertypes.InstallConfig{
828+
Platform: installertypes.Platform{
829+
VSphere: &platform,
830+
},
831+
}
832+
if err := conversion.ConvertInstallConfig(dummyInstallConfig); err != nil {
833+
return nil, fmt.Errorf("failed to update deprecated vSphere fields")
834+
}
821835
}
822836

837+
// Build a new-style creds object
838+
vcenterCreds := []installervsphere.VCenters{}
823839
for i := range platform.VCenters {
824-
if platform.VCenters[i].Username == "" {
825-
platform.VCenters[i].Username = vsphereUsername
826-
}
827-
if platform.VCenters[i].Password == "" {
828-
platform.VCenters[i].Password = vspherePassword
840+
// Allow a hybrid input style: creds can be included in the json blob OR individually
841+
// via env vars. The former takes precedence.
842+
for i := range platform.VCenters {
843+
if err := setCredValue("username", &platform.VCenters[i].Username, vsphereUsername); err != nil {
844+
return nil, err
845+
}
846+
if err := setCredValue("password", &platform.VCenters[i].Password, vspherePassword); err != nil {
847+
return nil, err
848+
}
829849
}
850+
vcenterCreds = append(vcenterCreds, installervsphere.VCenters{
851+
VCenter: platform.VCenters[i].Server,
852+
Username: platform.VCenters[i].Username,
853+
Password: platform.VCenters[i].Password,
854+
})
855+
}
856+
vcenterCredsb, err := json.Marshal(vcenterCreds)
857+
if err != nil {
858+
return nil, errors.Wrap(err, "failed to marhsal vcenter creds list")
830859
}
831860

832861
if len(platform.APIVIPs) == 0 {
862+
if o.VSphereAPIVIP == "" {
863+
return nil, fmt.Errorf("Must supply an API VIP")
864+
}
833865
platform.APIVIPs = []string{o.VSphereAPIVIP}
834866
}
835867
if len(platform.IngressVIPs) == 0 {
868+
if o.VSphereIngressVIP == "" {
869+
return nil, fmt.Errorf("Must supply an Ingress VIP")
870+
}
836871
platform.IngressVIPs = []string{o.VSphereIngressVIP}
837872
}
838873

839-
vsphereProvider := &clusterresource.VSphereCloudBuilder{
840-
Username: vsphereUsername,
841-
Password: vspherePassword,
842-
CACert: bytes.Join(caCerts, []byte("\n")),
843-
Infrastructure: &platform,
844-
}
845-
builder.CloudBuilder = vsphereProvider
874+
builder.CloudBuilder = clusterresource.NewVSphereCloudBuilder(
875+
map[string][]byte{
876+
constants.UsernameSecretKey: []byte(vsphereUsername),
877+
constants.PasswordSecretKey: []byte(vspherePassword),
878+
"vCenters": vcenterCredsb,
879+
},
880+
bytes.Join(caCerts, []byte("\n")),
881+
&platform,
882+
)
846883
case constants.PlatformIBMCloud:
847884
ibmCloudAPIKey := os.Getenv(constants.IBMCloudAPIKeyEnvVar)
848885
if ibmCloudAPIKey == "" {

0 commit comments

Comments
 (0)