diff --git a/cloudmock/gce/mockcompute/network.go b/cloudmock/gce/mockcompute/network.go index 42c77dfb7e..55ea399dea 100644 --- a/cloudmock/gce/mockcompute/network.go +++ b/cloudmock/gce/mockcompute/network.go @@ -90,3 +90,17 @@ func (c *networkClient) Get(project, name string) (*compute.Network, error) { } return network, nil } + +func (c *networkClient) List(project string) (*compute.NetworkList, error) { + c.Lock() + defer c.Unlock() + networks, ok := c.networks[project] + if !ok { + return nil, notFoundError() + } + networkList := &compute.NetworkList{} + for _, network := range networks { + networkList.Items = append(networkList.Items, network) + } + return networkList, nil +} diff --git a/pkg/resources/gce/gce.go b/pkg/resources/gce/gce.go index 4f1fac5695..2ea69e0444 100644 --- a/pkg/resources/gce/gce.go +++ b/pkg/resources/gce/gce.go @@ -43,6 +43,7 @@ const ( typeForwardingRule = "ForwardingRule" typeAddress = "Address" typeRoute = "Route" + typeNetwork = "Network" typeSubnet = "Subnet" typeRouter = "Router" typeDNSRecord = "DNSRecord" @@ -99,6 +100,7 @@ func ListResourcesGCE(gceCloud gce.GCECloud, clusterName string, region string) d.listAddresses, d.listSubnets, d.listRouters, + d.listNetworks, } for _, fn := range listFunctions { resourceTrackers, err := fn() @@ -741,6 +743,8 @@ func (d *clusterDiscoveryGCE) listSubnets() ([]*resources.Resource, error) { Obj: o, } + resourceTracker.Blocks = append(resourceTracker.Blocks, typeNetwork+":"+gce.LastComponent(o.Network)) + klog.V(4).Infof("found resource: %s", o.SelfLink) resourceTrackers = append(resourceTrackers, resourceTracker) } @@ -824,6 +828,78 @@ func deleteRouter(cloud fi.Cloud, r *resources.Resource) error { return c.WaitForOp(op) } +func (d *clusterDiscoveryGCE) listNetworks() ([]*resources.Resource, error) { + // Templates are very accurate because of the metadata, so use those as the sanity check + templates, err := d.findInstanceTemplates() + if err != nil { + return nil, err + } + networkUrls := make(map[string]bool) + for _, t := range templates { + for _, ni := range t.Properties.NetworkInterfaces { + if ni.Network != "" { + networkUrls[ni.Network] = true + } + } + } + + c := d.gceCloud + + var resourceTrackers []*resources.Resource + + networks, err := c.Compute().Networks().List(c.Project()) + if err != nil { + return nil, fmt.Errorf("error listing networks: %v", err) + } + + for _, o := range networks.Items { + if o.Name != gce.SafeClusterName(d.clusterName) { + klog.V(8).Infof("skipping network with name %q", o.Name) + continue + } + + if !networkUrls[o.SelfLink] { + klog.Warningf("skipping network %q because it didn't match any instance template", o.SelfLink) + continue + } + + resourceTracker := &resources.Resource{ + Name: o.Name, + ID: o.Name, + Type: typeNetwork, + Deleter: deleteNetwork, + Obj: o, + } + + klog.V(4).Infof("found resource: %s", o.SelfLink) + resourceTrackers = append(resourceTrackers, resourceTracker) + } + + return resourceTrackers, nil +} + +func deleteNetwork(cloud fi.Cloud, r *resources.Resource) error { + c := cloud.(gce.GCECloud) + o := r.Obj.(*compute.Network) + + klog.V(2).Infof("deleting GCE network %s", o.SelfLink) + u, err := gce.ParseGoogleCloudURL(o.SelfLink) + if err != nil { + return err + } + + op, err := c.Compute().Networks().Delete(u.Project, u.Name) + if err != nil { + if gce.IsNotFound(err) { + klog.Infof("network not found, assuming deleted: %q", o.SelfLink) + return nil + } + return fmt.Errorf("error deleting network %s: %v", o.SelfLink, err) + } + + return c.WaitForOp(op) +} + func (d *clusterDiscoveryGCE) matchesClusterName(name string) bool { // Names could have hypens in them, so really there is no limit. // 8 hyphens feels like enough for any "reasonable" name diff --git a/upup/pkg/fi/cloudup/gce/compute.go b/upup/pkg/fi/cloudup/gce/compute.go index 510707f17b..00a9e2d018 100644 --- a/upup/pkg/fi/cloudup/gce/compute.go +++ b/upup/pkg/fi/cloudup/gce/compute.go @@ -211,6 +211,8 @@ func (c *zoneClientImpl) List(ctx context.Context, project string) ([]*compute.Z type NetworkClient interface { Insert(project string, nw *compute.Network) (*compute.Operation, error) Get(project, name string) (*compute.Network, error) + Delete(project, name string) (*compute.Operation, error) + List(project string) (*compute.NetworkList, error) } type networkClientImpl struct { @@ -223,10 +225,18 @@ func (c *networkClientImpl) Insert(project string, nw *compute.Network) (*comput return c.srv.Insert(project, nw).Do() } +func (c *networkClientImpl) Delete(project string, name string) (*compute.Operation, error) { + return c.srv.Delete(project, name).Do() +} + func (c *networkClientImpl) Get(project, name string) (*compute.Network, error) { return c.srv.Get(project, name).Do() } +func (c *networkClientImpl) List(project string) (*compute.NetworkList, error) { + return c.srv.List(project).Do() +} + type SubnetworkClient interface { Insert(project, region string, subnet *compute.Subnetwork) (*compute.Operation, error) Patch(project, region, name string, subnet *compute.Subnetwork) (*compute.Operation, error)