Add `kops get secrets` command

Matches our naming pattern, and now using our text grid output
This commit is contained in:
Justin Santa Barbara 2016-07-29 01:12:03 -04:00
parent 3e3ca5a2b8
commit 19e19a0f09
5 changed files with 165 additions and 105 deletions

85
cmd/kops/get_secrets.go Normal file
View File

@ -0,0 +1,85 @@
package main
import (
"fmt"
"os"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/kops/upup/pkg/fi"
)
type GetSecretsCommand struct {
}
var getSecretsCommand GetSecretsCommand
func init() {
cmd := &cobra.Command{
Use: "secrets",
Aliases: []string{"secret"},
Short: "get secrets",
Long: `List or get secrets.`,
Run: func(cmd *cobra.Command, args []string) {
err := getSecretsCommand.Run()
if err != nil {
glog.Exitf("%v", err)
}
},
}
getCmd.AddCommand(cmd)
}
func (c *GetSecretsCommand) Run() error {
var items []*fi.KeystoreItem
{
caStore, err := rootCommand.KeyStore()
if err != nil {
return err
}
l, err := caStore.List()
if err != nil {
return fmt.Errorf("error listing CA store items %v", err)
}
for _, i := range l {
items = append(items, i)
}
}
{
secretStore, err := rootCommand.SecretStore()
if err != nil {
return err
}
l, err := secretStore.ListSecrets()
if err != nil {
return fmt.Errorf("error listing secrets %v", err)
}
for _, id := range l {
info := &fi.KeystoreItem{
Name: id,
Type: fi.SecretTypeSecret,
}
items = append(items, info)
}
}
if len(items) == 0 {
return nil
}
t := &Table{}
t.AddColumn("NAME", func(i *fi.KeystoreItem) string {
return i.Name
})
t.AddColumn("ID", func(i *fi.KeystoreItem) string {
return i.Id
})
t.AddColumn("TYPE", func(i *fi.KeystoreItem) string {
return i.Type
})
return t.Render(items, os.Stdout, "TYPE", "NAME", "ID")
}

View File

