github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/dns-dns.go (about)

     1  package powervs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"net/http"
     8  	"regexp"
     9  	"time"
    10  
    11  	"github.com/IBM/go-sdk-core/v5/core"
    12  	"k8s.io/apimachinery/pkg/util/wait"
    13  )
    14  
    15  const (
    16  	cisDNSRecordTypeName = "cis dns record"
    17  )
    18  
    19  // listDNSRecords lists DNS records for the cluster.
    20  func (o *ClusterUninstaller) listDNSRecords() (cloudResources, error) {
    21  	o.Logger.Debugf("Listing DNS records")
    22  
    23  	ctx, cancel := o.contextWithTimeout()
    24  	defer cancel()
    25  
    26  	select {
    27  	case <-ctx.Done():
    28  		o.Logger.Debugf("listDNSRecords: case <-ctx.Done()")
    29  		return nil, o.Context.Err() // we're cancelled, abort
    30  	default:
    31  	}
    32  
    33  	var (
    34  		foundOne       = false
    35  		perPage  int64 = 20
    36  		page     int64 = 1
    37  		moreData       = true
    38  	)
    39  
    40  	dnsRecordsOptions := o.dnsRecordsSvc.NewListAllDnsRecordsOptions()
    41  	dnsRecordsOptions.PerPage = &perPage
    42  	dnsRecordsOptions.Page = &page
    43  
    44  	result := []cloudResource{}
    45  
    46  	dnsMatcher, err := regexp.Compile(fmt.Sprintf(`.*\Q%s.%s\E$`, o.ClusterName, o.BaseDomain))
    47  	if err != nil {
    48  		return nil, fmt.Errorf("failed to build DNS records matcher: %w", err)
    49  	}
    50  
    51  	for moreData {
    52  		dnsResources, detailedResponse, err := o.dnsRecordsSvc.ListAllDnsRecordsWithContext(ctx, dnsRecordsOptions)
    53  		if err != nil {
    54  			return nil, fmt.Errorf("failed to list DNS records: %w and the response is: %s", err, detailedResponse)
    55  		}
    56  
    57  		for _, record := range dnsResources.Result {
    58  			// Match all of the cluster's DNS records
    59  			nameMatches := dnsMatcher.Match([]byte(*record.Name))
    60  			contentMatches := dnsMatcher.Match([]byte(*record.Content))
    61  			if nameMatches || contentMatches {
    62  				foundOne = true
    63  				o.Logger.Debugf("listDNSRecords: FOUND: %v, %v", *record.ID, *record.Name)
    64  				result = append(result, cloudResource{
    65  					key:      *record.ID,
    66  					name:     *record.Name,
    67  					status:   "",
    68  					typeName: cisDNSRecordTypeName,
    69  					id:       *record.ID,
    70  				})
    71  			}
    72  		}
    73  
    74  		o.Logger.Debugf("listDNSRecords: PerPage = %v, Page = %v, Count = %v", *dnsResources.ResultInfo.PerPage, *dnsResources.ResultInfo.Page, *dnsResources.ResultInfo.Count)
    75  
    76  		moreData = *dnsResources.ResultInfo.PerPage == *dnsResources.ResultInfo.Count
    77  		o.Logger.Debugf("listDNSRecords: moreData = %v", moreData)
    78  
    79  		page++
    80  	}
    81  	if !foundOne {
    82  		o.Logger.Debugf("listDNSRecords: NO matching DNS against: %s", o.InfraID)
    83  		for moreData {
    84  			dnsResources, detailedResponse, err := o.dnsRecordsSvc.ListAllDnsRecordsWithContext(ctx, dnsRecordsOptions)
    85  			if err != nil {
    86  				return nil, fmt.Errorf("failed to list DNS records: %w and the response is: %s", err, detailedResponse)
    87  			}
    88  			for _, record := range dnsResources.Result {
    89  				o.Logger.Debugf("listDNSRecords: FOUND: DNS: %v, %v", *record.ID, *record.Name)
    90  			}
    91  			moreData = *dnsResources.ResultInfo.PerPage == *dnsResources.ResultInfo.Count
    92  			page++
    93  		}
    94  	}
    95  
    96  	return cloudResources{}.insert(result...), nil
    97  }
    98  
    99  // destroyDNSRecord destroys a DNS record.
   100  func (o *ClusterUninstaller) destroyDNSRecord(item cloudResource) error {
   101  	var (
   102  		response *core.DetailedResponse
   103  		err      error
   104  	)
   105  
   106  	ctx, cancel := o.contextWithTimeout()
   107  	defer cancel()
   108  
   109  	select {
   110  	case <-ctx.Done():
   111  		o.Logger.Debugf("destroyDNSRecord: case <-ctx.Done()")
   112  		return o.Context.Err() // we're cancelled, abort
   113  	default:
   114  	}
   115  
   116  	getOptions := o.dnsRecordsSvc.NewGetDnsRecordOptions(item.id)
   117  	_, response, err = o.dnsRecordsSvc.GetDnsRecordWithContext(ctx, getOptions)
   118  
   119  	if err != nil && response != nil && response.StatusCode == http.StatusNotFound {
   120  		// The resource is gone
   121  		o.deletePendingItems(item.typeName, []cloudResource{item})
   122  		o.Logger.Infof("Deleted DNS Record %q", item.name)
   123  		return nil
   124  	}
   125  	if err != nil && response != nil && response.StatusCode == http.StatusInternalServerError {
   126  		o.Logger.Infof("destroyDNSRecord: internal server error")
   127  		return nil
   128  	}
   129  
   130  	deleteOptions := o.dnsRecordsSvc.NewDeleteDnsRecordOptions(item.id)
   131  
   132  	_, _, err = o.dnsRecordsSvc.DeleteDnsRecordWithContext(ctx, deleteOptions)
   133  	if err != nil {
   134  		return fmt.Errorf("failed to delete DNS record %s: %w", item.name, err)
   135  	}
   136  
   137  	o.Logger.Infof("Deleted DNS Record %q", item.name)
   138  	o.deletePendingItems(item.typeName, []cloudResource{item})
   139  
   140  	return nil
   141  }
   142  
   143  // destroyDNSRecords removes all DNS record resources that have a name containing
   144  // the cluster's infra ID.
   145  func (o *ClusterUninstaller) destroyDNSRecords() error {
   146  	if o.dnsRecordsSvc == nil {
   147  		// Install config didn't specify using these resources
   148  		return nil
   149  	}
   150  
   151  	firstPassList, err := o.listDNSRecords()
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	if len(firstPassList.list()) == 0 {
   157  		return nil
   158  	}
   159  
   160  	items := o.insertPendingItems(cisDNSRecordTypeName, firstPassList.list())
   161  
   162  	ctx, cancel := o.contextWithTimeout()
   163  	defer cancel()
   164  
   165  	for _, item := range items {
   166  		select {
   167  		case <-ctx.Done():
   168  			o.Logger.Debugf("destroyDNSRecords: case <-ctx.Done()")
   169  			return o.Context.Err() // we're cancelled, abort
   170  		default:
   171  		}
   172  
   173  		backoff := wait.Backoff{
   174  			Duration: 15 * time.Second,
   175  			Factor:   1.1,
   176  			Cap:      leftInContext(ctx),
   177  			Steps:    math.MaxInt32}
   178  		err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   179  			err2 := o.destroyDNSRecord(item)
   180  			if err2 == nil {
   181  				return true, err2
   182  			}
   183  			o.errorTracker.suppressWarning(item.key, err2, o.Logger)
   184  			return false, err2
   185  		})
   186  		if err != nil {
   187  			o.Logger.Fatal("destroyDNSRecords: ExponentialBackoffWithContext (destroy) returns ", err)
   188  		}
   189  	}
   190  
   191  	if items = o.getPendingItems(cisDNSRecordTypeName); len(items) > 0 {
   192  		for _, item := range items {
   193  			o.Logger.Debugf("destroyDNSRecords: found %s in pending items", item.name)
   194  		}
   195  		return fmt.Errorf("destroyDNSRecords: %d undeleted items pending", len(items))
   196  	}
   197  
   198  	backoff := wait.Backoff{
   199  		Duration: 15 * time.Second,
   200  		Factor:   1.1,
   201  		Cap:      leftInContext(ctx),
   202  		Steps:    math.MaxInt32}
   203  	err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) {
   204  		secondPassList, err2 := o.listDNSRecords()
   205  		if err2 != nil {
   206  			return false, err2
   207  		}
   208  		if len(secondPassList) == 0 {
   209  			// We finally don't see any remaining instances!
   210  			return true, nil
   211  		}
   212  		for _, item := range secondPassList {
   213  			o.Logger.Debugf("destroyDNSRecords: found %s in second pass", item.name)
   214  		}
   215  		return false, nil
   216  	})
   217  	if err != nil {
   218  		o.Logger.Fatal("destroyDNSRecords: ExponentialBackoffWithContext (list) returns ", err)
   219  	}
   220  
   221  	return nil
   222  }