diff --git a/data/data/powervs/bootstrap/vm/outputs.tf b/data/data/powervs/bootstrap/vm/outputs.tf index 89045bb75c0..563cc492924 100644 --- a/data/data/powervs/bootstrap/vm/outputs.tf +++ b/data/data/powervs/bootstrap/vm/outputs.tf @@ -1,4 +1,4 @@ -output bootstrap_ip { +output "bootstrap_ip" { value = local.bootstrap_ips[0] } diff --git a/data/data/powervs/cluster/bootstrap/lb/ouputs.tf b/data/data/powervs/cluster/bootstrap/lb/ouputs.tf index 067cb701e93..0170b3b179b 100644 --- a/data/data/powervs/cluster/bootstrap/lb/ouputs.tf +++ b/data/data/powervs/cluster/bootstrap/lb/ouputs.tf @@ -1,7 +1,7 @@ -output api_member_ext_id { +output "api_member_ext_id" { value = ibm_is_lb_pool_member.api_member.id } -output api_member_int_id { +output "api_member_int_id" { value = ibm_is_lb_pool_member.api_member_int.id } diff --git a/data/data/powervs/cluster/bootstrap/outputs.tf b/data/data/powervs/cluster/bootstrap/outputs.tf index e80c6106d16..bbba7acb96f 100644 --- a/data/data/powervs/cluster/bootstrap/outputs.tf +++ b/data/data/powervs/cluster/bootstrap/outputs.tf @@ -1,11 +1,11 @@ -output bootstrap_ip { +output "bootstrap_ip" { value = module.vm.bootstrap_ip } -output api_member_ext_id { +output "api_member_ext_id" { value = module.lb.api_member_ext_id } -output api_member_int_id { +output "api_member_int_id" { value = module.lb.api_member_int_id } diff --git a/data/data/powervs/cluster/dns/dns.tf b/data/data/powervs/cluster/dns/dns.tf index b37f8706e4e..53a82ac80a4 100644 --- a/data/data/powervs/cluster/dns/dns.tf +++ b/data/data/powervs/cluster/dns/dns.tf @@ -20,3 +20,78 @@ resource "ibm_cis_dns_record" "kubernetes_api_internal" { content = var.load_balancer_int_hostname ttl = 60 } + +locals { + proxy_count = var.publish_strategy == "Internal" ? 1 : 0 +} + +resource "ibm_is_ssh_key" "dns_ssh_key" { + count = local.proxy_count + name = "${var.cluster_id}-dns-ssh-key" + public_key = var.ssh_key +} + +resource "ibm_is_security_group" "dns_vm_sg" { + count = local.proxy_count + name = "${var.cluster_id}-dns-sg" + vpc = var.vpc_id +} + +# allow all outgoing network traffic +resource "ibm_is_security_group_rule" "dns_vm_sg_outgoing_all" { + count = local.proxy_count + group = ibm_is_security_group.dns_vm_sg[0].id + direction = "outbound" + remote = "0.0.0.0/0" +} + +# allow all incoming network traffic on port 22 +resource "ibm_is_security_group_rule" "dns_vm_sg_ssh_all" { + count = local.proxy_count + group = ibm_is_security_group.dns_vm_sg[0].id + direction = "inbound" + remote = "0.0.0.0/0" + + tcp { + port_min = 22 + port_max = 22 + } +} + +data "ibm_is_image" "dns_vm_image" { + count = local.proxy_count + name = var.dns_vm_image_name +} + +locals { + user_data_string = < 0 { + return errors.Errorf("destroyCloudInstances: %d undeleted items pending", len(items)) + } + + return nil +} diff --git a/pkg/destroy/powervs/cloud-sshkey.go b/pkg/destroy/powervs/cloud-sshkey.go new file mode 100644 index 00000000000..3254f3b1402 --- /dev/null +++ b/pkg/destroy/powervs/cloud-sshkey.go @@ -0,0 +1,196 @@ +package powervs + +import ( + "context" + "strings" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/pkg/errors" +) + +const ( + cloudSSHKeyTypeName = "cloudSshKey" +) + +// listCloudSSHKeys lists images in the vpc. +func (o *ClusterUninstaller) listCloudSSHKeys() (cloudResources, error) { + o.Logger.Debugf("Listing Cloud SSHKeys") + + select { + case <-o.Context.Done(): + o.Logger.Debugf("listCloudSSHKeys: case <-o.Context.Done()") + return nil, o.Context.Err() // we're cancelled, abort + default: + } + + // https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go + var ( + ctx context.Context + foundOne bool = false + perPage int64 = 20 + moreData bool = true + listKeysOptions *vpcv1.ListKeysOptions + sshKeyCollection *vpcv1.KeyCollection + detailedResponse *core.DetailedResponse + err error + sshKey vpcv1.Key + ) + + ctx, _ = o.contextWithTimeout() + + listKeysOptions = o.vpcSvc.NewListKeysOptions() + listKeysOptions.SetLimit(perPage) + + result := []cloudResource{} + + for moreData { + sshKeyCollection, detailedResponse, err = o.vpcSvc.ListKeysWithContext(ctx, listKeysOptions) + if err != nil { + return nil, errors.Wrapf(err, "failed to list Cloud ssh keys: %v and the response is: %s", err, detailedResponse) + } + + for _, sshKey = range sshKeyCollection.Keys { + if strings.Contains(*sshKey.Name, o.InfraID) { + foundOne = true + o.Logger.Debugf("listCloudSSHKeys: FOUND: %v", *sshKey.Name) + result = append(result, cloudResource{ + key: *sshKey.Name, + name: *sshKey.Name, + status: "", + typeName: cloudSSHKeyTypeName, + id: *sshKey.ID, + }) + } + } + + if sshKeyCollection.First != nil { + o.Logger.Debugf("listCloudSSHKeys: First = %v", *sshKeyCollection.First.Href) + } + if sshKeyCollection.Limit != nil { + o.Logger.Debugf("listCloudSSHKeys: Limit = %v", *sshKeyCollection.Limit) + } + if sshKeyCollection.Next != nil { + o.Logger.Debugf("listCloudSSHKeys: Next = %v", *sshKeyCollection.Next.Href) + listKeysOptions.SetStart(*sshKeyCollection.Next.Href) + } + + moreData = sshKeyCollection.Next != nil + o.Logger.Debugf("listCloudSSHKeys: moreData = %v", moreData) + } + if !foundOne { + o.Logger.Debugf("listCloudSSHKeys: NO matching sshKey against: %s", o.InfraID) + + listKeysOptions = o.vpcSvc.NewListKeysOptions() + listKeysOptions.SetLimit(perPage) + moreData = true + + for moreData { + sshKeyCollection, detailedResponse, err = o.vpcSvc.ListKeysWithContext(ctx, listKeysOptions) + if err != nil { + return nil, errors.Wrapf(err, "failed to list Cloud ssh keys: %v and the response is: %s", err, detailedResponse) + } + for _, sshKey = range sshKeyCollection.Keys { + o.Logger.Debugf("listCloudSSHKeys: FOUND: %v", *sshKey.Name) + } + if sshKeyCollection.First != nil { + o.Logger.Debugf("listCloudSSHKeys: First = %v", *sshKeyCollection.First.Href) + } + if sshKeyCollection.Limit != nil { + o.Logger.Debugf("listCloudSSHKeys: Limit = %v", *sshKeyCollection.Limit) + } + if sshKeyCollection.Next != nil { + o.Logger.Debugf("listCloudSSHKeys: Next = %v", *sshKeyCollection.Next.Href) + listKeysOptions.SetStart(*sshKeyCollection.Next.Href) + } + moreData = sshKeyCollection.Next != nil + o.Logger.Debugf("listCloudSSHKeys: moreData = %v", moreData) + } + } + + return cloudResources{}.insert(result...), nil +} + +// deleteCloudSSHKey deletes a given ssh key. +func (o *ClusterUninstaller) deleteCloudSSHKey(item cloudResource) error { + var ( + ctx context.Context + getKeyOptions *vpcv1.GetKeyOptions + deleteKeyOptions *vpcv1.DeleteKeyOptions + err error + ) + + ctx, _ = o.contextWithTimeout() + + getKeyOptions = o.vpcSvc.NewGetKeyOptions(item.id) + + _, _, err = o.vpcSvc.GetKey(getKeyOptions) + if err != nil { + o.deletePendingItems(item.typeName, []cloudResource{item}) + o.Logger.Infof("Deleted Cloud sshKey %q", item.name) + return nil + } + + o.Logger.Debugf("Deleting Cloud sshKey %q", item.name) + + select { + case <-o.Context.Done(): + o.Logger.Debugf("deleteCloudSSHKey: case <-o.Context.Done()") + return o.Context.Err() // we're cancelled, abort + default: + } + + deleteKeyOptions = o.vpcSvc.NewDeleteKeyOptions(item.id) + + _, err = o.vpcSvc.DeleteKeyWithContext(ctx, deleteKeyOptions) + if err != nil { + return errors.Wrapf(err, "failed to delete sshKey %s", item.name) + } + + return nil +} + +// destroyCloudSSHKeys removes all image resources that have a name prefixed +// with the cluster's infra ID. +func (o *ClusterUninstaller) destroyCloudSSHKeys() error { + found, err := o.listCloudSSHKeys() + if err != nil { + return err + } + + items := o.insertPendingItems(cloudSSHKeyTypeName, found.list()) + + ctx, _ := o.contextWithTimeout() + + for !o.timeout(ctx) { + for _, item := range items { + select { + case <-o.Context.Done(): + o.Logger.Debugf("destroyCloudSSHKeys: case <-o.Context.Done()") + return o.Context.Err() // we're cancelled, abort + default: + } + + if _, ok := found[item.key]; !ok { + // This item has finished deletion. + o.deletePendingItems(item.typeName, []cloudResource{item}) + o.Logger.Infof("Deleted sshKey %q", item.name) + continue + } + err := o.deleteCloudSSHKey(item) + if err != nil { + o.errorTracker.suppressWarning(item.key, err, o.Logger) + } + } + + items = o.getPendingItems(cloudSSHKeyTypeName) + if len(items) == 0 { + break + } + } + + if items = o.getPendingItems(cloudSSHKeyTypeName); len(items) > 0 { + return errors.Errorf("destroyCloudSSHKeys: %d undeleted items pending", len(items)) + } + return nil +} diff --git a/pkg/destroy/powervs/cloudconnection.go b/pkg/destroy/powervs/cloudconnection.go index 59a68bb6c32..3bc5db6399d 100644 --- a/pkg/destroy/powervs/cloudconnection.go +++ b/pkg/destroy/powervs/cloudconnection.go @@ -34,10 +34,13 @@ func (o *ClusterUninstaller) listCloudConnections() (cloudResources, error) { log.Fatalf("Failed to list cloud connections: %v", err) } + var foundOne = false + result := []cloudResource{} for _, cloudConnection = range cloudConnections.CloudConnections { if strings.Contains(*cloudConnection.Name, o.InfraID) { o.Logger.Debugf("listCloudConnections: FOUND: %s (%s)", *cloudConnection.Name, *cloudConnection.CloudConnectionID) + foundOne = true jobReference, err = o.cloudConnectionClient.Delete(*cloudConnection.CloudConnectionID) if err != nil { @@ -55,6 +58,12 @@ func (o *ClusterUninstaller) listCloudConnections() (cloudResources, error) { }) } } + if !foundOne { + o.Logger.Debugf("listCloudConnections: NO matching cloud connections against: %s", o.InfraID) + for _, cloudConnection = range cloudConnections.CloudConnections { + o.Logger.Debugf("listCloudConnections: only found cloud connection: %s", *cloudConnection.Name) + } + } return cloudResources{}.insert(result...), nil } diff --git a/pkg/destroy/powervs/instance.go b/pkg/destroy/powervs/power-instance.go similarity index 60% rename from pkg/destroy/powervs/instance.go rename to pkg/destroy/powervs/power-instance.go index 65b182c8ddd..37e491df172 100644 --- a/pkg/destroy/powervs/instance.go +++ b/pkg/destroy/powervs/power-instance.go @@ -7,15 +7,15 @@ import ( ) const ( - instanceTypeName = "instance" + powerInstanceTypeName = "powerInstance" ) -// listInstances lists instances in the vpc. -func (o *ClusterUninstaller) listInstances() (cloudResources, error) { +// listPowerInstances lists instances in the Power server. +func (o *ClusterUninstaller) listPowerInstances() (cloudResources, error) { // https://github.com/IBM-Cloud/power-go-client/blob/v1.0.88/power/models/p_vm_instance_network.go#L16-L44 var network *models.PVMInstanceNetwork - o.Logger.Debugf("Listing virtual service instances") + o.Logger.Debugf("Listing virtual Power service instances") instances, err := o.instanceClient.GetAll() if err != nil { @@ -30,12 +30,12 @@ func (o *ClusterUninstaller) listInstances() (cloudResources, error) { // https://github.com/IBM-Cloud/power-go-client/blob/master/power/models/p_vm_instance.go if strings.Contains(*instance.ServerName, o.InfraID) { foundOne = true - o.Logger.Debugf("listInstances: FOUND: %s, %s, %s", *instance.PvmInstanceID, *instance.ServerName, *instance.Status) + o.Logger.Debugf("listPowerInstances: FOUND: %s, %s, %s", *instance.PvmInstanceID, *instance.ServerName, *instance.Status) result = append(result, cloudResource{ key: *instance.PvmInstanceID, name: *instance.ServerName, status: *instance.Status, - typeName: instanceTypeName, + typeName: powerInstanceTypeName, id: *instance.PvmInstanceID, }) @@ -47,7 +47,7 @@ func (o *ClusterUninstaller) listInstances() (cloudResources, error) { } } if !foundOne { - o.Logger.Debugf("listInstances: NO matching virtual instance against: %s", o.InfraID) + o.Logger.Debugf("listPowerInstances: NO matching virtual instance against: %s", o.InfraID) for _, instance := range instances.PvmInstances { o.Logger.Debugf("listInstances: only found virtual instance: %s", *instance.ServerName) } @@ -56,17 +56,18 @@ func (o *ClusterUninstaller) listInstances() (cloudResources, error) { return cloudResources{}.insert(result...), nil } -func (o *ClusterUninstaller) destroyInstance(item cloudResource) error { +// destroyPowerInstance deletes a given instance. +func (o *ClusterUninstaller) destroyPowerInstance(item cloudResource) error { var err error _, err = o.instanceClient.Get(item.id) if err != nil { o.deletePendingItems(item.typeName, []cloudResource{item}) - o.Logger.Infof("Deleted instance %q", item.name) + o.Logger.Infof("Deleted Power instance %q", item.name) return nil } - o.Logger.Debugf("Deleting instance %q", item.name) + o.Logger.Debugf("Deleting Power instance %q", item.name) err = o.instanceClient.Delete(item.id) if err != nil { @@ -75,20 +76,20 @@ func (o *ClusterUninstaller) destroyInstance(item cloudResource) error { } o.deletePendingItems(item.typeName, []cloudResource{item}) - o.Logger.Infof("Deleted instance %q", item.name) + o.Logger.Infof("Deleted Power instance %q", item.name) return nil } -// destroyInstances searches for instances that have a name that starts with +// destroyPowerInstances searches for Power instances that have a name that starts with // the cluster's infra ID. -func (o *ClusterUninstaller) destroyInstances() error { - found, err := o.listInstances() +func (o *ClusterUninstaller) destroyPowerInstances() error { + found, err := o.listPowerInstances() if err != nil { return err } - items := o.insertPendingItems(instanceTypeName, found.list()) + items := o.insertPendingItems(powerInstanceTypeName, found.list()) ctx, _ := o.contextWithTimeout() @@ -96,7 +97,7 @@ func (o *ClusterUninstaller) destroyInstances() error { for _, item := range items { select { case <-o.Context.Done(): - o.Logger.Debugf("destroyInstances: case <-o.Context.Done()") + o.Logger.Debugf("destroyPowerInstances: case <-o.Context.Done()") return o.Context.Err() // we're cancelled, abort default: } @@ -104,23 +105,23 @@ func (o *ClusterUninstaller) destroyInstances() error { if _, ok := found[item.key]; !ok { // This item has finished deletion. o.deletePendingItems(item.typeName, []cloudResource{item}) - o.Logger.Infof("Deleted instance %q", item.name) + o.Logger.Infof("Deleted Power instance %q", item.name) continue } - err := o.destroyInstance(item) + err := o.destroyPowerInstance(item) if err != nil { o.errorTracker.suppressWarning(item.key, err, o.Logger) } } - items = o.getPendingItems(instanceTypeName) + items = o.getPendingItems(powerInstanceTypeName) if len(items) == 0 { break } } - if items = o.getPendingItems(instanceTypeName); len(items) > 0 { - return errors.Errorf("destroyInstances: %d undeleted items pending", len(items)) + if items = o.getPendingItems(powerInstanceTypeName); len(items) > 0 { + return errors.Errorf("destroyPowerInstances: %d undeleted items pending", len(items)) } return nil } diff --git a/pkg/destroy/powervs/sshkey.go b/pkg/destroy/powervs/power-sshkey.go similarity index 53% rename from pkg/destroy/powervs/sshkey.go rename to pkg/destroy/powervs/power-sshkey.go index cdee97fae55..bd4d341b1dc 100644 --- a/pkg/destroy/powervs/sshkey.go +++ b/pkg/destroy/powervs/power-sshkey.go @@ -7,15 +7,15 @@ import ( "github.com/pkg/errors" ) -const sshKeyTypeName = "sshKey" +const powerSSHKeyTypeName = "powerSshKey" -// listSSHKeys lists images in the vpc. -func (o *ClusterUninstaller) listSSHKeys() (cloudResources, error) { - o.Logger.Debugf("Listing SSHKeys") +// listPowerSSHKeys lists ssh keys in the Power server. +func (o *ClusterUninstaller) listPowerSSHKeys() (cloudResources, error) { + o.Logger.Debugf("Listing Power SSHKeys") select { case <-o.Context.Done(): - o.Logger.Debugf("listSSHKeys: case <-o.Context.Done()") + o.Logger.Debugf("listPowerSSHKeys: case <-o.Context.Done()") return nil, o.Context.Err() // we're cancelled, abort default: } @@ -25,7 +25,7 @@ func (o *ClusterUninstaller) listSSHKeys() (cloudResources, error) { sshKeys, err = o.keyClient.GetAll() if err != nil { - return nil, errors.Wrapf(err, "failed to list sshkeys: %v", err) + return nil, errors.Wrapf(err, "failed to list Power sshkeys: %v", err) } var sshKey *models.SSHKey @@ -35,62 +35,63 @@ func (o *ClusterUninstaller) listSSHKeys() (cloudResources, error) { for _, sshKey = range sshKeys.SSHKeys { if strings.Contains(*sshKey.Name, o.InfraID) { foundOne = true - o.Logger.Debugf("listSSHKeys: FOUND: %v", *sshKey.Name) + o.Logger.Debugf("listPowerSSHKeys: FOUND: %v", *sshKey.Name) result = append(result, cloudResource{ key: *sshKey.Name, name: *sshKey.Name, status: "", - typeName: sshKeyTypeName, + typeName: powerSSHKeyTypeName, id: *sshKey.Name, }) } } if !foundOne { - o.Logger.Debugf("listSSHKeys: NO matching sshKey against: %s", o.InfraID) + o.Logger.Debugf("listPowerSSHKeys: NO matching sshKey against: %s", o.InfraID) for _, sshKey := range sshKeys.SSHKeys { - o.Logger.Debugf("listSSHKeys: sshKey: %s", *sshKey.Name) + o.Logger.Debugf("listPowerSSHKeys: sshKey: %s", *sshKey.Name) } } return cloudResources{}.insert(result...), nil } -func (o *ClusterUninstaller) deleteSSHKey(item cloudResource) error { +// deletePowerSSHKey deleted a given ssh key. +func (o *ClusterUninstaller) deletePowerSSHKey(item cloudResource) error { var err error _, err = o.keyClient.Get(item.id) if err != nil { o.deletePendingItems(item.typeName, []cloudResource{item}) - o.Logger.Infof("Deleted sshKey %q", item.name) + o.Logger.Infof("Deleted Power sshKey %q", item.name) return nil } - o.Logger.Debugf("Deleting sshKey %q", item.name) + o.Logger.Debugf("Deleting Power sshKey %q", item.name) select { case <-o.Context.Done(): - o.Logger.Debugf("destroySSHKey: case <-o.Context.Done()") + o.Logger.Debugf("deletePowerSSHKey: case <-o.Context.Done()") return o.Context.Err() // we're cancelled, abort default: } err = o.keyClient.Delete(item.id) if err != nil { - return errors.Wrapf(err, "failed to delete sshKey %s", item.name) + return errors.Wrapf(err, "failed to delete Power sshKey %s", item.name) } return nil } -// destroySSHKeys removes all image resources that have a name prefixed +// destroyPowerSSHKeys removes all ssh keys that have a name prefixed // with the cluster's infra ID. -func (o *ClusterUninstaller) destroySSHKeys() error { - found, err := o.listSSHKeys() +func (o *ClusterUninstaller) destroyPowerSSHKeys() error { + found, err := o.listPowerSSHKeys() if err != nil { return err } - items := o.insertPendingItems(sshKeyTypeName, found.list()) + items := o.insertPendingItems(powerSSHKeyTypeName, found.list()) ctx, _ := o.contextWithTimeout() @@ -98,7 +99,7 @@ func (o *ClusterUninstaller) destroySSHKeys() error { for _, item := range items { select { case <-o.Context.Done(): - o.Logger.Debugf("destroySSHKeys: case <-o.Context.Done()") + o.Logger.Debugf("destroyPowerSSHKeys: case <-o.Context.Done()") return o.Context.Err() // we're cancelled, abort default: } @@ -109,20 +110,20 @@ func (o *ClusterUninstaller) destroySSHKeys() error { o.Logger.Infof("Deleted sshKey %q", item.name) continue } - err := o.deleteSSHKey(item) + err := o.deletePowerSSHKey(item) if err != nil { o.errorTracker.suppressWarning(item.key, err, o.Logger) } } - items = o.getPendingItems(sshKeyTypeName) + items = o.getPendingItems(powerSSHKeyTypeName) if len(items) == 0 { break } } - if items = o.getPendingItems(sshKeyTypeName); len(items) > 0 { - return errors.Errorf("destroySSHKeys: %d undeleted items pending", len(items)) + if items = o.getPendingItems(powerSSHKeyTypeName); len(items) > 0 { + return errors.Errorf("destroyPower1SSHKeys: %d undeleted items pending", len(items)) } return nil } diff --git a/pkg/destroy/powervs/powervs.go b/pkg/destroy/powervs/powervs.go index f8ccf6bca93..b2ac14589e7 100644 --- a/pkg/destroy/powervs/powervs.go +++ b/pkg/destroy/powervs/powervs.go @@ -36,7 +36,7 @@ import ( ) var ( - defaultTimeout = 15 * time.Minute + defaultTimeout = 30 * time.Minute stageTimeout = 5 * time.Minute ) @@ -274,11 +274,15 @@ func (o *ClusterUninstaller) destroyCluster() error { name string execute func() error }{{ - {name: "Instances", execute: o.destroyInstances}, + {name: "Cloud Instances", execute: o.destroyCloudInstances}, + }, { + {name: "Power Instances", execute: o.destroyPowerInstances}, }, { {name: "Load Balancers", execute: o.destroyLoadBalancers}, }, { {name: "Subnets", execute: o.destroySubnets}, + }, { + {name: "Public Gateways", execute: o.destroyPublicGateways}, }, { {name: "DHCPs", execute: o.destroyDHCPNetworks}, }, { @@ -290,7 +294,8 @@ func (o *ClusterUninstaller) destroyCluster() error { }, { {name: "Cloud Object Storage Instances", execute: o.destroyCOSInstances}, {name: "DNS Records", execute: o.destroyDNSRecords}, - {name: "SSH Keys", execute: o.destroySSHKeys}, + {name: "Cloud SSH Keys", execute: o.destroyCloudSSHKeys}, + {name: "Power SSH Keys", execute: o.destroyPowerSSHKeys}, }} for _, stage := range stagedFuncs { diff --git a/pkg/destroy/powervs/publicgateway.go b/pkg/destroy/powervs/publicgateway.go new file mode 100644 index 00000000000..82c0c2143fa --- /dev/null +++ b/pkg/destroy/powervs/publicgateway.go @@ -0,0 +1,198 @@ +package powervs + +import ( + "context" + "strings" + + "github.com/IBM/go-sdk-core/v5/core" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/pkg/errors" +) + +const ( + publicGatewayTypeName = "publicGateway" +) + +// listPublicGateways lists publicGateways in the vpc. +func (o *ClusterUninstaller) listPublicGateways() (cloudResources, error) { + var ( + ctx context.Context + // https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go + listPublicGatewaysOptions *vpcv1.ListPublicGatewaysOptions + publicGatewayCollection *vpcv1.PublicGatewayCollection + detailedResponse *core.DetailedResponse + err error + moreData bool = true + foundOne bool = false + perPage int64 = 20 + ) + + o.Logger.Debugf("Listing publicGateways") + + ctx, _ = o.contextWithTimeout() + + select { + case <-o.Context.Done(): + o.Logger.Debugf("listPublicGateways: case <-o.Context.Done()") + return nil, o.Context.Err() // we're cancelled, abort + default: + } + + listPublicGatewaysOptions = o.vpcSvc.NewListPublicGatewaysOptions() + + listPublicGatewaysOptions.SetLimit(perPage) + + result := []cloudResource{} + + for moreData { + + publicGatewayCollection, detailedResponse, err = o.vpcSvc.ListPublicGatewaysWithContext(ctx, listPublicGatewaysOptions) + if err != nil { + return nil, errors.Wrapf(err, "Failed to list publicGateways and the response is: %s", detailedResponse) + } + + for _, publicGateway := range publicGatewayCollection.PublicGateways { + if strings.Contains(*publicGateway.Name, o.InfraID) { + foundOne = true + o.Logger.Debugf("listPublicGateways: FOUND: %s", *publicGateway.Name) + result = append(result, cloudResource{ + key: *publicGateway.Name, + name: *publicGateway.Name, + status: "", + typeName: publicGatewayTypeName, + id: *publicGateway.ID, + }) + } + } + + if publicGatewayCollection.First != nil { + o.Logger.Debugf("listPublicGateways: First = %v", *publicGatewayCollection.First.Href) + } + if publicGatewayCollection.Limit != nil { + o.Logger.Debugf("listPublicGateways: Limit = %v", *publicGatewayCollection.Limit) + } + if publicGatewayCollection.Next != nil { + o.Logger.Debugf("listPublicGateways: Next = %v", *publicGatewayCollection.Next.Href) + listPublicGatewaysOptions.SetStart(*publicGatewayCollection.Next.Href) + } + + moreData = publicGatewayCollection.Next != nil + o.Logger.Debugf("listPublicGateways: moreData = %v", moreData) + } + if !foundOne { + o.Logger.Debugf("listPublicGateways: NO matching publicGateway against: %s", o.InfraID) + + listPublicGatewaysOptions = o.vpcSvc.NewListPublicGatewaysOptions() + listPublicGatewaysOptions.SetLimit(perPage) + + for moreData { + publicGatewayCollection, detailedResponse, err = o.vpcSvc.ListPublicGatewaysWithContext(ctx, listPublicGatewaysOptions) + if err != nil { + return nil, errors.Wrapf(err, "Failed to list publicGateways and the response is: %s", detailedResponse) + } + + for _, publicGateway := range publicGatewayCollection.PublicGateways { + o.Logger.Debugf("listPublicGateways: FOUND: %s", *publicGateway.Name) + } + if publicGatewayCollection.First != nil { + o.Logger.Debugf("listPublicGateways: First = %v", *publicGatewayCollection.First.Href) + } + if publicGatewayCollection.Limit != nil { + o.Logger.Debugf("listPublicGateways: Limit = %v", *publicGatewayCollection.Limit) + } + if publicGatewayCollection.Next != nil { + o.Logger.Debugf("listPublicGateways: Next = %v", *publicGatewayCollection.Next.Href) + listPublicGatewaysOptions.SetStart(*publicGatewayCollection.Next.Href) + } + moreData = publicGatewayCollection.Next != nil + o.Logger.Debugf("listPublicGateways: moreData = %v", moreData) + } + } + + return cloudResources{}.insert(result...), nil +} + +func (o *ClusterUninstaller) deletePublicGateway(item cloudResource) error { + var ( + ctx context.Context + // https://raw.githubusercontent.com/IBM/vpc-go-sdk/master/vpcv1/vpc_v1.go + getPublicGatewayOptions *vpcv1.GetPublicGatewayOptions + err error + deletePublicGatewayOptions *vpcv1.DeletePublicGatewayOptions + ) + + ctx, _ = o.contextWithTimeout() + + getPublicGatewayOptions = o.vpcSvc.NewGetPublicGatewayOptions(item.id) + + _, _, err = o.vpcSvc.GetPublicGatewayWithContext(ctx, getPublicGatewayOptions) + if err != nil { + o.Logger.Debugf("deletePublicGateway: publicGateway %q no longer exists", item.name) + o.deletePendingItems(item.typeName, []cloudResource{item}) + o.Logger.Infof("Deleted publicGateway %q", item.name) + return nil + } + + o.Logger.Debugf("Deleting publicGateway %q", item.name) + + select { + case <-o.Context.Done(): + o.Logger.Debugf("deletePublicGateway: case <-o.Context.Done()") + return o.Context.Err() // we're cancelled, abort + default: + } + + deletePublicGatewayOptions = o.vpcSvc.NewDeletePublicGatewayOptions(item.id) + + _, err = o.vpcSvc.DeletePublicGatewayWithContext(ctx, deletePublicGatewayOptions) + if err != nil { + return errors.Wrapf(err, "failed to delete publicGateway %s", item.name) + } + + return nil +} + +// destroyPublicGateways removes all publicGateway resources that have a name prefixed +// with the cluster's infra ID. +func (o *ClusterUninstaller) destroyPublicGateways() error { + found, err := o.listPublicGateways() + if err != nil { + return err + } + + items := o.insertPendingItems(publicGatewayTypeName, found.list()) + + ctx, _ := o.contextWithTimeout() + + for !o.timeout(ctx) { + for _, item := range items { + select { + case <-o.Context.Done(): + o.Logger.Debugf("destroyPublicGateways: case <-o.Context.Done()") + return o.Context.Err() // we're cancelled, abort + default: + } + + if _, ok := found[item.key]; !ok { + // This item has finished deletion. + o.deletePendingItems(item.typeName, []cloudResource{item}) + o.Logger.Infof("Deleted publicGateway %q", item.name) + continue + } + err := o.deletePublicGateway(item) + if err != nil { + o.errorTracker.suppressWarning(item.key, err, o.Logger) + } + } + + items = o.getPendingItems(publicGatewayTypeName) + if len(items) == 0 { + break + } + } + + if items = o.getPendingItems(publicGatewayTypeName); len(items) > 0 { + return errors.Errorf("destroyPublicGateways: %d undeleted items pending", len(items)) + } + return nil +} diff --git a/pkg/tfvars/powervs/powervs.go b/pkg/tfvars/powervs/powervs.go index 01a165346a3..70001bbc671 100644 --- a/pkg/tfvars/powervs/powervs.go +++ b/pkg/tfvars/powervs/powervs.go @@ -9,6 +9,7 @@ import ( "time" machinev1 "github.com/openshift/api/machine/v1" + "github.com/openshift/installer/pkg/types" "github.com/openshift/installer/pkg/types/powervs" ) @@ -34,6 +35,7 @@ type config struct { MasterProcessors string `json:"powervs_master_processors"` ProcType string `json:"powervs_proc_type"` SysType string `json:"powervs_sys_type"` + PublishStrategy string `json:"powervs_publish_strategy"` } // TFVarsSources contains the parameters to be converted into Terraform variables @@ -51,6 +53,7 @@ type TFVarsSources struct { CISInstanceCRN string VPCName string VPCSubnetName string + PublishStrategy types.PublishingStrategy } // TFVars generates Power VS-specific Terraform variables launching the cluster. @@ -99,6 +102,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) { MasterProcessors: processor, ProcType: strings.ToLower(string(masterConfig.ProcessorType)), SysType: masterConfig.SystemType, + PublishStrategy: string(sources.PublishStrategy), } if masterConfig.Network.Name != nil { cfg.NetworkName = *masterConfig.Network.Name diff --git a/pkg/types/validation/installconfig.go b/pkg/types/validation/installconfig.go index ff4873f7333..c603651e194 100644 --- a/pkg/types/validation/installconfig.go +++ b/pkg/types/validation/installconfig.go @@ -131,7 +131,7 @@ func ValidateInstallConfig(c *types.InstallConfig) field.ErrorList { if c.Publish == types.InternalPublishingStrategy { switch platformName := c.Platform.Name(); platformName { - case aws.Name, azure.Name, gcp.Name, alibabacloud.Name: + case aws.Name, azure.Name, gcp.Name, alibabacloud.Name, powervs.Name: default: allErrs = append(allErrs, field.Invalid(field.NewPath("publish"), c.Publish, fmt.Sprintf("Internal publish strategy is not supported on %q platform", platformName))) }