github.com/mweagle/Sparta@v1.15.0/explore.go (about)

     1  // +build !lambdabinary
     2  
     3  package sparta
     4  
     5  import (
     6  	"github.com/aws/aws-sdk-go/aws"
     7  	"github.com/aws/aws-sdk-go/service/cloudformation"
     8  	broadcast "github.com/dustin/go-broadcast"
     9  	"github.com/gdamore/tcell"
    10  	spartaAWS "github.com/mweagle/Sparta/aws"
    11  	"github.com/rivo/tview"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  const (
    16  	broadcasterFunctionSelect = "functionSelect"
    17  	broadcasterFileSubmit     = "fileSubmit"
    18  )
    19  
    20  ////////////////////////////////////////////////////////////////////////////////
    21  //
    22  // Public
    23  //
    24  
    25  // ExploreWithInputFilter allows the caller to provide additional filters
    26  // for the source files that will be used as inputs
    27  func ExploreWithInputFilter(serviceName string,
    28  	serviceDescription string,
    29  	lambdaAWSInfos []*LambdaAWSInfo,
    30  	api APIGateway,
    31  	site *S3Site,
    32  	inputExtensions []string,
    33  	s3BucketName string,
    34  	buildTags string,
    35  	linkerFlags string,
    36  	logger *logrus.Logger) error {
    37  
    38  	// Great - everybody get's an aws session
    39  	awsSession := spartaAWS.NewSession(logger)
    40  	// Go get the stack and put the ARNs in the list of things. For that
    41  	// we need to get the stack resources...
    42  	cfSvc := cloudformation.New(awsSession)
    43  	input := &cloudformation.DescribeStackResourcesInput{
    44  		StackName: aws.String(serviceName),
    45  	}
    46  	stackResourceOutputs, stackResourceOutputsErr := cfSvc.DescribeStackResources(input)
    47  	if stackResourceOutputsErr != nil {
    48  		return stackResourceOutputsErr
    49  	}
    50  
    51  	// Load the settings
    52  	settingsMap := loadSettings()
    53  
    54  	// Make the channel map
    55  	channelMap := make(map[string]broadcast.Broadcaster)
    56  	channelMap[broadcasterFunctionSelect] = broadcast.NewBroadcaster(1)
    57  	channelMap[broadcasterFileSubmit] = broadcast.NewBroadcaster(1)
    58  	application := tview.NewApplication()
    59  
    60  	// That's the list of functions, which we can map up against the operations to perform
    61  	// Create the logger first, since it will change the output sink
    62  	logView, logViewFocusable := newLogOutputView(awsSession,
    63  		application,
    64  		lambdaAWSInfos,
    65  		settingsMap,
    66  		logger)
    67  
    68  	focusTargets := []tview.Primitive{}
    69  	dropdown, selectorFocusable := newFunctionSelector(awsSession,
    70  		stackResourceOutputs.StackResources,
    71  		application,
    72  		lambdaAWSInfos,
    73  		settingsMap,
    74  		channelMap[broadcasterFunctionSelect],
    75  		logger)
    76  	eventDropdown, eventFocusable := newEventInputSelector(awsSession,
    77  		application,
    78  		lambdaAWSInfos,
    79  		settingsMap,
    80  		inputExtensions,
    81  		channelMap[broadcasterFunctionSelect],
    82  		logger)
    83  	outputView, outputViewFocusable := newCloudWatchLogTailView(awsSession,
    84  		application,
    85  		lambdaAWSInfos,
    86  		settingsMap,
    87  		channelMap[broadcasterFunctionSelect],
    88  		logger)
    89  
    90  	// There are four primary views
    91  	if selectorFocusable != nil {
    92  		focusTargets = append(focusTargets, selectorFocusable...)
    93  	}
    94  	if eventFocusable != nil {
    95  		focusTargets = append(focusTargets, eventFocusable...)
    96  	}
    97  	if logViewFocusable != nil {
    98  		focusTargets = append(focusTargets, logViewFocusable...)
    99  	}
   100  	if outputViewFocusable != nil {
   101  		focusTargets = append(focusTargets, outputViewFocusable...)
   102  	}
   103  
   104  	// Make it easy and use a Flex layout...
   105  	flex := tview.NewFlex().
   106  		SetDirection(tview.FlexRow).
   107  		AddItem(dropdown, 3, 0, true).
   108  		AddItem(tview.NewFlex().
   109  			SetDirection(tview.FlexColumn).
   110  			AddItem(eventDropdown, 0, 1, false).
   111  			AddItem(logView, 0, 2, false), 0, 1, false).
   112  		AddItem(outputView, 0, 1, false)
   113  
   114  	// Run  it...
   115  	application.SetRoot(flex, true).SetFocus(flex)
   116  	currentIndex := 0
   117  	application.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
   118  		logger.WithFields(logrus.Fields{
   119  			"Key":      event.Key(),
   120  			"Name":     event.Name(),
   121  			"Modifier": event.Modifiers(),
   122  		}).Debug("Input key")
   123  
   124  		switch event.Key() {
   125  		case tcell.KeyTab,
   126  			tcell.KeyBacktab:
   127  
   128  			direction := 1
   129  			if event.Key() == tcell.KeyBacktab {
   130  				direction = -1
   131  			}
   132  			nextIndex := (currentIndex + direction*1) % len(focusTargets)
   133  			application.SetFocus(focusTargets[nextIndex])
   134  			currentIndex = nextIndex
   135  		default:
   136  			// NOP
   137  		}
   138  		return event
   139  	})
   140  	return application.Run()
   141  
   142  }
   143  
   144  // Explore is an interactive command that brings up a GUI to test
   145  // lambda functions previously deployed into AWS lambda. It's not supported in the
   146  // AWS binary build
   147  func Explore(serviceName string,
   148  	serviceDescription string,
   149  	lambdaAWSInfos []*LambdaAWSInfo,
   150  	api APIGateway,
   151  	site *S3Site,
   152  	s3BucketName string,
   153  	buildTags string,
   154  	linkerFlags string,
   155  	logger *logrus.Logger) error {
   156  
   157  	return ExploreWithInputFilter(serviceName,
   158  		serviceDescription,
   159  		lambdaAWSInfos,
   160  		api,
   161  		site,
   162  		[]string{"json"},
   163  		s3BucketName,
   164  		buildTags,
   165  		linkerFlags,
   166  		logger)
   167  }