Skip to content

Commit ff829c2

Browse files
GouthamMLYashwantGohokar
authored andcommitted
System tag support in CPO. Backfilling existing LB & NLB
1 parent 27d1e1c commit ff829c2

20 files changed

+627
-21
lines changed

pkg/cloudprovider/providers/oci/instances_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,18 @@ func (c *MockLoadBalancerClient) DeleteListener(ctx context.Context, lbID, name
497497
return "", nil
498498
}
499499

500+
var updateLoadBalancerErrors = map[string]error{
501+
"work request fail": errors.New("internal server error"),
502+
}
503+
504+
func (c *MockLoadBalancerClient) UpdateLoadBalancer(ctx context.Context, lbID string, details *client.GenericUpdateLoadBalancerDetails) (string, error) {
505+
if err, ok := updateLoadBalancerErrors[lbID]; ok {
506+
return "", err
507+
}
508+
509+
return "", nil
510+
}
511+
500512
var awaitLoadbalancerWorkrequestMap = map[string]error{
501513
"failedToGetUpdateNetworkSecurityGroupsWorkRequest": errors.New("internal server error for get workrequest call"),
502514
}
@@ -612,6 +624,10 @@ func (c *MockNetworkLoadBalancerClient) UpdateNetworkSecurityGroups(ctx context.
612624
return "", nil
613625
}
614626

627+
func (c *MockNetworkLoadBalancerClient) UpdateLoadBalancer(ctx context.Context, lbID string, details *client.GenericUpdateLoadBalancerDetails) (string, error) {
628+
return "", nil
629+
}
630+
615631
// MockBlockStorageClient mocks BlockStorage client implementation
616632
type MockBlockStorageClient struct{}
617633

pkg/cloudprovider/providers/oci/load_balancer.go

+98-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ const DefaultNetworkLoadBalancerListenerProtocol = "TCP"
6868
// https://docs.oracle.com/en-us/iaas/Content/General/Concepts/servicelimits.htm#nsg_limits
6969
const MaxNsgPerVnic = 5
7070

