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

     1  package gcp
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/sirupsen/logrus"
     8  	"google.golang.org/api/compute/v1"
     9  	"google.golang.org/api/googleapi"
    10  
    11  	"github.com/openshift/installer/pkg/types/gcp"
    12  )
    13  
    14  func (o *ClusterUninstaller) listAddresses(ctx context.Context, scope resourceScope) ([]cloudResource, error) {
    15  	return o.listAddressesWithFilter(ctx, "items(name,region,addressType),nextPageToken", o.clusterIDFilter(), nil, scope)
    16  }
    17  
    18  func createAddressCloudResources(filterFunc func(address *compute.Address) bool, list *compute.AddressList) []cloudResource {
    19  	result := []cloudResource{}
    20  
    21  	for _, item := range list.Items {
    22  		if filterFunc == nil || filterFunc(item) {
    23  			logrus.Debugf("Found address: %s", item.Name)
    24  			var quota []gcp.QuotaUsage
    25  			if item.AddressType == "INTERNAL" {
    26  				quota = []gcp.QuotaUsage{{
    27  					Metric: &gcp.Metric{
    28  						Service: gcp.ServiceComputeEngineAPI,
    29  						Limit:   "internal_addresses",
    30  						Dimensions: map[string]string{
    31  							"region": getNameFromURL("regions", item.Region),
    32  						},
    33  					},
    34  					Amount: 1,
    35  				}}
    36  			}
    37  			result = append(result, cloudResource{
    38  				key:      item.Name,
    39  				name:     item.Name,
    40  				typeName: "address",
    41  				quota:    quota,
    42  			})
    43  		}
    44  	}
    45  
    46  	return result
    47  }
    48  
    49  // listAddressesWithFilter lists addresses in the project that satisfy the filter criteria.
    50  // The fields parameter specifies which fields should be returned in the result, the filter string contains
    51  // a filter string passed to the API to filter results. The filterFunc is a client-side filtering function
    52  // that determines whether a particular result should be returned or not.
    53  func (o *ClusterUninstaller) listAddressesWithFilter(ctx context.Context, fields string, filter string, filterFunc func(*compute.Address) bool, scope resourceScope) ([]cloudResource, error) {
    54  	o.Logger.Debugf("Listing %s addresses", scope)
    55  	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
    56  	defer cancel()
    57  	result := []cloudResource{}
    58  
    59  	if scope == gcpGlobalResource {
    60  		req := o.computeSvc.GlobalAddresses.List(o.ProjectID).Fields(googleapi.Field(fields))
    61  		if len(filter) > 0 {
    62  			req = req.Filter(filter)
    63  		}
    64  		err := req.Pages(ctx, func(list *compute.AddressList) error {
    65  			result = append(result, createAddressCloudResources(filterFunc, list)...)
    66  			return nil
    67  		})
    68  		if err != nil {
    69  			return nil, fmt.Errorf("failed to list global addresses: %w", err)
    70  		}
    71  		return result, nil
    72  	}
    73  
    74  	// Regional addresses
    75  	req := o.computeSvc.Addresses.List(o.ProjectID, o.Region).Fields(googleapi.Field(fields))
    76  	if len(filter) > 0 {
    77  		req = req.Filter(filter)
    78  	}
    79  	err := req.Pages(ctx, func(list *compute.AddressList) error {
    80  		result = append(result, createAddressCloudResources(filterFunc, list)...)
    81  		return nil
    82  	})
    83  	if err != nil {
    84  		return nil, fmt.Errorf("failed to list regional addresses: %w", err)
    85  	}
    86  
    87  	return result, nil
    88  }
    89  
    90  func (o *ClusterUninstaller) deleteAddress(ctx context.Context, item cloudResource, scope resourceScope) error {
    91  	o.Logger.Debugf("Deleting address %s", item.name)
    92  	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
    93  	defer cancel()
    94  
    95  	var op *compute.Operation
    96  	var err error
    97  	if scope == gcpGlobalResource {
    98  		op, err = o.computeSvc.GlobalAddresses.Delete(o.ProjectID, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
    99  	} else {
   100  		op, err = o.computeSvc.Addresses.Delete(o.ProjectID, o.Region, item.name).RequestId(o.requestID(item.typeName, item.name)).Context(ctx).Do()
   101  	}
   102  
   103  	if op != nil && op.Status == "DONE" && isErrorStatus(op.HttpErrorStatusCode) {
   104  		o.resetRequestID(item.typeName, item.name)
   105  		return fmt.Errorf("failed to delete address %s with error: %s: %w", item.name, operationErrorMessage(op), err)
   106  	}
   107  	if (err != nil && isNoOp(err)) || (op != nil && op.Status == "DONE") {
   108  		o.resetRequestID(item.typeName, item.name)
   109  		o.deletePendingItems(item.typeName, []cloudResource{item})
   110  		o.Logger.Infof("Deleted address %s", item.name)
   111  	}
   112  	return nil
   113  }
   114  
   115  // destroyAddresses removes all address resources that have a name prefixed
   116  // with the cluster's infra ID.
   117  func (o *ClusterUninstaller) destroyAddresses(ctx context.Context) error {
   118  	for _, scope := range []resourceScope{gcpGlobalResource, gcpRegionalResource} {
   119  		found, err := o.listAddresses(ctx, scope)
   120  		if err != nil {
   121  			return fmt.Errorf("failed to list %s addresses: %w", scope, err)
   122  		}
   123  		items := o.insertPendingItems("address", found)
   124  		for _, item := range items {
   125  			err := o.deleteAddress(ctx, item, scope)
   126  			if err != nil {
   127  				o.errorTracker.suppressWarning(item.key, err, o.Logger)
   128  			}
   129  		}
   130  		for _, item := range o.getPendingItems("address") {
   131  			if err := o.deleteAddress(ctx, item, scope); err != nil {
   132  				return fmt.Errorf("error deleting pending address %s: %w", item.name, err)
   133  			}
   134  		}
   135  	}
   136  	return nil
   137  }