// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package tui import ( "context" "fmt" "time" "github.com/aws/amazon-ec2-spot-interrupter/pkg/itn" ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" ) type options struct { instances []*ec2types.Instance ctx context.Context itn *itn.ITN textInput textinput.Model validationMsg string processingOpts bool } func NewOptions(ctx context.Context, itn *itn.ITN, instances []*ec2types.Instance) options { ti := textinput.New() ti.SetValue("15s") ti.Focus() ti.CharLimit = 20 ti.Width = 20 return options{ ctx: ctx, itn: itn, instances: instances, textInput: ti, } } type startInterruptMsg bool func (o options) Init() tea.Cmd { return textinput.Blink } func (o options) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { case startInterruptMsg: var instanceIDs []string for _, instance := range o.instances { instanceIDs = append(instanceIDs, *instance.InstanceId) } delay, err := o.validateDelay() if err != nil { o.textInput, cmd = o.textInput.Update(msg) return o, cmd } experiment, events, err := o.itn.Interrupt(o.ctx, instanceIDs, delay, true) if err != nil { fmt.Printf("❌ %s\n", err) return o, tea.Quit } monitor := NewMonitor(experiment, events) return monitor, monitor.Init() case tea.KeyMsg: switch msg.String() { case "ctrl+c", "q": return o, tea.Quit case "enter": o.processingOpts = true return o, func() tea.Msg { return startInterruptMsg(true) } } } o.textInput, cmd = o.textInput.Update(msg) return o, cmd } func (o *options) validateDelay() (time.Duration, error) { delay, err := time.ParseDuration(o.textInput.Value()) if err != nil { o.validationMsg = "❌ invalid duration format (example: 1m)" return delay, fmt.Errorf("invalid duration format: %v", err) } o.validationMsg = "✅" return delay, err } func (o options) View() string { if o.processingOpts { return fmt.Sprintf("Creating Interruption Experiment \n%s", help()) } return fmt.Sprintf( "How long to wait before sending the interruption notifications?\n%s\n%s\n%s", o.textInput.View(), o.validationMsg, help(), ) }