71+
const (
72+
OkeSystemTagNamesapce = "orcl-containerengine"
73+
// MaxDefinedTagPerLB is the maximum number of defined tags that be can be associated with the resource
74+
//https://docs.oracle.com/en-us/iaas/Content/Tagging/Concepts/taggingoverview.htm#limits
75+
MaxDefinedTagPerLB = 64
76+
resourceTrackingFeatureFlagName = "CPO_ENABLE_RESOURCE_ATTRIBUTION"
77+
)
78+
79+
var MaxDefinedTagPerLBErr = fmt.Errorf("max limit of defined tags for lb is reached. skip adding tags. sending metric")
80+
var enableOkeSystemTags = false
81+
7182
const (
7283
// Fallback value if annotation on service is not set
7384
lbDefaultShape = "100Mbps"
@@ -373,6 +384,11 @@ func (clb *CloudLoadBalancerProvider) createLoadBalancer(ctx context.Context, sp
373384
FreeformTags: spec.FreeformTags,
374385
DefinedTags: spec.DefinedTags,
375386
}
387+
// do not block creation if the defined tag limit is reached. defer LB to tracked by backfilling
388+
if len(details.DefinedTags) > MaxDefinedTagPerLB {
389+
logger.Warnf("the number of defined tags in the LB create request is beyond the limit. removing the resource tracking tags from the details..")
390+
delete(details.DefinedTags, OkeSystemTagNamesapce)
391+
}
376392

377393
if spec.Shape == flexible {
378394
details.ShapeDetails = &client.GenericShapeDetails{
@@ -714,6 +730,19 @@ func (cp *CloudProvider) EnsureLoadBalancer(ctx context.Context, clusterName str
714730

715731
if !lbExists {
716732
lbStatus, newLBOCID, err := lbProvider.createLoadBalancer(ctx, spec)
733+
if err != nil && client.IsSystemTagNotFoundOrNotAuthorisedError(logger, err) {
734+
logger.Warn("LB creation failed due to error in adding system tags. sending metric & retrying without system tags")
735+
736+
// send resource track tagging failure metrics
737+
errorType = util.SystemTagErrTypePrefix + util.GetError(err)
738+
lbMetricDimension = util.GetMetricDimensionForComponent(errorType, util.LoadBalancerType)
739+
dimensionsMap[metrics.ComponentDimension] = lbMetricDimension
740+
metrics.SendMetricData(cp.metricPusher, getMetric(loadBalancerType, Create), time.Since(startTime).Seconds(), dimensionsMap)
741+
742+
// retry create without resource tracking system tags
743+
delete(spec.DefinedTags, OkeSystemTagNamesapce)
744+
lbStatus, newLBOCID, err = lbProvider.createLoadBalancer(ctx, spec)
745+
}
717746
if err != nil {
718747
logger.With(zap.Error(err)).Error("Failed to provision LoadBalancer")
719748
errorType = util.GetError(err)
@@ -884,7 +913,7 @@ func (cp *CloudProvider) getLoadBalancerSubnets(ctx context.Context, logger *zap
884913

885914
func (clb *CloudLoadBalancerProvider) updateLoadBalancer(ctx context.Context, lb *client.GenericLoadBalancer, spec *LBSpec) error {
886915
lbID := *lb.Id
887-
916+
start := time.Now()
888917
logger := clb.logger.With("loadBalancerID", lbID, "compartmentID", clb.config.CompartmentID, "loadBalancerType", getLoadBalancerType(spec.service), "serviceName", spec.service.Name)
889918

890919
var actualPublicReservedIP *string
@@ -983,6 +1012,24 @@ func (clb *CloudLoadBalancerProvider) updateLoadBalancer(ctx context.Context, lb
9831012
return errors.Errorf("The Load Balancer service reserved IP cannot be updated after the Load Balancer is created.")
9841013
}
9851014
}
1015+
1016+
dimensionsMap := make(map[string]string)
1017+
var errType string
1018+
if enableOkeSystemTags && !doesLbHaveOkeSystemTags(lb, spec) {
1019+
logger.Info("detected loadbalancer without oke system tags. proceeding to add")
1020+
err = clb.addLoadBalancerOkeSystemTags(ctx, lb, spec)
1021+
if err != nil {
1022+
// fail open if the update request fails
1023+
logger.With(zap.Error(err)).Warn("updateLoadBalancer didn't succeed. unable to add oke system tags")
1024+
errType = util.SystemTagErrTypePrefix + util.GetError(err)
1025+
if errors.Is(err, MaxDefinedTagPerLBErr) {
1026+
errType = util.ErrTagLimitReached
1027+
}
1028+
dimensionsMap[metrics.ComponentDimension] = util.GetMetricDimensionForComponent(errType, util.LoadBalancerType)
1029+
dimensionsMap[metrics.ResourceOCIDDimension] = *lb.Id
1030+
metrics.SendMetricData(clb.metricPusher, getMetric(spec.Type, Update), time.Since(start).Seconds(), dimensionsMap)
1031+
}
1032+
}
9861033
return nil
9871034
}
9881035

@@ -1648,6 +1695,56 @@ func (clb *CloudLoadBalancerProvider) updateLoadBalancerNetworkSecurityGroups(ct
16481695
return nil
16491696
}
16501697

1698+
func doesLbHaveOkeSystemTags(lb *client.GenericLoadBalancer, spec *LBSpec) bool {
1699+
if lb.SystemTags == nil || spec.SystemTags == nil {
1700+
return false
1701+
}
1702+
if okeSystemTag, okeSystemTagNsExists := lb.SystemTags[OkeSystemTagNamesapce]; okeSystemTagNsExists {
1703+
return reflect.DeepEqual(okeSystemTag, spec.SystemTags[OkeSystemTagNamesapce])
1704+
}
1705+
return false
1706+
}
1707+
func (clb *CloudLoadBalancerProvider) addLoadBalancerOkeSystemTags(ctx context.Context, lb *client.GenericLoadBalancer, spec *LBSpec) error {
1708+
lbDefinedTagsRequest := make(map[string]map[string]interface{})
1709+
1710+
if spec.SystemTags == nil {
1711+
return fmt.Errorf("oke system tag is not found in LB spec. ignoring..")
1712+
}
1713+
if _, exists := spec.SystemTags[OkeSystemTagNamesapce]; !exists {
1714+
return fmt.Errorf("oke system tag namespace is not found in LB spec")
1715+
}
1716+
1717+
if lb.DefinedTags != nil {
1718+
lbDefinedTagsRequest = lb.DefinedTags
1719+
}
1720+
1721+
// no overwriting customer tags as customer can not have a tag namespace with prefix 'orcl-'
1722+
// system tags are passed as defined tags in the request
1723+
lbDefinedTagsRequest[OkeSystemTagNamesapce] = spec.SystemTags[OkeSystemTagNamesapce]
1724+
1725+
// update fails if the number of defined tags is more than the service limit i.e 64
1726+
if len(lbDefinedTagsRequest) > MaxDefinedTagPerLB {
1727+
return MaxDefinedTagPerLBErr
1728+
}
1729+
1730+
lbUpdateDetails := &client.GenericUpdateLoadBalancerDetails{
1731+
FreeformTags: lb.FreeformTags,
1732+
DefinedTags: lbDefinedTagsRequest,
1733+
}
1734+
wrID, err := clb.lbClient.UpdateLoadBalancer(ctx, *lb.Id, lbUpdateDetails)
1735+
if err != nil {
1736+
return errors.Wrap(err, "UpdateLoadBalancer request failed")
1737+
}
1738+
_, err = clb.lbClient.AwaitWorkRequest(ctx, wrID)
1739+
if err != nil {
1740+
return errors.Wrap(err, "failed to await updateloadbalancer work request")
1741+
}
1742+
1743+
logger := clb.logger.With("opc-workrequest-id", wrID, "loadBalancerID", lb.Id)
1744+
logger.Info("UpdateLoadBalancer request to add oke system tags completed successfully")
1745+
return nil
1746+
}
1747+
16511748
// Given an OCI load balancer, return a LoadBalancerStatus
16521749
func loadBalancerToStatus(lb *client.GenericLoadBalancer) (*v1.LoadBalancerStatus, error) {
16531750
if len(lb.IpAddresses) == 0 {

pkg/cloudprovider/providers/oci/load_balancer_spec.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package oci
1717
import (
1818
"encoding/json"
1919
"fmt"
20-
"github.com/oracle/oci-cloud-controller-manager/pkg/util"
2120
"net"
2221
"net/http"
2322
"strconv"
@@ -30,6 +29,7 @@ import (
3029

3130
"github.com/oracle/oci-cloud-controller-manager/pkg/cloudprovider/providers/oci/config"
3231
"github.com/oracle/oci-cloud-controller-manager/pkg/oci/client"
32+
"github.com/oracle/oci-cloud-controller-manager/pkg/util"
3333
"github.com/oracle/oci-go-sdk/v65/common"
3434
"github.com/pkg/errors"
3535
helper "k8s.io/cloud-provider/service/helpers"
@@ -318,6 +318,7 @@ type LBSpec struct {
318318
NetworkSecurityGroupIds []string
319319
FreeformTags map[string]string
320320
DefinedTags map[string]map[string]interface{}
321+
SystemTags map[string]map[string]interface{}
321322

322323
service *v1.Service
323324
nodes []*v1.Node
@@ -379,7 +380,7 @@ func NewLBSpec(logger *zap.SugaredLogger, svc *v1.Service, nodes []*v1.Node, sub
379380
return nil, err
380381
}
381382
// merge lbtags with common tags if present
382-
if util.IsCommonTagPresent(initialLBTags) {
383+
if enableOkeSystemTags && util.IsCommonTagPresent(initialLBTags) {
383384
lbTags = util.MergeTagConfig(lbTags, initialLBTags.Common)
384385
}
385386

@@ -421,6 +422,7 @@ func NewLBSpec(logger *zap.SugaredLogger, svc *v1.Service, nodes []*v1.Node, sub
421422
securityListManager: secListFactory(ruleManagementMode),
422423
FreeformTags: lbTags.FreeformTags,
423424
DefinedTags: lbTags.DefinedTags,
425+
SystemTags: getResourceTrackingSysTagsFromConfig(logger, initialLBTags),
424426
}, nil
425427
}
426428

@@ -1351,3 +1353,22 @@ func updateSpecWithLbSubnets(spec *LBSpec, lbSubnetId []string) (*LBSpec, error)
13511353

13521354
return spec, nil
13531355
}
1356+
1357+
// getResourceTrackingSysTagsFromConfig reads resource tracking tags from config
1358+
// which are specified under common tags
1359+
func getResourceTrackingSysTagsFromConfig(logger *zap.SugaredLogger, initialTags *config.InitialTags) (resourceTrackingTags map[string]map[string]interface{}) {
1360+
resourceTrackingTags = make(map[string]map[string]interface{})
1361+
// TODO: Fix the double negative
1362+
if !(util.IsCommonTagPresent(initialTags) && initialTags.Common.DefinedTags != nil) {
1363+
logger.Error("oke resource tracking system tags are not present in cloud-config.yaml")
1364+
return nil
1365+
}
1366+
1367+
if tag, exists := initialTags.Common.DefinedTags[OkeSystemTagNamesapce]; exists {
1368+
resourceTrackingTags[OkeSystemTagNamesapce] = tag
1369+
return
1370+
}
1371+
1372+
logger.Error("tag config doesn't consist resource tracking tags")
1373+
return nil
1374+
}

0 commit comments

Comments
 (0)