11package conversion
22
33import (
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
108233func createVCenters (platform * vsphere.Platform ) {
0 commit comments