Skip to content

Commit

Permalink
Add support for ssh command in beanstalk apps (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
BSick7 authored Jan 16, 2024
1 parent 02d3944 commit 0f7d8e8
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 17 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 0.0.108 (Jan 16, 2024)
* Added support for `nullstone ssh` and `nullstone exec` to Elastic Beanstalk apps.

# 0.0.107 (Dec 18, 2023)
* Added log streaming support for multiple cloudwatch log groups. (Use `/*` suffix to look for multiple cloudwatch log groups)
* Moved `LogStreamer` implementations to github.com/nullstone-io/deployment-sdk.
Expand Down
3 changes: 2 additions & 1 deletion admin/all/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package all
import (
"gopkg.in/nullstone-io/go-api-client.v0/types"
"gopkg.in/nullstone-io/nullstone.v0/admin"
"gopkg.in/nullstone-io/nullstone.v0/aws/beanstalk"
"gopkg.in/nullstone-io/nullstone.v0/aws/ec2"
"gopkg.in/nullstone-io/nullstone.v0/aws/ecs"
"gopkg.in/nullstone-io/nullstone.v0/gcp/gke"
Expand Down Expand Up @@ -59,7 +60,7 @@ var (
},
beanstalkContract: admin.Provider{
NewStatuser: nil, // TODO: beanstalk.NewStatuser
NewRemoter: ec2.NewRemoter,
NewRemoter: beanstalk.NewRemoter,
},
ec2Contract: admin.Provider{
NewStatuser: nil,
Expand Down
2 changes: 2 additions & 0 deletions admin/remoter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
)

type RemoteOptions struct {
// Instance refers to the VM Instance for remote access
Instance string
// Task refers to the ECS task id for remote access if using ECS
Task string
// Pod refers to the k8s pod for remote access if using k8s
Expand Down
34 changes: 34 additions & 0 deletions aws/beanstalk/get_instances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package beanstalk

import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk"
)

func GetInstances(ctx context.Context, infra Outputs) ([]string, error) {
client := elasticbeanstalk.NewFromConfig(infra.AdminerConfig())
out, err := client.DescribeEnvironmentResources(ctx, &elasticbeanstalk.DescribeEnvironmentResourcesInput{
EnvironmentId: aws.String(infra.EnvironmentId),
})
if err != nil {
return nil, err
}
instanceIds := make([]string, 0)
for _, instance := range out.EnvironmentResources.Instances {
instanceIds = append(instanceIds, *instance.Id)
}
return instanceIds, nil
}

func GetRandomInstance(ctx context.Context, infra Outputs) (string, error) {
instanceIds, err := GetInstances(ctx, infra)
if err != nil {
return "", err
}

for _, instanceId := range instanceIds {
return instanceId, nil
}
return "", nil
}
17 changes: 17 additions & 0 deletions aws/beanstalk/outputs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package beanstalk

import (
"github.com/aws/aws-sdk-go-v2/aws"
nsaws "github.com/nullstone-io/deployment-sdk/aws"
)

type Outputs struct {
Region string `ns:"region"`
BeanstalkArn string `ns:"beanstalk_arn"`
EnvironmentId string `ns:"environment_id"`
Adminer nsaws.User `ns:"adminer,optional"`
}

func (o Outputs) AdminerConfig() aws.Config {
return nsaws.NewConfig(o.Adminer, o.Region)
}
66 changes: 66 additions & 0 deletions aws/beanstalk/remoter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package beanstalk

import (
"context"
"fmt"
"github.com/nullstone-io/deployment-sdk/app"
"github.com/nullstone-io/deployment-sdk/logging"
"github.com/nullstone-io/deployment-sdk/outputs"
"gopkg.in/nullstone-io/go-api-client.v0"
"gopkg.in/nullstone-io/nullstone.v0/admin"
"gopkg.in/nullstone-io/nullstone.v0/aws/ssm"
)

func NewRemoter(osWriters logging.OsWriters, nsConfig api.Config, appDetails app.Details) (admin.Remoter, error) {
outs, err := outputs.Retrieve[Outputs](nsConfig, appDetails.Workspace)
if err != nil {
return nil, err
}

return Remoter{
OsWriters: osWriters,
Details: appDetails,
Infra: outs,
}, nil
}

type Remoter struct {
OsWriters logging.OsWriters
Details app.Details
Infra Outputs
}

func (r Remoter) Exec(ctx context.Context, options admin.RemoteOptions, cmd []string) error {
// TODO: Add support for cmd
instanceId, err := r.getInstanceId(ctx, options)
if err != nil {
return err
}
return ssm.StartEc2Session(ctx, r.Infra.AdminerConfig(), r.Infra.Region, instanceId, nil)
}

func (r Remoter) Ssh(ctx context.Context, options admin.RemoteOptions) error {
parameters, err := ssm.SessionParametersFromPortForwards(options.PortForwards)
if err != nil {
return err
}

instanceId, err := r.getInstanceId(ctx, options)
if err != nil {
return err
}
return ssm.StartEc2Session(ctx, r.Infra.AdminerConfig(), r.Infra.Region, instanceId, parameters)
}

func (r Remoter) getInstanceId(ctx context.Context, options admin.RemoteOptions) (string, error) {
if options.Instance == "" {
if instanceId, err := GetRandomInstance(ctx, r.Infra); err != nil {
return "", err
} else if instanceId == "" {
return "", fmt.Errorf("cannot exec command with no running instances")
} else {
return instanceId, nil
}
}
return options.Instance, nil
}
14 changes: 0 additions & 14 deletions aws/ec2/exec_command.go

This file was deleted.

5 changes: 5 additions & 0 deletions aws/ec2/outputs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ec2

import (
"github.com/aws/aws-sdk-go-v2/aws"
nsaws "github.com/nullstone-io/deployment-sdk/aws"
)

Expand All @@ -9,3 +10,7 @@ type Outputs struct {
InstanceId string `ns:"instance_id"`
Adminer nsaws.User `ns:"adminer,optional"`
}

func (o Outputs) AdminerConfig() aws.Config {
return nsaws.NewConfig(o.Adminer, o.Region)
}
5 changes: 3 additions & 2 deletions aws/ec2/remoter.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ type Remoter struct {
}

func (r Remoter) Exec(ctx context.Context, options admin.RemoteOptions, cmd []string) error {
return ExecCommand(ctx, r.Infra, cmd, nil)
// TODO: Add support for cmd
return ssm.StartEc2Session(ctx, r.Infra.AdminerConfig(), r.Infra.Region, r.Infra.InstanceId, nil)
}

func (r Remoter) Ssh(ctx context.Context, options admin.RemoteOptions) error {
Expand All @@ -39,5 +40,5 @@ func (r Remoter) Ssh(ctx context.Context, options admin.RemoteOptions) error {
return err
}

return ExecCommand(ctx, r.Infra, []string{"/bin/sh"}, parameters)
return ssm.StartEc2Session(ctx, r.Infra.AdminerConfig(), r.Infra.Region, r.Infra.InstanceId, parameters)
}
2 changes: 2 additions & 0 deletions cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var Exec = func(appProviders app.Providers, providers admin.Providers) *cli.Comm
StackFlag,
AppFlag,
EnvFlag,
InstanceFlag,
TaskFlag,
PodFlag,
ContainerFlag,
Expand Down Expand Up @@ -53,6 +54,7 @@ var Exec = func(appProviders app.Providers, providers admin.Providers) *cli.Comm
return err
}
options := admin.RemoteOptions{
Instance: c.String("instance"),
Task: c.String("task"),
Pod: c.String("pod"),
Container: c.String("container"),
Expand Down
7 changes: 7 additions & 0 deletions cmd/flag_ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ package cmd

import "github.com/urfave/cli/v2"

var InstanceFlag = &cli.StringFlag{
Name: "instance",
Usage: `Select a specific instance to execute the command against.
This allows the user to decide which instance to connect.
This is optional and by default will connect to a random instance.
This is only used for workspaces that use VMs (e.g. Elastic Beanstalk, EC2 Instances, GCP VMs, Azure VMs, etc.).`,
}
var TaskFlag = &cli.StringFlag{
Name: "task",
Usage: `Select a specific task to execute the command against.
Expand Down
2 changes: 2 additions & 0 deletions cmd/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var Ssh = func(providers admin.Providers) *cli.Command {
StackFlag,
AppFlag,
EnvFlag,
InstanceFlag,
TaskFlag,
PodFlag,
ContainerFlag,
Expand Down Expand Up @@ -52,6 +53,7 @@ var Ssh = func(providers admin.Providers) *cli.Command {
appDetails.App.Name, module.OrgName, module.Name, module.Subcategory, platform)
}
options := admin.RemoteOptions{
Instance: c.String("instance"),
Task: c.String("task"),
Pod: c.String("pod"),
Container: c.String("container"),
Expand Down

0 comments on commit 0f7d8e8

Please sign in to comment.