ssm-browse: new utility to browse SSM parameters

This is more of an exercise to work out how best to use controllers
This commit is contained in:
Leon Mika 2022-03-29 08:41:27 +11:00
parent 46be54b5fb
commit 0b745a6dfa
14 changed files with 348 additions and 5 deletions

View file

@ -0,0 +1,7 @@
package controllers
import "github.com/lmika/awstools/internal/ssm-browse/models"
type NewParameterListMsg struct {
Parameters *models.SSMParameters
}

View file

@ -0,0 +1,31 @@
package controllers
import (
"context"
tea "github.com/charmbracelet/bubbletea"
"github.com/lmika/awstools/internal/common/ui/events"
"github.com/lmika/awstools/internal/ssm-browse/services/ssmparameters"
)
type SSMController struct {
service *ssmparameters.Service
}
func New(service *ssmparameters.Service) *SSMController {
return &SSMController{
service: service,
}
}
func (c *SSMController) Fetch() tea.Cmd {
return func() tea.Msg {
res, err := c.service.List(context.Background())
if err != nil {
return events.Error(err)
}
return NewParameterListMsg{
Parameters: res,
}
}
}

View file

@ -0,0 +1,10 @@
package models
type SSMParameters struct {
Items []SSMParameter
}
type SSMParameter struct {
Name string
Value string
}

View file

@ -0,0 +1,42 @@
package awsssm
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ssm"
"github.com/lmika/awstools/internal/ssm-browse/models"
"github.com/pkg/errors"
)
type Provider struct {
client *ssm.Client
}
func NewProvider(client *ssm.Client) *Provider {
return &Provider{
client: client,
}
}
func (p *Provider) List(ctx context.Context) (*models.SSMParameters, error) {
pars, err := p.client.GetParametersByPath(ctx, &ssm.GetParametersByPathInput{
Path: aws.String("/"),
MaxResults: 10,
Recursive: true,
})
if err != nil {
return nil, errors.Wrap(err, "cannot get parameters from path")
}
res := &models.SSMParameters{
Items: make([]models.SSMParameter, len(pars.Parameters)),
}
for i, p := range pars.Parameters {
res.Items[i] = models.SSMParameter{
Name: aws.ToString(p.Name),
Value: aws.ToString(p.Value),
}
}
return res, nil
}

View file

@ -0,0 +1,10 @@
package ssmparameters
import (
"context"
"github.com/lmika/awstools/internal/ssm-browse/models"
)
type SSMProvider interface {
List(ctx context.Context) (*models.SSMParameters, error)
}

View file

@ -0,0 +1,20 @@
package ssmparameters
import (
"context"
"github.com/lmika/awstools/internal/ssm-browse/models"
)
type Service struct {
provider SSMProvider
}
func NewService(provider SSMProvider) *Service {
return &Service{
provider: provider,
}
}
func (s *Service) List(ctx context.Context) (*models.SSMParameters, error) {
return s.provider.List(ctx)
}

View file

@ -0,0 +1,55 @@
package ui
import (
tea "github.com/charmbracelet/bubbletea"
"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/ssm-browse/controllers"
"github.com/lmika/awstools/internal/ssm-browse/ui/ssmlist"
)
type Model struct {
controller *controllers.SSMController
root tea.Model
ssmList *ssmlist.Model
}
func NewModel(controller *controllers.SSMController) Model {
ssmList := ssmlist.New()
root := layout.FullScreen(
statusandprompt.New(ssmList, "Hello SSM"),
)
return Model{
controller: controller,
root: root,
ssmList: ssmList,
}
}
func (m Model) Init() tea.Cmd {
return m.controller.Fetch()
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case controllers.NewParameterListMsg:
m.ssmList.SetParameters(msg.Parameters)
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
}
}
newRoot, cmd := m.root.Update(msg)
m.root = newRoot
return m, cmd
}
func (m Model) View() string {
return m.root.View()
}

View file

@ -0,0 +1,69 @@
package ssmlist
import (
table "github.com/calyptia/go-bubble-table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/frame"
"github.com/lmika/awstools/internal/dynamo-browse/ui/teamodels/layout"
"github.com/lmika/awstools/internal/ssm-browse/models"
)
type Model struct {
frameTitle frame.FrameTitle
table table.Model
parameters *models.SSMParameters
w, h int
}
func New() *Model {
frameTitle := frame.NewFrameTitle("SSM", true)
table := table.New([]string{"name", "type", "value"}, 0, 0)
return &Model{
frameTitle: frameTitle,
table: table,
}
}
func (m *Model) SetParameters(parameters *models.SSMParameters) {
m.parameters = parameters
cols := []string{"name", "type", "value"}
newTbl := table.New(cols, m.w, m.h-m.frameTitle.HeaderHeight())
newRows := make([]table.Row, len(parameters.Items))
for i, r := range parameters.Items {
newRows[i] = itemTableRow{r}
}
newTbl.SetRows(newRows)
m.table = newTbl
}
func (m *Model) Init() tea.Cmd {
return nil
}
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
m.table, cmd = m.table.Update(msg)
return m, cmd
}
return m, nil
}
func (m *Model) View() string {
return lipgloss.JoinVertical(lipgloss.Top, m.frameTitle.View(), m.table.View())
}
func (m *Model) Resize(w, h int) layout.ResizingModel {
m.w, m.h = w, h
m.frameTitle.Resize(w, h)
m.table.SetSize(w, h - m.frameTitle.HeaderHeight())
return m
}

View file

@ -0,0 +1,22 @@
package ssmlist
import (
"fmt"
table "github.com/calyptia/go-bubble-table"
"github.com/lmika/awstools/internal/ssm-browse/models"
"io"
)
type itemTableRow struct {
item models.SSMParameter
}
func (mtr itemTableRow) Render(w io.Writer, model table.Model, index int) {
line := fmt.Sprintf("%s\t%s\t%s", mtr.item.Name, "String", mtr.item.Value)
if index == model.Cursor() {
fmt.Fprintln(w, model.Styles.SelectedRow.Render(line))
} else {
fmt.Fprintln(w, line)
}
}