github.com/openshift/installer@v1.4.17/pkg/destroy/powervs/dhcp.go (about) 1 package powervs 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "strings" 8 "time" 9 10 "github.com/IBM-Cloud/power-go-client/power/models" 11 "k8s.io/apimachinery/pkg/util/wait" 12 ) 13 14 const ( 15 dhcpTypeName = "dhcp" 16 ) 17 18 // listDHCPNetworks lists previously found DHCP networks in found instances in the vpc. 19 func (o *ClusterUninstaller) listDHCPNetworks() (cloudResources, error) { 20 // https://github.com/IBM-Cloud/power-go-client/blob/v1.0.88/power/models/d_h_c_p_servers.go#L19 21 var dhcpServers models.DHCPServers 22 // https://github.com/IBM-Cloud/power-go-client/blob/v1.0.88/power/models/d_h_c_p_server.go#L18-L31 23 var dhcpServer *models.DHCPServer 24 var err error 25 26 o.Logger.Debugf("Listing DHCP networks") 27 28 if o.dhcpClient == nil { 29 o.Logger.Infof("Skipping deleting DHCP servers because no service instance was found") 30 result := []cloudResource{} 31 return cloudResources{}.insert(result...), nil 32 } 33 34 dhcpServers, err = o.dhcpClient.GetAll() 35 if err != nil { 36 o.Logger.Fatalf("Failed to list DHCP servers: %v", err) 37 } 38 39 var foundOne = false 40 41 result := []cloudResource{} 42 for _, dhcpServer = range dhcpServers { 43 if dhcpServer.Network == nil { 44 o.Logger.Debugf("listDHCPNetworks: DHCP has empty Network: %s", *dhcpServer.ID) 45 continue 46 } 47 if dhcpServer.Network.Name == nil { 48 // https://github.com/IBM-Cloud/power-go-client/blob/master/power/models/p_vm_instance.go#L22 49 var instance *models.PVMInstance 50 51 o.Logger.Debugf("listDHCPNetworks: DHCP has empty Network.Name: %s", *dhcpServer.ID) 52 53 instance, err = o.instanceClient.Get(*dhcpServer.ID) 54 o.Logger.Debugf("listDHCPNetworks: Getting instance %s %v", *dhcpServer.ID, err) 55 if err != nil { 56 continue 57 } 58 59 if instance.Status == nil { 60 continue 61 } 62 // If there is a backing DHCP VM and it has a status, then check for an ERROR state 63 o.Logger.Debugf("listDHCPNetworks: instance.Status: %s", *instance.Status) 64 if *instance.Status != "ERROR" { 65 continue 66 } 67 68 foundOne = true 69 result = append(result, cloudResource{ 70 key: *dhcpServer.ID, 71 name: *dhcpServer.ID, 72 status: "VM", 73 typeName: dhcpTypeName, 74 id: *dhcpServer.ID, 75 }) 76 continue 77 } 78 79 if strings.Contains(*dhcpServer.Network.Name, o.InfraID) { 80 o.Logger.Debugf("listDHCPNetworks: FOUND: %s (%s)", *dhcpServer.Network.Name, *dhcpServer.ID) 81 foundOne = true 82 result = append(result, cloudResource{ 83 key: *dhcpServer.ID, 84 name: *dhcpServer.Network.Name, 85 status: "DHCP", 86 typeName: dhcpTypeName, 87 id: *dhcpServer.ID, 88 }) 89 } 90 } 91 if !foundOne { 92 o.Logger.Debugf("listDHCPNetworks: NO matching DHCP network found in:") 93 for _, dhcpServer = range dhcpServers { 94 if dhcpServer.Network == nil { 95 continue 96 } 97 if dhcpServer.Network.Name == nil { 98 continue 99 } 100 o.Logger.Debugf("listDHCPNetworks: only found DHCP: %s", *dhcpServer.Network.Name) 101 } 102 } 103 104 return cloudResources{}.insert(result...), nil 105 } 106 107 func (o *ClusterUninstaller) destroyDHCPNetwork(item cloudResource) error { 108 var err error 109 110 _, err = o.dhcpClient.Get(item.id) 111 if err != nil { 112 o.deletePendingItems(item.typeName, []cloudResource{item}) 113 o.Logger.Infof("Deleted DHCP Network %q", item.name) 114 return nil 115 } 116 117 o.Logger.Debugf("Deleting DHCP network %q", item.name) 118 119 err = o.dhcpClient.Delete(item.id) 120 if err != nil { 121 o.Logger.Infof("Error: o.dhcpClient.Delete: %q", err) 122 return err 123 } 124 125 o.deletePendingItems(item.typeName, []cloudResource{item}) 126 o.Logger.Infof("Deleted DHCP Network %q", item.name) 127 128 return nil 129 } 130 131 func (o *ClusterUninstaller) destroyDHCPVM(item cloudResource) error { 132 var err error 133 134 _, err = o.instanceClient.Get(item.id) 135 if err != nil { 136 o.deletePendingItems(item.typeName, []cloudResource{item}) 137 o.Logger.Infof("Deleted DHCP VM %q", item.name) 138 return nil 139 } 140 141 o.Logger.Debugf("Deleting DHCP VM %q", item.name) 142 143 err = o.instanceClient.Delete(item.id) 144 if err != nil { 145 o.Logger.Infof("Error: DHCP o.instanceClient.Delete: %q", err) 146 return err 147 } 148 149 o.deletePendingItems(item.typeName, []cloudResource{item}) 150 o.Logger.Infof("Deleted DHCP VM %q", item.name) 151 152 return nil 153 } 154 155 // destroyDHCPNetworks searches for DHCP networks that are in a previous list 156 // the cluster's infra ID. 157 func (o *ClusterUninstaller) destroyDHCPNetworks() error { 158 firstPassList, err := o.listDHCPNetworks() 159 if err != nil { 160 return err 161 } 162 163 if len(firstPassList.list()) == 0 { 164 return nil 165 } 166 167 items := o.insertPendingItems(dhcpTypeName, firstPassList.list()) 168 169 ctx, cancel := o.contextWithTimeout() 170 defer cancel() 171 172 for _, item := range items { 173 select { 174 case <-ctx.Done(): 175 o.Logger.Debugf("destroyDHCPNetworks: case <-ctx.Done()") 176 return o.Context.Err() // we're cancelled, abort 177 default: 178 } 179 180 backoff := wait.Backoff{ 181 Duration: 15 * time.Second, 182 Factor: 1.1, 183 Cap: leftInContext(ctx), 184 Steps: math.MaxInt32} 185 err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) { 186 var err2 error 187 188 switch item.status { 189 case "DHCP": 190 err2 = o.destroyDHCPNetwork(item) 191 case "VM": 192 err2 = o.destroyDHCPVM(item) 193 default: 194 err2 = fmt.Errorf("unknown DHCP item status %s", item.status) 195 return true, err2 196 } 197 if err2 == nil { 198 return true, err2 199 } 200 o.errorTracker.suppressWarning(item.key, err2, o.Logger) 201 return false, err2 202 }) 203 if err != nil { 204 o.Logger.Fatal("destroyDHCPNetworks: ExponentialBackoffWithContext (destroy) returns ", err) 205 } 206 } 207 208 if items = o.getPendingItems(dhcpTypeName); len(items) > 0 { 209 for _, item := range items { 210 o.Logger.Debugf("destroyDHCPNetworks: found %s in pending items", item.name) 211 } 212 return fmt.Errorf("destroyDHCPNetworks: %d undeleted items pending", len(items)) 213 } 214 215 backoff := wait.Backoff{ 216 Duration: 15 * time.Second, 217 Factor: 1.1, 218 Cap: leftInContext(ctx), 219 Steps: math.MaxInt32} 220 err = wait.ExponentialBackoffWithContext(ctx, backoff, func(context.Context) (bool, error) { 221 secondPassList, err2 := o.listDHCPNetworks() 222 if err2 != nil { 223 return false, err2 224 } 225 if len(secondPassList) == 0 { 226 // We finally don't see any remaining instances! 227 return true, nil 228 } 229 for _, item := range secondPassList { 230 o.Logger.Debugf("destroyDHCPNetworks: found %s in second pass", item.name) 231 } 232 return false, nil 233 }) 234 if err != nil { 235 o.Logger.Fatal("destroyDHCPNetworks: ExponentialBackoffWithContext (list) returns ", err) 236 } 237 238 return nil 239 }