Skip to content

Commit 3add9b2

Browse files
authored
Feature: PowerVS cluster creation with dynamic resource creation (#1608)
* api changes to support infra creation * controller changes to support infra creation * scope changes to create infra creation * package files changes to support infra creation * docs changes to support infra creation * go module changes * Fix test failures Signed-off-by: Prajyot-Parab <[email protected]> --------- Signed-off-by: Prajyot-Parab <[email protected]>
1 parent 469a6ba commit 3add9b2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+5225
-348
lines changed

api/v1beta1/ibmpowervs_conversion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func Convert_v1beta2_IBMPowerVSMachineSpec_To_v1beta1_IBMPowerVSMachineSpec(in *
195195
}
196196

197197
func Convert_v1beta2_IBMPowerVSClusterSpec_To_v1beta1_IBMPowerVSClusterSpec(in *infrav1beta2.IBMPowerVSClusterSpec, out *IBMPowerVSClusterSpec, s apiconversion.Scope) error {
198-
if in.ServiceInstance.ID != nil {
198+
if in.ServiceInstance != nil && in.ServiceInstance.ID != nil {
199199
out.ServiceInstanceID = *in.ServiceInstance.ID
200200
}
201201
return autoConvert_v1beta2_IBMPowerVSClusterSpec_To_v1beta1_IBMPowerVSClusterSpec(in, out, s)

api/v1beta1/zz_generated.conversion.go

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1beta2/conditions_consts.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,44 @@ const (
7575
)
7676

7777
const (
78-
// LoadBalancerReadyCondition reports on current status of the load balancer. Ready indicates the load balancer is in a active state.
78+
// ServiceInstanceReadyCondition reports on the successful reconciliation of a Power VS workspace.
79+
ServiceInstanceReadyCondition capiv1beta1.ConditionType = "ServiceInstanceReady"
80+
// ServiceInstanceReconciliationFailedReason used when an error occurs during workspace reconciliation.
81+
ServiceInstanceReconciliationFailedReason = "ServiceInstanceReconciliationFailed"
82+
83+
// NetworkReadyCondition reports on the successful reconciliation of a Power VS network.
84+
NetworkReadyCondition capiv1beta1.ConditionType = "NetworkReady"
85+
// NetworkReconciliationFailedReason used when an error occurs during network reconciliation.
86+
NetworkReconciliationFailedReason = "NetworkReconciliationFailed"
87+
88+
// VPCReadyCondition reports on the successful reconciliation of a VPC.
89+
VPCReadyCondition capiv1beta1.ConditionType = "VPCReady"
90+
// VPCReconciliationFailedReason used when an error occurs during VPC reconciliation.
91+
VPCReconciliationFailedReason = "VPCReconciliationFailed"
92+
93+
// VPCSubnetReadyCondition reports on the successful reconciliation of a VPC subnet.
94+
VPCSubnetReadyCondition capiv1beta1.ConditionType = "VPCSubnetReady"
95+
// VPCSubnetReconciliationFailedReason used when an error occurs during VPC subnet reconciliation.
96+
VPCSubnetReconciliationFailedReason = "VPCSubnetReconciliationFailed"
97+
98+
// TransitGatewayReadyCondition reports on the successful reconciliation of a Power VS transit gateway.
99+
TransitGatewayReadyCondition capiv1beta1.ConditionType = "TransitGatewayReady"
100+
// TransitGatewayReconciliationFailedReason used when an error occurs during transit gateway reconciliation.
101+
TransitGatewayReconciliationFailedReason = "TransitGatewayReconciliationFailed"
102+
103+
// LoadBalancerReadyCondition reports on the successful reconciliation of a Power VS network.
79104
LoadBalancerReadyCondition capiv1beta1.ConditionType = "LoadBalancerReady"
105+
// LoadBalancerReconciliationFailedReason used when an error occurs during loadbalancer reconciliation.
106+
LoadBalancerReconciliationFailedReason = "LoadBalancerReconciliationFailed"
107+
108+
// COSInstanceReadyCondition reports on the successful reconciliation of a COS instance.
109+
COSInstanceReadyCondition capiv1beta1.ConditionType = "COSInstanceCreated"
110+
// COSInstanceReconciliationFailedReason used when an error occurs during COS instance reconciliation.
111+
COSInstanceReconciliationFailedReason = "COSInstanceCreationFailed"
112+
)
113+
114+
const (
115+
// CreateInfrastructureAnnotation is the name of an annotation that indicates if
116+
// Power VS infrastructure should be created as a part of cluster creation.
117+
CreateInfrastructureAnnotation = "powervs.cluster.x-k8s.io/create-infra"
80118
)

api/v1beta2/ibmpowervscluster_types.go

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,21 @@ type IBMPowerVSClusterSpec struct {
3737
ServiceInstanceID string `json:"serviceInstanceID"`
3838

3939
// Network is the reference to the Network to use for this cluster.
40-
// when the field is omitted, A DHCP service will be created in the Power VS server workspace and its private network will be used.
40+
// when the field is omitted, A DHCP service will be created in the Power VS workspace and its private network will be used.
41+
// the DHCP service created network will have the following name format
42+
// 1. in the case of DHCPServer.Name is not set the name will be DHCPSERVER<CLUSTER_NAME>_Private.
43+
// 2. if DHCPServer.Name is set the name will be DHCPSERVER<DHCPServer.Name>_Private.
44+
// when Network.ID is set, its expected that there exist a network in PowerVS workspace with id or else system will give error.
45+
// when Network.Name is set, system will first check for network with Name in PowerVS workspace, if not exist network will be created by DHCP service.
46+
// Network.RegEx is not yet supported and system will ignore the value.
4147
Network IBMPowerVSResourceReference `json:"network"`
4248

49+
// dhcpServer is contains the configuration to be used while creating a new DHCP server in PowerVS workspace.
50+
// when the field is omitted, CLUSTER_NAME will be used as DHCPServer.Name and DHCP server will be created.
51+
// it will automatically create network with name DHCPSERVER<DHCPServer.Name>_Private in PowerVS workspace.
52+
// +optional
53+
DHCPServer *DHCPServer `json:"dhcpServer,omitempty"`
54+
4355
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
4456
// +optional
4557
ControlPlaneEndpoint capiv1beta1.APIEndpoint `json:"controlPlaneEndpoint"`
@@ -50,48 +62,108 @@ type IBMPowerVSClusterSpec struct {
5062
// supported serviceInstance identifier in PowerVSResource are Name and ID and that can be obtained from IBM Cloud UI or IBM Cloud cli.
5163
// More detail about Power VS service instance.
5264
// https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-power-virtual-server
53-
// when omitted system will dynamically create the service instance
65+
// when omitted system will dynamically create the service instance with name CLUSTER_NAME-serviceInstance.
66+
// when ServiceInstance.ID is set, its expected that there exist a service instance in PowerVS workspace with id or else system will give error.
67+
// when ServiceInstance.Name is set, system will first check for service instance with Name in PowerVS workspace, if not exist system will create new instance.
68+
// ServiceInstance.Regex is not yet supported not yet supported and system will ignore the value.
5469
// +optional
5570
ServiceInstance *IBMPowerVSResourceReference `json:"serviceInstance,omitempty"`
5671

5772
// zone is the name of Power VS zone where the cluster will be created
5873
// possible values can be found here https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-power-virtual-server.
59-
// when omitted syd04 will be set as default zone.
60-
// +kubebuilder:default=dal10
74+
// when powervs.cluster.x-k8s.io/create-infra=true annotation is set on IBMPowerVSCluster resource,
75+
// 1. it is expected to set the zone, not setting will result in webhook error.
76+
// 2. the zone should have PER capabilities, or else system will give error.
6177
// +optional
6278
Zone *string `json:"zone,omitempty"`
6379

6480
// resourceGroup name under which the resources will be created.
65-
// when omitted default resource group of the account will be used.
81+
// when powervs.cluster.x-k8s.io/create-infra=true annotation is set on IBMPowerVSCluster resource,
82+
// 1. it is expected to set the ResourceGroup.Name, not setting will result in webhook error.
83+
// ServiceInstance.ID and ServiceInstance.Regex is not yet supported and system will ignore the value.
6684
// +optional
67-
ResourceGroup *string `json:"resourceGroup,omitempty"`
85+
ResourceGroup *IBMPowerVSResourceReference `json:"resourceGroup,omitempty"`
6886

6987
// vpc contains information about IBM Cloud VPC resources.
88+
// when omitted system will dynamically create the VPC with name CLUSTER_NAME-vpc.
89+
// when VPC.ID is set, its expected that there exist a VPC with ID or else system will give error.
90+
// when VPC.Name is set, system will first check for VPC with Name, if not exist system will create new VPC.
91+
// when powervs.cluster.x-k8s.io/create-infra=true annotation is set on IBMPowerVSCluster resource,
92+
// 1. it is expected to set the VPC.Region, not setting will result in webhook error.
7093
// +optional
7194
VPC *VPCResourceReference `json:"vpc,omitempty"`
7295

7396
// vpcSubnets contains information about IBM Cloud VPC Subnet resources.
97+
// when omitted system will create the subnets in all the zone corresponding to VPC.Region, with name CLUSTER_NAME-vpcsubnet-ZONE_NAME.
98+
// possible values can be found here https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-creating-power-virtual-server.
99+
// when VPCSubnets[].ID is set, its expected that there exist a subnet with ID or else system will give error.
100+
// when VPCSubnets[].Zone is not set, a random zone is picked from available zones of VPC.Region.
101+
// when VPCSubnets[].Name is not set, system will set name as CLUSTER_NAME-vpcsubnet-INDEX.
102+
// if subnet with name VPCSubnets[].Name not found, system will create new subnet in VPCSubnets[].Zone.
74103
// +optional
75104
VPCSubnets []Subnet `json:"vpcSubnets,omitempty"`
76105

77106
// transitGateway contains information about IBM Cloud TransitGateway
78107
// IBM Cloud TransitGateway helps in establishing network connectivity between IBM Cloud Power VS and VPC infrastructure
79108
// more information about TransitGateway can be found here https://www.ibm.com/products/transit-gateway.
109+
// when TransitGateway.ID is set, its expected that there exist a TransitGateway with ID or else system will give error.
110+
// when TransitGateway.Name is set, system will first check for TransitGateway with Name, if not exist system will create new TransitGateway.
80111
// +optional
81112
TransitGateway *TransitGateway `json:"transitGateway,omitempty"`
82113

83-
// loadBalancers is optional configuration for configuring loadbalancers to control plane or data plane nodes
114+
// loadBalancers is optional configuration for configuring loadbalancers to control plane or data plane nodes.
115+
// when omitted system will create a public loadbalancer with name CLUSTER_NAME-loadbalancer.
84116
// when specified a vpc loadbalancer will be created and controlPlaneEndpoint will be set with associated hostname of loadbalancer.
85-
// when omitted user is expected to set controlPlaneEndpoint.
117+
// ControlPlaneEndpoint will be set with associated hostname of public loadbalancer.
118+
// when LoadBalancers[].ID is set, its expected that there exist a loadbalancer with ID or else system will give error.
119+
// when LoadBalancers[].Name is set, system will first check for loadbalancer with Name, if not exist system will create new loadbalancer.
86120
// +optional
87121
LoadBalancers []VPCLoadBalancerSpec `json:"loadBalancers,omitempty"`
88122

89123
// cosInstance contains options to configure a supporting IBM Cloud COS bucket for this
90124
// cluster - currently used for nodes requiring Ignition
91125
// (https://coreos.github.io/ignition/) for bootstrapping (requires
92126
// BootstrapFormatIgnition feature flag to be enabled).
127+
// when powervs.cluster.x-k8s.io/create-infra=true annotation is set on IBMPowerVSCluster resource and Ignition is set, then
128+
// 1. CosInstance.Name should be set not setting will result in webhook error.
129+
// 2. CosInstance.BucketName should be set not setting will result in webhook error.
130+
// 3. CosInstance.BucketRegion should be set not setting will result in webhook error.
93131
// +optional
94132
CosInstance *CosInstance `json:"cosInstance,omitempty"`
133+
134+
// Ignition defined options related to the bootstrapping systems where Ignition is used.
135+
// +optional
136+
Ignition *Ignition `json:"ignition,omitempty"`
137+
}
138+
139+
// Ignition defines options related to the bootstrapping systems where Ignition is used.
140+
type Ignition struct {
141+
// Version defines which version of Ignition will be used to generate bootstrap data.
142+
//
143+
// +optional
144+
// +kubebuilder:default="2.3"
145+
// +kubebuilder:validation:Enum="2.3";"2.4";"3.0";"3.1";"3.2";"3.3";"3.4"
146+
Version string `json:"version,omitempty"`
147+
}
148+
149+
// DHCPServer contains the DHCP server configurations.
150+
type DHCPServer struct {
151+
// Optional cidr for DHCP private network
152+
Cidr *string `json:"cidr,omitempty"`
153+
154+
// Optional DNS Server for DHCP service
155+
// +kubebuilder:default="1.1.1.1"
156+
DNSServer *string `json:"dnsServer,omitempty"`
157+
158+
// Optional name of DHCP Service. Only alphanumeric characters and dashes are allowed.
159+
Name *string `json:"name,omitempty"`
160+
161+
// Optional id of the existing DHCPServer
162+
ID *string `json:"id,omitempty"`
163+
164+
// Optional indicates if SNAT will be enabled for DHCP service
165+
// +kubebuilder:default=true
166+
Snat *bool `json:"snat,omitempty"`
95167
}
96168

97169
// ResourceReference identifies a resource with id.
@@ -109,6 +181,9 @@ type IBMPowerVSClusterStatus struct {
109181
// +kubebuilder:default=false
110182
Ready bool `json:"ready"`
111183

184+
// ResourceGroup is the reference to the Power VS resource group under which the resources will be created.
185+
ResourceGroup *ResourceReference `json:"resourceGroupID,omitempty"`
186+
112187
// serviceInstance is the reference to the Power VS service on which the server instance(VM) will be created.
113188
ServiceInstance *ResourceReference `json:"serviceInstance,omitempty"`
114189

@@ -166,40 +241,38 @@ type IBMPowerVSClusterList struct {
166241

167242
// TransitGateway holds the TransitGateway information.
168243
type TransitGateway struct {
244+
// name of resource.
245+
// +optional
169246
Name *string `json:"name,omitempty"`
170-
ID *string `json:"id,omitempty"`
247+
// id of resource.
248+
// +optional
249+
ID *string `json:"id,omitempty"`
171250
}
172251

173252
// VPCResourceReference is a reference to a specific VPC resource by ID or Name
174253
// Only one of ID or Name may be specified. Specifying more than one will result in
175254
// a validation error.
176255
type VPCResourceReference struct {
177-
// ID of resource
256+
// id of resource.
178257
// +kubebuilder:validation:MinLength=1
179258
// +optional
180259
ID *string `json:"id,omitempty"`
181260

182-
// Name of resource
261+
// name of resource.
183262
// +kubebuilder:validation:MinLength=1
184263
// +optional
185264
Name *string `json:"name,omitempty"`
186265

187-
// IBM Cloud VPC region
266+
// region of IBM Cloud VPC.
267+
// when powervs.cluster.x-k8s.io/create-infra=true annotation is set on IBMPowerVSCluster resource,
268+
// it is expected to set the region, not setting will result in webhook error.
188269
Region *string `json:"region,omitempty"`
189270
}
190271

191272
// CosInstance represents IBM Cloud COS instance.
192273
type CosInstance struct {
193-
// PresignedURLDuration defines the duration for which presigned URLs are valid.
194-
//
195-
// This is used to generate presigned URLs for S3 Bucket objects, which are used by
196-
// control-plane and worker nodes to fetch bootstrap data.
197-
//
198-
// When enabled, the IAM instance profiles specified are not used.
199-
// +optional
200-
PresignedURLDuration *metav1.Duration `json:"presignedURLDuration,omitempty"`
201-
202-
// Name defines name of IBM cloud COS instance to be created.
274+
// name defines name of IBM cloud COS instance to be created.
275+
// when IBMPowerVSCluster.Ignition is set
203276
// +kubebuilder:validation:MinLength:=3
204277
// +kubebuilder:validation:MaxLength:=63
205278
// +kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$`
@@ -222,6 +295,14 @@ func (r *IBMPowerVSCluster) SetConditions(conditions capiv1beta1.Conditions) {
222295
r.Status.Conditions = conditions
223296
}
224297

298+
// Set sets the details of the resource.
299+
func (rf *ResourceReference) Set(resource ResourceReference) {
300+
rf.ID = resource.ID
301+
if !*rf.ControllerCreated {
302+
rf.ControllerCreated = resource.ControllerCreated
303+
}
304+
}
305+
225306
func init() {
226307
SchemeBuilder.Register(&IBMPowerVSCluster{}, &IBMPowerVSClusterList{})
227308
}

api/v1beta2/ibmpowervscluster_webhook.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package v1beta2
1818

1919
import (
20+
"strconv"
21+
2022
apierrors "k8s.io/apimachinery/pkg/api/errors"
2123
"k8s.io/apimachinery/pkg/runtime"
2224
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -74,6 +76,11 @@ func (r *IBMPowerVSCluster) validateIBMPowerVSCluster() (admission.Warnings, err
7476
if err := r.validateIBMPowerVSClusterNetwork(); err != nil {
7577
allErrs = append(allErrs, err)
7678
}
79+
80+
if err := r.validateIBMPowerVSClusterCreateInfraPrereq(); err != nil {
81+
allErrs = append(allErrs, err)
82+
}
83+
7784
if len(allErrs) == 0 {
7885
return nil, nil
7986
}
@@ -89,3 +96,56 @@ func (r *IBMPowerVSCluster) validateIBMPowerVSClusterNetwork() *field.Error {
8996
}
9097
return nil
9198
}
99+
100+
func (r *IBMPowerVSCluster) validateIBMPowerVSClusterCreateInfraPrereq() *field.Error {
101+
annotations := r.GetAnnotations()
102+
if len(annotations) == 0 {
103+
return nil
104+
}
105+
106+
value, found := annotations[CreateInfrastructureAnnotation]
107+
if !found {
108+
return nil
109+
}
110+
111+
createInfra, err := strconv.ParseBool(value)
112+
if err != nil {
113+
return field.Invalid(field.NewPath("annotations"), r.Annotations, "value of powervs.cluster.x-k8s.io/create-infra should be boolean")
114+
}
115+
116+
if !createInfra {
117+
return nil
118+
}
119+
120+
if r.Spec.Zone == nil {
121+
return field.Invalid(field.NewPath("spec.zone"), r.Spec.Zone, "value of zone is empty")
122+
}
123+
124+
if r.Spec.VPC.Region == nil {
125+
return field.Invalid(field.NewPath("spec.vpc.region"), r.Spec.VPC.Region, "value of VPC region is empty")
126+
}
127+
128+
if r.Spec.ResourceGroup == nil {
129+
return field.Invalid(field.NewPath("spec.resourceGroup"), r.Spec.ResourceGroup, "value of resource group is empty")
130+
}
131+
132+
if r.Spec.Ignition == nil {
133+
return nil
134+
}
135+
136+
// TODO(Phase 1): If ignition is set and these resources are not set, auto create them.
137+
// If ignition is set, make sure to check that CosInstanceName, BucketName and region is set
138+
if r.Spec.CosInstance == nil {
139+
return field.Invalid(field.NewPath("spec.cosInstance"), r.Spec.CosInstance, "ignition is set but value of cosInstance is empty")
140+
}
141+
if r.Spec.CosInstance.Name == "" {
142+
return field.Invalid(field.NewPath("spec.cosInstance.name"), r.Spec.CosInstance, "ignition is set but value of cosInstance name is empty")
143+
}
144+
if r.Spec.CosInstance.BucketName == "" {
145+
return field.Invalid(field.NewPath("spec.cosInstance.bucketName"), r.Spec.CosInstance, "ignition is set but value of bucketName is empty")
146+
}
147+
if r.Spec.CosInstance.BucketRegion == "" {
148+
return field.Invalid(field.NewPath("spec.cosInstance.bucketRegion"), r.Spec.CosInstance, "ignition is set but value of bucketRegion is empty")
149+
}
150+
return nil
151+
}

0 commit comments

Comments
 (0)