mirror of https://github.com/kubernetes/kops.git
Support `kops get/edit instancegroup`
This lets us start to manage instancegroups through the CLI Issue #66
This commit is contained in:
parent
8f12f3e4fe
commit
992a3e7d7f
|
@ -11,8 +11,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
var editorEnvs = []string{"KUBE_EDITOR", "EDITOR"}
|
|
||||||
|
|
||||||
type EditClusterCmd struct {
|
type EditClusterCmd struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EditInstanceGroupCmd struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var editInstanceGroupCmd EditInstanceGroupCmd
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "instancegroup",
|
||||||
|
Aliases: []string{"instancegroups", "ig"},
|
||||||
|
Short: "Edit instancegroup",
|
||||||
|
Long: `Edit an instancegroup configuration.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
glog.Exitf("Specify name of instance group to edit")
|
||||||
|
}
|
||||||
|
if len(args) != 1 {
|
||||||
|
glog.Exitf("Can only edit one instance group at a time!")
|
||||||
|
}
|
||||||
|
err := editInstanceGroupCmd.Run(args[0])
|
||||||
|
if err != nil {
|
||||||
|
glog.Exitf("%v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
editCmd.AddCommand(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *EditInstanceGroupCmd) Run(groupName string) error {
|
||||||
|
stateStore, err := rootCommand.StateStore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
edit = editor.NewDefaultEditor(editorEnvs)
|
||||||
|
)
|
||||||
|
|
||||||
|
ext := "yaml"
|
||||||
|
|
||||||
|
raw, err := stateStore.VFSPath().Join("instancegroup", groupName).ReadFile()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error reading instancegroup file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// launch the editor
|
||||||
|
edited, file, err := edit.LaunchTempFile(fmt.Sprintf("%s-edit-", filepath.Base(os.Args[0])), ext, bytes.NewReader(raw))
|
||||||
|
defer func() {
|
||||||
|
if file != "" {
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error launching editor: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(edited, raw) {
|
||||||
|
fmt.Fprintln(os.Stderr, "Edit cancelled, no changes made.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stateStore.VFSPath().Join("instancegroup", groupName).WriteFile(edited)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing instancegroup file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
var editorEnvs = []string{"KUBE_EDITOR", "EDITOR"}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"io"
|
||||||
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
|
"reflect"
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Table renders tables to stdout
|
||||||
|
type Table struct {
|
||||||
|
columns []string
|
||||||
|
getters []reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddColumn registers an available column for formatting
|
||||||
|
func (t *Table) AddColumn(name string, getter interface{}) {
|
||||||
|
getterVal := reflect.ValueOf(getter)
|
||||||
|
|
||||||
|
t.columns = append(t.columns, name)
|
||||||
|
t.getters = append(t.getters, getterVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render writes the items in a table, to out
|
||||||
|
func (t *Table) Render(items interface{}, out io.Writer) error {
|
||||||
|
itemsValue := reflect.ValueOf(items)
|
||||||
|
if itemsValue.Kind() != reflect.Slice {
|
||||||
|
glog.Fatal("unexpected kind for items: ", itemsValue.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
length := itemsValue.Len()
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
w := new(tabwriter.Writer)
|
||||||
|
|
||||||
|
// Format in tab-separated columns with a tab stop of 8.
|
||||||
|
w.Init(out, 0, 8, 0, '\t', tabwriter.StripEscape)
|
||||||
|
|
||||||
|
writeHeader := true
|
||||||
|
if writeHeader {
|
||||||
|
for i, c := range t.columns {
|
||||||
|
if i != 0 {
|
||||||
|
b.WriteByte('\t')
|
||||||
|
}
|
||||||
|
b.WriteByte(tabwriter.Escape)
|
||||||
|
b.WriteString(c)
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
item := itemsValue.Index(i)
|
||||||
|
|
||||||
|
for j := range t.columns {
|
||||||
|
if j != 0 {
|
||||||
|
b.WriteByte('\t')
|
||||||
|
}
|
||||||
|
|
||||||
|
getter := t.getters[j]
|
||||||
|
var args []reflect.Value
|
||||||
|
args = append(args, item)
|
||||||
|
fvs := getter.Call(args)
|
||||||
|
fv := fvs[0]
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,16 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"os"
|
||||||
|
|
||||||
"bytes"
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/kops/upup/pkg/api"
|
"k8s.io/kops/upup/pkg/api"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"text/tabwriter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetClustersCmd struct {
|
type GetClustersCmd struct {
|
||||||
|
@ -20,8 +15,8 @@ var getClustersCmd GetClustersCmd
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "cluster",
|
Use: "clusters",
|
||||||
Aliases: []string{"clusters"},
|
Aliases: []string{"cluster"},
|
||||||
Short: "get clusters",
|
Short: "get clusters",
|
||||||
Long: `List or get clusters.`,
|
Long: `List or get clusters.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
@ -41,14 +36,6 @@ func (c *GetClustersCmd) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
columns := []string{}
|
|
||||||
fields := []func(*api.Cluster) string{}
|
|
||||||
|
|
||||||
columns = append(columns, "NAME")
|
|
||||||
fields = append(fields, func(c *api.Cluster) string {
|
|
||||||
return c.Name
|
|
||||||
})
|
|
||||||
|
|
||||||
var clusters []*api.Cluster
|
var clusters []*api.Cluster
|
||||||
|
|
||||||
for _, clusterName := range clusterNames {
|
for _, clusterName := range clusterNames {
|
||||||
|
@ -58,82 +45,17 @@ func (c *GetClustersCmd) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Faster if we don't read groups...
|
// TODO: Faster if we don't read groups...
|
||||||
// We probably can just have a comand which directly reads all cluster config files
|
// We probably can just have a command which directly reads all cluster config files
|
||||||
cluster, _, err := api.ReadConfig(stateStore)
|
cluster, _, err := api.ReadConfig(stateStore)
|
||||||
clusters = append(clusters, cluster)
|
clusters = append(clusters, cluster)
|
||||||
}
|
}
|
||||||
if len(clusters) == 0 {
|
if len(clusters) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return WriteTable(clusters, columns, fields)
|
|
||||||
}
|
t := &Table{}
|
||||||
|
t.AddColumn("NAME", func(c *api.Cluster) string {
|
||||||
func WriteTable(items interface{}, columns []string, fields interface{}) error {
|
return c.Name
|
||||||
itemsValue := reflect.ValueOf(items)
|
})
|
||||||
if itemsValue.Kind() != reflect.Slice {
|
return t.Render(clusters, os.Stdout)
|
||||||
glog.Fatal("unexpected kind for items in WriteTable: ", itemsValue.Kind())
|
|
||||||
}
|
|
||||||
fieldsValue := reflect.ValueOf(fields)
|
|
||||||
if fieldsValue.Kind() != reflect.Slice {
|
|
||||||
glog.Fatal("unexpected kind for fields in WriteTable: ", fieldsValue.Kind())
|
|
||||||
}
|
|
||||||
|
|
||||||
length := itemsValue.Len()
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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('\n')
|
|
||||||
|
|
||||||
_, err := w.Write(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error writing to output: %v", err)
|
|
||||||
}
|
|
||||||
b.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < length; i++ {
|
|
||||||
item := itemsValue.Index(i)
|
|
||||||
|
|
||||||
for j := range columns {
|
|
||||||
if j != 0 {
|
|
||||||
b.WriteByte('\t')
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldFunc := fieldsValue.Index(j)
|
|
||||||
var args []reflect.Value
|
|
||||||
args = append(args, item)
|
|
||||||
fvs := fieldFunc.Call(args)
|
|
||||||
fv := fvs[0]
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/kops/upup/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetInstanceGroupsCmd struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var getInstanceGroupsCmd GetInstanceGroupsCmd
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "instancegroups",
|
||||||
|
Aliases: []string{"instancegroup", "ig"},
|
||||||
|
Short: "get instancegroups",
|
||||||
|
Long: `List or get InstanceGroups.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := getInstanceGroupsCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
glog.Exitf("%v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
getCmd.AddCommand(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GetInstanceGroupsCmd) Run() error {
|
||||||
|
stateStore, err := rootCommand.StateStore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, instancegroups, err := api.ReadConfig(stateStore)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(instancegroups) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := &Table{}
|
||||||
|
t.AddColumn("NAME", func(c *api.InstanceGroup) string {
|
||||||
|
return c.Name
|
||||||
|
})
|
||||||
|
return t.Render(instancegroups, os.Stdout)
|
||||||
|
}
|
Loading…
Reference in New Issue