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 }