Skip to content

Commit

Permalink
VPC: Create v2 path for new Infrastructure implementation
Browse files Browse the repository at this point in the history
Create a v2 path that will be used for the new Infrastructure
implementation for VPC Clusters. All new functionality will
be placed in these new v2 paths, based on the new NetworkSpec
field, to prevent breaking existing implementation.
  • Loading branch information
cjschaef committed Jun 26, 2024
1 parent 392efd0 commit df3d98d
Show file tree
Hide file tree
Showing 10 changed files with 447 additions and 20 deletions.
8 changes: 8 additions & 0 deletions api/v1beta1/ibmvpc_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,11 @@ func Convert_Slice_Pointer_v1beta2_IBMVPCResourceReference_To_Slice_Pointer_stri
func Convert_v1beta2_VPCLoadBalancerSpec_To_v1beta1_VPCLoadBalancerSpec(in *infrav1beta2.VPCLoadBalancerSpec, out *VPCLoadBalancerSpec, s apiconversion.Scope) error {
return autoConvert_v1beta2_VPCLoadBalancerSpec_To_v1beta1_VPCLoadBalancerSpec(in, out, s)
}

func Convert_v1beta2_IBMVPCClusterSpec_To_v1beta1_IBMVPCClusterSpec(in *infrav1beta2.IBMVPCClusterSpec, out *IBMVPCClusterSpec, s apiconversion.Scope) error {
return autoConvert_v1beta2_IBMVPCClusterSpec_To_v1beta1_IBMVPCClusterSpec(in, out, s)
}

func Convert_v1beta2_IBMVPCClusterStatus_To_v1beta1_IBMVPCClusterStatus(in *infrav1beta2.IBMVPCClusterStatus, out *IBMVPCClusterStatus, s apiconversion.Scope) error {
return autoConvert_v1beta2_IBMVPCClusterStatus_To_v1beta1_IBMVPCClusterStatus(in, out, s)
}
31 changes: 11 additions & 20 deletions api/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/v1beta2/conditions_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,8 @@ const (
// CreateInfrastructureAnnotation is the name of an annotation that indicates if
// Power VS infrastructure should be created as a part of cluster creation.
CreateInfrastructureAnnotation = "powervs.cluster.x-k8s.io/create-infra"

// CreateVPCInfrastructureAnnotation is the name of an annotation that indicates if
// VPC infrastructure should be created as part of cluster creation.
CreateVPCInfrastructureAnnotation = "vpc.cluster.x-k8s.io/create-infra"
)
17 changes: 17 additions & 0 deletions api/v1beta2/ibmvpccluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ type IBMVPCClusterSpec struct {
// ControlPlaneLoadBalancer is optional configuration for customizing control plane behavior.
// +optional
ControlPlaneLoadBalancer *VPCLoadBalancerSpec `json:"controlPlaneLoadBalancer,omitempty"`

// networkSpec represents the VPC network to use for the cluster.
// +optional
NetworkSpec *VPCNetworkSpec `json:"networkSpec,omitempty"`
}

// VPCLoadBalancerSpec defines the desired state of an VPC load balancer.
Expand Down Expand Up @@ -94,6 +98,19 @@ type AdditionalListenerSpec struct {
Port int64 `json:"port"`
}

// VPCNetworkSpec defines the desired state of the network resources for the cluster.
type VPCNetworkSpec struct {
// computeSubnetsSpec is a set of Subnet's which define the Compute subnets.
ComputeSubnetsSpec []Subnet `json:"computeSubnetsSpec,omitempty"`
// controlPlaneSubnetsSpec is a set of Subnet's which define the Control Plane subnets.
ControlPlaneSubnetsSpec []Subnet `json:"controlPlaneSubentsSpec,omitempty"`
// resourceGroup is the name of the Resource Group containing all of the newtork resources.
// This can be different than the Resource Group containing the remaining cluster resources.
ResourceGroup *string `json:"resourceGroup,omitempty"`

// TODO(cjschaef): Complete spec definition (SecurityGroups, VPC)
}

// VPCSecurityGroupStatus defines a vpc security group resource status with its id and respective rule's ids.
type VPCSecurityGroupStatus struct {
// id represents the id of the resource.
Expand Down
39 changes: 39 additions & 0 deletions api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions cloud/scope/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,20 @@ func CheckCreateInfraAnnotation(cluster infrav1beta2.IBMPowerVSCluster) bool {
}
return createInfra
}

// CheckCreateVPCInfraAnnotation checks for annotations set on IBMVPCCluster object to determine cluster creation workflow.
func CheckCreateVPCInfraAnnotation(cluster infrav1beta2.IBMVPCCluster) bool {
annotations := cluster.GetAnnotations()
if len(annotations) == 0 {
return false
}
value, found := annotations[infrav1beta2.CreateVPCInfrastructureAnnotation]
if !found {
return false
}
createInfra, err := strconv.ParseBool(value)
if err != nil {
return false
}
return createInfra
}
179 changes: 179 additions & 0 deletions cloud/scope/vpc_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
Copyright 2024 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package scope

import (
"context"
"errors"
"fmt"

"github.com/go-logr/logr"

"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"

"k8s.io/klog/v2/textlogger"

"sigs.k8s.io/controller-runtime/pkg/client"

capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/patch"

infrav1beta2 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/authenticator"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/cos"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/resourcecontroller"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/resourcemanager"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/vpc"
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/endpoints"
)

