upup: More delete cleanup, use statestore by default

This commit is contained in:
Justin Santa Barbara 2016-06-28 11:47:19 -04:00
parent 8e52111c0f
commit e315564cfa
2 changed files with 204 additions and 104 deletions

View File

@ -6,7 +6,9 @@ import (
"bytes"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/kube-deploy/upup/pkg/api"
"k8s.io/kube-deploy/upup/pkg/fi"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/awsup"
"k8s.io/kube-deploy/upup/pkg/kutil"
"os"
@ -15,8 +17,9 @@ import (
)
type DeleteClusterCmd struct {
Yes bool
Region string
Yes bool
Region string
External bool
}
var deleteCluster DeleteClusterCmd
@ -38,30 +41,59 @@ func init() {
cmd.Flags().BoolVar(&deleteCluster.Yes, "yes", false, "Delete without confirmation")
cmd.Flags().BoolVar(&deleteCluster.External, "external", false, "Delete an external cluster")
cmd.Flags().StringVar(&deleteCluster.Region, "region", "", "region")
}
type getter func(o interface{}) interface{}
func (c *DeleteClusterCmd) Run() error {
if c.Region == "" {
return fmt.Errorf("--region is required")
}
clusterName := rootCommand.clusterName
if clusterName == "" {
return fmt.Errorf("--name is required")
}
var stateStore fi.StateStore
var err error
tags := map[string]string{"KubernetesCluster": clusterName}
cloud, err := awsup.NewAWSCloud(c.Region, tags)
if err != nil {
return fmt.Errorf("error initializing AWS client: %v", err)
var cloud fi.Cloud
clusterName := ""
region := ""
if c.External {
region = c.Region
if region == "" {
return fmt.Errorf("--region is required")
}
clusterName := rootCommand.clusterName
if clusterName == "" {
return fmt.Errorf("--name is required (when --external)")
}
tags := map[string]string{"KubernetesCluster": clusterName}
cloud, err = awsup.NewAWSCloud(c.Region, tags)
if err != nil {
return fmt.Errorf("error initializing AWS client: %v", err)
}
} else {
stateStore, err = rootCommand.StateStore()
if err != nil {
return err
}
cluster, _, err := api.ReadConfig(stateStore)
if err != nil {
return err
}
if rootCommand.clusterName != cluster.Name {
return fmt.Errorf("sanity check failed: cluster name mismatch")
}
cloud, err = cloudup.BuildCloud(cluster)
if err != nil {
return err
}
}
d := &kutil.DeleteCluster{}
d.ClusterName = clusterName
d.Region = c.Region
d.Region = region
d.Cloud = cloud
resources, err := d.ListResources()
@ -71,68 +103,84 @@ func (c *DeleteClusterCmd) Run() error {
if len(resources) == 0 {
fmt.Printf("Nothing to delete\n")
return nil
}
} else {
columns := []string{"TYPE", "ID", "NAME"}
fields := []string{"Type", "ID", "Name"}
columns := []string{"TYPE", "ID", "NAME"}
fields := []string{"Type", "ID", "Name"}
var b bytes.Buffer
w := new(tabwriter.Writer)
var b bytes.Buffer
w := new(tabwriter.Writer)
// Format in tab-separated columns with a tab stop of 8.
w.Init(os.Stdout, 0, 8, 0, '\t', tabwriter.StripEscape)
// Format in tab-separated columns with a tab stop of 8.
w.Init(os.Stdout, 0, 8, 0, '\t', tabwriter.StripEscape)
writeHeader := true
if writeHeader {
for i, c := range columns {
if i != 0 {
b.WriteByte('\t')
writeHeader := true
if writeHeader {
for i, c := range columns {
if i != 0 {
b.WriteByte('\t')
}
b.WriteByte(tabwriter.Escape)
b.WriteString(c)
b.WriteByte(tabwriter.Escape)
}
b.WriteByte(tabwriter.Escape)
b.WriteString(c)
b.WriteByte(tabwriter.Escape)
}
b.WriteByte('\n')
b.WriteByte('\n')
_, err := w.Write(b.Bytes())
_, err := w.Write(b.Bytes())
if err != nil {
return fmt.Errorf("error writing to output: %v", err)
}
b.Reset()
}
for _, t := range resources {
for i := range columns {
if i != 0 {
b.WriteByte('\t')
}
v := reflect.ValueOf(t)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
fv := v.FieldByName(fields[i])
s := fi.ValueAsString(fv)
b.WriteByte(tabwriter.Escape)
b.WriteString(s)
b.WriteByte(tabwriter.Escape)
}
b.WriteByte('\n')
_, err := w.Write(b.Bytes())
if err != nil {
return fmt.Errorf("error writing to output: %v", err)
}
b.Reset()
}
w.Flush()
if !c.Yes {
return fmt.Errorf("Must specify --yes to delete")
}
err := d.DeleteResources(resources)
if err != nil {
return fmt.Errorf("error writing to output: %v", err)
return err
}
b.Reset()
}
for _, t := range resources {
for i := range columns {
if i != 0 {
b.WriteByte('\t')
}
v := reflect.ValueOf(t)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
fv := v.FieldByName(fields[i])
s := fi.ValueAsString(fv)
b.WriteByte(tabwriter.Escape)
b.WriteString(s)
b.WriteByte(tabwriter.Escape)
if stateStore != nil {
if !c.Yes {
return fmt.Errorf("Must specify --yes to delete")
}
b.WriteByte('\n')
_, err := w.Write(b.Bytes())
err := api.DeleteConfig(stateStore)
if err != nil {
return fmt.Errorf("error writing to output: %v", err)
return fmt.Errorf("error removing cluster from state store: %v", err)
}
b.Reset()
}
w.Flush()
if !c.Yes {
return fmt.Errorf("Must specify --yes to delete")
}
return d.DeleteResources(resources)
fmt.Printf("\nCluster deleted\n")
return nil
}

View File

@ -96,20 +96,17 @@ func (c *DeleteCluster) ListResources() (map[string]*ResourceTracker, error) {
}
}
// TODO: Move to ListUntaggedInternetGateways?
{
// Gateways weren't tagged in kube-up
// If we are deleting the VPC, we should delete the attached gateway
// (no real reason not to; easy to recreate; no real state etc)
glog.V(2).Infof("Listing all Internet Gateways")
request := &ec2.DescribeInternetGatewaysInput{}
response, err := cloud.EC2.DescribeInternetGateways(request)
gateways, err := DescribeInternetGatewaysIgnoreTags(cloud)
if err != nil {
return nil, fmt.Errorf("error listing InternetGateways: %v", err)
return nil, err
}
for _, igw := range response.InternetGateways {
for _, igw := range gateways {
for _, attachment := range igw.Attachments {
vpcID := aws.StringValue(attachment.VpcId)
igwID := aws.StringValue(igw.InternetGatewayId)
@ -336,7 +333,8 @@ func ListInstances(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, erro
continue
case "running":
// Fine
case "stopped":
// We need to delete
glog.V(4).Infof("instance %q has state=%q", id, stateName)
default:
@ -847,20 +845,14 @@ func DeleteInternetGateway(cloud fi.Cloud, r *ResourceTracker) error {
}
func ListInternetGateways(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, error) {
c := cloud.(*awsup.AWSCloud)
glog.V(2).Infof("Listing EC2 InternetGateways")
request := &ec2.DescribeInternetGatewaysInput{
Filters: buildEC2Filters(cloud),
}
response, err := c.EC2.DescribeInternetGateways(request)
gateways, err := DescribeInternetGateways(cloud)
if err != nil {
return nil, fmt.Errorf("error listing InternetGateway: %v", err)
return nil, err
}
var trackers []*ResourceTracker
for _, o := range response.InternetGateways {
for _, o := range gateways {
tracker := &ResourceTracker{
Name: FindName(o.Tags),
ID: aws.StringValue(o.InternetGatewayId),
@ -882,6 +874,48 @@ func ListInternetGateways(cloud fi.Cloud, clusterName string) ([]*ResourceTracke
return trackers, nil
}
func DescribeInternetGateways(cloud fi.Cloud) ([]*ec2.InternetGateway, error) {
c := cloud.(*awsup.AWSCloud)
glog.V(2).Infof("Listing EC2 InternetGateways")
request := &ec2.DescribeInternetGatewaysInput{
Filters: buildEC2Filters(cloud),
}
response, err := c.EC2.DescribeInternetGateways(request)
if err != nil {
return nil, fmt.Errorf("error listing InternetGateway: %v", err)
}
var gateways []*ec2.InternetGateway
for _, o := range response.InternetGateways {
gateways = append(gateways, o)
}
return gateways, nil
}
// DescribeInternetGatewaysIgnoreTags returns all ec2.InternetGateways, ignoring tags
// (gateways were not always tagged in kube-up)
func DescribeInternetGatewaysIgnoreTags(cloud fi.Cloud) ([]*ec2.InternetGateway, error) {
c := cloud.(*awsup.AWSCloud)
glog.V(2).Infof("Listing all Internet Gateways")
request := &ec2.DescribeInternetGatewaysInput{}
response, err := c.EC2.DescribeInternetGateways(request)
if err != nil {
return nil, fmt.Errorf("error listing (all) InternetGateways: %v", err)
}
var gateways []*ec2.InternetGateway
for _, igw := range response.InternetGateways {
gateways = append(gateways, igw)
}
return gateways, nil
}
func DeleteVPC(cloud fi.Cloud, r *ResourceTracker) error {
c := cloud.(*awsup.AWSCloud)
@ -1082,15 +1116,49 @@ func DeleteELB(cloud fi.Cloud, r *ResourceTracker) error {
}
func ListELBs(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, error) {
c := cloud.(*awsup.AWSCloud)
tags := c.Tags()
elbs, elbTags, err := DescribeELBs(cloud)
if err != nil {
return nil, err
}
var trackers []*ResourceTracker
for _, elb := range elbs {
id := aws.StringValue(elb.LoadBalancerName)
tracker := &ResourceTracker{
Name: FindELBName(elbTags[id]),
ID: id,
Type: "load-balancer",
deleter: DeleteELB,
}
var blocks []string
for _, sg := range elb.SecurityGroups {
blocks = append(blocks, "security-group:"+aws.StringValue(sg))
}
for _, s := range elb.Subnets {
blocks = append(blocks, "subnet:"+aws.StringValue(s))
}
blocks = append(blocks, "vpc:"+aws.StringValue(elb.VPCId))
tracker.blocks = blocks
trackers = append(trackers, tracker)
}
return trackers, nil
}
func DescribeELBs(cloud fi.Cloud) ([]*elb.LoadBalancerDescription, map[string][]*elb.Tag, error) {
c := cloud.(*awsup.AWSCloud)
tags := c.Tags()
glog.V(2).Infof("Listing all ELBs")
request := &elb.DescribeLoadBalancersInput{}
var elbs []*elb.LoadBalancerDescription
elbTags := make(map[string][]*elb.Tag)
var innerError error
err := c.ELB.DescribeLoadBalancersPages(request, func(p *elb.DescribeLoadBalancersOutput, lastPage bool) bool {
if len(p.LoadBalancerDescriptions) == 0 {
@ -1120,37 +1188,21 @@ func ListELBs(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, error) {
continue
}
tracker := &ResourceTracker{
Name: FindELBName(t.Tags),
ID: elbName,
Type: "load-balancer",
deleter: DeleteELB,
}
elbTags[elbName] = t.Tags
elb := nameToELB[elbName]
var blocks []string
for _, sg := range elb.SecurityGroups {
blocks = append(blocks, "security-group:"+aws.StringValue(sg))
}
for _, s := range elb.Subnets {
blocks = append(blocks, "subnet:"+aws.StringValue(s))
}
blocks = append(blocks, "vpc:"+aws.StringValue(elb.VPCId))
tracker.blocks = blocks
trackers = append(trackers, tracker)
elbs = append(elbs, elb)
}
return true
})
if err != nil {
return nil, fmt.Errorf("error describing LoadBalances: %v", err)
return nil, nil, fmt.Errorf("error describing LoadBalancers: %v", err)
}
if innerError != nil {
return nil, fmt.Errorf("error describing LoadBalancers: %v", innerError)
return nil, nil, fmt.Errorf("error describing LoadBalancers: %v", innerError)
}
return trackers, nil
return elbs, elbTags, nil
}
func DeleteElasticIP(cloud fi.Cloud, t *ResourceTracker) error {