@@ -862,6 +862,20 @@ func applyNodeSecurityGroupIDForLB(compute *gophercloud.ServiceClient, network *
862
862
}
863
863
864
864
for _ , port := range allPorts {
865
+ // If the Security Group is already present on the port, skip it.
866
+ // As soon as this only supports Go 1.18, this can be replaces by
867
+ // slices.Contains.
868
+ if func () bool {
869
+ for _ , currentSG := range port .SecurityGroups {
870
+ if currentSG == sg {
871
+ return true
872
+ }
873
+ }
874
+ return false
875
+ }() {
876
+ continue
877
+ }
878
+
865
879
newSGs := append (port .SecurityGroups , sg )
866
880
updateOpts := neutronports.UpdateOpts {SecurityGroups : & newSGs }
867
881
mc := metrics .NewMetricContext ("port" , "update" )
@@ -2633,10 +2647,64 @@ func (lbaas *LbaasV2) getSubnet(subnet string) (*subnets.Subnet, error) {
2633
2647
return nil , fmt .Errorf ("found multiple subnets with name %s" , subnet )
2634
2648
}
2635
2649
2650
+ // ensureSecurityRule ensures to create a security rule for a defined security
2651
+ // group, if it not present.
2652
+ func (lbaas * LbaasV2 ) ensureSecurityRule (
2653
+ direction rules.RuleDirection ,
2654
+ protocol rules.RuleProtocol ,
2655
+ etherType rules.RuleEtherType ,
2656
+ remoteIPPrefix , secGroupID string ,
2657
+ portRangeMin , portRangeMax int ,
2658
+ ) error {
2659
+ sgListopts := rules.ListOpts {
2660
+ Direction : string (direction ),
2661
+ Protocol : string (protocol ),
2662
+ PortRangeMax : portRangeMin ,
2663
+ PortRangeMin : portRangeMax ,
2664
+ RemoteIPPrefix : remoteIPPrefix ,
2665
+ SecGroupID : secGroupID ,
2666
+ }
2667
+ sgRules , err := getSecurityGroupRules (lbaas .network , sgListopts )
2668
+ if err != nil && ! cpoerrors .IsNotFound (err ) {
2669
+ return fmt .Errorf (
2670
+ "failed to find security group rules in %s: %v" , secGroupID , err )
2671
+ }
2672
+ if len (sgRules ) != 0 {
2673
+ return nil
2674
+ }
2675
+
2676
+ sgRuleCreateOpts := rules.CreateOpts {
2677
+ Direction : direction ,
2678
+ Protocol : protocol ,
2679
+ PortRangeMax : portRangeMin ,
2680
+ PortRangeMin : portRangeMax ,
2681
+ RemoteIPPrefix : remoteIPPrefix ,
2682
+ SecGroupID : secGroupID ,
2683
+ EtherType : etherType ,
2684
+ }
2685
+
2686
+ mc := metrics .NewMetricContext ("security_group_rule" , "create" )
2687
+ _ , err = rules .Create (lbaas .network , sgRuleCreateOpts ).Extract ()
2688
+ if mc .ObserveRequest (err ) != nil {
2689
+ return fmt .Errorf (
2690
+ "failed to create rule for security group %s: %v" ,
2691
+ secGroupID , err )
2692
+ }
2693
+ return nil
2694
+ }
2695
+
2636
2696
// ensureSecurityGroup ensures security group exist for specific loadbalancer service.
2637
2697
// Creating security group for specific loadbalancer service when it does not exist.
2638
2698
func (lbaas * LbaasV2 ) ensureSecurityGroup (clusterName string , apiService * corev1.Service , nodes []* corev1.Node ,
2639
2699
loadbalancer * loadbalancers.LoadBalancer , preferredIPFamily corev1.IPFamily , memberSubnetID string ) error {
2700
+
2701
+ if lbaas .opts .UseOctavia {
2702
+ return lbaas .ensureAndUpdateOctaviaSecurityGroup (clusterName , apiService , nodes , memberSubnetID )
2703
+ }
2704
+
2705
+ // Following code is just for legacy Neutron-LBaaS support which has been deprecated since OpenStack stable/queens
2706
+ // and not recommended using in production. No new features should be added.
2707
+
2640
2708
// find node-security-group for service
2641
2709
var err error
2642
2710
if len (lbaas .opts .NodeSecurityGroupIDs ) == 0 && ! lbaas .opts .UseOctavia {
@@ -2928,7 +2996,7 @@ func (lbaas *LbaasV2) updateOctaviaLoadBalancer(ctx context.Context, clusterName
2928
2996
}
2929
2997
2930
2998
if lbaas .opts .ManageSecurityGroups {
2931
- err := lbaas .updateSecurityGroup (clusterName , service , nodes )
2999
+ err := lbaas .updateSecurityGroup (clusterName , service , nodes , svcConf . lbMemberSubnetID )
2932
3000
if err != nil {
2933
3001
return fmt .Errorf ("failed to update Security Group for loadbalancer service %s: %v" , serviceName , err )
2934
3002
}
@@ -3092,7 +3160,8 @@ func (lbaas *LbaasV2) updateLoadBalancer(ctx context.Context, clusterName string
3092
3160
}
3093
3161
3094
3162
if lbaas .opts .ManageSecurityGroups {
3095
- err := lbaas .updateSecurityGroup (clusterName , service , nodes )
3163
+ // MemberSubnetID is not needed, since this is the legacy call
3164
+ err := lbaas .updateSecurityGroup (clusterName , service , nodes , "" )
3096
3165
if err != nil {
3097
3166
return fmt .Errorf ("failed to update Security Group for loadbalancer service %s: %v" , serviceName , err )
3098
3167
}
@@ -3101,8 +3170,102 @@ func (lbaas *LbaasV2) updateLoadBalancer(ctx context.Context, clusterName string
3101
3170
return nil
3102
3171
}
3103
3172
3173
+ // ensureAndUpdateOctaviaSecurityGroup handles the creation and update of the security group and the securiry rules for the octavia load balancer
3174
+ func (lbaas * LbaasV2 ) ensureAndUpdateOctaviaSecurityGroup (clusterName string , apiService * corev1.Service , nodes []* corev1.Node , memberSubnetID string ) error {
3175
+ // get service ports
3176
+ ports := apiService .Spec .Ports
3177
+ if len (ports ) == 0 {
3178
+ return fmt .Errorf ("no ports provided to openstack load balancer" )
3179
+ }
3180
+
3181
+ // ensure security group for LB
3182
+ lbSecGroupName := getSecurityGroupName (apiService )
3183
+ lbSecGroupID , err := secgroups .IDFromName (lbaas .network , lbSecGroupName )
3184
+ if err != nil {
3185
+ // If the security group of LB not exist, create it later
3186
+ if isSecurityGroupNotFound (err ) {
3187
+ lbSecGroupID = ""
3188
+ } else {
3189
+ return fmt .Errorf ("error occurred finding security group: %s: %v" , lbSecGroupName , err )
3190
+ }
3191
+ }
3192
+ if len (lbSecGroupID ) == 0 {
3193
+ // create security group
3194
+ lbSecGroupCreateOpts := groups.CreateOpts {
3195
+ Name : lbSecGroupName ,
3196
+ Description : fmt .Sprintf ("Security Group for %s/%s Service LoadBalancer in cluster %s" , apiService .Namespace , apiService .Name , clusterName ),
3197
+ }
3198
+
3199
+ mc := metrics .NewMetricContext ("security_group" , "create" )
3200
+ lbSecGroup , err := groups .Create (lbaas .network , lbSecGroupCreateOpts ).Extract ()
3201
+ if mc .ObserveRequest (err ) != nil {
3202
+ return fmt .Errorf ("failed to create Security Group for loadbalancer service %s/%s: %v" , apiService .Namespace , apiService .Name , err )
3203
+ }
3204
+ lbSecGroupID = lbSecGroup .ID
3205
+ }
3206
+
3207
+ mc := metrics .NewMetricContext ("subnet" , "get" )
3208
+ subnet , err := subnets .Get (lbaas .network , memberSubnetID ).Extract ()
3209
+ if mc .ObserveRequest (err ) != nil {
3210
+ return fmt .Errorf (
3211
+ "failed to find subnet %s from openstack: %v" , memberSubnetID , err )
3212
+ }
3213
+
3214
+ etherType := rules .EtherType4
3215
+ if netutils .IsIPv6CIDRString (subnet .CIDR ) {
3216
+ etherType = rules .EtherType6
3217
+ }
3218
+
3219
+ if apiService .Spec .HealthCheckNodePort != 0 {
3220
+ err = lbaas .ensureSecurityRule (
3221
+ rules .DirIngress ,
3222
+ rules .ProtocolTCP ,
3223
+ etherType ,
3224
+ subnet .CIDR ,
3225
+ lbSecGroupID ,
3226
+ int (apiService .Spec .HealthCheckNodePort ),
3227
+ int (apiService .Spec .HealthCheckNodePort ),
3228
+ )
3229
+ if err != nil {
3230
+ return fmt .Errorf (
3231
+ "failed to apply security rule for health check node port, %w" ,
3232
+ err )
3233
+ }
3234
+ }
3235
+
3236
+ // ensure rules for node security group
3237
+ for _ , port := range ports {
3238
+ err = lbaas .ensureSecurityRule (
3239
+ rules .DirIngress ,
3240
+ rules .RuleProtocol (port .Protocol ),
3241
+ etherType ,
3242
+ subnet .CIDR ,
3243
+ lbSecGroupID ,
3244
+ int (port .NodePort ),
3245
+ int (port .NodePort ),
3246
+ )
3247
+ if err != nil {
3248
+ return fmt .Errorf (
3249
+ "failed to apply security rule for port %d, %w" ,
3250
+ port .NodePort , err )
3251
+ }
3252
+
3253
+ if err := applyNodeSecurityGroupIDForLB (lbaas .compute , lbaas .network , nodes , lbSecGroupID ); err != nil {
3254
+ return err
3255
+ }
3256
+ }
3257
+ return nil
3258
+ }
3259
+
3104
3260
// updateSecurityGroup updating security group for specific loadbalancer service.
3105
- func (lbaas * LbaasV2 ) updateSecurityGroup (_ string , apiService * corev1.Service , nodes []* corev1.Node ) error {
3261
+ func (lbaas * LbaasV2 ) updateSecurityGroup (clusterName string , apiService * corev1.Service , nodes []* corev1.Node , memberSubnetID string ) error {
3262
+ if lbaas .opts .UseOctavia {
3263
+ return lbaas .ensureAndUpdateOctaviaSecurityGroup (clusterName , apiService , nodes , memberSubnetID )
3264
+ }
3265
+
3266
+ // Following code is just for legacy Neutron-LBaaS support which has been deprecated since OpenStack stable/queens
3267
+ // and not recommended using in production. No new features should be added.
3268
+
3106
3269
originalNodeSecurityGroupIDs := lbaas .opts .NodeSecurityGroupIDs
3107
3270
3108
3271
var err error
0 commit comments