const (
// LOGDEBUGLEVEL indicates the debug level of the logs.
LOGDEBUGLEVEL = 5
)

// VPCClusterScopeParams defines the input parameters used to create a new VPCClusterScope.
type VPCClusterScopeParams struct {
Client client.Client
Cluster *capiv1beta1.Cluster
IBMVPCCluster *infrav1beta2.IBMVPCCluster
Logger logr.Logger
ServiceEndpoint []endpoints.ServiceEndpoint

IBMVPCClient vpc.Vpc
}

// VPCClusterScope defines a scope defined around a VPC Cluster.
type VPCClusterScope struct {
logr.Logger
Client client.Client
patchHelper *patch.Helper

COSClient cos.Cos
ResourceControllerClient resourcecontroller.ResourceController
ResourceManagerClient resourcemanager.ResourceManager
VPCClient vpc.Vpc

Cluster *capiv1beta1.Cluster
IBMVPCCluster *infrav1beta2.IBMVPCCluster
ServiceEndpoint []endpoints.ServiceEndpoint
}

// NewVPCClusterScope creates a new VPCClusterScope from the supplied parameters.
func NewVPCClusterScope(params VPCClusterScopeParams) (*VPCClusterScope, error) {
if params.Client == nil {
err := errors.New("error failed to generate new scope from nil Client")
return nil, err
}
if params.Cluster == nil {
err := errors.New("error failed to generate new scope from nil Cluster")
return nil, err
}
if params.IBMVPCCluster == nil {
err := errors.New("error failed to generate new scope from nil IBMVPCCluster")
return nil, err
}
if params.Logger == (logr.Logger{}) {
params.Logger = textlogger.NewLogger(textlogger.NewConfig())
}

helper, err := patch.NewHelper(params.IBMVPCCluster, params.Client)
if err != nil {
return nil, fmt.Errorf("error failed to init patch helper: %w", err)
}

vpcEndpoint := endpoints.FetchVPCEndpoint(params.IBMVPCCluster.Spec.Region, params.ServiceEndpoint)
vpcClient, err := vpc.NewService(vpcEndpoint)
if err != nil {
return nil, fmt.Errorf("error failed to create IBM VPC client: %w", err)
}

// if vpc.cluster.x-k8s.io/create-infra=true annotation is not set, only need vpc client.
if !CheckCreateVPCInfraAnnotation(*params.IBMVPCCluster) {
return &VPCClusterScope{
Logger: params.Logger,
Client: params.Client,
patchHelper: helper,
Cluster: params.Cluster,
IBMVPCCluster: params.IBMVPCCluster,
ServiceEndpoint: params.ServiceEndpoint,
VPCClient: vpcClient,
}, nil
}

// if vpc.cluster.x-k8s.io/create-infra=true annotation is set, create necessary clients.
if params.IBMVPCCluster.Spec.NetworkSpec == nil || params.IBMVPCCluster.Spec.Region == "" {
return nil, fmt.Errorf("error failed to generate vpc client as NetworkSpec info is nil")
}

if params.Logger.V(LOGDEBUGLEVEL).Enabled() {
core.SetLoggingLevel(core.LevelDebug)
}

auth, err := authenticator.GetAuthenticator()
if err != nil {
return nil, fmt.Errorf("error failed to create authenticator: %w", err)
}

// Create Global Tagging client.
// TODO(cjschaef): need service support.

// Create Resource Controller client.
rcOptions := resourcecontroller.ServiceOptions{
ResourceControllerV2Options: &resourcecontrollerv2.ResourceControllerV2Options{
Authenticator: auth,
},
}
// Fetch the resource controller endpoint.
rcEndpoint := endpoints.FetchEndpoints(string(endpoints.RC), params.ServiceEndpoint)
if rcEndpoint != "" {
rcOptions.URL = rcEndpoint
params.Logger.V(3).Info("Overriding the default resource controller endpoint", "ResourceControllerEndpoint", rcEndpoint)
}
resourceControllerClient, err := resourcecontroller.NewService(rcOptions)
if err != nil {
return nil, fmt.Errorf("error failed to create resource controller client: %w", err)
}

// Create Resource Manager client.
// TODO(cjschaef): Need to extend ResourceManager service and endpoint support to add properly.

clusterScope := &VPCClusterScope{
Logger: params.Logger,
Client: params.Client,
patchHelper: helper,
Cluster: params.Cluster,
IBMVPCCluster: params.IBMVPCCluster,
ServiceEndpoint: params.ServiceEndpoint,
ResourceControllerClient: resourceControllerClient,
VPCClient: vpcClient,
}
return clusterScope, nil
}

// PatchObject persists the cluster configuration and status.
func (s *VPCClusterScope) PatchObject() error {
return s.patchHelper.Patch(context.TODO(), s.IBMVPCCluster)
}

// Close closes the current scope persisting the cluster configuration and status.
func (s *VPCClusterScope) Close() error {
return s.PatchObject()
}

// Name returns the CAPI cluster name.
func (s *VPCClusterScope) Name() string {
return s.Cluster.Name
}
Loading

0 comments on commit df3d98d

Please sign in to comment.