Merge pull request #19 from gravitational/alex/kingpin

Migrated tctl to kingpin cmd args parser
This commit is contained in:
alexlyulkov 2015-08-24 18:26:58 +03:00
commit 501e091cbb
6 changed files with 216 additions and 262 deletions

View file

@ -2,98 +2,14 @@ package command
import (
"fmt"
"time"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/buger/goterm"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codegangsta/cli"
"github.com/gravitational/teleport/backend"
)
func newHostCACommand(c *Command) cli.Command {
return cli.Command{
Name: "hostca",
Usage: "Operations with host certificate authority",
Subcommands: []cli.Command{
{
Name: "reset",
Usage: "Reset host certificate authority keys",
Flags: []cli.Flag{
cli.BoolFlag{Name: "confirm", Usage: "Automatically apply the operation without confirmation"},
},
Action: c.resetHostCA,
},
{
Name: "pubkey",
Usage: "print host certificate authority public key",
Action: c.getHostCAPub,
},
},
}
}
func newUserCACommand(c *Command) cli.Command {
return cli.Command{
Name: "userca",
Usage: "Operations with user certificate authority",
Subcommands: []cli.Command{
{
Name: "reset",
Usage: "Reset user certificate authority keys",
Flags: []cli.Flag{
cli.BoolFlag{Name: "confirm", Usage: "Automatically apply the operation without confirmation"},
},
Action: c.resetUserCA,
},
{
Name: "pubkey",
Usage: "print user certificate authority public key",
Action: c.getUserCAPub,
},
},
}
}
func newRemoteCACommand(c *Command) cli.Command {
return cli.Command{
Name: "remoteca",
Usage: "Operations with remote certificate authority",
Subcommands: []cli.Command{
{
Name: "upsert",
Usage: "Upsert remote certificate to trust",
Flags: []cli.Flag{
cli.StringFlag{Name: "id", Usage: "Certificate id"},
cli.StringFlag{Name: "fqdn", Usage: "FQDN of the remote party"},
cli.StringFlag{Name: "type", Usage: "Cert type (host or user)"},
cli.StringFlag{Name: "path", Usage: "Cert path (reads from stdout if omitted)"},
cli.DurationFlag{Name: "ttl", Usage: "ttl for certificate to be trusted"},
},
Action: c.upsertRemoteCert,
},
{
Name: "ls",
Usage: "List trusted remote certificates",
Flags: []cli.Flag{
cli.StringFlag{Name: "fqdn", Usage: "FQDN of the remote party"},
cli.StringFlag{Name: "type", Usage: "Cert type (host or user)"},
},
Action: c.getRemoteCerts,
},
{
Name: "rm",
Usage: "Remote remote CA from list of trusted certs",
Flags: []cli.Flag{
cli.StringFlag{Name: "id", Usage: "Certificate id"},
cli.StringFlag{Name: "fqdn", Usage: "FQDN of the remote party"},
cli.StringFlag{Name: "type", Usage: "Cert type (host or user)"},
},
Action: c.deleteRemoteCert,
},
},
}
}
func (cmd *Command) resetHostCA(c *cli.Context) {
if !c.Bool("confirm") && !cmd.confirm("Reseting private and public keys for Host CA. This will invalidate all signed host certs. Continue?") {
func (cmd *Command) resetHostCA(confirm bool) {
if !confirm && !cmd.confirm("Reseting private and public keys for Host CA. This will invalidate all signed host certs. Continue?") {
cmd.printError(fmt.Errorf("aborted by user"))
return
}
@ -104,7 +20,7 @@ func (cmd *Command) resetHostCA(c *cli.Context) {
cmd.printOK("CA keys have been regenerated")
}
func (cmd *Command) getHostCAPub(c *cli.Context) {
func (cmd *Command) getHostCAPub() {
key, err := cmd.client.GetHostCAPub()
if err != nil {
cmd.printError(err)
@ -114,8 +30,8 @@ func (cmd *Command) getHostCAPub(c *cli.Context) {
fmt.Fprintf(cmd.out, string(key))
}
func (cmd *Command) resetUserCA(c *cli.Context) {
if !c.Bool("confirm") && !cmd.confirm("Reseting private and public keys for User CA. This will invalidate all signed user certs. Continue?") {
func (cmd *Command) resetUserCA(confirm bool) {
if !confirm && !cmd.confirm("Reseting private and public keys for User CA. This will invalidate all signed user certs. Continue?") {
cmd.printError(fmt.Errorf("aborted by user"))
return
}
@ -126,7 +42,7 @@ func (cmd *Command) resetUserCA(c *cli.Context) {
cmd.printOK("CA keys have been regenerated")
}
func (cmd *Command) getUserCAPub(c *cli.Context) {
func (cmd *Command) getUserCAPub() {
key, err := cmd.client.GetUserCAPub()
if err != nil {
cmd.printError(err)
@ -136,28 +52,27 @@ func (cmd *Command) getUserCAPub(c *cli.Context) {
fmt.Fprintf(cmd.out, string(key))
}
func (cmd *Command) upsertRemoteCert(c *cli.Context) {
ctype, fqdn, id := c.String("type"), c.String("fqdn"), c.String("id")
val, err := cmd.readInput(c.String("path"))
func (cmd *Command) upsertRemoteCert(id, fqdn, certType, path string, ttl time.Duration) {
val, err := cmd.readInput(path)
if err != nil {
cmd.printError(err)
return
}
cert := backend.RemoteCert{
FQDN: fqdn,
Type: ctype,
Type: certType,
ID: id,
Value: val,
}
if err := cmd.client.UpsertRemoteCert(cert, c.Duration("ttl")); err != nil {
if err := cmd.client.UpsertRemoteCert(cert, ttl); err != nil {
cmd.printError(err)
return
}
cmd.printOK("Remote cert have been upserted")
}
func (cmd *Command) getRemoteCerts(c *cli.Context) {
certs, err := cmd.client.GetRemoteCerts(c.String("type"), c.String("fqdn"))
func (cmd *Command) getRemoteCerts(fqdn, certType string) {
certs, err := cmd.client.GetRemoteCerts(certType, fqdn)
if err != nil {
cmd.printError(err)
return
@ -165,8 +80,8 @@ func (cmd *Command) getRemoteCerts(c *cli.Context) {
fmt.Fprintf(cmd.out, remoteCertsView(certs))
}
func (cmd *Command) deleteRemoteCert(c *cli.Context) {
err := cmd.client.DeleteRemoteCert(c.String("type"), c.String("fqdn"), c.String("id"))
func (cmd *Command) deleteRemoteCert(id, fqdn, certType string) {
err := cmd.client.DeleteRemoteCert(certType, fqdn, id)
if err != nil {
cmd.printError(err)
return

View file

@ -11,6 +11,7 @@ import (
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codegangsta/cli"
"github.com/gravitational/teleport/auth"
"github.com/gravitational/teleport/utils"
"gopkg.in/alecthomas/kingpin.v2"
)
type Command struct {
@ -27,11 +28,81 @@ func NewCommand() *Command {
}
func (cmd *Command) Run(args []string) error {
addr, args, err := findAddr(args)
if err != nil {
return err
}
a, err := utils.ParseAddr(addr)
app := kingpin.New("tctl", "CLI for key management of teleport SSH cluster")
authUrl := app.Flag("auth", "Teleport URL").Default(DefaultTeleportURL).String()
// Host CA
hostCa := app.Command("host-ca", "Operations with host certificate authority")
hostCaReset := hostCa.Command("reset", "Reset host certificate authority keys")
hostCaResetConfirm := hostCaReset.Flag("confirm", "Automatically apply the operation without confirmation").Bool()
hostCaPubKey := hostCa.Command("pub-key", "print host certificate authority public key")
// User CA
userCa := app.Command("user-ca", "Operations with user certificate authority")
userCaReset := userCa.Command("reset", "Reset user certificate authority keys")
userCaResetConfirm := userCaReset.Flag("confirm", "Automatically apply the operation without confirmation").Bool()
userCaPubKey := userCa.Command("pub-key", "Print user certificate authority public key")
// Remote CA
remoteCa := app.Command("remote-ca", "Operations with remote certificate authority")
remoteCaUpsert := remoteCa.Command("upsert", "Upsert remote certificate to trust")
remoteCaUpsertID := remoteCaUpsert.Flag("id", "Certificate id").Required().String()
remoteCaUpsertFQDN := remoteCaUpsert.Flag("fqdn", "FQDN of the remote party").Required().String()
remoteCaUpsertType := remoteCaUpsert.Flag("type", "Cert type (host or user)").Required().String()
remoteCaUpsertPath := remoteCaUpsert.Flag("path", "Cert path (reads from stdout if omitted)").Required().ExistingFile()
remoteCaUpsertTTL := remoteCaUpsert.Flag("ttl", "ttl for certificate to be trusted").Duration()
remoteCaLs := remoteCa.Command("ls", "List trusted remote certificates")
remoteCaLsFQDN := remoteCaLs.Flag("fqdn", "FQDN of the remote party").String()
remoteCaLsType := remoteCaLs.Flag("type", "Cert type (host or user)").Required().String()
remoteCaRm := remoteCa.Command("rm", "Remote remote CA from list of trusted certs")
remoteCaRmID := remoteCaRm.Flag("id", "Certificate id").Required().String()
remoteCaRmFQDN := remoteCaRm.Flag("fqdn", "FQDN of the remote party").Required().String()
remoteCaRmType := remoteCaRm.Flag("type", "Cert type (host or user)").Required().String()
// Secret
secret := app.Command("secret", "Operations with secret tokens")
secretNew := secret.Command("new", "Generate new secret key")
// Token
token := app.Command("token", "Generates provisioning tokens")
tokenGenerate := token.Command("generate", "Generate provisioning token for server with fqdn")
tokenGenerateFQDN := tokenGenerate.Flag("fqdn", "FQDN of the server").Required().String()
tokenGenerateTTL := tokenGenerate.Flag("ttl", "Time to live").Default("120").Duration()
tokenGenerateOutput := tokenGenerate.Flag("output", "Optional output file").String()
// User
user := app.Command("user", "Operations with registered users")
userLs := user.Command("ls", "List users registered in teleport")
userDelete := user.Command("delete", "Delete user")
userDeleteUser := userDelete.Flag("user", "User to delete").Required().String()
userUpsertKey := user.Command("upsert-key", "Grant access to the user key, returns signed certificate")
userUpsertKeyUser := userUpsertKey.Flag("user", "User holding the key").Required().String()
userUpsertKeyKeyID := userUpsertKey.Flag("key-id", "SSH key ID").Required().String()
userUpsertKeyKey := userUpsertKey.Flag("key", "Path to public key").Required().ExistingFile()
userUpsertKeyTTL := userUpsertKey.Flag("ttl", "Access time to live, certificate and access entry will expire when set").Duration()
userLsKeys := user.Command("ls-keys", "List user's keys registered in teleport")
userLsKeysUser := userLsKeys.Flag("user", "User to list keys form").Required().String()
userSetPass := user.Command("set-pass", "Set user password")
userSetPassUser := userSetPass.Flag("user", "User name").Required().String()
userSetPassPass := userSetPass.Flag("pass", "Password").Required().String()
selectedCommand := kingpin.MustParse(app.Parse(args[1:]))
a, err := utils.ParseAddr(*authUrl)
if err != nil {
return err
}
@ -42,20 +113,52 @@ func (cmd *Command) Run(args []string) error {
cmd.client = clt
app := cli.NewApp()
app.Name = "tctl"
app.Usage = "CLI for key management of teleport SSH cluster"
app.Flags = flags()
switch selectedCommand {
// Host CA
case hostCaReset.FullCommand():
cmd.resetHostCA(*hostCaResetConfirm)
case hostCaPubKey.FullCommand():
cmd.getHostCAPub()
app.Commands = []cli.Command{
newHostCACommand(cmd),
newUserCACommand(cmd),
newRemoteCACommand(cmd),
newUserCommand(cmd),
newTokenCommand(cmd),
newSecretCommand(cmd),
// User CA
case userCaReset.FullCommand():
cmd.resetUserCA(*userCaResetConfirm)
case userCaPubKey.FullCommand():
cmd.getUserCAPub()
// Remote CA
case remoteCaUpsert.FullCommand():
cmd.upsertRemoteCert(*remoteCaUpsertID, *remoteCaUpsertFQDN,
*remoteCaUpsertType, *remoteCaUpsertPath, *remoteCaUpsertTTL)
case remoteCaLs.FullCommand():
cmd.getRemoteCerts(*remoteCaLsFQDN, *remoteCaLsType)
case remoteCaRm.FullCommand():
cmd.deleteRemoteCert(*remoteCaRmID, *remoteCaRmFQDN, *remoteCaRmType)
// Secret
case secretNew.FullCommand():
cmd.newKey()
// Token
case tokenGenerate.FullCommand():
cmd.generateToken(*tokenGenerateFQDN, *tokenGenerateTTL,
*tokenGenerateOutput)
// User
case userLs.FullCommand():
cmd.getUsers()
case userDelete.FullCommand():
cmd.deleteUser(*userDeleteUser)
case userUpsertKey.FullCommand():
cmd.upsertKey(*userUpsertKeyUser, *userUpsertKeyKeyID,
*userUpsertKeyKey, *userUpsertKeyTTL)
case userLsKeys.FullCommand():
cmd.getUserKeys(*userLsKeysUser)
case userSetPass.FullCommand():
cmd.setPass(*userSetPassUser, *userSetPassPass)
}
return app.Run(args)
return nil
}
func (cmd *Command) readInput(path string) ([]byte, error) {
@ -104,24 +207,6 @@ func (cmd *Command) printInfo(message string, params ...interface{}) {
fmt.Fprintf(cmd.out, "INFO: %s\n", fmt.Sprintf(message, params...))
}
// This function extracts url from the command line regardless of it's position
// this is a workaround, as cli libary does not support "superglobal" urls yet.
func findAddr(args []string) (string, []string, error) {
for i, arg := range args {
if strings.HasPrefix(arg, "--teleport=") || strings.HasPrefix(arg, "-teleport=") {
out := strings.Split(arg, "=")
return out[1], cut(i, i+1, args), nil
} else if strings.HasPrefix(arg, "-teleport") || strings.HasPrefix(arg, "--teleport") {
// This argument should not be the last one
if i > len(args)-2 {
return "", nil, fmt.Errorf("provide a valid address")
}
return args[i+1], cut(i, i+2, args), nil
}
}
return DefaultTeleportURL, args, nil
}
func cut(i, j int, args []string) []string {
s := []string{}
s = append(s, args[:i]...)

View file

@ -6,15 +6,21 @@ import (
"io/ioutil"
"net/http/httptest"
"net/url"
"path/filepath"
"strings"
"testing"
"github.com/gravitational/teleport/auth"
authority "github.com/gravitational/teleport/auth/native"
"github.com/gravitational/teleport/backend/membk"
"github.com/gravitational/teleport/backend"
"github.com/gravitational/teleport/backend/boltbk"
"github.com/gravitational/teleport/events/boltlog"
"github.com/gravitational/teleport/recorder"
"github.com/gravitational/teleport/recorder/boltrec"
"github.com/gravitational/teleport/session"
"github.com/gravitational/teleport/utils"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/memlog"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/log"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/mailgun/lemma/secret"
. "github.com/gravitational/teleport/Godeps/_workspace/src/gopkg.in/check.v1"
@ -30,9 +36,12 @@ type CmdSuite struct {
clt *auth.Client
cmd *Command
out *bytes.Buffer
bk *membk.MemBackend
bk *boltbk.BoltBackend
bl *boltlog.BoltLog
scrt *secret.Service
rec recorder.Recorder
addr utils.NetAddr
dir string
}
var _ = Suite(&CmdSuite{})
@ -43,12 +52,25 @@ func (s *CmdSuite) SetUpSuite(c *C) {
srv, err := secret.New(&secret.Config{KeyBytes: key})
c.Assert(err, IsNil)
s.scrt = srv
log.Init([]*log.LogConfig{&log.LogConfig{Name: "console"}})
}
func (s *CmdSuite) SetUpTest(c *C) {
s.bk = membk.New()
s.dir = c.MkDir()
var err error
s.bk, err = boltbk.New(filepath.Join(s.dir, "db"))
c.Assert(err, IsNil)
s.bl, err = boltlog.New(filepath.Join(s.dir, "eventsdb"))
c.Assert(err, IsNil)
s.rec, err = boltrec.New(s.dir)
c.Assert(err, IsNil)
s.asrv = auth.NewAuthServer(s.bk, authority.New(), s.scrt)
s.srv = httptest.NewServer(auth.NewAPIServer(s.asrv, memlog.New()))
s.srv = httptest.NewServer(auth.NewAPIServer(s.asrv, s.bl,
session.New(s.bk), s.rec))
u, err := url.Parse(s.srv.URL)
c.Assert(err, IsNil)
@ -74,7 +96,7 @@ func (s *CmdSuite) runString(in string) string {
func (s *CmdSuite) run(params ...string) string {
args := []string{"tctl"}
args = append(args, params...)
args = append(args, fmt.Sprintf("--teleport=%v", &s.addr))
args = append(args, fmt.Sprintf("--auth=%v", &s.addr))
s.out = &bytes.Buffer{}
s.cmd = &Command{out: s.out}
s.cmd.Run(args)
@ -83,24 +105,31 @@ func (s *CmdSuite) run(params ...string) string {
func (s *CmdSuite) TestHostCACRUD(c *C) {
c.Assert(
s.run("hostca", "reset", "-confirm"),
s.run("host-ca", "reset", "--confirm"),
Matches, fmt.Sprintf(".*%v.*", "regenerated"))
c.Assert(s.bk.HostCA, NotNil)
hostCA, err := s.bk.GetHostCA()
c.Assert(err, IsNil)
c.Assert(hostCA, NotNil)
c.Assert(
s.run("hostca", "pubkey"),
Matches, fmt.Sprintf(".*%v.*", s.bk.HostCA.Pub))
s.run("host-ca", "pub-key"),
Matches, fmt.Sprintf(".*%v.*", hostCA.Pub))
}
func (s *CmdSuite) TestUserCACRUD(c *C) {
c.Assert(
s.run("userca", "reset", "-confirm"),
s.run("user-ca", "reset", "--confirm"),
Matches, fmt.Sprintf(".*%v.*", "regenerated"))
c.Assert(s.bk.UserCA, NotNil)
userCA, err := s.bk.GetUserCA()
c.Assert(err, IsNil)
c.Assert(userCA, NotNil)
c.Assert(userCA, NotNil)
c.Assert(
s.run("userca", "pubkey"),
Matches, fmt.Sprintf(".*%v.*", s.bk.UserCA.Pub))
s.run("user-ca", "pub-key"),
Matches, fmt.Sprintf(".*%v.*", userCA.Pub))
}
func (s *CmdSuite) TestUserCRUD(c *C) {
@ -114,25 +143,29 @@ func (s *CmdSuite) TestUserCRUD(c *C) {
defer fkey.Close()
fkey.Write(pub)
out := s.run("user", "upsert_key", "-user", "alex", "-keyid", "key1", "-key", fkey.Name())
out := s.run("user", "upsert-key", "--user", "alex", "--key-id", "key1", "--key", fkey.Name())
c.Assert(out, Matches, fmt.Sprintf(".*%v.*", pub))
c.Assert(trim(string(s.bk.Users["alex"].Keys["key1"].Value)), Equals, trim(out))
var keys []backend.AuthorizedKey
keys, err = s.bk.GetUserKeys("alex")
c.Assert(err, IsNil)
c.Assert(trim(keys[0].ID), Equals, "key1")
c.Assert(trim(string(keys[0].Value)), Equals, trim(out))
c.Assert(
s.run("user", "ls"),
Matches, fmt.Sprintf(".*%v.*", "alex"))
c.Assert(s.run("user", "ls_keys", "-user", "alex"), Matches, fmt.Sprintf(".*%v.*", "key1"))
c.Assert(s.run("user", "ls-keys", "--user", "alex"), Matches, fmt.Sprintf(".*%v.*", "key1"))
c.Assert(
s.run("user", "delete", "-user", "alex"),
s.run("user", "delete", "--user", "alex"),
Matches, fmt.Sprintf(".*%v.*", "alex"))
}
func (s *CmdSuite) TestGenerateToken(c *C) {
token := s.run(
"token", "generate", "-fqdn", "a.example.com", "-ttl", "100s")
"token", "generate", "--fqdn", "a.example.com", "--ttl", "100s")
c.Assert(s.asrv.ValidateToken(token, "a.example.com"), IsNil)
}
@ -147,17 +180,22 @@ func (s *CmdSuite) TestRemoteCertCRUD(c *C) {
defer fkey.Close()
fkey.Write(pub)
out := s.run("remoteca", "upsert", "-id", "id1", "-type", "user", "-fqdn", "example.com", "-path", fkey.Name())
out := s.run("remote-ca", "upsert", "--id", "id1", "--type", "user", "--fqdn", "example.com", "--path", fkey.Name())
c.Assert(out, Matches, fmt.Sprintf(".*%v.*", "upserted"))
c.Assert(trim(string(s.bk.RemoteCerts[0].Value)), Equals, trim(string(pub)))
out = s.run("remoteca", "ls", "-type", "user")
var remoteCerts []backend.RemoteCert
remoteCerts, err = s.bk.GetRemoteCerts("user", "example.com")
c.Assert(err, IsNil)
c.Assert(trim(string(remoteCerts[0].Value)), Equals, trim(string(pub)))
out = s.run("remote-ca", "ls", "--type", "user")
c.Assert(out, Matches, fmt.Sprintf(".*%v.*", "example.com"))
out = s.run("remoteca", "rm", "-type", "user", "-fqdn", "example.com", "-id", "id1")
out = s.run("remote-ca", "rm", "--type", "user", "--fqdn", "example.com", "--id", "id1")
c.Assert(out, Matches, fmt.Sprintf(".*%v.*", "deleted"))
c.Assert(len(s.bk.RemoteCerts), Equals, 0)
remoteCerts, err = s.bk.GetRemoteCerts("user", "")
c.Assert(len(remoteCerts), Equals, 0)
}
func trim(val string) string {

View file

@ -3,25 +3,10 @@ package command
import (
"fmt"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codegangsta/cli"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/mailgun/lemma/secret"
)
func newSecretCommand(c *Command) cli.Command {
return cli.Command{
Name: "secret",
Usage: "Operations with secret tokens",
Subcommands: []cli.Command{
{
Name: "new",
Usage: "Generate new secret key",
Action: c.newKey,
},
},
}
}
func (cmd *Command) newKey(c *cli.Context) {
func (cmd *Command) newKey() {
key, err := secret.NewKey()
if err != nil {
cmd.printError(fmt.Errorf("failed to generate key: %v", err))

View file

@ -4,40 +4,21 @@ import (
"fmt"
"io/ioutil"
"time"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codegangsta/cli"
)
func newTokenCommand(c *Command) cli.Command {
return cli.Command{
Name: "token",
Usage: "Generates provisioning tokens",
Subcommands: []cli.Command{
{
Name: "generate",
Usage: "Generate provisioning token for server with fqdn",
Flags: []cli.Flag{
cli.StringFlag{Name: "fqdn", Usage: "FQDN of the server"},
cli.DurationFlag{Name: "ttl", Value: 120 * time.Second, Usage: "TTL"},
cli.StringFlag{Name: "output", Usage: "Optional output file"},
},
Action: c.generateToken,
},
},
}
}
func (cmd *Command) generateToken(fqdn string, ttl time.Duration,
output string) {
func (cmd *Command) generateToken(c *cli.Context) {
token, err := cmd.client.GenerateToken(c.String("fqdn"), c.Duration("ttl"))
token, err := cmd.client.GenerateToken(fqdn, ttl)
if err != nil {
cmd.printError(err)
return
}
if c.String("output") == "" {
if output == "" {
fmt.Fprintf(cmd.out, token)
return
}
err = ioutil.WriteFile(c.String("output"), []byte(token), 0644)
err = ioutil.WriteFile(output, []byte(token), 0644)
if err != nil {
cmd.printError(err)
}

View file

@ -2,79 +2,29 @@ package command
import (
"fmt"
"time"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/buger/goterm"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/codegangsta/cli"
"github.com/gravitational/teleport/backend"
)
func newUserCommand(c *Command) cli.Command {
return cli.Command{
Name: "user",
Usage: "Operations with registered users",
Subcommands: []cli.Command{
{
Name: "ls",
Usage: "List users registered in teleport",
Action: c.getUsers,
},
{
Name: "delete",
Usage: "Delete user",
Action: c.deleteUser,
Flags: []cli.Flag{
cli.StringFlag{Name: "user", Usage: "User to delete"},
},
},
{
Name: "upsert_key",
Usage: "Grant access to the user key, returns signed certificate",
Flags: []cli.Flag{
cli.StringFlag{Name: "user", Usage: "User holding the key"},
cli.StringFlag{Name: "keyid", Usage: "SSH key ID"},
cli.StringFlag{Name: "key", Usage: "Path to public key"},
cli.DurationFlag{Name: "ttl", Usage: "Access time to live, certificate and access entry will expire when set"},
},
Action: c.upsertKey,
},
{
Name: "ls_keys",
Usage: "List user's keys registered in teleport",
Action: c.getUserKeys,
Flags: []cli.Flag{
cli.StringFlag{Name: "user", Usage: "User to list keys form"},
},
},
{
Name: "set_pass",
Usage: "Set user password",
Flags: []cli.Flag{
cli.StringFlag{Name: "user", Usage: "User name"},
cli.StringFlag{Name: "pass", Usage: "Password"},
},
Action: c.setPass,
},
},
}
}
func (cmd *Command) setPass(c *cli.Context) {
err := cmd.client.UpsertPassword(c.String("user"), []byte(c.String("pass")))
func (cmd *Command) setPass(user, pass string) {
err := cmd.client.UpsertPassword(user, []byte(pass))
if err != nil {
cmd.printError(err)
return
}
cmd.printOK("password has been set for user '%v'", c.String("user"))
cmd.printOK("password has been set for user '%v'", user)
}
func (cmd *Command) upsertKey(c *cli.Context) {
bytes, err := cmd.readInput(c.String("key"))
func (cmd *Command) upsertKey(user, keyID, key string, ttl time.Duration) {
bytes, err := cmd.readInput(key)
if err != nil {
cmd.printError(err)
return
}
signed, err := cmd.client.UpsertUserKey(
c.String("user"), backend.AuthorizedKey{ID: c.String("keyid"), Value: bytes}, c.Duration("ttl"))
user, backend.AuthorizedKey{ID: keyID, Value: bytes}, ttl)
if err != nil {
cmd.printError(err)
return
@ -82,15 +32,15 @@ func (cmd *Command) upsertKey(c *cli.Context) {
fmt.Fprintf(cmd.out, "%v", string(signed))
}
func (cmd *Command) deleteUser(c *cli.Context) {
if err := cmd.client.DeleteUser(c.String("user")); err != nil {
func (cmd *Command) deleteUser(user string) {
if err := cmd.client.DeleteUser(user); err != nil {
cmd.printError(err)
return
}
cmd.printOK("User %v deleted", c.String("user"))
cmd.printOK("User %v deleted", user)
}
func (cmd *Command) getUsers(c *cli.Context) {
func (cmd *Command) getUsers() {
users, err := cmd.client.GetUsers()
if err != nil {
cmd.printError(err)
@ -100,8 +50,8 @@ func (cmd *Command) getUsers(c *cli.Context) {
fmt.Fprintf(cmd.out, usersView(users))
}
func (cmd *Command) getUserKeys(c *cli.Context) {
keys, err := cmd.client.GetUserKeys(c.String("user"))
func (cmd *Command) getUserKeys(user string) {
keys, err := cmd.client.GetUserKeys(user)
if err != nil {
cmd.printError(err)
return