@@ -17,34 +17,50 @@ package infracluster
1717
1818import (
1919 "context"
20+ "errors"
2021 "fmt"
2122 "net/url"
2223 "strconv"
24+ "strings"
2325
2426 "github.com/go-logr/logr"
2527 cerrors "k8s.io/apimachinery/pkg/api/errors"
2628 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+ "k8s.io/klog/v2"
2730 awsv1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2831 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2932 "sigs.k8s.io/controller-runtime/pkg/client"
33+
34+ mapiv1beta1 "github.com/openshift/api/machine/v1beta1"
35+ )
36+
37+ var (
38+ // ErrNoControlPlaneLoadBalancerConfigured indicates there is no control plane load balancer configuration present.
39+ ErrNoControlPlaneLoadBalancerConfigured = errors .New ("no control plane load balancer configured" )
40+ // ErrNilProviderSpec indicates a nil provider spec raw extension.
41+ ErrNilProviderSpec = errors .New ("provider spec is nil" )
42+ // ErrInvalidNumberOfControlPlaneLoadBalancers indicates an invalid number of control plane load balancers has been configured.
43+ ErrInvalidNumberOfControlPlaneLoadBalancers = errors .New ("invalid number of control plane load balancers" )
44+ // ErrUnsupportedLoadBalancerType indicates an unsupported load balancer type.
45+ ErrUnsupportedLoadBalancerType = errors .New ("unsupported load balancer type" )
3046)
3147
3248// ensureAWSCluster ensures the AWSCluster cluster object exists.
3349func (r * InfraClusterController ) ensureAWSCluster (ctx context.Context , log logr.Logger ) (client.Object , error ) {
34- target := & awsv1.AWSCluster {ObjectMeta : metav1.ObjectMeta {
50+ awsCluster := & awsv1.AWSCluster {ObjectMeta : metav1.ObjectMeta {
3551 Name : r .Infra .Status .InfrastructureName ,
36- Namespace : defaultCAPINamespace ,
52+ Namespace : r . CAPINamespace ,
3753 }}
3854
3955 // Checking whether InfraCluster object exists. If it doesn't, create it.
40-
41- if err := r .Get (ctx , client .ObjectKeyFromObject (target ), target ); err != nil && ! cerrors .IsNotFound (err ) {
56+ if err := r .Get (ctx , client .ObjectKeyFromObject (awsCluster ), awsCluster ); err != nil && ! cerrors .IsNotFound (err ) {
4257 return nil , fmt .Errorf ("failed to get InfraCluster: %w" , err )
4358 } else if err == nil {
44- return target , nil
59+ return awsCluster , nil
4560 }
4661
47- log .Info (fmt .Sprintf ("AWSCluster %s/%s does not exist, creating it" , target .Namespace , target .Name ))
62+ log = log .WithValues ("AWSCluster" , klog .KObj (awsCluster ))
63+ log .Info ("AWSCluster does not exist, creating it" )
4864
4965 apiURL , err := url .Parse (r .Infra .Status .APIServerInternalURL )
5066 if err != nil {
@@ -60,10 +76,35 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
6076 return nil , fmt .Errorf ("infrastructure PlatformStatus should not be nil: %w" , err )
6177 }
6278
63- target = & awsv1.AWSCluster {
79+ providerSpec , err := r .getAWSMAPIProviderSpec (ctx , r .Client )
80+ if err != nil {
81+ return nil , fmt .Errorf ("unable to obtain MAPI ProviderSpec: %w" , err )
82+ }
83+
84+ awsCluster , err = r .newAWSCluster (providerSpec , apiURL , int32 (port ))
85+ if err != nil {
86+ return nil , fmt .Errorf ("failed to get AWSCluster: %w" , err )
87+ }
88+
89+ if err := r .Create (ctx , awsCluster ); err != nil {
90+ return nil , fmt .Errorf ("failed to create AWSCluster: %w" , err )
91+ }
92+
93+ log .Info ("AWSCluster successfully created" )
94+
95+ return awsCluster , nil
96+ }
97+
98+ func (r * InfraClusterController ) newAWSCluster (providerSpec * mapiv1beta1.AWSMachineProviderConfig , apiURL * url.URL , port int32 ) (* awsv1.AWSCluster , error ) {
99+ controlPlaneLoadBalancer , secondaryControlPlaneLoadBalancer , err := extractLoadBalancerConfigFromMAPIAWSProviderSpec (providerSpec )
100+ if err != nil {
101+ return nil , fmt .Errorf ("failed to extract control plane load balancer configuration: %w" , err )
102+ }
103+
104+ target := & awsv1.AWSCluster {
64105 ObjectMeta : metav1.ObjectMeta {
65106 Name : r .Infra .Status .InfrastructureName ,
66- Namespace : defaultCAPINamespace ,
107+ Namespace : r . CAPINamespace ,
67108 // The ManagedBy Annotation is set so CAPI infra providers ignore the InfraCluster object,
68109 // as that's managed externally, in this case by this controller.
69110 Annotations : map [string ]string {
@@ -74,7 +115,7 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
74115 Region : r .Infra .Status .PlatformStatus .AWS .Region ,
75116 ControlPlaneEndpoint : clusterv1.APIEndpoint {
76117 Host : apiURL .Hostname (),
77- Port : int32 ( port ) ,
118+ Port : port ,
78119 },
79120 // This default IdentityRef will be created by the controlleridentitycreator controller.
80121 // Leaving it as nil works the same as this value, but fills the log with log messages
@@ -84,14 +125,80 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
84125 Kind : awsv1 .ControllerIdentityKind ,
85126 Name : "default" ,
86127 },
128+ // Set control plane load balancer configuration extracted from MAPI machines
129+ ControlPlaneLoadBalancer : controlPlaneLoadBalancer ,
130+ SecondaryControlPlaneLoadBalancer : secondaryControlPlaneLoadBalancer ,
87131 },
88132 }
89133
90- if err := r .Create (ctx , target ); err != nil {
91- return nil , fmt .Errorf ("failed to create InfraCluster: %w" , err )
134+ return target , nil
135+ }
136+
137+ func (r * InfraClusterController ) getAWSMAPIProviderSpec (ctx context.Context , cl client.Client ) (* mapiv1beta1.AWSMachineProviderConfig , error ) {
138+ return getMAPIProviderSpec [mapiv1beta1.AWSMachineProviderConfig ](ctx , cl , r .getRawMAPIProviderSpec )
139+ }
140+
141+ // extractLoadBalancerConfigFromMAPIAWSProviderSpec extracts one or two control plane load balancers from a MAPI machine's provider spec.
142+ // When two load balancers are present, the one whose name ends with "-int" is preferred as the return value.
143+ // Returns an error if zero or more than two load balancers are defined.
144+ func extractLoadBalancerConfigFromMAPIAWSProviderSpec (providerSpec * mapiv1beta1.AWSMachineProviderConfig ) (* awsv1.AWSLoadBalancerSpec , * awsv1.AWSLoadBalancerSpec , error ) {
145+ if providerSpec == nil {
146+ return nil , nil , ErrNilProviderSpec
92147 }
93148
94- log .Info (fmt .Sprintf ("InfraCluster '%s/%s' successfully created" , defaultCAPINamespace , r .Infra .Status .InfrastructureName ))
149+ switch len (providerSpec .LoadBalancers ) {
150+ case 0 :
151+ return nil , nil , ErrNoControlPlaneLoadBalancerConfigured
152+ case 1 :
153+ lbPrimary := providerSpec .LoadBalancers [0 ]
154+
155+ lbType , err := convertMAPILoadBalancerTypeToCAPI (lbPrimary .Type )
156+ if err != nil {
157+ return nil , nil , fmt .Errorf ("failed to convert load balancer type: %w" , err )
158+ }
159+
160+ return & awsv1.AWSLoadBalancerSpec {
161+ Name : & lbPrimary .Name ,
162+ LoadBalancerType : lbType ,
163+ }, nil , nil
164+ case 2 :
165+ lbFirst := providerSpec .LoadBalancers [0 ]
166+ lbSecond := providerSpec .LoadBalancers [1 ]
167+ // Prefer the load balancer with "-int" suffix as primary when two are present.
168+ if strings .HasSuffix (lbSecond .Name , "-int" ) && ! strings .HasSuffix (lbFirst .Name , "-int" ) {
169+ lbFirst , lbSecond = lbSecond , lbFirst
170+ }
171+
172+ lbTypeFirst , err := convertMAPILoadBalancerTypeToCAPI (lbFirst .Type )
173+ if err != nil {
174+ return nil , nil , fmt .Errorf ("failed to convert load balancer type: %w" , err )
175+ }
176+
177+ lbTypeSecond , err := convertMAPILoadBalancerTypeToCAPI (lbSecond .Type )
178+ if err != nil {
179+ return nil , nil , fmt .Errorf ("failed to convert load balancer type: %w" , err )
180+ }
181+
182+ return & awsv1.AWSLoadBalancerSpec {
183+ Name : & lbFirst .Name ,
184+ LoadBalancerType : lbTypeFirst ,
185+ }, & awsv1.AWSLoadBalancerSpec {
186+ Name : & lbSecond .Name ,
187+ LoadBalancerType : lbTypeSecond ,
188+ }, nil
189+ default :
190+ return nil , nil , fmt .Errorf ("%w: expected 1 or 2, got %d" , ErrInvalidNumberOfControlPlaneLoadBalancers , len (providerSpec .LoadBalancers ))
191+ }
192+ }
95193
96- return target , nil
194+ // convertMAPILoadBalancerTypeToCAPI converts MAPI AWSLoadBalancerType to CAPI LoadBalancerType.
195+ func convertMAPILoadBalancerTypeToCAPI (mapiType mapiv1beta1.AWSLoadBalancerType ) (awsv1.LoadBalancerType , error ) {
196+ switch mapiType {
197+ case mapiv1beta1 .ClassicLoadBalancerType :
198+ return awsv1 .LoadBalancerTypeClassic , nil
199+ case mapiv1beta1 .NetworkLoadBalancerType :
200+ return awsv1 .LoadBalancerTypeNLB , nil
201+ default :
202+ return "" , fmt .Errorf ("%w: unknown load balancer type: %s" , ErrUnsupportedLoadBalancerType , mapiType )
203+ }
97204}
0 commit comments