| // Copyright 2020 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package bigquery |
| |
| import ( |
| "context" |
| "errors" |
| "fmt" |
| |
| "cloud.google.com/go/iam" |
| "cloud.google.com/go/internal/trace" |
| bq "google.golang.org/api/bigquery/v2" |
| iampb "google.golang.org/genproto/googleapis/iam/v1" |
| ) |
| |
| // IAM provides access to an iam.Handle that allows access to IAM functionality for |
| // the given BigQuery table. For more information, see |
| // https://pkg.go.dev/cloud.google.com/go/iam |
| func (t *Table) IAM() *iam.Handle { |
| return iam.InternalNewHandleClient(&bqIAMClient{ |
| bqs: t.c.bqs, |
| }, fmt.Sprintf("projects/%s/datasets/%s/tables/%s", |
| t.ProjectID, t.DatasetID, t.TableID)) |
| } |
| |
| // bqIAMClient is a client that satisfies the IAM "client" interface. |
| // |
| // This client has an explicit assumption that it's only working with Table resources. |
| type bqIAMClient struct { |
| bqs *bq.Service |
| } |
| |
| func (c *bqIAMClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) { |
| return c.GetWithVersion(ctx, resource, 1) |
| } |
| |
| func (c *bqIAMClient) GetWithVersion(ctx context.Context, resource string, requestedPolicyVersion int32) (p *iampb.Policy, err error) { |
| if requestedPolicyVersion > 1 { |
| return nil, errors.New("bigquery: only IAM policy version 1 is supported") |
| } |
| ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.IAM.Get") |
| defer func() { trace.EndSpan(ctx, err) }() |
| |
| iamReq := &bq.GetIamPolicyRequest{ |
| Options: &bq.GetPolicyOptions{ |
| RequestedPolicyVersion: int64(requestedPolicyVersion), |
| }, |
| } |
| call := c.bqs.Tables.GetIamPolicy(resource, iamReq) |
| setClientHeader(call.Header()) |
| |
| var bqp *bq.Policy |
| err = runWithRetry(ctx, func() error { |
| bqp, err = call.Context(ctx).Do() |
| return err |
| }) |
| if err != nil { |
| return nil, err |
| } |
| return iamFromBigQueryPolicy(bqp), nil |
| } |
| |
| func (c *bqIAMClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) { |
| ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.IAM.Set") |
| defer func() { trace.EndSpan(ctx, err) }() |
| |
| bqp := iamToBigQueryPolicy(p) |
| call := c.bqs.Tables.SetIamPolicy(resource, &bq.SetIamPolicyRequest{Policy: bqp}) |
| setClientHeader(call.Header()) |
| return runWithRetry(ctx, func() error { |
| _, err := call.Context(ctx).Do() |
| return err |
| }) |
| } |
| |
| func (c *bqIAMClient) Test(ctx context.Context, resource string, perms []string) (p []string, err error) { |
| ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.IAM.Test") |
| defer func() { trace.EndSpan(ctx, err) }() |
| |
| call := c.bqs.Tables.TestIamPermissions(resource, &bq.TestIamPermissionsRequest{Permissions: perms}) |
| setClientHeader(call.Header()) |
| |
| var res *bq.TestIamPermissionsResponse |
| err = runWithRetry(ctx, func() error { |
| res, err = call.Context(ctx).Do() |
| return err |
| }) |
| if err != nil { |
| return nil, err |
| } |
| return res.Permissions, nil |
| } |
| |
| func iamToBigQueryPolicy(ip *iampb.Policy) *bq.Policy { |
| return &bq.Policy{ |
| Bindings: iamToBigQueryBindings(ip.Bindings), |
| Etag: string(ip.Etag), |
| Version: int64(ip.Version), |
| } |
| } |
| |
| func iamToBigQueryBindings(ibs []*iampb.Binding) []*bq.Binding { |
| var bqBindings []*bq.Binding |
| for _, ib := range ibs { |
| bqBindings = append(bqBindings, &bq.Binding{ |
| Role: ib.Role, |
| Members: ib.Members, |
| }) |
| } |
| return bqBindings |
| } |
| |
| func iamFromBigQueryPolicy(bqPolicy *bq.Policy) *iampb.Policy { |
| return &iampb.Policy{ |
| Bindings: iamFromBigQueryBindings(bqPolicy.Bindings), |
| Etag: []byte(bqPolicy.Etag), |
| Version: int32(bqPolicy.Version), |
| } |
| } |
| |
| func iamFromBigQueryBindings(bqBindings []*bq.Binding) []*iampb.Binding { |
| var ibs []*iampb.Binding |
| for _, bqb := range bqBindings { |
| ibs = append(ibs, &iampb.Binding{ |
| Role: bqb.Role, |
| Members: bqb.Members, |
| }) |
| } |
| return ibs |
| } |