mirror of https://github.com/kubernetes/kops.git
Merge pull request #1274 from justinsb/kops_inspect
First step towards cluster-dump command
This commit is contained in:
commit
94c4e5fb4c
|
|
@ -100,6 +100,7 @@ func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command {
|
|||
cmd.AddCommand(NewCmdEdit(f, out))
|
||||
cmd.AddCommand(NewCmdUpdate(f, out))
|
||||
cmd.AddCommand(NewCmdReplace(f, out))
|
||||
cmd.AddCommand(NewCmdToolbox(f, out))
|
||||
cmd.AddCommand(NewCmdValidate(f, out))
|
||||
|
||||
return cmd
|
||||
|
|
|
|||
|
|
@ -18,14 +18,18 @@ package main
|
|||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"k8s.io/kops/cmd/kops/util"
|
||||
)
|
||||
|
||||
// toolboxCmd represents the toolbox command
|
||||
var toolboxCmd = &cobra.Command{
|
||||
Use: "toolbox",
|
||||
Short: "Misc infrequently used commands",
|
||||
}
|
||||
func NewCmdToolbox(f *util.Factory, out io.Writer) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "toolbox",
|
||||
Short: "Misc infrequently used commands",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCommand.AddCommand(toolboxCmd)
|
||||
cmd.AddCommand(NewCmdToolboxConvertImported(f, out))
|
||||
cmd.AddCommand(NewCmdToolboxDump(f, out))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,46 +19,64 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"k8s.io/kops/cmd/kops/util"
|
||||
api "k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||
"k8s.io/kops/upup/pkg/kutil"
|
||||
k8sapi "k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
type ConvertImportedCmd struct {
|
||||
type ToolboxConvertImportedOptions struct {
|
||||
NewClusterName string
|
||||
|
||||
// Channel is the location of the api.Channel to use for our defaults
|
||||
Channel string
|
||||
|
||||
ClusterName string
|
||||
}
|
||||
|
||||
var convertImported ConvertImportedCmd
|
||||
func (o *ToolboxConvertImportedOptions) InitDefaults() {
|
||||
o.Channel = api.DefaultChannel
|
||||
}
|
||||
|
||||
func NewCmdToolboxConvertImported(f *util.Factory, out io.Writer) *cobra.Command {
|
||||
options := &ToolboxConvertImportedOptions{}
|
||||
|
||||
func init() {
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert-imported",
|
||||
Short: "Convert an imported cluster into a kops cluster",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := convertImported.Run()
|
||||
if err := rootCommand.ProcessArgs(args); err != nil {
|
||||
exitWithError(err)
|
||||
}
|
||||
|
||||
options.ClusterName = rootCommand.ClusterName()
|
||||
|
||||
err := RunToolboxConvertImported(f, out, options)
|
||||
if err != nil {
|
||||
exitWithError(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
toolboxCmd.AddCommand(cmd)
|
||||
cmd.Flags().StringVar(&options.NewClusterName, "newname", options.NewClusterName, "new cluster name")
|
||||
cmd.Flags().StringVar(&options.Channel, "channel", options.Channel, "Channel to use for upgrade")
|
||||
|
||||
cmd.Flags().StringVar(&convertImported.NewClusterName, "newname", "", "new cluster name")
|
||||
cmd.Flags().StringVar(&convertImported.Channel, "channel", api.DefaultChannel, "Channel to use for upgrade")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ConvertImportedCmd) Run() error {
|
||||
cluster, err := rootCommand.Cluster()
|
||||
func RunToolboxConvertImported(f *util.Factory, out io.Writer, options *ToolboxConvertImportedOptions) error {
|
||||
clientset, err := f.Clientset()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientset, err := rootCommand.Clientset()
|
||||
if options.ClusterName == "" {
|
||||
return fmt.Errorf("ClusterName is required")
|
||||
}
|
||||
|
||||
cluster, err := clientset.Clusters().Get(options.ClusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -76,7 +94,7 @@ func (c *ConvertImportedCmd) Run() error {
|
|||
return fmt.Errorf("cluster %q does not appear to be a cluster imported using kops import", cluster.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
if c.NewClusterName == "" {
|
||||
if options.NewClusterName == "" {
|
||||
return fmt.Errorf("--newname is required for converting an imported cluster")
|
||||
}
|
||||
|
||||
|
|
@ -110,13 +128,13 @@ func (c *ConvertImportedCmd) Run() error {
|
|||
return fmt.Errorf("error initializing AWS client: %v", err)
|
||||
}
|
||||
|
||||
channel, err := api.LoadChannel(c.Channel)
|
||||
channel, err := api.LoadChannel(options.Channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d := &kutil.ConvertKubeupCluster{
|
||||
NewClusterName: c.NewClusterName,
|
||||
NewClusterName: options.NewClusterName,
|
||||
OldClusterName: oldClusterName,
|
||||
Cloud: cloud,
|
||||
ClusterConfig: cluster,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"k8s.io/kops/cmd/kops/util"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||
"k8s.io/kops/upup/pkg/kutil"
|
||||
)
|
||||
|
||||
type ToolboxDumpOptions struct {
|
||||
Output string
|
||||
|
||||
ClusterName string
|
||||
}
|
||||
|
||||
func (o *ToolboxDumpOptions) InitDefaults() {
|
||||
o.Output = OutputYaml
|
||||
}
|
||||
|
||||
func NewCmdToolboxDump(f *util.Factory, out io.Writer) *cobra.Command {
|
||||
options := &ToolboxDumpOptions{}
|
||||
options.InitDefaults()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "dump",
|
||||
Short: "Dump information about a cluster",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := rootCommand.ProcessArgs(args); err != nil {
|
||||
exitWithError(err)
|
||||
}
|
||||
|
||||
options.ClusterName = rootCommand.ClusterName()
|
||||
|
||||
err := RunToolboxDump(f, out, options)
|
||||
if err != nil {
|
||||
exitWithError(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Push up to top-level command?
|
||||
cmd.Flags().StringVarP(&options.Output, "output", "o", options.Output, "output format. One of: yaml, json")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunToolboxDump(f *util.Factory, out io.Writer, options *ToolboxDumpOptions) error {
|
||||
clientset, err := f.Clientset()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.ClusterName == "" {
|
||||
return fmt.Errorf("ClusterName is required")
|
||||
}
|
||||
|
||||
cluster, err := clientset.Clusters().Get(options.ClusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cluster == nil {
|
||||
return fmt.Errorf("cluster not found %q", options.ClusterName)
|
||||
}
|
||||
|
||||
cloud, err := cloudup.BuildCloud(cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d := &kutil.DeleteCluster{}
|
||||
d.ClusterName = options.ClusterName
|
||||
d.Cloud = cloud
|
||||
|
||||
resources, err := d.ListResources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := make(map[string]interface{})
|
||||
|
||||
dumpedResources := []interface{}{}
|
||||
for k, r := range resources {
|
||||
if r.Dumper == nil {
|
||||
glog.V(8).Infof("skipping dump of %q (no Dumper)", k)
|
||||
continue
|
||||
}
|
||||
|
||||
o, err := r.Dumper(r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error dumping %q: %v", k, err)
|
||||
}
|
||||
if o != nil {
|
||||
dumpedResources = append(dumpedResources, o)
|
||||
}
|
||||
}
|
||||
data["resources"] = dumpedResources
|
||||
|
||||
switch options.Output {
|
||||
case OutputYaml:
|
||||
b, err := kops.ToRawYaml(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling yaml: %v", err)
|
||||
}
|
||||
_, err = out.Write(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing to stdout: %v", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
case OutputJSON:
|
||||
b, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling json: %v", err)
|
||||
}
|
||||
_, err = out.Write(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing to stdout: %v", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Unsupported output format: %q", options.Output)
|
||||
}
|
||||
}
|
||||
|
|
@ -65,6 +65,8 @@ type ResourceTracker struct {
|
|||
groupKey string
|
||||
groupDeleter func(cloud fi.Cloud, trackers []*ResourceTracker) error
|
||||
|
||||
Dumper func(r *ResourceTracker) (interface{}, error)
|
||||
|
||||
obj interface{}
|
||||
}
|
||||
|
||||
|
|
@ -484,8 +486,10 @@ func ListInstances(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, erro
|
|||
tracker := &ResourceTracker{
|
||||
Name: FindName(instance.Tags),
|
||||
ID: id,
|
||||
Type: "instance",
|
||||
Type: ec2.ResourceTypeInstance,
|
||||
deleter: DeleteInstance,
|
||||
Dumper: DumpInstance,
|
||||
obj: instance,
|
||||
}
|
||||
|
||||
var blocks []string
|
||||
|
|
@ -518,6 +522,14 @@ func ListInstances(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, erro
|
|||
return trackers, nil
|
||||
}
|
||||
|
||||
func DumpInstance(r *ResourceTracker) (interface{}, error) {
|
||||
data := make(map[string]interface{})
|
||||
data["id"] = r.ID
|
||||
data["type"] = ec2.ResourceTypeInstance
|
||||
data["raw"] = r.obj
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func DeleteSecurityGroup(cloud fi.Cloud, t *ResourceTracker) error {
|
||||
c := cloud.(awsup.AWSCloud)
|
||||
|
||||
|
|
@ -1236,6 +1248,14 @@ func DeleteVPC(cloud fi.Cloud, r *ResourceTracker) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func DumpVPC(r *ResourceTracker) (interface{}, error) {
|
||||
data := make(map[string]interface{})
|
||||
data["id"] = r.ID
|
||||
data["type"] = ec2.ResourceTypeVpc
|
||||
data["raw"] = r.obj
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func DescribeVPCs(cloud fi.Cloud) ([]*ec2.Vpc, error) {
|
||||
c := cloud.(awsup.AWSCloud)
|
||||
|
||||
|
|
@ -1262,8 +1282,10 @@ func ListVPCs(cloud fi.Cloud, clusterName string) ([]*ResourceTracker, error) {
|
|||
tracker := &ResourceTracker{
|
||||
Name: FindName(v.Tags),
|
||||
ID: aws.StringValue(v.VpcId),
|
||||
Type: "vpc",
|
||||
Type: ec2.ResourceTypeVpc,
|
||||
deleter: DeleteVPC,
|
||||
Dumper: DumpVPC,
|
||||
obj: v,
|
||||
}
|
||||
|
||||
var blocks []string
|
||||
|
|
|
|||
Loading…
Reference in New Issue