github.com/openshift/installer@v1.4.17/pkg/destroy/gcp/serviceaccount.go (about)

     1  package gcp
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/pkg/errors"
     8  	"google.golang.org/api/iam/v1"
     9  	"k8s.io/apimachinery/pkg/util/sets"
    10  
    11  	"github.com/openshift/installer/pkg/types/gcp"
    12  )
    13  
    14  // listServiceAccounts retrieves all service accounts with a display name prefixed with the cluster's
    15  // infra ID. Filtering is done client side because the API doesn't offer filtering for service accounts.
    16  func (o *ClusterUninstaller) listServiceAccounts(ctx context.Context) ([]cloudResource, error) {
    17  	o.Logger.Debugf("Listing service accounts")
    18  
    19  	result := []cloudResource{}
    20  	sas, err := o.listClusterServiceAccount(ctx)
    21  	if err != nil {
    22  		errors.Wrapf(err, "failed to fetch service accounts for the cluster")
    23  	}
    24  	for _, item := range sas {
    25  		o.Logger.Debugf("Found service account: %s", item.Name)
    26  		result = append(result, cloudResource{
    27  			key:      item.Name,
    28  			name:     item.Name,
    29  			url:      item.Email,
    30  			typeName: "serviceaccount",
    31  			quota: []gcp.QuotaUsage{{
    32  				Metric: &gcp.Metric{
    33  					Service: gcp.ServiceIAMAPI,
    34  					Limit:   "quota/service-account-count",
    35  				},
    36  				Amount: 1,
    37  			}},
    38  		})
    39  	}
    40  	return result, nil
    41  }
    42  
    43  func (o *ClusterUninstaller) listClusterServiceAccount(ctx context.Context) ([]*iam.ServiceAccount, error) {
    44  	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
    45  	defer cancel()
    46  	result := []*iam.ServiceAccount{}
    47  	req := o.iamSvc.Projects.ServiceAccounts.List(fmt.Sprintf("projects/%s", o.ProjectID)).Fields("accounts(name,displayName,email),nextPageToken")
    48  	err := req.Pages(ctx, func(list *iam.ListServiceAccountsResponse) error {
    49  		for idx, item := range list.Accounts {
    50  			if o.isClusterResource(item.Email) || o.isClusterResource(item.DisplayName) {
    51  				result = append(result, list.Accounts[idx])
    52  			}
    53  		}
    54  		return nil
    55  	})
    56  	if err != nil {
    57  		return nil, errors.Wrapf(err, "failed to fetch service accounts")
    58  	}
    59  	return result, nil
    60  }
    61  
    62  func (o *ClusterUninstaller) deleteServiceAccount(ctx context.Context, item cloudResource) error {
    63  	o.Logger.Debugf("Deleting service account %s", item.name)
    64  	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
    65  	defer cancel()
    66  	_, err := o.iamSvc.Projects.ServiceAccounts.Delete(item.name).Context(ctx).Do()
    67  	if err != nil && !isNoOp(err) {
    68  		return errors.Wrapf(err, "failed to delete service account %s", item.name)
    69  	}
    70  	o.deletePendingItems(item.typeName, []cloudResource{item})
    71  	o.Logger.Infof("Deleted service account %s", item.name)
    72  	return nil
    73  }
    74  
    75  // destroyServiceAccounts removes service accounts with a display name prefixed
    76  // with the cluster's infra ID.
    77  func (o *ClusterUninstaller) destroyServiceAccounts(ctx context.Context) error {
    78  	found, err := o.listServiceAccounts(ctx)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	items := o.insertPendingItems("serviceaccount", found)
    83  	if len(items) == 0 {
    84  		return nil
    85  	}
    86  
    87  	// Remove service accounts from project policy
    88  	policy, err := o.getProjectIAMPolicy(ctx)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	emails := sets.NewString()
    93  	for _, item := range items {
    94  		emails.Insert(item.url)
    95  	}
    96  	if o.clearIAMPolicyBindings(policy, emails, o.Logger) {
    97  		err = o.setProjectIAMPolicy(ctx, policy)
    98  		if err != nil {
    99  			o.errorTracker.suppressWarning("iampolicy", err, o.Logger)
   100  			return errors.Errorf("%d items pending", len(items))
   101  		}
   102  		o.Logger.Infof("Deleted IAM project role bindings")
   103  	}
   104  
   105  	for _, item := range items {
   106  		err := o.deleteServiceAccount(ctx, item)
   107  		if err != nil {
   108  			o.errorTracker.suppressWarning(item.key, err, o.Logger)
   109  		}
   110  	}
   111  	if items = o.getPendingItems("serviceaccount"); len(items) > 0 {
   112  		return errors.Errorf("%d items pending", len(items))
   113  	}
   114  	return nil
   115  }