Skip to content

Commit baf76f9

Browse files
committed
vsphere-fix convert if only provided name
In 4.12 and prior versions of the installer allowed non-pathed names of vCenter objects. In 4.13+ that is no longer allowed and absolute full paths are required. This change is causing issues with ACM/Hive. The only resolution (not ideal) is to connect to vCenter and determine from potentially only the objects name to determine the absolute full path. If there is no available connection to vCenter in the case of AI or Agent installer this fails back to only merging paths. Move existing functions from private to public to assist hive - reducing copy and paste.
1 parent e28c80f commit baf76f9

File tree

3 files changed

+346
-123
lines changed

3 files changed

+346
-123
lines changed

pkg/asset/installconfig/vsphere/mock/vsphere_sim.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func StartSimulator(setVersionToSupported bool) (*simulator.Server, error) {
4545
}
4646

4747
model.Folder = 1
48-
model.Datacenter = 2
48+
model.Datacenter = 5
4949
model.OpaqueNetwork = 1
5050
err := model.Create()
5151
if err != nil {

pkg/types/vsphere/conversion/installconfig.go

Lines changed: 160 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package conversion
22

33
import (
4-
"fmt"
5-
"strings"
4+
"context"
5+
"errors"
6+
"net/url"
7+
"path"
8+
"time"
69

710
"github.com/sirupsen/logrus"
11+
"github.com/vmware/govmomi"
12+
"github.com/vmware/govmomi/find"
13+
"github.com/vmware/govmomi/vim25/soap"
814

915
"github.com/openshift/installer/pkg/types"
1016
"github.com/openshift/installer/pkg/types/vsphere"
@@ -21,11 +27,59 @@ const (
2127
GeneratedFailureDomainZone string = "generated-zone"
2228
)
2329

24-
// ConvertInstallConfig modifies a given platform spec for the new requirements.
25-
func ConvertInstallConfig(config *types.InstallConfig) error {
26-
platform := config.Platform.VSphere
30+
// GetFinder connects to vCenter via SOAP and returns the Finder object if the SOAP
31+
// connection is successful. If the connection fails it returns nil.
32+
// Errors are mostly ignored to support AI and agent installers.
33+
func GetFinder(server, username, password string) (*find.Finder, error) {
34+
var finder *find.Finder
35+
36+
if server != "" && password != "" && username != "" {
37+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
38+
defer cancel()
39+
u, err := soap.ParseURL(server)
40+
if err != nil {
41+
return nil, err
42+
}
43+
u.User = url.UserPassword(username, password)
44+
45+
client, err := govmomi.NewClient(ctx, u, false)
46+
if err != nil {
47+
// If bogus authentication is provided in the scenario of AI or assisted
48+
// just provide warning message. If this is IPI or UPI validation will
49+
// catch and halt on incorrect authentication.
50+
localLogger.Warnf("unable to log into vCenter %s, %v", server, err)
51+
return nil, nil
52+
}
53+
finder = find.NewFinder(client.Client, true)
54+
}
55+
56+
return finder, nil
57+
}
58+
59+
func findViaPathOrName(finder *find.Finder, objectPath, objectFindPath string) (string, error) {
60+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
61+
defer cancel()
2762

28-
// Scenario: IPI or 4.12 Zonal IPI w/o vcenters defined
63+
elements, err := finder.ManagedObjectListChildren(ctx, objectFindPath)
64+
if err != nil {
65+
return "", err
66+
}
67+
68+
for _, e := range elements {
69+
if e.Path == objectPath {
70+
return objectPath, nil
71+
}
72+
73+
if path.Base(e.Path) == path.Base(objectPath) {
74+
return e.Path, nil
75+
}
76+
}
77+
return "", errors.New("unable to find object")
78+
}
79+
80+
// fixNoVCentersScenario this function creates the VCenters slice
81+
// with existing legacy vcenter authentication and configuration.
82+
func fixNoVCentersScenario(platform *vsphere.Platform) {
2983
if len(platform.VCenters) == 0 {
3084
createVCenters(platform)
3185

@@ -44,23 +98,40 @@ func ConvertInstallConfig(config *types.InstallConfig) error {
4498
}
4599
}
46100
}
101+
}
47102

48-
// Scenario: Fields are not paths
103+
func fixTechPreviewZonalFailureDomainsScenario(platform *vsphere.Platform, finder *find.Finder) error {
49104
if len(platform.FailureDomains) > 0 {
105+
var err error
106+
50107
for i := range platform.FailureDomains {
51-
platform.FailureDomains[i].Topology.ComputeCluster = setComputeClusterPath(platform.FailureDomains[i].Topology.ComputeCluster,
52-
platform.FailureDomains[i].Topology.Datacenter)
108+
computeCluster := platform.FailureDomains[i].Topology.ComputeCluster
109+
datastore := platform.FailureDomains[i].Topology.Datastore
110+
folder := platform.FailureDomains[i].Topology.Folder
111+
datacenter := platform.FailureDomains[i].Topology.Datacenter
53112

54-
platform.FailureDomains[i].Topology.Datastore = setDatastorePath(platform.FailureDomains[i].Topology.Datastore,
55-
platform.FailureDomains[i].Topology.Datacenter)
113+
platform.FailureDomains[i].Topology.ComputeCluster, err = SetObjectPath(finder, "host", computeCluster, datacenter)
114+
if err != nil {
115+
return err
116+
}
117+
118+
platform.FailureDomains[i].Topology.Datastore, err = SetObjectPath(finder, "datastore", datastore, datacenter)
119+
if err != nil {
120+
return err
121+
}
56122

57-
platform.FailureDomains[i].Topology.Folder = setFolderPath(platform.FailureDomains[i].Topology.Folder,
58-
platform.FailureDomains[i].Topology.Datacenter)
123+
platform.FailureDomains[i].Topology.Folder, err = SetObjectPath(finder, "vm", folder, datacenter)
124+
if err != nil {
125+
return err
126+
}
59127
}
60128
}
129+
return nil
130+
}
61131

62-
// Scenario: legacy UPI or IPI
132+
func fixLegacyPlatformScenario(platform *vsphere.Platform, finder *find.Finder) error {
63133
if len(platform.FailureDomains) == 0 {
134+
var err error
64135
localLogger.Warn("vsphere topology fields are now deprecated; please use failureDomains")
65136

66137
platform.FailureDomains = make([]vsphere.FailureDomain, 1)
@@ -71,38 +142,92 @@ func ConvertInstallConfig(config *types.InstallConfig) error {
71142

72143
platform.FailureDomains[0].Topology.Datacenter = platform.DeprecatedDatacenter
73144
platform.FailureDomains[0].Topology.ResourcePool = platform.DeprecatedResourcePool
74-
platform.FailureDomains[0].Topology.ComputeCluster = setComputeClusterPath(platform.DeprecatedCluster, platform.DeprecatedDatacenter)
75145
platform.FailureDomains[0].Topology.Networks = make([]string, 1)
76146
platform.FailureDomains[0].Topology.Networks[0] = platform.DeprecatedNetwork
77-
platform.FailureDomains[0].Topology.Datastore = setDatastorePath(platform.DeprecatedDefaultDatastore, platform.DeprecatedDatacenter)
78-
platform.FailureDomains[0].Topology.Folder = setFolderPath(platform.DeprecatedFolder, platform.DeprecatedDatacenter)
79-
}
80147

81-
return nil
82-
}
148+
platform.FailureDomains[0].Topology.ComputeCluster, err = SetObjectPath(finder, "host", platform.DeprecatedCluster, platform.DeprecatedDatacenter)
149+
if err != nil {
150+
return err
151+
}
83152

84-
func setComputeClusterPath(cluster, datacenter string) string {
85-
if cluster != "" && !strings.HasPrefix(cluster, "/") {
86-
localLogger.Warnf("computeCluster as a non-path is now deprecated; please use the form: /%s/host/%s", datacenter, cluster)
87-
return fmt.Sprintf("/%s/host/%s", datacenter, cluster)
153+
platform.FailureDomains[0].Topology.Datastore, err = SetObjectPath(finder, "datastore", platform.DeprecatedDefaultDatastore, platform.DeprecatedDatacenter)
154+
if err != nil {
155+
return err
156+
}
157+
158+
platform.FailureDomains[0].Topology.Folder, err = SetObjectPath(finder, "vm", platform.DeprecatedFolder, platform.DeprecatedDatacenter)
159+
if err != nil {
160+
return err
161+
}
88162
}
89-
return cluster
163+
return nil
90164
}
91165

92-
func setDatastorePath(datastore, datacenter string) string {
93-
if datastore != "" && !strings.HasPrefix(datastore, "/") {
94-
localLogger.Warnf("datastore as a non-path is now deprecated; please use the form: /%s/datastore/%s", datacenter, datastore)
95-
return fmt.Sprintf("/%s/datastore/%s", datacenter, datastore)
166+
// ConvertInstallConfig modifies a given platform spec for the new requirements.
167+
func ConvertInstallConfig(config *types.InstallConfig) error {
168+
platform := config.Platform.VSphere
169+
170+
fixNoVCentersScenario(platform)
171+
finder, err := GetFinder(platform.VCenters[0].Server, platform.VCenters[0].Username, platform.VCenters[0].Password)
172+
if err != nil {
173+
return err
174+
}
175+
err = fixTechPreviewZonalFailureDomainsScenario(platform, finder)
176+
if err != nil {
177+
return err
178+
}
179+
err = fixLegacyPlatformScenario(platform, finder)
180+
if err != nil {
181+
return err
96182
}
97-
return datastore
183+
184+
return nil
98185
}
99186

100-
func setFolderPath(folder, datacenter string) string {
101-
if folder != "" && !strings.HasPrefix(folder, "/") {
102-
localLogger.Warnf("folder as a non-path is now deprecated; please use the form: /%s/vm/%s", datacenter, folder)
103-
return fmt.Sprintf("/%s/vm/%s", datacenter, folder)
187+
// SetObjectPath based on the pathType will either determine the path for the type via
188+
// a simple join of the datacenter, pathType and objectPath if finder is nil
189+
// or via a connection to vCenter find of all child objects under the
190+
// datacenter and pathType.
191+
// pathType must only be "host", "vm", or "datastore".
192+
func SetObjectPath(finder *find.Finder, pathType, objectPath, datacenter string) (string, error) {
193+
if objectPath != "" && !path.IsAbs(objectPath) {
194+
var joinedObjectPath string
195+
var joinedObjectFindPath string
196+
var paramName string
197+
198+
switch pathType {
199+
case "host":
200+
paramName = "computeCluster"
201+
case "vm":
202+
paramName = "folder"
203+
case "datastore":
204+
paramName = "datastore"
205+
default:
206+
return "", errors.New("pathType can only be host, datastore or vm")
207+
}
208+
209+
joinedObjectFindPath = path.Join("/", datacenter, pathType, "...")
210+
joinedObjectPath = path.Join("/", datacenter, pathType, objectPath)
211+
212+
if finder == nil {
213+
localLogger.Warnf("%s as a non-path is now deprecated; please use the joined form: %s", paramName, joinedObjectPath)
214+
return joinedObjectPath, nil
215+
}
216+
217+
newObjectPath, err := findViaPathOrName(finder, joinedObjectPath, joinedObjectFindPath)
218+
if err != nil {
219+
return "", err
220+
}
221+
222+
if objectPath != newObjectPath {
223+
localLogger.Debugf("%s path changed from %s to %s", paramName, objectPath, newObjectPath)
224+
}
225+
localLogger.Warnf("%s as a non-path is now deprecated; please use the discovered form: %s", paramName, newObjectPath)
226+
227+
return newObjectPath, nil
104228
}
105-
return folder
229+
230+
return objectPath, nil
106231
}
107232

108233
func createVCenters(platform *vsphere.Platform) {

0 commit comments

Comments
 (0)