Skip to content

Commit 37a5995

Browse files
rvanderp3jcpowermac
authored andcommitted
generate capi machine manifests
1 parent a421cc1 commit 37a5995

File tree

9 files changed

+722
-88
lines changed

9 files changed

+722
-88
lines changed

pkg/asset/cluster/cluster.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/openshift/installer/pkg/asset/cluster/azure"
1515
"github.com/openshift/installer/pkg/asset/cluster/openstack"
1616
"github.com/openshift/installer/pkg/asset/cluster/tfvars"
17+
vcentercontexts "github.com/openshift/installer/pkg/asset/cluster/vsphere"
1718
"github.com/openshift/installer/pkg/asset/ignition/bootstrap"
1819
"github.com/openshift/installer/pkg/asset/ignition/machine"
1920
"github.com/openshift/installer/pkg/asset/installconfig"
@@ -54,13 +55,14 @@ func (c *Cluster) Dependencies() []asset.Asset {
5455
return []asset.Asset{
5556
&installconfig.ClusterID{},
5657
&installconfig.InstallConfig{},
57-
// PlatformCredsCheck, PlatformPermsCheck and PlatformProvisionCheck
58+
// PlatformCredsCheck, PlatformPermsCheck, PlatformProvisionCheck, and VCenterContexts.
5859
// perform validations & check perms required to provision infrastructure.
5960
// We do not actually use them in this asset directly, hence
6061
// they are put in the dependencies but not fetched in Generate.
6162
&installconfig.PlatformCredsCheck{},
6263
&installconfig.PlatformPermsCheck{},
6364
&installconfig.PlatformProvisionCheck{},
65+
&vcentercontexts.VCenterContexts{},
6466
&quota.PlatformQuotaCheck{},
6567
&tfvars.TerraformVariables{},
6668
&password.KubeadminPassword{},
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package vsphere
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"path"
7+
8+
"github.com/openshift/installer/pkg/asset"
9+
"github.com/openshift/installer/pkg/asset/installconfig"
10+
"github.com/openshift/installer/pkg/types/vsphere"
11+
vsphereplatform "github.com/openshift/installer/pkg/types/vsphere"
12+
"github.com/vmware/govmomi/object"
13+
"github.com/vmware/govmomi/vapi/tags"
14+
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/session"
15+
)
16+
17+
func (a *VCenterContexts) cacheNetworkNames(ctx context.Context, failureDomain vsphere.FailureDomain, session *session.Session, server string) error {
18+
19+
finder := session.Finder
20+
clusterPath := failureDomain.Topology.ComputeCluster
21+
22+
clusterRef, err := finder.ClusterComputeResource(ctx, clusterPath)
23+
if err != nil {
24+
return fmt.Errorf("unable to retrieve compute cluster: %v", err)
25+
}
26+
27+
pools, err := finder.ResourcePoolList(ctx, clusterRef.InventoryPath)
28+
if err != nil {
29+
return fmt.Errorf("unable to retrieve resource pools relative to compute cluster: %v", err)
30+
}
31+
32+
for _, network := range failureDomain.Topology.Networks {
33+
clusterMap, present := a.VCenters[server].ClusterNetworkMap[clusterPath]
34+
if !present {
35+
clusterMap = NetworkNameMap{
36+
Cluster: clusterPath,
37+
NetworkNames: map[string]string{},
38+
ResourcePools: map[string]*object.ResourcePool{},
39+
}
40+
for _, pool := range pools {
41+
clusterMap.ResourcePools[path.Clean(pool.InventoryPath)] = pool
42+
}
43+
44+
a.VCenters[server].ClusterNetworkMap[clusterPath] = clusterMap
45+
}
46+
47+
networkName := path.Join(clusterRef.InventoryPath, network)
48+
clusterMap.NetworkNames[network] = networkName
49+
50+
}
51+
52+
return nil
53+
}
54+
55+
func (a *VCenterContexts) createClusterTagID(ctx context.Context, session *session.Session, clusterId string, server string) error {
56+
tagManager := session.TagManager
57+
categories, err := tagManager.GetCategories(ctx)
58+
if err != nil {
59+
return fmt.Errorf("unable to get tag categories: %v", err)
60+
}
61+
62+
var clusterTagCategory *tags.Category
63+
clusterTagCategoryName := fmt.Sprintf("openshift-%s", clusterId)
64+
tagCategoryId := ""
65+
66+
for _, category := range categories {
67+
if category.Name == clusterTagCategoryName {
68+
clusterTagCategory = &category
69+
tagCategoryId = category.ID
70+
break
71+
}
72+
}
73+
74+
if clusterTagCategory == nil {
75+
clusterTagCategory = &tags.Category{
76+
Name: clusterTagCategoryName,
77+
Description: "Added by openshift-install do not remove",
78+
Cardinality: "SINGLE",
79+
AssociableTypes: []string{
80+
"urn:vim25:VirtualMachine",
81+
"urn:vim25:ResourcePool",
82+
"urn:vim25:Folder",
83+
"urn:vim25:Datastore",
84+
"urn:vim25:StoragePod",
85+
},
86+
}
87+
tagCategoryId, err = tagManager.CreateCategory(ctx, clusterTagCategory)
88+
if err != nil {
89+
return fmt.Errorf("unable to create tag category: %v", err)
90+
}
91+
}
92+
93+
var categoryTag *tags.Tag
94+
tagId := ""
95+
96+
categoryTags, err := tagManager.GetTagsForCategory(ctx, tagCategoryId)
97+
if err != nil {
98+
return fmt.Errorf("unable to get tags for category: %v", err)
99+
}
100+
for _, tag := range categoryTags {
101+
if tag.Name == clusterId {
102+
categoryTag = &tag
103+
tagId = tag.ID
104+
break
105+
}
106+
}
107+
108+
if categoryTag == nil {
109+
categoryTag = &tags.Tag{
110+
Description: "Added by openshift-install do not remove",
111+
Name: clusterId,
112+
CategoryID: tagCategoryId,
113+
}
114+
tagId, err = tagManager.CreateTag(ctx, categoryTag)
115+
if err != nil {
116+
return fmt.Errorf("unable to create tag: %v", err)
117+
}
118+
}
119+
120+
vCenterContext := a.VCenters[server]
121+
vCenterContext.TagID = tagId
122+
a.VCenters[server] = vCenterContext
123+
124+
return nil
125+
}
126+
127+
type NetworkNameMap struct {
128+
Cluster string
129+
ResourcePools map[string]*object.ResourcePool
130+
NetworkNames map[string]string
131+
}
132+
133+
// VCenterContext maintains context of known vCenters to be used in CAPI manifest reconciliation.
134+
type VCenterContext struct {
135+
VCenter string
136+
TagID string
137+
Datacenters []string
138+
ClusterNetworkMap map[string]NetworkNameMap
139+
}
140+
141+
type VCenterContexts struct {
142+
VCenters map[string]VCenterContext
143+
}
144+
145+
var (
146+
_ asset.Asset = (*VCenterContexts)(nil)
147+
)
148+
149+
func (a *VCenterContexts) Generate(parents asset.Parents) error {
150+
ctx := context.TODO()
151+
152+
a.VCenters = map[string]VCenterContext{}
153+
154+
ic := &installconfig.InstallConfig{}
155+
clusterID := &installconfig.ClusterID{}
156+
parents.Get(
157+
ic,
158+
clusterID,
159+
)
160+
161+
if ic.Config.Platform.Name() != vsphereplatform.Name {
162+
return nil
163+
}
164+
165+
installConfig := ic.Config
166+
167+
for _, vcenter := range installConfig.VSphere.VCenters {
168+
server := vcenter.Server
169+
params := session.NewParams().WithServer(server).WithUserInfo(vcenter.Username, vcenter.Password)
170+
tempConnection, err := session.GetOrCreate(ctx, params)
171+
if err != nil {
172+
return fmt.Errorf("unable to create session: %v", err)
173+
}
174+
175+
defer tempConnection.CloseIdleConnections()
176+
177+
a.VCenters[server] = VCenterContext{
178+
VCenter: server,
179+
Datacenters: vcenter.Datacenters,
180+
ClusterNetworkMap: map[string]NetworkNameMap{},
181+
}
182+
183+
if err = a.createClusterTagID(ctx, tempConnection, clusterID.InfraID, server); err != nil {
184+
return fmt.Errorf("unable to create cluster tag ID: %v", err)
185+
}
186+
187+
for _, failureDomain := range installConfig.VSphere.FailureDomains {
188+
if failureDomain.Server != server {
189+
continue
190+
}
191+
if err = a.cacheNetworkNames(ctx, failureDomain, tempConnection, server); err != nil {
192+
return fmt.Errorf("unable to retrieve network names: %v", err)
193+
}
194+
}
195+
}
196+
return nil
197+
}
198+
199+
func (a *VCenterContexts) Dependencies() []asset.Asset {
200+
return []asset.Asset{
201+
&installconfig.InstallConfig{},
202+
&installconfig.ClusterID{},
203+
}
204+
}
205+
206+
func (a *VCenterContexts) Name() string {
207+
return "vCenter Context"
208+
}

pkg/asset/machines/clusterapi.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import (
1818
"sigs.k8s.io/controller-runtime/pkg/client"
1919
"sigs.k8s.io/yaml"
2020

21+
vspherecapi "github.com/openshift/installer/pkg/asset/machines/vsphere"
22+
2123
configv1 "github.com/openshift/api/config/v1"
2224
"github.com/openshift/installer/pkg/asset"
25+
vspherectx "github.com/openshift/installer/pkg/asset/cluster/vsphere"
2326
"github.com/openshift/installer/pkg/asset/installconfig"
2427
"github.com/openshift/installer/pkg/asset/machines/aws"
2528
"github.com/openshift/installer/pkg/asset/machines/gcp"
@@ -30,6 +33,7 @@ import (
3033
awsdefaults "github.com/openshift/installer/pkg/types/aws/defaults"
3134
azuretypes "github.com/openshift/installer/pkg/types/azure"
3235
gcptypes "github.com/openshift/installer/pkg/types/gcp"
36+
vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
3337
)
3438

3539
var _ asset.WritableRuntimeAsset = (*ClusterAPI)(nil)
@@ -51,15 +55,18 @@ func (c *ClusterAPI) Dependencies() []asset.Asset {
5155
&installconfig.InstallConfig{},
5256
&installconfig.ClusterID{},
5357
new(rhcos.Image),
58+
&vspherectx.VCenterContexts{},
5459
}
5560
}
5661

5762
// Generate generates Cluster API machine manifests.
5863
func (c *ClusterAPI) Generate(dependencies asset.Parents) error {
64+
5965
installConfig := &installconfig.InstallConfig{}
6066
clusterID := &installconfig.ClusterID{}
67+
vsphereContexts := &vspherectx.VCenterContexts{}
6168
rhcosImage := new(rhcos.Image)
62-
dependencies.Get(installConfig, clusterID, rhcosImage)
69+
dependencies.Get(installConfig, clusterID, rhcosImage, vsphereContexts)
6370

6471
// If the feature gate is not enabled, do not generate any manifests.
6572
if !capiutils.IsEnabled(installConfig) {
@@ -249,12 +256,42 @@ func (c *ClusterAPI) Generate(dependencies asset.Parents) error {
249256
return fmt.Errorf("failed to create bootstrap machine objects %w", err)
250257
}
251258
c.FileList = append(c.FileList, bootstrapMachines...)
259+
case vspheretypes.Name:
260+
mpool := defaultVSphereMachinePoolPlatform()
261+
mpool.NumCPUs = 4
262+
mpool.NumCoresPerSocket = 4
263+
mpool.MemoryMiB = 16384
264+
mpool.Set(ic.Platform.VSphere.DefaultMachinePlatform)
265+
mpool.Set(pool.Platform.VSphere)
266+
267+
// The machinepool has no zones defined, there are FailureDomains
268+
// This is a vSphere zonal installation. Generate machinepool zone
269+
// list.
270+
271+
fdCount := int64(len(ic.Platform.VSphere.FailureDomains))
272+
var idx int64
273+
if len(mpool.Zones) == 0 && len(ic.VSphere.FailureDomains) != 0 {
274+
for i := int64(0); i < *(ic.ControlPlane.Replicas); i++ {
275+
idx = i
276+
if idx >= fdCount {
277+
idx = i % fdCount
278+
}
279+
mpool.Zones = append(mpool.Zones, ic.VSphere.FailureDomains[idx].Name)
280+
}
281+
}
282+
283+
pool.Platform.VSphere = &mpool
284+
templateName := clusterID.InfraID + "-rhcos"
252285

286+
c.FileList, err = vspherecapi.GenerateMachines(ctx, clusterID.InfraID, ic, &pool, templateName, "master", vsphereContexts)
287+
if err != nil {
288+
errors.Wrap(err, "unable to generate CAPI machines for vSphere")
289+
}
253290
default:
254291
// TODO: support other platforms
255292
}
256293

257-
// Create the infrastructure manifests.
294+
// Create the machine manifests.
258295
for _, m := range c.FileList {
259296
objData, err := yaml.Marshal(m.Object)
260297
if err != nil {

0 commit comments

Comments
 (0)