Support `kops get/edit instancegroup`

This lets us start to manage instancegroups through the CLI

Issue #66
This commit is contained in:
Justin Santa Barbara 2016-07-07 01:09:37 -04:00
parent 8f12f3e4fe
commit 992a3e7d7f
6 changed files with 239 additions and 90 deletions

View File

@ -11,8 +11,6 @@ import (
"path/filepath"
)
var editorEnvs = []string{"KUBE_EDITOR", "EDITOR"}
type EditClusterCmd struct {
}

View File

@ -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
}

3
cmd/kops/editor.go Normal file
View File

@ -0,0 +1,3 @@
package main
var editorEnvs = []string{"KUBE_EDITOR", "EDITOR"}

92
cmd/kops/format.go Normal file
View File

@ -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
}

View File

@ -1,16 +1,11 @@
package main
import (
"fmt"
"os"
"bytes"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/kops/upup/pkg/api"
"k8s.io/kops/upup/pkg/fi"
"os"
"reflect"
"text/tabwriter"
)
type GetClustersCmd struct {
@ -20,8 +15,8 @@ var getClustersCmd GetClustersCmd
func init() {
cmd := &cobra.Command{
Use: "cluster",
Aliases: []string{"clusters"},
Use: "clusters",
Aliases: []string{"cluster"},
Short: "get clusters",
Long: `List or get clusters.`,
Run: func(cmd *cobra.Command, args []string) {
@ -41,14 +36,6 @@ func (c *GetClustersCmd) Run() error {
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
for _, clusterName := range clusterNames {
@ -58,82 +45,17 @@ func (c *GetClustersCmd) Run() error {
}
// 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)
clusters = append(clusters, cluster)
}
if len(clusters) == 0 {
return nil
}
return WriteTable(clusters, columns, fields)
}
func WriteTable(items interface{}, columns []string, fields interface{}) error {
itemsValue := reflect.ValueOf(items)
if itemsValue.Kind() != reflect.Slice {
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
t := &Table{}
t.AddColumn("NAME", func(c *api.Cluster) string {
return c.Name
})
return t.Render(clusters, os.Stdout)
}

View File

@ -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)
}