@ -48,12 +48,18 @@ func (c *DescribeSecretsCommand) Run() error {
if err != nil {
return err
}
ids, err := caStore.List()
items, err := caStore.List()
if err != nil {
return fmt.Errorf("error listing CA store items %v", err)
}
for _, id := range ids {
for _, item := range items {
if item.Type != fi.SecretTypeKeypair {
continue
}
id := item.Name
cert, err := caStore.FindCert(id)
if err != nil {
return fmt.Errorf("error retrieving cert %q: %v", id, err)

View File

@ -1,20 +1,10 @@
package main
import (
"fmt"
"bytes"
"github.com/golang/glog"
"github.com/spf13/cobra"
"os"
"text/tabwriter"
)
type GetSecretsCommand struct {
}
var getSecretsCommand GetSecretsCommand
func init() {
cmd := &cobra.Command{
Use: "get",
@ -30,73 +20,3 @@ func init() {
secretsCmd.AddCommand(cmd)
}
type SecretInfo struct {
Id string
Type string
}
func (c *GetSecretsCommand) Run() error {
var infos []*SecretInfo
{
caStore, err := rootCommand.KeyStore()
if err != nil {
return err
}
ids, err := caStore.List()
if err != nil {
return fmt.Errorf("error listing CA store items %v", err)
}
for _, id := range ids {
info := &SecretInfo{
Id: id,
Type: "keypair",
}
infos = append(infos, info)
}
}
{
secretStore, err := rootCommand.SecretStore()
if err != nil {
return err
}
ids, err := secretStore.ListSecrets()
if err != nil {
return fmt.Errorf("error listing secrets %v", err)
}
for _, id := range ids {
info := &SecretInfo{
Id: id,
Type: "secret",
}
infos = append(infos, info)
}
}
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)
for _, info := range infos {
b.WriteByte(tabwriter.Escape)
b.WriteString(info.Type)
b.WriteByte(tabwriter.Escape)
b.WriteByte('\t')
b.WriteByte(tabwriter.Escape)
b.WriteString(info.Id)
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

@ -28,6 +28,12 @@ type Certificate struct {
PublicKey crypto.PublicKey
}
const (
SecretTypeSSHPublicKey = "SSHPublicKey"
SecretTypeKeypair = "Keypair"
SecretTypeSecret = "Secret"
)
type KeystoreItem struct {
Type string
Name string
@ -74,29 +80,30 @@ func (c *Certificate) MarshalJSON() ([]byte, error) {
type CAStore interface {
// Cert returns the primary specified certificate
Cert(id string) (*Certificate, error)
Cert(name string) (*Certificate, error)
// CertificatePool returns all active certificates with the specified id
CertificatePool(id string) (*CertificatePool, error)
PrivateKey(id string) (*PrivateKey, error)
CertificatePool(name string) (*CertificatePool, error)
PrivateKey(name string) (*PrivateKey, error)
FindCert(id string) (*Certificate, error)
FindPrivateKey(id string) (*PrivateKey, error)
FindCert(name string) (*Certificate, error)
FindPrivateKey(name string) (*PrivateKey, error)
//IssueCert(id string, privateKey *PrivateKey, template *x509.Certificate) (*Certificate, error)
//CreatePrivateKey(id string) (*PrivateKey, error)
CreateKeypair(id string, template *x509.Certificate) (*Certificate, *PrivateKey, error)
CreateKeypair(name string, template *x509.Certificate) (*Certificate, *PrivateKey, error)
List() ([]string, error)
// List will list all the items, but will not fetch the data
List() ([]*KeystoreItem, error)
// VFSPath returns the path where the CAStore is stored
VFSPath() vfs.Path
// AddCert adds an alternative certificate to the pool (primarily useful for CAs)
AddCert(id string, cert *Certificate) error
AddCert(name string, cert *Certificate) error
// AddSSHPublicKey adds an SSH public key
AddSSHPublicKey(id string, data []byte) error
AddSSHPublicKey(name string, data []byte) error
// FindSSHPublicKeys retrieves the SSH public keys with the specific name
FindSSHPublicKeys(name string) ([]*KeystoreItem, error)

View File

@ -27,10 +27,6 @@ type VFSCAStore struct {
cacheCaPrivateKeys *privateKeys
}
const (
SecretTypeSSHPublicKey = "SSHPublicKey"
)
var _ CAStore = &VFSCAStore{}
func NewVFSCAStore(basedir vfs.Path) CAStore {
@ -322,20 +318,66 @@ func (c *VFSCAStore) FindCertificatePool(id string) (*CertificatePool, error) {
return pool, nil
}
func (c *VFSCAStore) List() ([]string, error) {
var ids []string
func (c *VFSCAStore) List() ([]*KeystoreItem, error) {
var items []*KeystoreItem
issuedDir := c.basedir.Join("issued")
files, err := issuedDir.ReadDir()
if err != nil {
return nil, fmt.Errorf("error reading directory %q: %v", issuedDir, err)
{
baseDir := c.basedir.Join("issued")
files, err := baseDir.ReadTree()
if err != nil {
return nil, fmt.Errorf("error reading directory %q: %v", baseDir, err)
}
for _, f := range files {
relativePath, err := vfs.RelativePath(baseDir, f)
if err != nil {
return nil, err
}
tokens := strings.Split(relativePath, "/")
if len(tokens) != 2 {
glog.V(2).Infof("ignoring unexpected file in keystore: %q", f)
continue
}
item := &KeystoreItem{
Name: tokens[0],
Id: strings.TrimSuffix(tokens[1], ".crt"),
Type: SecretTypeKeypair,
}
items = append(items, item)
}
}
for _, f := range files {
name := f.Base()
ids = append(ids, name)
{
baseDir := c.basedir.Join("ssh", "public")
files, err := baseDir.ReadTree()
if err != nil {
return nil, fmt.Errorf("error reading directory %q: %v", baseDir, err)
}
for _, f := range files {
relativePath, err := vfs.RelativePath(baseDir, f)
if err != nil {
return nil, err
}
tokens := strings.Split(relativePath, "/")
if len(tokens) != 2 {
glog.V(2).Infof("ignoring unexpected file in keystore: %q", f)
continue
}
item := &KeystoreItem{
Name: tokens[0],
Id: tokens[1],
Type: SecretTypeSSHPublicKey,
}
items = append(items, item)
}
}
return ids, nil
return items, nil
}
func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKey, template *x509.Certificate) (*Certificate, error) {