-
Story
-
Resolution: Done
-
Normal
-
openshift-4.15
-
None
-
None
-
BU Product Work
-
8
-
False
-
None
-
False
-
OCPSTRAT-768 - Apply user defined tags to all resources created by OpenShift (GCP) GA
-
-
-
CFE Sprint 242, CFE Sprint 243, CFE Sprint 244, CFE Sprint 245, CFE Sprint 246, CFE Sprint 247, CFE Sprint 252, CFE Sprint 253
Issue(Feature Request): https://github.com/kubernetes-sigs/gcp-filestore-csi-driver/issues/567
Driver should be added with the functionality to accept user-defined tags as process arguments and these tags must be added to the resources managed by the driver i.e. Filestore Instances.
Adding tags to a resource in controlled through quota and hence the implementation should have logic for proactively limiting request rate and to retry to quota exceeded error, and also should have handling for ignoring already exist error.
import "golang.org/x/time/rate" // newLimiter returns token bucket based request rate limiter after initializing // the passed values for limit, burst(or token bucket) size. If opted for emptyBucket // all initial tokens are reserved for the first burst. func newLimiter(limit, burst int, emptyBucket bool) *rate.Limiter { limiter := rate.NewLimiter(rate.Every(time.Second/time.Duration(limit)), burst) if emptyBucket { limiter.AllowN(time.Now(), burst) } return limiter }
import ( rscmgr "cloud.google.com/go/resourcemanager/apiv3" rscmgrpb "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb" "github.com/googleapis/gax-go/v2" "github.com/googleapis/gax-go/v2/apierror" "google.golang.org/api/iterator" "google.golang.org/api/option" ) // getCreateCallOptions returns a list of additional call options to use for // the create operations. func getCreateCallOptions() []gax.CallOption { return []gax.CallOption{ gax.WithRetry(func() gax.Retryer { return gax.OnHTTPCodes(gax.Backoff{ Initial: 90 * time.Second, Max: 5 * time.Minute, Multiplier: 2, }, http.StatusTooManyRequests) }), } } // getTagBindingsClient returns the client to be used for creating tag bindings to // the resources. func getTagBindingsClient(ctx context.Context) (*rscmgr.TagBindingsClient, error) { cred, err := GetCredentialsSecret(tags.CoreClient, tags.Namespace, tags.ProviderSpec) if err != nil { return nil, fmt.Errorf("failed to read to gcp config: %w", err) } endpoint := fmt.Sprintf("https://%s-%s", tags.InstanceZone, resourceManagerHostSubPath) opts := []option.ClientOption{ option.WithCredentialsJSON([]byte(cred)), option.WithEndpoint(endpoint), } return rscmgr.NewTagBindingsRESTClient(ctx, opts...) } func addTags() { client, err := getTagBindingsClient(ctx) if err != nil { return err } defer client.Close() // GCP has a rate limit of 600 requests per minute, restricting // here to 8 requests per second. limiter := newLimiter(8, 8, true) tagBindingReq := &rscmgrpb.CreateTagBindingRequest{ TagBinding: &rscmgrpb.TagBinding{ Parent: parent, }, } for _, value := range userTags { if err := limiter.Wait(ctx); err != nil { errFlag = true continue } tagBindingReq.TagBinding.TagValueNamespacedName = value result, err := client.CreateTagBinding(ctx, tagBindingReq, getCreateCallOptions()...) if err != nil { e, ok := err.(*apierror.APIError) if ok && e.HTTPCode() == http.StatusConflict { klog.Infof("tag binding %s/%s already exists", instanceID, value) continue } errFlag = true klog.Errorf("request to add %s tag to %d compute instance failed: %v", value, instanceID, err) continue } if _, err = result.Wait(ctx); err != nil { errFlag = true klog.Errorf("failed to add %s tag to %d compute instance: %v", value, instanceID, err) } } }
Acceptance Criteria
- Code linting, validation and best practices adhered to
- Unit tests for applicable changes.
- gcp-filestore-disk-csi-driver managed resources should have user-defined tags.