Skip to content

Commit

Permalink
Add events command to view ECS events for a service
Browse files Browse the repository at this point in the history
  • Loading branch information
ipmb committed Nov 14, 2021
1 parent 10abb65 commit fa06a35
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
22 changes: 22 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,28 @@ func (a *App) DescribeTasks() ([]*ecs.Task, error) {
return appTasks, nil
}

func (a *App) GetECSEvents(service string) ([]*ecs.ServiceEvent, error) {
ecsSvc := ecs.New(a.Session)
a.LoadSettings()
logrus.WithFields(logrus.Fields{"service": service}).Debug("fetching service events")
serviceStatus, err := ecsSvc.DescribeServices(&ecs.DescribeServicesInput{
Cluster: &a.Settings.Cluster.ARN,
Services: aws.StringSlice([]string{fmt.Sprintf("%s-%s", a.Name, service)}),
})
if err != nil {
return nil, err
}
if len(serviceStatus.Services) == 0 {
return nil, fmt.Errorf("could not find service %s", service)
}
events := serviceStatus.Services[0].Events
// reverse events so the oldest is first
for i, j := 0, len(events)-1; i < j; i, j = i+1, j-1 {
events[i], events[j] = events[j], events[i]
}
return events, nil
}

func (a *App) DBDumpLocation(prefix string) (*s3.GetObjectInput, error) {
currentTime := time.Now()
username, err := auth.WhoAmI()
Expand Down
106 changes: 106 additions & 0 deletions cmd/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License 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 cmd

import (
"fmt"
"strings"
"time"

"github.com/apppackio/apppack/app"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/logrusorgru/aurora"
"github.com/spf13/cobra"
)

func printEvent(event *ecs.ServiceEvent) {
fmt.Println(aurora.Faint(event.CreatedAt.Local().Format("Jan 02, 2006 15:04:05 MST")), *event.Message)
}

// eventsCmd represents the events command
var eventsCmd = &cobra.Command{
Use: "events <service>",
Short: "Show recent events for the given service",
Example: "apppack -a my-app events web",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName, UseAWSCredentials, SessionDurationSeconds)
checkErr(err)
events, err := a.GetECSEvents(args[0])
checkErr(err)
waitForSteadyState := cmd.Flag("wait-for-steady").Value.String() == "true"
Spinner.Stop()
fmt.Println("⏳", aurora.Blue(fmt.Sprintf("waiting for `%s` service to reach a steady state...", args[0])))
for _, event := range events {
// when waiting for steady, only show the last minute of events to start
if !waitForSteadyState || event.CreatedAt.After(time.Now().Add(-time.Minute)) {
printEvent(event)
}
}
if !waitForSteadyState {
return
}
startSpinner()
// if no events, wait for some to come in
if len(events) == 0 {
for {
events, err = a.GetECSEvents(args[0])
checkErr(err)
if len(events) > 0 {
break
}
time.Sleep(time.Second * 5)
}
}
cursor := *events[len(events)-1].Id
startEventTime := events[0].CreatedAt
for {
events, err := a.GetECSEvents(args[0])
checkErr(err)
lastEvent := events[len(events)-1]
// no new events, sleep and check again
if *lastEvent.Id == cursor {
time.Sleep(time.Second * 5)
continue
}
Spinner.Stop()
display := false
// loop through events, only printing new ones and break on steady state
for _, event := range events {
if display {
printEvent(event)
if strings.Contains(*event.Message, "has reached a steady state") && event.CreatedAt.After(*startEventTime) {
return
}
} else if *event.Id == cursor {
display = true
}
}
startSpinner()
cursor = *lastEvent.Id
time.Sleep(time.Second * 5)
}
},
}

func init() {
rootCmd.AddCommand(eventsCmd)
eventsCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
eventsCmd.MarkPersistentFlagRequired("app-name")
eventsCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")
eventsCmd.Flags().BoolP("wait-for-steady", "w", false, "wait for service to reach a steady state")
}

0 comments on commit fa06a35

Please sign in to comment.