Added the clone command in SSM
This commit is contained in:
parent
ee6011bc3e
commit
306640abdb
|
@ -2,6 +2,8 @@ package commandctrl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lmika/awstools/internal/common/ui/events"
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
|
@ -35,15 +37,18 @@ func (c *CommandController) Prompt() tea.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandController) Execute(commandInput string) tea.Cmd {
|
func (c *CommandController) Execute(commandInput string) tea.Cmd {
|
||||||
|
log.Println("Received input: ", commandInput)
|
||||||
input := strings.TrimSpace(commandInput)
|
input := strings.TrimSpace(commandInput)
|
||||||
if input == "" {
|
if input == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens := shellwords.Split(input)
|
tokens := shellwords.Split(input)
|
||||||
|
log.Println("Tokens: ", tokens)
|
||||||
command := c.lookupCommand(tokens[0])
|
command := c.lookupCommand(tokens[0])
|
||||||
if command == nil {
|
if command == nil {
|
||||||
return events.SetStatus("no such command: " + tokens[0])
|
log.Println("No such command: ", tokens)
|
||||||
|
return events.SetError(errors.New("no such command: " + tokens[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return command(tokens[1:])
|
return command(tokens[1:])
|
||||||
|
@ -51,6 +56,7 @@ func (c *CommandController) Execute(commandInput string) tea.Cmd {
|
||||||
|
|
||||||
func (c *CommandController) lookupCommand(name string) Command {
|
func (c *CommandController) lookupCommand(name string) Command {
|
||||||
for ctx := c.commandList; ctx != nil; ctx = ctx.parent {
|
for ctx := c.commandList; ctx != nil; ctx = ctx.parent {
|
||||||
|
log.Printf("Looking in command list: %v", c.commandList)
|
||||||
if cmd, ok := ctx.Commands[name]; ok {
|
if cmd, ok := ctx.Commands[name]; ok {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ func Error(err error) tea.Msg {
|
||||||
return ErrorMsg(err)
|
return ErrorMsg(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetError(err error) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetStatus(msg string) tea.Cmd {
|
func SetStatus(msg string) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
return StatusMsg(msg)
|
return StatusMsg(msg)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/lmika/awstools/internal/common/ui/events"
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
|
"github.com/lmika/awstools/internal/ssm-browse/models"
|
||||||
"github.com/lmika/awstools/internal/ssm-browse/services/ssmparameters"
|
"github.com/lmika/awstools/internal/ssm-browse/services/ssmparameters"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -55,3 +56,24 @@ func (c *SSMController) ChangePrefix(newPrefix string) tea.Cmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *SSMController) Clone(param models.SSMParameter) tea.Cmd {
|
||||||
|
return events.PromptForInput("New key: ", func(value string) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
ctx := context.Background()
|
||||||
|
if err := c.service.Clone(ctx, param, value); err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.service.List(context.Background(), c.prefix)
|
||||||
|
if err != nil {
|
||||||
|
return events.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewParameterListMsg{
|
||||||
|
Prefix: c.prefix,
|
||||||
|
Parameters: res,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go-v2/service/ssm/types"
|
||||||
|
|
||||||
type SSMParameters struct {
|
type SSMParameters struct {
|
||||||
Items []SSMParameter
|
Items []SSMParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSMParameter struct {
|
type SSMParameter struct {
|
||||||
Name string
|
Name string
|
||||||
|
Type types.ParameterType
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/ssm"
|
"github.com/aws/aws-sdk-go-v2/service/ssm"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/ssm/types"
|
||||||
"github.com/lmika/awstools/internal/ssm-browse/models"
|
"github.com/lmika/awstools/internal/ssm-browse/models"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultKMSKeyIDForSecureStrings = "alias/aws/ssm"
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
client *ssm.Client
|
client *ssm.Client
|
||||||
}
|
}
|
||||||
|
@ -29,7 +32,8 @@ func (p *Provider) List(ctx context.Context, prefix string, maxCount int) (*mode
|
||||||
})
|
})
|
||||||
|
|
||||||
items := make([]models.SSMParameter, 0)
|
items := make([]models.SSMParameter, 0)
|
||||||
outer: for pager.HasMorePages() {
|
outer:
|
||||||
|
for pager.HasMorePages() {
|
||||||
out, err := pager.NextPage(ctx)
|
out, err := pager.NextPage(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot get parameters from path")
|
return nil, errors.Wrap(err, "cannot get parameters from path")
|
||||||
|
@ -38,6 +42,7 @@ func (p *Provider) List(ctx context.Context, prefix string, maxCount int) (*mode
|
||||||
for _, p := range out.Parameters {
|
for _, p := range out.Parameters {
|
||||||
items = append(items, models.SSMParameter{
|
items = append(items, models.SSMParameter{
|
||||||
Name: aws.ToString(p.Name),
|
Name: aws.ToString(p.Name),
|
||||||
|
Type: p.Type,
|
||||||
Value: aws.ToString(p.Value),
|
Value: aws.ToString(p.Value),
|
||||||
})
|
})
|
||||||
if len(items) >= maxCount {
|
if len(items) >= maxCount {
|
||||||
|
@ -48,3 +53,22 @@ func (p *Provider) List(ctx context.Context, prefix string, maxCount int) (*mode
|
||||||
|
|
||||||
return &models.SSMParameters{Items: items}, nil
|
return &models.SSMParameters{Items: items}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) Put(ctx context.Context, param models.SSMParameter, override bool) error {
|
||||||
|
in := &ssm.PutParameterInput{
|
||||||
|
Name: aws.String(param.Name),
|
||||||
|
Type: param.Type,
|
||||||
|
Value: aws.String(param.Value),
|
||||||
|
Overwrite: override,
|
||||||
|
}
|
||||||
|
if param.Type == types.ParameterTypeSecureString {
|
||||||
|
in.KeyId = aws.String(defaultKMSKeyIDForSecureStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := p.client.PutParameter(ctx, in)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "unable to put new SSM parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -7,4 +7,5 @@ import (
|
||||||
|
|
||||||
type SSMProvider interface {
|
type SSMProvider interface {
|
||||||
List(ctx context.Context, prefix string, maxCount int) (*models.SSMParameters, error)
|
List(ctx context.Context, prefix string, maxCount int) (*models.SSMParameters, error)
|
||||||
|
Put(ctx context.Context, param models.SSMParameter, override bool) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,3 +18,12 @@ func NewService(provider SSMProvider) *Service {
|
||||||
func (s *Service) List(ctx context.Context, prefix string) (*models.SSMParameters, error) {
|
func (s *Service) List(ctx context.Context, prefix string) (*models.SSMParameters, error) {
|
||||||
return s.provider.List(ctx, prefix, 100)
|
return s.provider.List(ctx, prefix, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) Clone(ctx context.Context, param models.SSMParameter, newName string) error {
|
||||||
|
newParam := models.SSMParameter{
|
||||||
|
Name: newName,
|
||||||
|
Type: param.Type,
|
||||||
|
Value: param.Value,
|
||||||
|
}
|
||||||
|
return s.provider.Put(ctx, newParam, false)
|
||||||
|
}
|
|
@ -3,11 +3,13 @@ package ui
|
||||||
import (
|
import (
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
"github.com/lmika/awstools/internal/common/ui/commandctrl"
|
||||||
|
"github.com/lmika/awstools/internal/common/ui/events"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
|
||||||
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/statusandprompt"
|
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/statusandprompt"
|
||||||
"github.com/lmika/awstools/internal/ssm-browse/controllers"
|
"github.com/lmika/awstools/internal/ssm-browse/controllers"
|
||||||
"github.com/lmika/awstools/internal/ssm-browse/ui/ssmdetails"
|
"github.com/lmika/awstools/internal/ssm-browse/ui/ssmdetails"
|
||||||
"github.com/lmika/awstools/internal/ssm-browse/ui/ssmlist"
|
"github.com/lmika/awstools/internal/ssm-browse/ui/ssmlist"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
|
@ -27,6 +29,17 @@ func NewModel(controller *controllers.SSMController, cmdController *commandctrl.
|
||||||
layout.NewVBox(layout.LastChildFixedAt(17), ssmList, ssmdDetails),
|
layout.NewVBox(layout.LastChildFixedAt(17), ssmList, ssmdDetails),
|
||||||
"")
|
"")
|
||||||
|
|
||||||
|
cmdController.AddCommands(&commandctrl.CommandContext{
|
||||||
|
Commands: map[string]commandctrl.Command{
|
||||||
|
"clone": func(args []string) tea.Cmd {
|
||||||
|
if currentParam := ssmList.CurrentParameter(); currentParam != nil {
|
||||||
|
return controller.Clone(*currentParam)
|
||||||
|
}
|
||||||
|
return events.SetError(errors.New("no parameter selected"))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
root := layout.FullScreen(statusAndPrompt)
|
root := layout.FullScreen(statusAndPrompt)
|
||||||
|
|
||||||
return Model{
|
return Model{
|
||||||
|
|
|
@ -85,6 +85,14 @@ func (m *Model) emitNewSelectedParameter() tea.Cmd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) CurrentParameter() *models.SSMParameter {
|
||||||
|
if row, ok := m.table.SelectedRow().(itemTableRow); ok {
|
||||||
|
return &(row.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Model) View() string {
|
func (m *Model) View() string {
|
||||||
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.table.View())
|
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.table.View())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue