refactor resource tracker to be usable across packages

This commit is contained in:
andrewsykim 2017-09-02 17:23:25 -04:00
parent 022529c470
commit d9fa618de6
10 changed files with 409 additions and 334 deletions

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kops/pkg/apis/kops/registry" "k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/kubeconfig" "k8s.io/kops/pkg/kubeconfig"
"k8s.io/kops/pkg/resources" "k8s.io/kops/pkg/resources"
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup" "k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup" "k8s.io/kops/upup/pkg/fi/cloudup/awsup"
@ -148,7 +149,7 @@ func RunDeleteCluster(f *util.Factory, out io.Writer, options *DeleteClusterOpti
return err return err
} }
clusterResources := make(map[string]*resources.ResourceTracker) clusterResources := make(map[string]*tracker.Resource)
for k, resource := range allResources { for k, resource := range allResources {
if resource.Shared { if resource.Shared {
continue continue
@ -162,16 +163,16 @@ func RunDeleteCluster(f *util.Factory, out io.Writer, options *DeleteClusterOpti
wouldDeleteCloudResources = true wouldDeleteCloudResources = true
t := &tables.Table{} t := &tables.Table{}
t.AddColumn("TYPE", func(r *resources.ResourceTracker) string { t.AddColumn("TYPE", func(r *tracker.Resource) string {
return r.Type return r.Type
}) })
t.AddColumn("ID", func(r *resources.ResourceTracker) string { t.AddColumn("ID", func(r *tracker.Resource) string {
return r.ID return r.ID
}) })
t.AddColumn("NAME", func(r *resources.ResourceTracker) string { t.AddColumn("NAME", func(r *tracker.Resource) string {
return r.Name return r.Name
}) })
var l []*resources.ResourceTracker var l []*tracker.Resource
for _, v := range clusterResources { for _, v := range clusterResources {
l = append(l, v) l = append(l, v)
} }

View File

@ -77,6 +77,7 @@ k8s.io/kops/pkg/pretty
k8s.io/kops/pkg/resources k8s.io/kops/pkg/resources
k8s.io/kops/pkg/resources/digitalocean k8s.io/kops/pkg/resources/digitalocean
k8s.io/kops/pkg/resources/digitalocean/dns k8s.io/kops/pkg/resources/digitalocean/dns
k8s.io/kops/pkg/resources/tracker
k8s.io/kops/pkg/systemd k8s.io/kops/pkg/systemd
k8s.io/kops/pkg/templates k8s.io/kops/pkg/templates
k8s.io/kops/pkg/testutils k8s.io/kops/pkg/testutils

File diff suppressed because it is too large Load Diff

View File

@ -24,12 +24,13 @@ import (
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/kops/cloudmock/aws/mockec2" "k8s.io/kops/cloudmock/aws/mockec2"
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup" "k8s.io/kops/upup/pkg/fi/cloudup/awsup"
) )
func TestAddUntaggedRouteTables(t *testing.T) { func TestAddUntaggedRouteTables(t *testing.T) {
cloud := awsup.BuildMockAWSCloud("us-east-1", "abc") cloud := awsup.BuildMockAWSCloud("us-east-1", "abc")
resources := make(map[string]*ResourceTracker) resources := make(map[string]*tracker.Resource)
clusterName := "me.example.com" clusterName := "me.example.com"
@ -71,7 +72,7 @@ func TestAddUntaggedRouteTables(t *testing.T) {
RouteTableId: aws.String("rt-5555"), RouteTableId: aws.String("rt-5555"),
}) })
resources["vpc:vpc-1234"] = &ResourceTracker{} resources["vpc:vpc-1234"] = &tracker.Resource{}
err := addUntaggedRouteTables(cloud, clusterName, resources) err := addUntaggedRouteTables(cloud, clusterName, resources)
if err != nil { if err != nil {

View File

@ -23,36 +23,16 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
) )
type ResourceTracker struct {
Name string
Type string
ID string
// If true, this resource is not owned by the cluster
Shared bool
blocks []string
blocked []string
done bool
deleter func(cloud fi.Cloud, tracker *ResourceTracker) error
groupKey string
groupDeleter func(cloud fi.Cloud, trackers []*ResourceTracker) error
Dumper func(r *ResourceTracker) (interface{}, error)
obj interface{}
}
var _ Resources = &ClusterResources{} var _ Resources = &ClusterResources{}
// Resources is a representation of a cluster with abilities to ListResources and DeleteResources // Resources is a representation of a cluster with abilities to ListResources and DeleteResources
type Resources interface { type Resources interface {
ListResources() (map[string]*ResourceTracker, error) ListResources() (map[string]*tracker.Resource, error)
DeleteResources(resources map[string]*ResourceTracker) error DeleteResources(resources map[string]*tracker.Resource) error
} }
// ClusterResources is an implementation of Resources // ClusterResources is an implementation of Resources
@ -65,7 +45,7 @@ type ClusterResources struct {
Region string Region string
} }
func (c *ClusterResources) ListResources() (map[string]*ResourceTracker, error) { func (c *ClusterResources) ListResources() (map[string]*tracker.Resource, error) {
switch c.Cloud.ProviderID() { switch c.Cloud.ProviderID() {
case kops.CloudProviderAWS: case kops.CloudProviderAWS:
return c.listResourcesAWS() return c.listResourcesAWS()
@ -80,23 +60,23 @@ func (c *ClusterResources) ListResources() (map[string]*ResourceTracker, error)
} }
} }
func (c *ClusterResources) DeleteResources(resources map[string]*ResourceTracker) error { func (c *ClusterResources) DeleteResources(resources map[string]*tracker.Resource) error {
depMap := make(map[string][]string) depMap := make(map[string][]string)
done := make(map[string]*ResourceTracker) done := make(map[string]*tracker.Resource)
var mutex sync.Mutex var mutex sync.Mutex
for k, t := range resources { for k, t := range resources {
for _, block := range t.blocks { for _, block := range t.Blocks {
depMap[block] = append(depMap[block], k) depMap[block] = append(depMap[block], k)
} }
for _, blocked := range t.blocked { for _, blocked := range t.Blocked {
depMap[k] = append(depMap[k], blocked) depMap[k] = append(depMap[k], blocked)
} }
if t.done { if t.Done {
done[k] = t done[k] = t
} }
} }
@ -110,10 +90,10 @@ func (c *ClusterResources) DeleteResources(resources map[string]*ResourceTracker
for { for {
// TODO: Some form of default ordering based on types? // TODO: Some form of default ordering based on types?
failed := make(map[string]*ResourceTracker) failed := make(map[string]*tracker.Resource)
for { for {
phase := make(map[string]*ResourceTracker) phase := make(map[string]*tracker.Resource)
for k, r := range resources { for k, r := range resources {
if _, d := done[k]; d { if _, d := done[k]; d {
@ -143,9 +123,9 @@ func (c *ClusterResources) DeleteResources(resources map[string]*ResourceTracker
break break
} }
groups := make(map[string][]*ResourceTracker) groups := make(map[string][]*tracker.Resource)
for k, t := range phase { for k, t := range phase {
groupKey := t.groupKey groupKey := t.GroupKey
if groupKey == "" { if groupKey == "" {
groupKey = "_" + k groupKey = "_" + k
} }
@ -156,7 +136,7 @@ func (c *ClusterResources) DeleteResources(resources map[string]*ResourceTracker
for _, trackers := range groups { for _, trackers := range groups {
wg.Add(1) wg.Add(1)
go func(trackers []*ResourceTracker) { go func(trackers []*tracker.Resource) {
mutex.Lock() mutex.Lock()
for _, t := range trackers { for _, t := range trackers {
k := t.Type + ":" + t.ID k := t.Type + ":" + t.ID
@ -169,13 +149,13 @@ func (c *ClusterResources) DeleteResources(resources map[string]*ResourceTracker
human := trackers[0].Type + ":" + trackers[0].ID human := trackers[0].Type + ":" + trackers[0].ID
var err error var err error
if trackers[0].groupDeleter != nil { if trackers[0].GroupDeleter != nil {
err = trackers[0].groupDeleter(c.Cloud, trackers) err = trackers[0].GroupDeleter(c.Cloud, trackers)
} else { } else {
if len(trackers) != 1 { if len(trackers) != 1 {
glog.Fatalf("found group without groupKey") glog.Fatalf("found group without groupKey")
} }
err = trackers[0].deleter(c.Cloud, trackers[0]) err = trackers[0].Deleter(c.Cloud, trackers[0])
} }
if err != nil { if err != nil {
mutex.Lock() mutex.Lock()

View File

@ -0,0 +1,37 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package digitalocean
import (
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi"
)
type Resources struct {
Cloud fi.Cloud
ClusterName string
}
// ListResources fetches all digitalocean resources into tracker.Resources
func (r *Resources) ListResources() (map[string]*tracker.Resource, error) {
return nil, nil
}
// DeleteResources deletes all resources passed in the form in tracker.Resources
func (r *Resources) DeleteResources(resources map[string]*tracker.Resource) error {
return nil
}

View File

@ -16,6 +16,16 @@ limitations under the License.
package resources package resources
func (c *ClusterResources) listResourcesDO() (map[string]*ResourceTracker, error) { import (
return nil, nil "k8s.io/kops/pkg/resources/digitalocean"
"k8s.io/kops/pkg/resources/tracker"
)
func (c *ClusterResources) listResourcesDO() (map[string]*tracker.Resource, error) {
r := digitalocean.Resources{
Cloud: c.Cloud,
ClusterName: c.ClusterName,
}
return r.ListResources()
} }

View File

@ -26,12 +26,13 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kops/pkg/dns" "k8s.io/kops/pkg/dns"
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/gce" "k8s.io/kops/upup/pkg/fi/cloudup/gce"
"k8s.io/kubernetes/federation/pkg/dnsprovider" "k8s.io/kubernetes/federation/pkg/dnsprovider"
) )
type gceListFn func() ([]*ResourceTracker, error) type gceListFn func() ([]*tracker.Resource, error)
const ( const (
typeInstance = "Instance" typeInstance = "Instance"
@ -44,13 +45,13 @@ const (
typeRoute = "Route" typeRoute = "Route"
) )
func (c *ClusterResources) listResourcesGCE() (map[string]*ResourceTracker, error) { func (c *ClusterResources) listResourcesGCE() (map[string]*tracker.Resource, error) {
gceCloud := c.Cloud.(gce.GCECloud) gceCloud := c.Cloud.(gce.GCECloud)
if c.Region == "" { if c.Region == "" {
c.Region = gceCloud.Region() c.Region = gceCloud.Region()
} }
resources := make(map[string]*ResourceTracker) resources := make(map[string]*tracker.Resource)
d := &clusterDiscoveryGCE{ d := &clusterDiscoveryGCE{
cloud: c.Cloud, cloud: c.Cloud,
@ -91,11 +92,11 @@ func (c *ClusterResources) listResourcesGCE() (map[string]*ResourceTracker, erro
d.listAddresses, d.listAddresses,
} }
for _, fn := range listFunctions { for _, fn := range listFunctions {
trackers, err := fn() resourceTrackers, err := fn()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, t := range trackers { for _, t := range resourceTrackers {
resources[t.Type+":"+t.ID] = t resources[t.Type+":"+t.ID] = t
} }
} }
@ -104,17 +105,17 @@ func (c *ClusterResources) listResourcesGCE() (map[string]*ResourceTracker, erro
// Technically we still have a race condition here - until the master(s) are terminated, they will keep // Technically we still have a race condition here - until the master(s) are terminated, they will keep
// creating routes. Another option might be to have a post-destroy cleanup, and only remove routes with no target. // creating routes. Another option might be to have a post-destroy cleanup, and only remove routes with no target.
{ {
trackers, err := d.listRoutes(resources) resourceTrackers, err := d.listRoutes(resources)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, t := range trackers { for _, t := range resourceTrackers {
resources[t.Type+":"+t.ID] = t resources[t.Type+":"+t.ID] = t
} }
} }
for k, t := range resources { for k, t := range resources {
if t.done { if t.Done {
delete(resources, k) delete(resources, k)
} }
} }
@ -178,32 +179,32 @@ func (d *clusterDiscoveryGCE) findInstanceTemplates() ([]*compute.InstanceTempla
return matches, nil return matches, nil
} }
func (d *clusterDiscoveryGCE) listGCEInstanceTemplates() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listGCEInstanceTemplates() ([]*tracker.Resource, error) {
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
templates, err := d.findInstanceTemplates() templates, err := d.findInstanceTemplates()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, t := range templates { for _, t := range templates {
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: t.Name, Name: t.Name,
ID: t.Name, ID: t.Name,
Type: typeInstanceTemplate, Type: typeInstanceTemplate,
deleter: deleteGCEInstanceTemplate, Deleter: deleteGCEInstanceTemplate,
obj: t, Obj: t,
} }
glog.V(4).Infof("Found resource: %s", t.SelfLink) glog.V(4).Infof("Found resource: %s", t.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteGCEInstanceTemplate(cloud fi.Cloud, r *ResourceTracker) error { func deleteGCEInstanceTemplate(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.InstanceTemplate) t := r.Obj.(*compute.InstanceTemplate)
glog.V(2).Infof("Deleting GCE InstanceTemplate %s", t.SelfLink) glog.V(2).Infof("Deleting GCE InstanceTemplate %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -223,11 +224,11 @@ func deleteGCEInstanceTemplate(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listInstanceGroupManagersAndInstances() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listInstanceGroupManagersAndInstances() ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
project := c.Project() project := c.Project()
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
instanceTemplates := make(map[string]*compute.InstanceTemplate) instanceTemplates := make(map[string]*compute.InstanceTemplate)
{ {
@ -251,24 +252,24 @@ func (d *clusterDiscoveryGCE) listInstanceGroupManagersAndInstances() ([]*Resour
continue continue
} }
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: mig.Name, Name: mig.Name,
ID: zoneName + "/" + mig.Name, ID: zoneName + "/" + mig.Name,
Type: typeInstanceGroupManager, Type: typeInstanceGroupManager,
deleter: deleteInstanceGroupManager, Deleter: deleteInstanceGroupManager,
obj: mig, Obj: mig,
} }
tracker.blocks = append(tracker.blocks, typeInstanceTemplate+":"+instanceTemplate.Name) resourceTracker.Blocks = append(resourceTracker.Blocks, typeInstanceTemplate+":"+instanceTemplate.Name)
glog.V(4).Infof("Found resource: %s", mig.SelfLink) glog.V(4).Infof("Found resource: %s", mig.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
instanceTrackers, err := d.listManagedInstances(mig) instanceTrackers, err := d.listManagedInstances(mig)
if err != nil { if err != nil {
return fmt.Errorf("error listing instances in InstanceGroupManager: %v", err) return fmt.Errorf("error listing instances in InstanceGroupManager: %v", err)
} }
trackers = append(trackers, instanceTrackers...) resourceTrackers = append(resourceTrackers, instanceTrackers...)
} }
return nil return nil
}) })
@ -278,12 +279,12 @@ func (d *clusterDiscoveryGCE) listInstanceGroupManagersAndInstances() ([]*Resour
} }
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteInstanceGroupManager(cloud fi.Cloud, r *ResourceTracker) error { func deleteInstanceGroupManager(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.InstanceGroupManager) t := r.Obj.(*compute.InstanceGroupManager)
glog.V(2).Infof("Deleting GCE InstanceGroupManager %s", t.SelfLink) glog.V(2).Infof("Deleting GCE InstanceGroupManager %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -305,11 +306,11 @@ func deleteInstanceGroupManager(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listManagedInstances(igm *compute.InstanceGroupManager) ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listManagedInstances(igm *compute.InstanceGroupManager) ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
project := c.Project() project := c.Project()
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
zoneName := gce.LastComponent(igm.Zone) zoneName := gce.LastComponent(igm.Zone)
@ -322,20 +323,20 @@ func (d *clusterDiscoveryGCE) listManagedInstances(igm *compute.InstanceGroupMan
for _, i := range instances.ManagedInstances { for _, i := range instances.ManagedInstances {
name := gce.LastComponent(i.Instance) name := gce.LastComponent(i.Instance)
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: name, Name: name,
ID: zoneName + "/" + name, ID: zoneName + "/" + name,
Type: typeInstance, Type: typeInstance,
deleter: deleteManagedInstance, Deleter: deleteManagedInstance,
obj: i.Instance, Obj: i.Instance,
} }
// We don't block deletion of the instance group manager // We don't block deletion of the instance group manager
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return trackers, nil return resourceTrackers, nil
} }
// findGCEDisks finds all Disks that are associated with the current cluster // findGCEDisks finds all Disks that are associated with the current cluster
@ -383,36 +384,36 @@ func (d *clusterDiscoveryGCE) findGCEDisks() ([]*compute.Disk, error) {
return matches, nil return matches, nil
} }
func (d *clusterDiscoveryGCE) listGCEDisks() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listGCEDisks() ([]*tracker.Resource, error) {
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
disks, err := d.findGCEDisks() disks, err := d.findGCEDisks()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, t := range disks { for _, t := range disks {
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: t.Name, Name: t.Name,
ID: t.Name, ID: t.Name,
Type: typeDisk, Type: typeDisk,
deleter: deleteGCEDisk, Deleter: deleteGCEDisk,
obj: t, Obj: t,
} }
for _, u := range t.Users { for _, u := range t.Users {
tracker.blocked = append(tracker.blocked, typeInstance+":"+gce.LastComponent(t.Zone)+"/"+gce.LastComponent(u)) resourceTracker.Blocked = append(resourceTracker.Blocked, typeInstance+":"+gce.LastComponent(t.Zone)+"/"+gce.LastComponent(u))
} }
glog.V(4).Infof("Found resource: %s", t.SelfLink) glog.V(4).Infof("Found resource: %s", t.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteGCEDisk(cloud fi.Cloud, r *ResourceTracker) error { func deleteGCEDisk(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.Disk) t := r.Obj.(*compute.Disk)
glog.V(2).Infof("Deleting GCE Disk %s", t.SelfLink) glog.V(2).Infof("Deleting GCE Disk %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -432,10 +433,10 @@ func deleteGCEDisk(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listTargetPools() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listTargetPools() ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
ctx := context.Background() ctx := context.Background()
@ -445,16 +446,16 @@ func (d *clusterDiscoveryGCE) listTargetPools() ([]*ResourceTracker, error) {
continue continue
} }
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: tp.Name, Name: tp.Name,
ID: tp.Name, ID: tp.Name,
Type: typeTargetPool, Type: typeTargetPool,
deleter: deleteTargetPool, Deleter: deleteTargetPool,
obj: tp, Obj: tp,
} }
glog.V(4).Infof("Found resource: %s", tp.SelfLink) glog.V(4).Infof("Found resource: %s", tp.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return nil return nil
@ -463,12 +464,12 @@ func (d *clusterDiscoveryGCE) listTargetPools() ([]*ResourceTracker, error) {
return nil, fmt.Errorf("error listing TargetPools: %v", err) return nil, fmt.Errorf("error listing TargetPools: %v", err)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteTargetPool(cloud fi.Cloud, r *ResourceTracker) error { func deleteTargetPool(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.TargetPool) t := r.Obj.(*compute.TargetPool)
glog.V(2).Infof("Deleting GCE TargetPool %s", t.SelfLink) glog.V(2).Infof("Deleting GCE TargetPool %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -490,10 +491,10 @@ func deleteTargetPool(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listForwardingRules() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listForwardingRules() ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
ctx := context.Background() ctx := context.Background()
@ -503,24 +504,24 @@ func (d *clusterDiscoveryGCE) listForwardingRules() ([]*ResourceTracker, error)
continue continue
} }
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: fr.Name, Name: fr.Name,
ID: fr.Name, ID: fr.Name,
Type: typeForwardingRule, Type: typeForwardingRule,
deleter: deleteForwardingRule, Deleter: deleteForwardingRule,
obj: fr, Obj: fr,
} }
if fr.Target != "" { if fr.Target != "" {
tracker.blocks = append(tracker.blocks, typeTargetPool+":"+gce.LastComponent(fr.Target)) resourceTracker.Blocks = append(resourceTracker.Blocks, typeTargetPool+":"+gce.LastComponent(fr.Target))
} }
if fr.IPAddress != "" { if fr.IPAddress != "" {
tracker.blocks = append(tracker.blocks, typeAddress+":"+gce.LastComponent(fr.IPAddress)) resourceTracker.Blocks = append(resourceTracker.Blocks, typeAddress+":"+gce.LastComponent(fr.IPAddress))
} }
glog.V(4).Infof("Found resource: %s", fr.SelfLink) glog.V(4).Infof("Found resource: %s", fr.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return nil return nil
}) })
@ -528,12 +529,12 @@ func (d *clusterDiscoveryGCE) listForwardingRules() ([]*ResourceTracker, error)
return nil, fmt.Errorf("error listing ForwardingRules: %v", err) return nil, fmt.Errorf("error listing ForwardingRules: %v", err)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteForwardingRule(cloud fi.Cloud, r *ResourceTracker) error { func deleteForwardingRule(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.ForwardingRule) t := r.Obj.(*compute.ForwardingRule)
glog.V(2).Infof("Deleting GCE ForwardingRule %s", t.SelfLink) glog.V(2).Infof("Deleting GCE ForwardingRule %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -553,9 +554,9 @@ func deleteForwardingRule(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func deleteManagedInstance(cloud fi.Cloud, r *ResourceTracker) error { func deleteManagedInstance(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
selfLink := r.obj.(string) selfLink := r.Obj.(string)
glog.V(2).Infof("Deleting GCE Instance %s", selfLink) glog.V(2).Infof("Deleting GCE Instance %s", selfLink)
u, err := gce.ParseGoogleCloudURL(selfLink) u, err := gce.ParseGoogleCloudURL(selfLink)
@ -575,10 +576,10 @@ func deleteManagedInstance(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listRoutes(resources map[string]*ResourceTracker) ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listRoutes(resources map[string]*tracker.Resource) ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
instances := sets.NewString() instances := sets.NewString()
for _, resource := range resources { for _, resource := range resources {
@ -619,21 +620,21 @@ func (d *clusterDiscoveryGCE) listRoutes(resources map[string]*ResourceTracker)
} }
if remove { if remove {
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: r.Name, Name: r.Name,
ID: r.Name, ID: r.Name,
Type: typeRoute, Type: typeRoute,
deleter: deleteRoute, Deleter: deleteRoute,
obj: r, Obj: r,
} }
// We don't need to block // We don't need to block
//if r.NextHopInstance != "" { //if r.NextHopInstance != "" {
// tracker.blocked = append(tracker.blocks, typeInstance+":"+gce.LastComponent(r.NextHopInstance)) // resourceTracker.Blocked = append(resourceTracker.Blocks, typeInstance+":"+gce.LastComponent(r.NextHopInstance))
//} //}
glog.V(4).Infof("Found resource: %s", r.SelfLink) glog.V(4).Infof("Found resource: %s", r.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
} }
@ -642,12 +643,12 @@ func (d *clusterDiscoveryGCE) listRoutes(resources map[string]*ResourceTracker)
if err != nil { if err != nil {
return nil, fmt.Errorf("error listing Routes: %v", err) return nil, fmt.Errorf("error listing Routes: %v", err)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteRoute(cloud fi.Cloud, r *ResourceTracker) error { func deleteRoute(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.Route) t := r.Obj.(*compute.Route)
glog.V(2).Infof("Deleting GCE Route %s", t.SelfLink) glog.V(2).Infof("Deleting GCE Route %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -667,10 +668,10 @@ func deleteRoute(cloud fi.Cloud, r *ResourceTracker) error {
return c.WaitForOp(op) return c.WaitForOp(op)
} }
func (d *clusterDiscoveryGCE) listAddresses() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listAddresses() ([]*tracker.Resource, error) {
c := d.gceCloud c := d.gceCloud
var trackers []*ResourceTracker var resourceTrackers []*tracker.Resource
ctx := context.Background() ctx := context.Background()
@ -681,16 +682,16 @@ func (d *clusterDiscoveryGCE) listAddresses() ([]*ResourceTracker, error) {
continue continue
} }
tracker := &ResourceTracker{ resourceTracker := &tracker.Resource{
Name: a.Name, Name: a.Name,
ID: a.Name, ID: a.Name,
Type: typeAddress, Type: typeAddress,
deleter: deleteAddress, Deleter: deleteAddress,
obj: a, Obj: a,
} }
glog.V(4).Infof("Found resource: %s", a.SelfLink) glog.V(4).Infof("Found resource: %s", a.SelfLink)
trackers = append(trackers, tracker) resourceTrackers = append(resourceTrackers, resourceTracker)
} }
return nil return nil
}) })
@ -698,12 +699,12 @@ func (d *clusterDiscoveryGCE) listAddresses() ([]*ResourceTracker, error) {
return nil, fmt.Errorf("error listing Addresses: %v", err) return nil, fmt.Errorf("error listing Addresses: %v", err)
} }
return trackers, nil return resourceTrackers, nil
} }
func deleteAddress(cloud fi.Cloud, r *ResourceTracker) error { func deleteAddress(cloud fi.Cloud, r *tracker.Resource) error {
c := cloud.(gce.GCECloud) c := cloud.(gce.GCECloud)
t := r.obj.(*compute.Address) t := r.Obj.(*compute.Address)
glog.V(2).Infof("Deleting GCE Address %s", t.SelfLink) glog.V(2).Infof("Deleting GCE Address %s", t.SelfLink)
u, err := gce.ParseGoogleCloudURL(t.SelfLink) u, err := gce.ParseGoogleCloudURL(t.SelfLink)
@ -733,7 +734,7 @@ func (d *clusterDiscoveryGCE) matchesClusterName(name string) bool {
return name == gce.SafeObjectName(id, d.clusterName) return name == gce.SafeObjectName(id, d.clusterName)
} }
func (d *clusterDiscoveryGCE) listGCEDNSZone() ([]*ResourceTracker, error) { func (d *clusterDiscoveryGCE) listGCEDNSZone() ([]*tracker.Resource, error) {
if dns.IsGossipHostname(d.clusterName) { if dns.IsGossipHostname(d.clusterName) {
return nil, nil return nil, nil
} }
@ -743,13 +744,13 @@ func (d *clusterDiscoveryGCE) listGCEDNSZone() ([]*ResourceTracker, error) {
return nil, err return nil, err
} }
return []*ResourceTracker{ return []*tracker.Resource{
{ {
Name: zone.Name(), Name: zone.Name(),
ID: zone.Name(), ID: zone.Name(),
Type: "DNS Zone", Type: "DNS Zone",
deleter: d.deleteDNSZone, Deleter: d.deleteDNSZone,
obj: zone, Obj: zone,
}, },
}, nil }, nil
} }
@ -779,8 +780,8 @@ func (d *clusterDiscoveryGCE) findDNSZone() (dnsprovider.Zone, error) {
return nil, fmt.Errorf("DNS Zone for cluster %s could not be found", d.clusterName) return nil, fmt.Errorf("DNS Zone for cluster %s could not be found", d.clusterName)
} }
func (d *clusterDiscoveryGCE) deleteDNSZone(cloud fi.Cloud, r *ResourceTracker) error { func (d *clusterDiscoveryGCE) deleteDNSZone(cloud fi.Cloud, r *tracker.Resource) error {
clusterZone := r.obj.(dnsprovider.Zone) clusterZone := r.Obj.(dnsprovider.Zone)
rrs, supported := clusterZone.ResourceRecordSets() rrs, supported := clusterZone.ResourceRecordSets()
if !supported { if !supported {

View File

@ -0,0 +1,42 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tracker
import (
"k8s.io/kops/upup/pkg/fi"
)
type Resource struct {
Name string
Type string
ID string
// If true, this resource is not owned by the cluster
Shared bool
Blocks []string
Blocked []string
Done bool
Deleter func(cloud fi.Cloud, tracker *Resource) error
GroupKey string
GroupDeleter func(cloud fi.Cloud, trackers []*Resource) error
Dumper func(r *Resource) (interface{}, error)
Obj interface{}
}

View File

@ -21,6 +21,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/vmware/govmomi/find" "github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object" "github.com/vmware/govmomi/object"
"k8s.io/kops/pkg/resources/tracker"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/vsphere" "k8s.io/kops/upup/pkg/fi/cloudup/vsphere"
) )
@ -35,12 +36,12 @@ type clusterDiscoveryVSphere struct {
clusterName string clusterName string
} }
type vsphereListFn func() ([]*ResourceTracker, error) type vsphereListFn func() ([]*tracker.Resource, error)
func (c *ClusterResources) listResourcesVSphere() (map[string]*ResourceTracker, error) { func (c *ClusterResources) listResourcesVSphere() (map[string]*tracker.Resource, error) {
vsphereCloud := c.Cloud.(*vsphere.VSphereCloud) vsphereCloud := c.Cloud.(*vsphere.VSphereCloud)
resources := make(map[string]*ResourceTracker) resources := make(map[string]*tracker.Resource)
d := &clusterDiscoveryVSphere{ d := &clusterDiscoveryVSphere{
cloud: c.Cloud, cloud: c.Cloud,
@ -65,7 +66,7 @@ func (c *ClusterResources) listResourcesVSphere() (map[string]*ResourceTracker,
return resources, nil return resources, nil
} }
func (d *clusterDiscoveryVSphere) listVMs() ([]*ResourceTracker, error) { func (d *clusterDiscoveryVSphere) listVMs() ([]*tracker.Resource, error) {
c := d.vsphereCloud c := d.vsphereCloud
regexForMasterVMs := "*" + "." + "masters" + "." + d.clusterName + "*" regexForMasterVMs := "*" + "." + "masters" + "." + d.clusterName + "*"
@ -79,25 +80,25 @@ func (d *clusterDiscoveryVSphere) listVMs() ([]*ResourceTracker, error) {
glog.Warning(err) glog.Warning(err)
} }
var trackers []*ResourceTracker var trackers []*tracker.Resource
for _, vm := range vms { for _, vm := range vms {
tracker := &ResourceTracker{ tracker := &tracker.Resource{
Name: vm.Name(), Name: vm.Name(),
ID: vm.Name(), ID: vm.Name(),
Type: typeVM, Type: typeVM,
deleter: deleteVM, Deleter: deleteVM,
Dumper: DumpVMInfo, Dumper: DumpVMInfo,
obj: vm, Obj: vm,
} }
trackers = append(trackers, tracker) trackers = append(trackers, tracker)
} }
return trackers, nil return trackers, nil
} }
func deleteVM(cloud fi.Cloud, r *ResourceTracker) error { func deleteVM(cloud fi.Cloud, r *tracker.Resource) error {
vsphereCloud := cloud.(*vsphere.VSphereCloud) vsphereCloud := cloud.(*vsphere.VSphereCloud)
vm := r.obj.(*object.VirtualMachine) vm := r.Obj.(*object.VirtualMachine)
task, err := vm.PowerOff(context.TODO()) task, err := vm.PowerOff(context.TODO())
if err != nil { if err != nil {
@ -120,14 +121,14 @@ func deleteVM(cloud fi.Cloud, r *ResourceTracker) error {
return nil return nil
} }
func DumpVMInfo(r *ResourceTracker) (interface{}, error) { func DumpVMInfo(r *tracker.Resource) (interface{}, error) {
data := make(map[string]interface{}) data := make(map[string]interface{})
data["id"] = r.ID data["id"] = r.ID
data["type"] = r.Type data["type"] = r.Type
data["raw"] = r.obj data["raw"] = r.Obj
return data, nil return data, nil
} }
func GetResourceTrackerKey(t *ResourceTracker) string { func GetResourceTrackerKey(t *tracker.Resource) string {
return t.Type + ":" + t.ID return t.Type + ":" + t.ID
} }