func FixedRoleBindComputedVariables(role string) []varcontext.DefaultVariable {
	fixedRoleVar := varcontext.DefaultVariable{Name: "role", Default: role, Overwrite: true}
	return append(ServiceAccountBindComputedVariables(), fixedRoleVar)
}
FixedRoleBindComputedVariables allows you to create a service account with a
fixed role.
package account_managers
import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"
	"code.cloudfoundry.org/lager"
	"github.com/GoogleCloudPlatform/gcp-service-broker/db_service/models"
	"github.com/GoogleCloudPlatform/gcp-service-broker/pkg/broker"
	"github.com/GoogleCloudPlatform/gcp-service-broker/pkg/validation"
	"github.com/GoogleCloudPlatform/gcp-service-broker/pkg/varcontext"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/jwt"
	cloudres "google.golang.org/api/cloudresourcemanager/v1"
	"google.golang.org/api/googleapi"
	iam "google.golang.org/api/iam/v1"
)
const (
	roleResourcePrefix    = "roles/"
	saResourcePrefix      = "serviceAccount:"
	projectResourcePrefix = "projects/"
)
type ServiceAccountManager struct {
	ProjectId  string
	HttpConfig *jwt.Config
	Logger     lager.Logger
}
func (sam *ServiceAccountManager) CreateCredentials(ctx context.Context, vc *varcontext.VarContext) (map[string]interface{}, error) {
	role := vc.GetString("role")
	accountId := vc.GetString("service_account_name")
	displayName := vc.GetString("service_account_display_name")
	if err := vc.Error(); err != nil {
		return nil, err
	}
	sam.Logger.Info("create-service-account", lager.Data{
		"role":                         role,
		"service_account_name":         accountId,
		"service_account_display_name": displayName,
	})
	newSA, err := sam.createServiceAccount(ctx, accountId, displayName)
	if err != nil {
		return nil, err
	}
	if err := sam.grantRoleToAccount(ctx, role, newSA); err != nil {
		return nil, err
	}
	newSAKey, err := sam.createServiceAccountKey(ctx, newSA)
	if err != nil {
		return nil, fmt.Errorf("Error creating new service account key: %s", err)
	}
	newSAInfo := ServiceAccountInfo{
		Name:           newSA.DisplayName,
		Email:          newSA.Email,
		UniqueId:       newSA.UniqueId,
		PrivateKeyData: newSAKey.PrivateKeyData,
		ProjectId:      sam.ProjectId,
	}
	return varcontext.Builder().MergeStruct(newSAInfo).BuildMap()
}
func (sam *ServiceAccountManager) DeleteCredentials(ctx context.Context, binding models.ServiceBindingCredentials) error {
	var saCreds ServiceAccountInfo
	if err := json.Unmarshal([]byte(binding.OtherDetails), &saCreds); err != nil {
		return fmt.Errorf("Error unmarshalling credentials: %s", err)
	}
	iamService, err := iam.New(sam.HttpConfig.Client(ctx))
	if err != nil {
		return fmt.Errorf("Error creating IAM service: %s", err)
	}
	if err := sam.revokeRolesFromAccount(ctx, saCreds.Email); err != nil {
		return fmt.Errorf("Error deleting role bindings from service account: %s", err)
	}
	resourceName := projectResourcePrefix + sam.ProjectId + "/serviceAccounts/" + saCreds.UniqueId
	if _, err := iam.NewProjectsServiceAccountsService(iamService).Delete(resourceName).Do(); err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == http.StatusNotFound {
			return nil
		}
		return fmt.Errorf("Error deleting service account: %s", err)
	}
	return nil
}
func (sam *ServiceAccountManager) createServiceAccount(ctx context.Context, accountId, displayName string) (*iam.ServiceAccount, error) {
	client := sam.HttpConfig.Client(ctx)
	iamService, err := iam.New(client)
	if err != nil {
		return nil, fmt.Errorf("Error creating new IAM service: %s", err)
	}
	resourceName := projectResourcePrefix + sam.ProjectId
	newSARequest := iam.CreateServiceAccountRequest{
		AccountId: accountId,
		ServiceAccount: &iam.ServiceAccount{
			DisplayName: displayName,
		},
	}
	return iam.NewProjectsServiceAccountsService(iamService).Create(resourceName, &newSARequest).Do()
}
func (sam *ServiceAccountManager) createServiceAccountKey(ctx context.Context, account *iam.ServiceAccount) (*iam.ServiceAccountKey, error) {
	client := sam.HttpConfig.Client(ctx)
	iamService, err := iam.New(client)
	if err != nil {
		return nil, fmt.Errorf("Error creating new IAM service: %s", err)
	}
	saKeyService := iam.NewProjectsServiceAccountsKeysService(iamService)
	return saKeyService.Create(account.Name, &iam.CreateServiceAccountKeyRequest{}).Do()
}
func (sam *ServiceAccountManager) grantRoleToAccount(ctx context.Context, role string, account *iam.ServiceAccount) error {
	client := sam.HttpConfig.Client(ctx)
	cloudresService, err := cloudres.New(client)
	if err != nil {
		return fmt.Errorf("Error creating new cloud resource management service: %s", err)
	}
	for attempt := 0; attempt < 3; attempt++ {
		currPolicy, err := cloudresService.Projects.GetIamPolicy(sam.ProjectId, &cloudres.GetIamPolicyRequest{}).Do()
		if err != nil {
			return fmt.Errorf("Error getting current project iam policy: %s", err)
		}
		currPolicy.Bindings = mergeBindings(append(currPolicy.Bindings, &cloudres.Binding{
			Members: []string{saResourcePrefix + account.Email},
			Role:    roleResourcePrefix + role,
		}))
		newPolicyRequest := cloudres.SetIamPolicyRequest{
			Policy: currPolicy,
		}
		_, err = cloudresService.Projects.SetIamPolicy(sam.ProjectId, &newPolicyRequest).Do()
		if err == nil {
			return nil
		}
		if isConflictError(err) {
			time.Sleep(5 * time.Second)
			continue
		} else {
			return fmt.Errorf("Error assigning policy to service account: %s", err)
		}
	}
	return err
}
func (sam *ServiceAccountManager) revokeRolesFromAccount(ctx context.Context, email string) error {
	client := sam.HttpConfig.Client(ctx)
	cloudresService, err := cloudres.New(client)
	if err != nil {
		return fmt.Errorf("Error creating new cloud resource management service: %s", err)
	}
	for attempt := 0; attempt < 3; attempt++ {
		currPolicy, err := cloudresService.Projects.GetIamPolicy(sam.ProjectId, &cloudres.GetIamPolicyRequest{}).Do()
		if err != nil {
			return fmt.Errorf("Error getting current project iam policy: %s", err)
		}
		currPolicy.Bindings = mergeBindings(removeMemberFromBindings(currPolicy.Bindings, saResourcePrefix+email))
		newPolicyRequest := cloudres.SetIamPolicyRequest{
			Policy: currPolicy,
		}
		_, err = cloudresService.Projects.SetIamPolicy(sam.ProjectId, &newPolicyRequest).Do()
		if err == nil {
			return nil
		}
		if isConflictError(err) {
			time.Sleep(5 * time.Second)
			continue
		} else {
			return fmt.Errorf("Error updating iam policy: %s", err)
		}
	}
	return err
}
func isConflictError(err error) bool {
	gerr, ok := err.(*googleapi.Error)
	return ok && gerr != nil && gerr.Code == 409
}
type ServiceAccountInfo struct {
	Name      string `json:"Name"`
	Email     string `json:"Email"`
	UniqueId  string `json:"UniqueId"`
	ProjectId string `json:"ProjectId"`
	PrivateKeyData string `json:"PrivateKeyData"`
}
func ServiceAccountWhitelistWithDefault(whitelist []string, defaultValue string) []broker.BrokerVariable {
	whitelistEnum := make(map[interface{}]string)
	for _, val := range whitelist {
		whitelistEnum[val] = roleResourcePrefix + val
	}
	return []broker.BrokerVariable{
		{
			FieldName: "role",
			Type:      broker.JsonTypeString,
			Details:   `The role for the account without the "roles/" prefix. See: https: 
			Enum:      whitelistEnum,
			Default:   defaultValue,
		},
	}
}
func ServiceAccountBindComputedVariables() []varcontext.DefaultVariable {
	return []varcontext.DefaultVariable{
		{Name: "service_account_name", Default: `${str.truncate(20, "pcf-binding-${request.binding_id}")}`, Overwrite: true},
		{Name: "service_account_display_name", Default: "${service_account_name}", Overwrite: true},
	}
}