66 "math"
77 "reflect"
88 "regexp"
9- "strings"
109 "time"
1110
1211 "github.com/IBM/vpc-go-sdk/vpcv1"
@@ -56,17 +55,10 @@ const publicPrefix = "api."
5655// InfraReady is called once cluster.Status.InfrastructureReady
5756// is true, typically after load balancers have been provisioned. It can be used
5857// to create DNS records.
59- // nolint:gocyclo
6058func (p Provider ) InfraReady (ctx context.Context , in clusterapi.InfraReadyInput ) error {
6159 var (
62- client * powervsconfig.Client
63- vpcRegion string
64- instanceCRN string
65- rules * vpcv1.SecurityGroupRuleCollection
66- rule * vpcv1.SecurityGroupRulePrototype
67- wantedPorts = sets .New [int64 ](22 , 10258 , 22623 )
68- foundPorts = sets.Set [int64 ]{}
69- err error
60+ err error
61+ rule * vpcv1.SecurityGroupRulePrototype
7062 )
7163
7264 logrus .Debugf ("InfraReady: in = %+v" , in )
@@ -103,129 +95,115 @@ func (p Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput)
10395 }
10496 logrus .Debugf ("InfraReady: image = %+v" , powerVSImage )
10597
106- // SAD: client in the Metadata struct is lowercase and therefore private
107- // client = in.InstallConfig.PowerVS.client
108- client , err = powervsconfig .NewClient ()
109- if err != nil {
110- return fmt .Errorf ("failed to get NewClient in InfraReady: %w" , err )
111- }
112- logrus .Debugf ("InfraReady: NewClient returns %+v" , client )
113-
11498 // We need to set the region we will eventually query inside
115- vpcRegion = in .InstallConfig .Config .Platform .PowerVS .VPCRegion
99+ vpcRegion : = in .InstallConfig .Config .Platform .PowerVS .VPCRegion
116100 if vpcRegion == "" {
117101 vpcRegion , err = powervstypes .VPCRegionForPowerVSRegion (in .InstallConfig .Config .Platform .PowerVS .Region )
118102 if err != nil {
119103 return fmt .Errorf ("failed to get VPC region (%s) in InfraReady: %w" , vpcRegion , err )
120104 }
121105 }
122106 logrus .Debugf ("InfraReady: vpcRegion = %s" , vpcRegion )
123- if err = client .SetVPCServiceURLForRegion (ctx , vpcRegion ); err != nil {
107+ if err = in . InstallConfig . PowerVS .SetVPCServiceURLForRegion (ctx , vpcRegion ); err != nil {
124108 return fmt .Errorf ("failed to set the VPC service region (%s) in InfraReady: %w" , vpcRegion , err )
125109 }
126110
127- // Step 1.
128- // Create DNS records for the two load balancers
129- // map[string]VPCLoadBalancerStatus
130- instanceCRN , err = client .GetInstanceCRNByName (ctx ,
131- in .InstallConfig .PowerVS .BaseDomain ,
132- in .InstallConfig .Config .Publish )
111+ // Step 1: Create DNS records for the two load balancers
112+ if err = createLoadBalancerDNSRecords (ctx , in , powerVSCluster .Status .LoadBalancers ); err != nil {
113+ return fmt .Errorf ("failed to create DNS records for loadbalancers: %w" , err )
114+ }
115+
116+ // Step 2: See which ports are already allowed.
117+ missingPorts , err := findMissingSecurityGroupRules (ctx , in , * powerVSCluster .Status .VPC .ID )
133118 if err != nil {
134- return fmt .Errorf ("failed to get InstanceCRN (%s) by name in InfraReady: %w" ,
135- in .InstallConfig .Config .Publish ,
136- err )
119+ return fmt .Errorf ("failed to find missing security group rules: %w" , err )
137120 }
138- logrus .Debugf ("InfraReady: instanceCRN = %s" , instanceCRN )
139121
122+ // Step 3: Add to security group rules
123+ for port := range missingPorts {
124+ port := port // TODO: remove when using golang 1.22+
125+ rule = & vpcv1.SecurityGroupRulePrototype {
126+ Direction : ptr .To ("inbound" ),
127+ Protocol : ptr .To ("tcp" ),
128+ PortMin : ptr .To (port ),
129+ PortMax : ptr .To (port ),
130+ }
131+
132+ logrus .Debugf ("InfraReady: Adding port %d to security group rule to %v" , port , * powerVSCluster .Status .VPC .ID )
133+ err := in .InstallConfig .PowerVS .AddSecurityGroupRule (ctx , rule , * powerVSCluster .Status .VPC .ID )
134+ if err != nil {
135+ return fmt .Errorf ("failed to add security group rule for port %d: %w" , port , err )
136+ }
137+ }
138+
139+ // Also allow ping so we can debug
140+ rule = & vpcv1.SecurityGroupRulePrototype {
141+ Direction : ptr .To ("inbound" ),
142+ Protocol : ptr .To ("icmp" ),
143+ }
144+
145+ err = in .InstallConfig .PowerVS .AddSecurityGroupRule (ctx , rule , * powerVSCluster .Status .VPC .ID )
146+ if err != nil {
147+ return fmt .Errorf ("failed to add ping security group rule: %w" , err )
148+ }
149+ return nil
150+ }
151+
152+ func createLoadBalancerDNSRecords (ctx context.Context , in clusterapi.InfraReadyInput , loadBalancers map [string ]capibm.VPCLoadBalancerStatus ) error {
140153 lbExtExp := regexp .MustCompile (`\b-loadbalancer\b$` )
141154 lbIntExp := regexp .MustCompile (`\b-loadbalancer-int\b$` )
155+ for lbKey , loadBalancerStatus := range loadBalancers {
156+ var hostnames []string
142157
143- for lbKey , loadBalancerStatus := range powerVSCluster .Status .LoadBalancers {
144- var (
145- idx int
146- substr string
147- infraID string
148- hostnames []string
149- prefix string
150- )
151-
152- // The infra id is "rdr-hamzy-test-dal10-846vd" and we need "rdr-hamzy-test-dal10"
153- logrus .Debugf ("in.InfraID = %s" , in .InfraID )
154- idx = strings .LastIndex (in .InfraID , "-" )
155- logrus .Debugf ("idx = %d" , idx )
156- substr = in .InfraID [idx :]
157- logrus .Debugf ("substr = %s" , substr )
158- infraID = strings .ReplaceAll (in .InfraID , substr , "" )
159- logrus .Debugf ("infraID = %s" , infraID )
158+ clusterName := in .InstallConfig .Config .ObjectMeta .Name
160159
161160 // Is it external (public) or internal (private)?
162161 logrus .Debugf ("lbKey = %s" , lbKey )
163162 switch {
164163 case lbExtExp .MatchString (lbKey ):
165164 if in .InstallConfig .Config .Publish == types .ExternalPublishingStrategy {
166- hostnames = append (hostnames , fmt .Sprintf ("%s%s" , publicPrefix , infraID ))
165+ hostnames = append (hostnames , fmt .Sprintf ("%s%s" , publicPrefix , clusterName ))
167166 }
168167 case lbIntExp .MatchString (lbKey ):
169- hostnames = append (hostnames , fmt .Sprintf ("%s%s" , privatePrefix , infraID ))
168+ hostnames = append (hostnames , fmt .Sprintf ("%s%s" , privatePrefix , clusterName ))
170169 // In the private cluster scenario, also point api.* to internal LB
171170 if in .InstallConfig .Config .Publish == types .InternalPublishingStrategy {
172- hostnames = append (hostnames , fmt .Sprintf ("%s%s" , publicPrefix , infraID ))
171+ hostnames = append (hostnames , fmt .Sprintf ("%s%s" , publicPrefix , clusterName ))
173172 }
174173 }
175- logrus .Debugf ("prefix = %s" , prefix )
176174
177175 for _ , hostname := range hostnames {
178- logrus .Debugf ("InfraReady: crn = %s, base domain = %s, hostname = %s, cname = %s" ,
179- instanceCRN ,
180- in .InstallConfig .PowerVS .BaseDomain ,
176+ logrus .Debugf ("InfraReady: hostname = %s, cname = %s" ,
181177 hostname ,
182178 * loadBalancerStatus .Hostname )
183179
184- backoff := wait.Backoff {
185- Duration : 15 * time .Second ,
186- Factor : 1.1 ,
187- Cap : leftInContext (ctx ),
188- Steps : math .MaxInt32 }
189- var lastErr error
190- err = wait .ExponentialBackoffWithContext (ctx , backoff , func (context.Context ) (bool , error ) {
191- lastErr = client .CreateDNSRecord (ctx ,
192- in .InstallConfig .Config .Publish ,
193- instanceCRN ,
194- in .InstallConfig .PowerVS .BaseDomain ,
195- hostname ,
196- * loadBalancerStatus .Hostname )
197- if lastErr == nil {
198- return true , nil
199- }
200- return false , nil
201- })
202-
180+ err := in .InstallConfig .PowerVS .CreateDNSRecord (ctx ,
181+ hostname ,
182+ * loadBalancerStatus .Hostname )
203183 if err != nil {
204- if lastErr != nil {
205- err = lastErr
206- }
207- return fmt .Errorf ("failed to create a DNS CNAME record (%s, %s): %w" ,
208- hostname ,
209- * loadBalancerStatus .Hostname ,
210- err )
184+ return fmt .Errorf ("InfraReady: Failed to create DNS record: %w" , err )
211185 }
212186 }
213187 }
188+ return nil
189+ }
214190
215- // Step 2.
216- // See which ports are already allowed.
217- rules , err = client .ListSecurityGroupRules (ctx , * powerVSCluster .Status .VPC .ID )
191+ func findMissingSecurityGroupRules (ctx context.Context , in clusterapi.InfraReadyInput , vpcID string ) (sets.Set [int64 ], error ) {
192+ foundPorts := sets.Set [int64 ]{}
193+ wantedPorts := sets .New [int64 ](22 , 10258 , 22623 )
194+
195+ existingRules , err := in .InstallConfig .PowerVS .ListSecurityGroupRules (ctx , vpcID )
218196 if err != nil {
219- return fmt .Errorf ("failed to list security group rules: %w" , err )
197+ return nil , fmt .Errorf ("failed to list security group rules: %w" , err )
220198 }
221199
222- for _ , existingRule := range rules .Rules {
200+ for _ , existingRule := range existingRules .Rules {
223201 switch reflect .TypeOf (existingRule ).String () {
224202 case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll" :
225203 case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp" :
226204 securityGroupRule , ok := existingRule .(* vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp )
227205 if ! ok {
228- return fmt .Errorf ("could not convert to ProtocolTcpudp" )
206+ return nil , fmt .Errorf ("could not convert to ProtocolTcpudp" )
229207 }
230208 logrus .Debugf ("InfraReady: VPC has rule: direction = %s, proto = %s, min = %d, max = %d" ,
231209 * securityGroupRule .Direction ,
@@ -239,66 +217,14 @@ func (p Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput)
239217 case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp" :
240218 }
241219 }
242- logrus .Debugf ("InfraReady: foundPorts = %+v" , foundPorts )
243- logrus .Debugf ("InfraReady: wantedPorts = %+v" , wantedPorts )
244- logrus .Debugf ("InfraReady: wantedPorts.Difference(foundPorts) = %+v" , wantedPorts .Difference (foundPorts ))
245220
246- // Step 3.
247- // Add to security group rules
248- for port := range wantedPorts .Difference (foundPorts ) {
249- rule = & vpcv1.SecurityGroupRulePrototype {
250- Direction : ptr .To ("inbound" ),
251- Protocol : ptr .To ("tcp" ),
252- PortMin : ptr .To (port ),
253- PortMax : ptr .To (port ),
254- }
255-
256- backoff := wait.Backoff {
257- Duration : 15 * time .Second ,
258- Factor : 1.1 ,
259- Cap : leftInContext (ctx ),
260- Steps : math .MaxInt32 }
261- err = wait .ExponentialBackoffWithContext (ctx , backoff , func (context.Context ) (bool , error ) {
262- logrus .Debugf ("InfraReady: Adding port %d to security group rule to %v" ,
263- port ,
264- * powerVSCluster .Status .VPC .ID )
265- err2 := client .AddSecurityGroupRule (ctx , * powerVSCluster .Status .VPC .ID , rule )
266- if err2 == nil {
267- return true , nil
268- }
269- return false , err2
270- })
271- if err != nil {
272- return fmt .Errorf ("failed to add security group rule for port %d: %w" , port , err )
273- }
274- }
221+ missingPorts := wantedPorts .Difference (foundPorts )
275222
276- // Allow ping so we can debug
277- rule = & vpcv1.SecurityGroupRulePrototype {
278- Direction : ptr .To ("inbound" ),
279- Protocol : ptr .To ("icmp" ),
280- }
281- backoff := wait.Backoff {
282- Duration : 15 * time .Second ,
283- Factor : 1.1 ,
284- Cap : leftInContext (ctx ),
285- Steps : math .MaxInt32 }
286- var lastErr error
287- err = wait .ExponentialBackoffWithContext (ctx , backoff , func (context.Context ) (bool , error ) {
288- lastErr = client .AddSecurityGroupRule (ctx , * powerVSCluster .Status .VPC .ID , rule )
289- if lastErr == nil {
290- return true , nil
291- }
292- return false , nil
293- })
294- if err != nil {
295- if lastErr != nil {
296- err = lastErr
297- }
298- return fmt .Errorf ("failed to add security group rule for icmp: %w" , err )
299- }
223+ logrus .Debugf ("InfraReady: foundPorts = %+v" , foundPorts )
224+ logrus .Debugf ("InfraReady: wantedPorts = %+v" , wantedPorts )
225+ logrus .Debugf ("InfraReady: wantedPorts.Difference(foundPorts) = %+v" , missingPorts )
300226
301- return nil
227+ return missingPorts , nil
302228}
303229
304230func findMachineAddress (ctx context.Context , in clusterapi.PostProvisionInput , key crclient.ObjectKey ) (string , error ) {
0 commit comments