mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-26 15:27:53 -05:00
Remove cli/ec2
This commit is contained in:
parent
064151a956
commit
6a9419e89c
@ -397,8 +397,6 @@ func readOrGeneratedMasterSecret(w io.Writer, fileHandler file.Handler, filename
|
||||
|
||||
func getScalingGroupsFromConfig(stat state.ConstellationState, config *config.Config) (coordinators, nodes ScalingGroup, err error) {
|
||||
switch {
|
||||
case len(stat.EC2Instances) != 0:
|
||||
return getAWSInstances(stat)
|
||||
case len(stat.GCPCoordinators) != 0:
|
||||
return getGCPInstances(stat, config)
|
||||
case len(stat.AzureCoordinators) != 0:
|
||||
@ -410,39 +408,6 @@ func getScalingGroupsFromConfig(stat state.ConstellationState, config *config.Co
|
||||
}
|
||||
}
|
||||
|
||||
func getAWSInstances(stat state.ConstellationState) (coordinators, nodes ScalingGroup, err error) {
|
||||
coordinatorID, _, err := stat.EC2Instances.GetOne()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
coordinatorMap := stat.EC2Instances
|
||||
var coordinatorInstances Instances
|
||||
for _, node := range coordinatorMap {
|
||||
coordinatorInstances = append(coordinatorInstances, Instance(node))
|
||||
}
|
||||
// GroupID of coordinators is empty, since they currently do not scale.
|
||||
coordinators = ScalingGroup{
|
||||
Instances: coordinatorInstances,
|
||||
GroupID: "",
|
||||
}
|
||||
|
||||
nodeMap := stat.EC2Instances.GetOthers(coordinatorID)
|
||||
if len(nodeMap) == 0 {
|
||||
return ScalingGroup{}, ScalingGroup{}, errors.New("no worker nodes available, can't create Constellation cluster with one instance")
|
||||
}
|
||||
|
||||
var nodeInstances Instances
|
||||
for _, node := range nodeMap {
|
||||
nodeInstances = append(nodeInstances, Instance(node))
|
||||
}
|
||||
|
||||
// TODO: make min / max configurable and abstract autoscaling for different cloud providers
|
||||
// TODO: GroupID of workers is empty, since they currently do not scale.
|
||||
nodes = ScalingGroup{Instances: nodeInstances, GroupID: ""}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getGCPInstances(stat state.ConstellationState, config *config.Config) (coordinators, nodes ScalingGroup, err error) {
|
||||
coordinatorMap := stat.GCPCoordinators
|
||||
if len(coordinatorMap) == 0 {
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/file"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
@ -167,15 +166,12 @@ func TestInitialize(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
"no instances to pick one": {
|
||||
existingState: state.ConstellationState{
|
||||
EC2Instances: ec2.Instances{},
|
||||
EC2SecurityGroup: "sg-test",
|
||||
},
|
||||
client: &stubProtoClient{},
|
||||
waiter: &stubStatusWaiter{},
|
||||
privKey: testKey,
|
||||
vpnHandler: &stubVPNHandler{},
|
||||
wantErr: true,
|
||||
existingState: state.ConstellationState{GCPNodes: cloudtypes.Instances{}},
|
||||
client: &stubProtoClient{},
|
||||
waiter: &stubStatusWaiter{},
|
||||
privKey: testKey,
|
||||
vpnHandler: &stubVPNHandler{},
|
||||
wantErr: true,
|
||||
},
|
||||
"public key to short": {
|
||||
existingState: testGcpState,
|
||||
|
@ -1,42 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
)
|
||||
|
||||
// api collects used functions of AWS' ec2.Client as interfaces to enable testing.
|
||||
type api interface {
|
||||
ec2.DescribeInstancesAPIClient
|
||||
|
||||
// Instances
|
||||
RunInstances(ctx context.Context,
|
||||
params *ec2.RunInstancesInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.RunInstancesOutput, error)
|
||||
|
||||
TerminateInstances(ctx context.Context,
|
||||
params *ec2.TerminateInstancesInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.TerminateInstancesOutput, error)
|
||||
|
||||
CreateTags(ctx context.Context,
|
||||
params *ec2.CreateTagsInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.CreateTagsOutput, error)
|
||||
|
||||
// SecurityGroup
|
||||
CreateSecurityGroup(ctx context.Context,
|
||||
params *ec2.CreateSecurityGroupInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.CreateSecurityGroupOutput, error)
|
||||
|
||||
DeleteSecurityGroup(ctx context.Context,
|
||||
params *ec2.DeleteSecurityGroupInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.DeleteSecurityGroupOutput, error)
|
||||
|
||||
AuthorizeSecurityGroupIngress(ctx context.Context,
|
||||
params *ec2.AuthorizeSecurityGroupIngressInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.AuthorizeSecurityGroupIngressOutput, error)
|
||||
|
||||
AuthorizeSecurityGroupEgress(ctx context.Context,
|
||||
params *ec2.AuthorizeSecurityGroupEgressInput,
|
||||
optFns ...func(*ec2.Options)) (*ec2.AuthorizeSecurityGroupEgressOutput, error)
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/aws/smithy-go"
|
||||
)
|
||||
|
||||
// stubAPI is a stub ec2 api for testing.
|
||||
type stubAPI struct {
|
||||
instances []types.Instance
|
||||
securityGroup types.SecurityGroup
|
||||
|
||||
describeInstancesErr error
|
||||
runInstancesErr error
|
||||
runInstancesDryRunErr *error
|
||||
terminateInstancesErr error
|
||||
terminateInstancesDryRunErr *error
|
||||
createTagsErr error
|
||||
createSecurityGroupErr error
|
||||
createSecurityGroupDryRunErr *error
|
||||
deleteSecurityGroupErr error
|
||||
deleteSecurityGroupDryRunErr *error
|
||||
authorizeSecurityGroupIngressErr error
|
||||
authorizeSecurityGroupIngressDryRunErr *error
|
||||
authorizeSecurityGroupEgressErr error
|
||||
authorizeSecurityGroupEgressDryRunErr *error
|
||||
}
|
||||
|
||||
func (a stubAPI) DescribeInstances(ctx context.Context,
|
||||
params *ec2.DescribeInstancesInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.DescribeInstancesOutput, error) {
|
||||
return &ec2.DescribeInstancesOutput{
|
||||
Reservations: []types.Reservation{
|
||||
{Instances: a.instances},
|
||||
},
|
||||
}, a.describeInstancesErr
|
||||
}
|
||||
|
||||
func (a stubAPI) RunInstances(ctx context.Context,
|
||||
params *ec2.RunInstancesInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.RunInstancesOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.runInstancesDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ec2.RunInstancesOutput{Instances: a.instances}, a.runInstancesErr
|
||||
}
|
||||
|
||||
func (a stubAPI) CreateTags(ctx context.Context,
|
||||
params *ec2.CreateTagsInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.CreateTagsOutput, error) {
|
||||
return nil, a.createTagsErr
|
||||
}
|
||||
|
||||
func (a stubAPI) TerminateInstances(ctx context.Context,
|
||||
params *ec2.TerminateInstancesInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.TerminateInstancesOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.terminateInstancesDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, a.terminateInstancesErr
|
||||
}
|
||||
|
||||
func (a stubAPI) CreateSecurityGroup(ctx context.Context,
|
||||
params *ec2.CreateSecurityGroupInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.CreateSecurityGroupOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.createSecurityGroupDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ec2.CreateSecurityGroupOutput{
|
||||
GroupId: a.securityGroup.GroupId,
|
||||
}, a.createSecurityGroupErr
|
||||
}
|
||||
|
||||
func (a stubAPI) DeleteSecurityGroup(ctx context.Context,
|
||||
params *ec2.DeleteSecurityGroupInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.DeleteSecurityGroupOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.deleteSecurityGroupDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, a.deleteSecurityGroupErr
|
||||
}
|
||||
|
||||
func (a stubAPI) AuthorizeSecurityGroupIngress(ctx context.Context,
|
||||
params *ec2.AuthorizeSecurityGroupIngressInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.AuthorizeSecurityGroupIngressOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.authorizeSecurityGroupIngressDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, a.authorizeSecurityGroupIngressErr
|
||||
}
|
||||
|
||||
func (a stubAPI) AuthorizeSecurityGroupEgress(ctx context.Context,
|
||||
params *ec2.AuthorizeSecurityGroupEgressInput,
|
||||
optFns ...func(*ec2.Options),
|
||||
) (*ec2.AuthorizeSecurityGroupEgressOutput, error) {
|
||||
if err := getDryRunErr(params.DryRun, a.authorizeSecurityGroupEgressDryRunErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, a.authorizeSecurityGroupEgressErr
|
||||
}
|
||||
|
||||
func getDryRunErr(dryRun *bool, stubErr *error) error {
|
||||
if dryRun == nil || !*dryRun {
|
||||
return nil
|
||||
}
|
||||
if stubErr != nil {
|
||||
return *stubErr
|
||||
}
|
||||
return &smithy.GenericAPIError{Code: "DryRunOperation"}
|
||||
}
|
||||
|
||||
var stateRunning = types.InstanceState{
|
||||
Code: aws.Int32(int32(16)),
|
||||
Name: types.InstanceStateNameRunning,
|
||||
}
|
||||
|
||||
var stateTerminated = types.InstanceState{
|
||||
Code: aws.Int32(48),
|
||||
Name: types.InstanceStateNameTerminated,
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
)
|
||||
|
||||
// Client for the AWS EC2 API.
|
||||
type Client struct {
|
||||
api api
|
||||
instances ec2.Instances
|
||||
securityGroup string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func newClient(api api) (*Client, error) {
|
||||
return &Client{
|
||||
api: api,
|
||||
instances: make(map[string]ec2.Instance),
|
||||
timeout: 2 * time.Minute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewFromDefault creates a Client from the default config.
|
||||
func NewFromDefault(ctx context.Context) (*Client, error) {
|
||||
cfg, err := awsconfig.LoadDefaultConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newClient(awsec2.NewFromConfig(cfg))
|
||||
}
|
||||
|
||||
// GetState returns the current configuration of the Constellation,
|
||||
// which can be stored and used through later CLI commands.
|
||||
func (c *Client) GetState() (state.ConstellationState, error) {
|
||||
if len(c.instances) == 0 {
|
||||
return state.ConstellationState{}, errors.New("client has no instances")
|
||||
}
|
||||
if c.securityGroup == "" {
|
||||
return state.ConstellationState{}, errors.New("client has no security group")
|
||||
}
|
||||
return state.ConstellationState{
|
||||
CloudProvider: cloudprovider.AWS.String(),
|
||||
EC2Instances: c.instances,
|
||||
EC2SecurityGroup: c.securityGroup,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetState sets a Client to an existing configuration.
|
||||
func (c *Client) SetState(stat state.ConstellationState) error {
|
||||
if stat.CloudProvider != cloudprovider.AWS.String() {
|
||||
return errors.New("state is not aws state")
|
||||
}
|
||||
if len(stat.EC2Instances) == 0 {
|
||||
return errors.New("state has no instances")
|
||||
}
|
||||
if stat.EC2SecurityGroup == "" {
|
||||
return errors.New("state has no security group")
|
||||
}
|
||||
c.instances = stat.EC2Instances
|
||||
c.securityGroup = stat.EC2SecurityGroup
|
||||
return nil
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
"github.com/edgelesssys/constellation/internal/state"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetState(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
client Client
|
||||
wantState state.ConstellationState
|
||||
wantErr bool
|
||||
}{
|
||||
"successful get": {
|
||||
client: Client{
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
securityGroup: "sg",
|
||||
},
|
||||
wantState: state.ConstellationState{
|
||||
CloudProvider: "AWS",
|
||||
EC2Instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
EC2SecurityGroup: "sg",
|
||||
},
|
||||
},
|
||||
"client without security group": {
|
||||
client: Client{
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"client without instances": {
|
||||
client: Client{
|
||||
securityGroup: "sg",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
stat, err := tc.client.GetState()
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantState, stat)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetState(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
state state.ConstellationState
|
||||
wantInstances ec2.Instances
|
||||
wantSecurityGroup string
|
||||
wantErr bool
|
||||
}{
|
||||
"successful set": {
|
||||
state: state.ConstellationState{
|
||||
CloudProvider: "AWS",
|
||||
EC2SecurityGroup: "sg-test",
|
||||
EC2Instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
},
|
||||
wantInstances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantSecurityGroup: "sg-test",
|
||||
},
|
||||
"state without cloudprovider": {
|
||||
state: state.ConstellationState{
|
||||
EC2SecurityGroup: "sg-test",
|
||||
EC2Instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"state with incorrect cloudprovider": {
|
||||
state: state.ConstellationState{
|
||||
CloudProvider: "incorrect",
|
||||
EC2SecurityGroup: "sg-test",
|
||||
EC2Instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"state without instances": {
|
||||
state: state.ConstellationState{
|
||||
CloudProvider: "AWS",
|
||||
EC2SecurityGroup: "sg-test",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"state without security group": {
|
||||
state: state.ConstellationState{
|
||||
CloudProvider: "AWS",
|
||||
EC2Instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &Client{}
|
||||
|
||||
err := client.SetState(tc.state)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantInstances, client.instances)
|
||||
assert.Equal(tc.wantSecurityGroup, client.securityGroup)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
)
|
||||
|
||||
// CreateInstances creates the instances defined in input.
|
||||
//
|
||||
// An existing security group is needed to create instances.
|
||||
func (c *Client) CreateInstances(ctx context.Context, input CreateInput) error {
|
||||
if c.securityGroup == "" {
|
||||
return errors.New("no security group set")
|
||||
}
|
||||
input.securityGroupIds = []string{c.securityGroup}
|
||||
|
||||
if err := c.createDryRun(ctx, input); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := c.api.RunInstances(ctx, input.AWS())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create instances: %w", err)
|
||||
}
|
||||
|
||||
for _, instance := range resp.Instances {
|
||||
id := instance.InstanceId
|
||||
if id == nil {
|
||||
return errors.New("instanceId is nil pointer")
|
||||
}
|
||||
c.instances[*id] = ec2.Instance{}
|
||||
}
|
||||
|
||||
if err := c.waitStateRunning(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.tagInstances(ctx, input.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.getInstanceIPs(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminateInstances terminates all instances of a Client.
|
||||
func (c *Client) TerminateInstances(ctx context.Context) error {
|
||||
if len(c.instances) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
input := &awsec2.TerminateInstancesInput{
|
||||
InstanceIds: c.instances.IDs(),
|
||||
}
|
||||
if err := c.terminateDryRun(ctx, *input); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := c.api.TerminateInstances(ctx, input); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.waitStateTerminated(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
c.instances = ec2.Instances{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitStateRunning waits until all the client's instances reached the running state.
|
||||
//
|
||||
// A set of instances is also considered to be running if at least one of the
|
||||
// instances' state is 'running' and the other instances have a nil state.
|
||||
func (c *Client) waitStateRunning(ctx context.Context) error {
|
||||
if len(c.instances) == 0 {
|
||||
return errors.New("client has no instances")
|
||||
}
|
||||
describeInput := &awsec2.DescribeInstancesInput{
|
||||
InstanceIds: c.instances.IDs(),
|
||||
}
|
||||
waiter := awsec2.NewInstanceRunningWaiter(c.api)
|
||||
return waiter.Wait(ctx, describeInput, c.timeout)
|
||||
}
|
||||
|
||||
// waitStateTerminated waits until all the client's instances reached the terminated state.
|
||||
//
|
||||
// A set of instances is also considered to be terminated if at least one of the
|
||||
// instances' state is 'terminated' and the other instances have a nil state.
|
||||
func (c *Client) waitStateTerminated(ctx context.Context) error {
|
||||
if len(c.instances) == 0 {
|
||||
return errors.New("client has no instances")
|
||||
}
|
||||
|
||||
describeInput := &awsec2.DescribeInstancesInput{
|
||||
InstanceIds: c.instances.IDs(),
|
||||
}
|
||||
waiter := awsec2.NewInstanceTerminatedWaiter(c.api)
|
||||
return waiter.Wait(ctx, describeInput, c.timeout)
|
||||
}
|
||||
|
||||
// tagInstances tags all instances of a client with a given set of tags.
|
||||
func (c *Client) tagInstances(ctx context.Context, tags ec2.Tags) error {
|
||||
if len(c.instances) == 0 {
|
||||
return errors.New("client has no instances")
|
||||
}
|
||||
|
||||
tagInput := &awsec2.CreateTagsInput{
|
||||
Resources: c.instances.IDs(),
|
||||
Tags: tags.AWS(),
|
||||
}
|
||||
if _, err := c.api.CreateTags(ctx, tagInput); err != nil {
|
||||
return fmt.Errorf("failed to tag instances: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createDryRun checks if user has the privilege to create the instances
|
||||
// which were defined in input.
|
||||
func (c *Client) createDryRun(ctx context.Context, input CreateInput) error {
|
||||
runInput := input.AWS()
|
||||
runInput.DryRun = aws.Bool(true)
|
||||
_, err := c.api.RunInstances(ctx, runInput)
|
||||
return checkDryRunError(err)
|
||||
}
|
||||
|
||||
// terminateDryRun checks if user has the privilege to terminate the instances
|
||||
// which were defined in input.
|
||||
func (c *Client) terminateDryRun(ctx context.Context, input awsec2.TerminateInstancesInput) error {
|
||||
input.DryRun = aws.Bool(true)
|
||||
_, err := c.api.TerminateInstances(ctx, &input)
|
||||
return checkDryRunError(err)
|
||||
}
|
||||
|
||||
// getInstanceIPs queries the private and public IP addresses
|
||||
// and adds the information to each instance.
|
||||
//
|
||||
// The instances must be in 'running' state.
|
||||
func (c *Client) getInstanceIPs(ctx context.Context) error {
|
||||
describeInput := &awsec2.DescribeInstancesInput{
|
||||
InstanceIds: c.instances.IDs(),
|
||||
}
|
||||
paginator := awsec2.NewDescribeInstancesPaginator(c.api, describeInput)
|
||||
for paginator.HasMorePages() {
|
||||
output, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, reservation := range output.Reservations {
|
||||
for _, instanceDescription := range reservation.Instances {
|
||||
if instanceDescription.InstanceId == nil {
|
||||
return errors.New("instanceId is nil pointer")
|
||||
}
|
||||
if instanceDescription.PublicIpAddress == nil {
|
||||
return errors.New("publicIpAddress is nil pointer")
|
||||
}
|
||||
if instanceDescription.PrivateIpAddress == nil {
|
||||
return errors.New("privateIpAddress is nil pointer")
|
||||
}
|
||||
instance, ok := c.instances[*instanceDescription.InstanceId]
|
||||
if !ok {
|
||||
return errors.New("got an instance description to an unknown instanceId")
|
||||
}
|
||||
instance.PublicIP = *instanceDescription.PublicIpAddress
|
||||
instance.PrivateIP = *instanceDescription.PrivateIpAddress
|
||||
c.instances[*instanceDescription.InstanceId] = instance
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateInput defines the propertis of the instances to create.
|
||||
type CreateInput struct {
|
||||
ImageId string
|
||||
InstanceType string
|
||||
Count int
|
||||
Tags ec2.Tags
|
||||
securityGroupIds []string
|
||||
}
|
||||
|
||||
// AWS creates a AWS ec2.RunInstancesInput from an CreateInput.
|
||||
func (ci *CreateInput) AWS() *awsec2.RunInstancesInput {
|
||||
return &awsec2.RunInstancesInput{
|
||||
ImageId: aws.String(ci.ImageId),
|
||||
InstanceType: ec2.InstanceTypes[ci.InstanceType],
|
||||
MaxCount: aws.Int32(int32(ci.Count)),
|
||||
MinCount: aws.Int32(int32(ci.Count)),
|
||||
EnclaveOptions: &types.EnclaveOptionsRequest{Enabled: aws.Bool(true)},
|
||||
SecurityGroupIds: ci.securityGroupIds,
|
||||
}
|
||||
}
|
@ -1,493 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateInstances(t *testing.T) {
|
||||
testInstances := []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
PublicIpAddress: aws.String("192.0.2.1"),
|
||||
PrivateIpAddress: aws.String("192.0.2.2"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-2"),
|
||||
PublicIpAddress: aws.String("192.0.2.3"),
|
||||
PrivateIpAddress: aws.String("192.0.2.4"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-3"),
|
||||
PublicIpAddress: aws.String("192.0.2.5"),
|
||||
PrivateIpAddress: aws.String("192.0.2.6"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
}
|
||||
someErr := errors.New("failed")
|
||||
var noErr error
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
instances ec2.Instances
|
||||
securityGroup string
|
||||
wantErr bool
|
||||
wantInstances ec2.Instances
|
||||
}{
|
||||
"create": {
|
||||
api: stubAPI{instances: testInstances},
|
||||
securityGroup: "sg-test",
|
||||
wantInstances: ec2.Instances{
|
||||
"id-1": {PublicIP: "192.0.2.1", PrivateIP: "192.0.2.2"},
|
||||
"id-2": {PublicIP: "192.0.2.3", PrivateIP: "192.0.2.4"},
|
||||
"id-3": {PublicIP: "192.0.2.5", PrivateIP: "192.0.2.6"},
|
||||
},
|
||||
},
|
||||
"client already has instances": {
|
||||
api: stubAPI{instances: testInstances},
|
||||
instances: ec2.Instances{"id-4": {}, "id-5": {}},
|
||||
securityGroup: "sg-test",
|
||||
wantInstances: ec2.Instances{
|
||||
"id-1": {PublicIP: "192.0.2.1", PrivateIP: "192.0.2.2"},
|
||||
"id-2": {PublicIP: "192.0.2.3", PrivateIP: "192.0.2.4"},
|
||||
"id-3": {PublicIP: "192.0.2.5", PrivateIP: "192.0.2.6"},
|
||||
"id-4": {},
|
||||
"id-5": {},
|
||||
},
|
||||
},
|
||||
"client already has same instance id": {
|
||||
api: stubAPI{instances: testInstances},
|
||||
instances: ec2.Instances{"id-1": {}, "id-4": {}, "id-5": {}},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: false,
|
||||
wantInstances: ec2.Instances{
|
||||
"id-1": {PublicIP: "192.0.2.1", PrivateIP: "192.0.2.2"},
|
||||
"id-2": {PublicIP: "192.0.2.3", PrivateIP: "192.0.2.4"},
|
||||
"id-3": {PublicIP: "192.0.2.5", PrivateIP: "192.0.2.6"},
|
||||
"id-4": {},
|
||||
"id-5": {},
|
||||
},
|
||||
},
|
||||
"client has no security group": {
|
||||
api: stubAPI{},
|
||||
wantErr: true,
|
||||
},
|
||||
"run API error": {
|
||||
api: stubAPI{runInstancesErr: someErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
"runDryRun API error": {
|
||||
api: stubAPI{runInstancesDryRunErr: &someErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
"runDryRun missing expected API error": {
|
||||
api: stubAPI{runInstancesDryRunErr: &noErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &Client{
|
||||
api: tc.api,
|
||||
instances: tc.instances,
|
||||
timeout: time.Millisecond,
|
||||
securityGroup: tc.securityGroup,
|
||||
}
|
||||
if client.instances == nil {
|
||||
client.instances = make(map[string]ec2.Instance)
|
||||
}
|
||||
input := CreateInput{
|
||||
ImageId: "test-image",
|
||||
InstanceType: "",
|
||||
Count: 13,
|
||||
}
|
||||
|
||||
err := client.CreateInstances(context.Background(), input)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.ElementsMatch(tc.wantInstances.IDs(), client.instances.IDs())
|
||||
assert.ElementsMatch(tc.wantInstances.PublicIPs(), client.instances.PublicIPs())
|
||||
assert.ElementsMatch(tc.wantInstances.PrivateIPs(), client.instances.PrivateIPs())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTerminateInstances(t *testing.T) {
|
||||
testAWSInstances := []types.Instance{
|
||||
{InstanceId: aws.String("id-1"), State: &stateTerminated},
|
||||
{InstanceId: aws.String("id-2"), State: &stateTerminated},
|
||||
{InstanceId: aws.String("id-3"), State: &stateTerminated},
|
||||
}
|
||||
someErr := errors.New("failed")
|
||||
var noErr error
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
instances ec2.Instances
|
||||
wantErr bool
|
||||
}{
|
||||
"client with instances": {
|
||||
api: stubAPI{instances: testAWSInstances},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"client no instances set": {
|
||||
api: stubAPI{},
|
||||
},
|
||||
"terminate API error": {
|
||||
api: stubAPI{terminateInstancesErr: someErr},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"terminateDryRun API error": {
|
||||
api: stubAPI{terminateInstancesDryRunErr: &someErr},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"terminateDryRun miss expected API error": {
|
||||
api: stubAPI{terminateInstancesDryRunErr: &noErr},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &Client{
|
||||
api: tc.api,
|
||||
instances: tc.instances,
|
||||
timeout: time.Millisecond,
|
||||
}
|
||||
if client.instances == nil {
|
||||
client.instances = make(map[string]ec2.Instance)
|
||||
}
|
||||
|
||||
err := client.TerminateInstances(context.Background())
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Empty(client.instances)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitStateRunning(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
api api
|
||||
instances ec2.Instances
|
||||
wantErr bool
|
||||
}{
|
||||
"instances are running": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-2"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-3"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"one instance running, rest nil": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"one instance terminated, rest nil": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"instances with different state": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-2"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"all instances have nil state": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{InstanceId: aws.String("id-1")},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"client has no instances": {
|
||||
api: &stubAPI{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
client := &Client{
|
||||
api: tc.api,
|
||||
instances: tc.instances,
|
||||
timeout: time.Millisecond,
|
||||
}
|
||||
if client.instances == nil {
|
||||
client.instances = make(map[string]ec2.Instance)
|
||||
}
|
||||
|
||||
err := client.waitStateRunning(context.Background())
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitStateTerminated(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
api api
|
||||
instances ec2.Instances
|
||||
wantErr bool
|
||||
}{
|
||||
"instances are terminated": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-2"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-3"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"one instance terminated, rest nil": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"one instance running, rest nil": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"instances with different state": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{
|
||||
InstanceId: aws.String("id-1"),
|
||||
State: &stateTerminated,
|
||||
},
|
||||
{
|
||||
InstanceId: aws.String("id-2"),
|
||||
State: &stateRunning,
|
||||
},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"all instances have nil state": {
|
||||
api: stubAPI{instances: []types.Instance{
|
||||
{InstanceId: aws.String("id-1")},
|
||||
{InstanceId: aws.String("id-2")},
|
||||
{InstanceId: aws.String("id-3")},
|
||||
}},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
"client has no instances": {
|
||||
api: &stubAPI{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &Client{
|
||||
api: tc.api,
|
||||
instances: tc.instances,
|
||||
timeout: time.Millisecond,
|
||||
}
|
||||
if client.instances == nil {
|
||||
client.instances = make(map[string]ec2.Instance)
|
||||
}
|
||||
|
||||
err := client.waitStateTerminated(context.Background())
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagInstances(t *testing.T) {
|
||||
testTags := ec2.Tags{
|
||||
{Key: "Name", Value: "Test"},
|
||||
{Key: "Foo", Value: "Bar"},
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
instances ec2.Instances
|
||||
wantErr bool
|
||||
}{
|
||||
"tag": {
|
||||
api: stubAPI{},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: false,
|
||||
},
|
||||
"client without instances": {
|
||||
api: stubAPI{createTagsErr: errors.New("failed")},
|
||||
wantErr: true,
|
||||
},
|
||||
"tag API error": {
|
||||
api: stubAPI{createTagsErr: errors.New("failed")},
|
||||
instances: ec2.Instances{"id-1": {}, "id-2": {}, "id-3": {}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &Client{
|
||||
api: tc.api,
|
||||
instances: tc.instances,
|
||||
timeout: time.Millisecond,
|
||||
}
|
||||
if client.instances == nil {
|
||||
client.instances = make(map[string]ec2.Instance)
|
||||
}
|
||||
|
||||
err := client.tagInstances(context.Background(), testTags)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEc2RunInstanceInput(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
testCases := []struct {
|
||||
in CreateInput
|
||||
wantOutput awsec2.RunInstancesInput
|
||||
}{
|
||||
{
|
||||
in: CreateInput{
|
||||
ImageId: "test-image",
|
||||
InstanceType: "4xlarge",
|
||||
Count: 13,
|
||||
securityGroupIds: []string{"test-sec-group"},
|
||||
},
|
||||
wantOutput: awsec2.RunInstancesInput{
|
||||
ImageId: aws.String("test-image"),
|
||||
InstanceType: types.InstanceTypeC5a4xlarge,
|
||||
MinCount: aws.Int32(int32(13)),
|
||||
MaxCount: aws.Int32(int32(13)),
|
||||
EnclaveOptions: &types.EnclaveOptionsRequest{Enabled: aws.Bool(true)},
|
||||
SecurityGroupIds: []string{"test-sec-group"},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: CreateInput{
|
||||
ImageId: "test-image-2",
|
||||
InstanceType: "12xlarge",
|
||||
Count: 2,
|
||||
securityGroupIds: []string{"test-sec-group-2"},
|
||||
},
|
||||
wantOutput: awsec2.RunInstancesInput{
|
||||
ImageId: aws.String("test-image-2"),
|
||||
InstanceType: types.InstanceTypeC5a12xlarge,
|
||||
MinCount: aws.Int32(int32(2)),
|
||||
MaxCount: aws.Int32(int32(2)),
|
||||
EnclaveOptions: &types.EnclaveOptionsRequest{Enabled: aws.Bool(true)},
|
||||
SecurityGroupIds: []string{"test-sec-group-2"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
out := tc.in.AWS()
|
||||
assert.Equal(tc.wantOutput, *out)
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// CreateSecurityGroup creates a AWS security group with the handed properties.
|
||||
func (c *Client) CreateSecurityGroup(ctx context.Context, input SecurityGroupInput) error {
|
||||
if c.securityGroup != "" {
|
||||
return errors.New("client already has a security group")
|
||||
}
|
||||
|
||||
id := uuid.New()
|
||||
createInput := &awsec2.CreateSecurityGroupInput{
|
||||
Description: aws.String("Security group of Constellation cluster. This group was generated through the Constellation CLI."),
|
||||
GroupName: aws.String("Constellation-" + id.String()),
|
||||
DryRun: aws.Bool(true),
|
||||
}
|
||||
|
||||
// DryRun
|
||||
_, err := c.api.CreateSecurityGroup(ctx, createInput)
|
||||
if err := checkDryRunError(err); err != nil {
|
||||
return err
|
||||
}
|
||||
createInput.DryRun = aws.Bool(false)
|
||||
|
||||
// Create
|
||||
out, err := c.api.CreateSecurityGroup(ctx, createInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if out.GroupId == nil {
|
||||
return errors.New("security group creation didn't return an id")
|
||||
}
|
||||
c.securityGroup = *out.GroupId
|
||||
|
||||
// Authorize.
|
||||
return c.authorizeSecurityGroup(ctx, input)
|
||||
}
|
||||
|
||||
// DeleteSecurityGroup deletes the security group of the client.
|
||||
// The deletion is idempotent, no error is returned if the client has
|
||||
// an empty securityGroupID.
|
||||
func (c *Client) DeleteSecurityGroup(ctx context.Context) error {
|
||||
if c.securityGroup == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
input := &awsec2.DeleteSecurityGroupInput{
|
||||
GroupId: aws.String(c.securityGroup),
|
||||
DryRun: aws.Bool(true),
|
||||
}
|
||||
|
||||
// DryRun
|
||||
_, err := c.api.DeleteSecurityGroup(ctx, input)
|
||||
if err := checkDryRunError(err); err != nil {
|
||||
return err
|
||||
}
|
||||
input.DryRun = aws.Bool(false)
|
||||
|
||||
// Delete
|
||||
if _, err := c.api.DeleteSecurityGroup(ctx, input); err != nil {
|
||||
return err
|
||||
}
|
||||
c.securityGroup = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) authorizeSecurityGroup(ctx context.Context, input SecurityGroupInput) error {
|
||||
if c.securityGroup == "" {
|
||||
return errors.New("client hasn't got a security group id")
|
||||
}
|
||||
|
||||
if err := c.authorizeSecurityGroupIngress(ctx, input.Inbound); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.authorizeSecurityGroupEgress(ctx, input.Outbound)
|
||||
}
|
||||
|
||||
func (c *Client) authorizeSecurityGroupIngress(ctx context.Context, perms cloudtypes.Firewall) error {
|
||||
if len(perms) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
authInput := &awsec2.AuthorizeSecurityGroupIngressInput{
|
||||
GroupId: aws.String(c.securityGroup),
|
||||
IpPermissions: perms.AWS(),
|
||||
DryRun: aws.Bool(true),
|
||||
}
|
||||
|
||||
// DryRun
|
||||
_, err := c.api.AuthorizeSecurityGroupIngress(ctx, authInput)
|
||||
if err := checkDryRunError(err); err != nil {
|
||||
return err
|
||||
}
|
||||
authInput.DryRun = aws.Bool(false)
|
||||
|
||||
// Authorize
|
||||
_, err = c.api.AuthorizeSecurityGroupIngress(ctx, authInput)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) authorizeSecurityGroupEgress(ctx context.Context, perms cloudtypes.Firewall) error {
|
||||
if len(perms) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
authInput := &awsec2.AuthorizeSecurityGroupEgressInput{
|
||||
GroupId: aws.String(c.securityGroup),
|
||||
IpPermissions: perms.AWS(),
|
||||
DryRun: aws.Bool(true),
|
||||
}
|
||||
|
||||
// DryRun
|
||||
_, err := c.api.AuthorizeSecurityGroupEgress(ctx, authInput)
|
||||
if err := checkDryRunError(err); err != nil {
|
||||
return err
|
||||
}
|
||||
authInput.DryRun = aws.Bool(false)
|
||||
|
||||
// Authorize
|
||||
_, err = c.api.AuthorizeSecurityGroupEgress(ctx, authInput)
|
||||
return err
|
||||
}
|
||||
|
||||
type SecurityGroupInput struct {
|
||||
Inbound cloudtypes.Firewall
|
||||
Outbound cloudtypes.Firewall
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCreateSecurityGroup(t *testing.T) {
|
||||
testInput := SecurityGroupInput{
|
||||
Inbound: cloudtypes.Firewall{
|
||||
{
|
||||
Description: "perm1",
|
||||
Protocol: "TCP",
|
||||
IPRange: "192.0.2.0/24",
|
||||
FromPort: 22,
|
||||
},
|
||||
{
|
||||
Description: "perm2",
|
||||
Protocol: "UDP",
|
||||
IPRange: "192.0.2.0/24",
|
||||
FromPort: 4433,
|
||||
},
|
||||
},
|
||||
Outbound: cloudtypes.Firewall{
|
||||
{
|
||||
Description: "perm3",
|
||||
Protocol: "TCP",
|
||||
IPRange: "192.0.2.0/24",
|
||||
FromPort: 4040,
|
||||
},
|
||||
},
|
||||
}
|
||||
someErr := errors.New("failed")
|
||||
var noErr error
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
securityGroup string
|
||||
input SecurityGroupInput
|
||||
wantErr bool
|
||||
wantSecurityGroup string
|
||||
}{
|
||||
"create security group": {
|
||||
api: stubAPI{securityGroup: types.SecurityGroup{GroupId: aws.String("sg-test")}},
|
||||
input: testInput,
|
||||
wantSecurityGroup: "sg-test",
|
||||
},
|
||||
"create security group without permissions": {
|
||||
api: stubAPI{securityGroup: types.SecurityGroup{GroupId: aws.String("sg-test")}},
|
||||
input: SecurityGroupInput{},
|
||||
wantSecurityGroup: "sg-test",
|
||||
},
|
||||
"client already has security group": {
|
||||
api: stubAPI{},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"create returns nil security group ID": {
|
||||
api: stubAPI{securityGroup: types.SecurityGroup{GroupId: nil}},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"create API error": {
|
||||
api: stubAPI{createSecurityGroupErr: someErr},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"create DryRun API error": {
|
||||
api: stubAPI{createSecurityGroupDryRunErr: &someErr},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"create DryRun missing expected error": {
|
||||
api: stubAPI{createSecurityGroupDryRunErr: &noErr},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorize error": {
|
||||
api: stubAPI{
|
||||
securityGroup: types.SecurityGroup{GroupId: aws.String("sg-test")},
|
||||
authorizeSecurityGroupIngressErr: someErr,
|
||||
},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
client, err := newClient(tc.api)
|
||||
require.NoError(err)
|
||||
client.securityGroup = tc.securityGroup
|
||||
|
||||
err = client.CreateSecurityGroup(context.Background(), tc.input)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantSecurityGroup, client.securityGroup)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteSecurityGroup(t *testing.T) {
|
||||
someErr := errors.New("failed")
|
||||
var noErr error
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
securityGroup string
|
||||
wantErr bool
|
||||
}{
|
||||
"delete security group": {
|
||||
api: stubAPI{},
|
||||
securityGroup: "sg-test",
|
||||
},
|
||||
"client without security group": {
|
||||
api: stubAPI{},
|
||||
},
|
||||
"delete API error": {
|
||||
api: stubAPI{deleteSecurityGroupErr: someErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
"delete DryRun API error": {
|
||||
api: stubAPI{deleteSecurityGroupDryRunErr: &someErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
"delete DryRun missing expected error": {
|
||||
api: stubAPI{deleteSecurityGroupDryRunErr: &noErr},
|
||||
securityGroup: "sg-test",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
client, err := newClient(tc.api)
|
||||
require.NoError(err)
|
||||
client.securityGroup = tc.securityGroup
|
||||
|
||||
err = client.DeleteSecurityGroup(context.Background())
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Empty(client.securityGroup)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthorizeSecurityGroup(t *testing.T) {
|
||||
testInput := SecurityGroupInput{
|
||||
Inbound: cloudtypes.Firewall{
|
||||
{
|
||||
Description: "perm1",
|
||||
Protocol: "TCP",
|
||||
IPRange: " 192.0.2.0/24",
|
||||
FromPort: 22,
|
||||
},
|
||||
{
|
||||
Description: "perm2",
|
||||
Protocol: "UDP",
|
||||
IPRange: "192.0.2.0/24",
|
||||
FromPort: 4433,
|
||||
},
|
||||
},
|
||||
Outbound: cloudtypes.Firewall{
|
||||
{
|
||||
Description: "perm3",
|
||||
Protocol: "TCP",
|
||||
IPRange: "192.0.2.0/24",
|
||||
FromPort: 4040,
|
||||
},
|
||||
},
|
||||
}
|
||||
someErr := errors.New("failed")
|
||||
var noErr error
|
||||
|
||||
testCases := map[string]struct {
|
||||
api stubAPI
|
||||
securityGroup string
|
||||
input SecurityGroupInput
|
||||
wantErr bool
|
||||
}{
|
||||
"authorize": {
|
||||
api: stubAPI{},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: false,
|
||||
},
|
||||
"client without security group": {
|
||||
api: stubAPI{},
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeIngress API error": {
|
||||
api: stubAPI{authorizeSecurityGroupIngressErr: someErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeIngress DryRun API error": {
|
||||
api: stubAPI{authorizeSecurityGroupIngressDryRunErr: &someErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeIngress DryRun missing expected error": {
|
||||
api: stubAPI{authorizeSecurityGroupIngressDryRunErr: &noErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeEgress API error": {
|
||||
api: stubAPI{authorizeSecurityGroupEgressErr: someErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeEgress DryRun API error": {
|
||||
api: stubAPI{authorizeSecurityGroupEgressDryRunErr: &someErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
"authorizeEgress DryRun missing expected error": {
|
||||
api: stubAPI{authorizeSecurityGroupEgressDryRunErr: &noErr},
|
||||
securityGroup: "sg-test",
|
||||
input: testInput,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
client, err := newClient(tc.api)
|
||||
require.NoError(err)
|
||||
client.securityGroup = tc.securityGroup
|
||||
|
||||
err = client.authorizeSecurityGroup(context.Background(), tc.input)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
)
|
||||
|
||||
// checkDryRunError error checks if an error is a DryRun error.
|
||||
// If the error is nil, an error is returned, since a DryRun error
|
||||
// is the expected result of a DryRun operation.
|
||||
func checkDryRunError(err error) error {
|
||||
var apiErr smithy.APIError
|
||||
if errors.As(err, &apiErr) && apiErr.ErrorCode() == "DryRunOperation" {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New("expected APIError: DryRunOperation, but got no error at all")
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCheckDryRunError(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
someErr := errors.New("failed")
|
||||
assert.ErrorIs(checkDryRunError(someErr), someErr)
|
||||
|
||||
dryRunErr := smithy.GenericAPIError{Code: "DryRunOperation"}
|
||||
assert.NoError(checkDryRunError(&dryRunErr))
|
||||
|
||||
var nilErr error
|
||||
assert.Error(checkDryRunError(nilErr))
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package ec2
|
||||
|
||||
import "errors"
|
||||
|
||||
// Instance is an ec2 instance.
|
||||
type Instance struct {
|
||||
PublicIP string
|
||||
PrivateIP string
|
||||
}
|
||||
|
||||
// Instances is a map of ec2 Instances. The ID of an instance is used as key.
|
||||
type Instances map[string]Instance
|
||||
|
||||
// IDs returns the IDs of all instances of the Constellation.
|
||||
func (i Instances) IDs() []string {
|
||||
var ids []string
|
||||
for id := range i {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// PublicIPs returns the public IPs of all the instances of the Constellation.
|
||||
func (i Instances) PublicIPs() []string {
|
||||
var ips []string
|
||||
for _, instance := range i {
|
||||
ips = append(ips, instance.PublicIP)
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
// PrivateIPs returns the private IPs of all the instances of the Constellation.
|
||||
func (i Instances) PrivateIPs() []string {
|
||||
var ips []string
|
||||
for _, instance := range i {
|
||||
ips = append(ips, instance.PrivateIP)
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
// GetOne return anyone instance out of the instances and its ID.
|
||||
func (i Instances) GetOne() (string, Instance, error) {
|
||||
for id, instance := range i {
|
||||
return id, instance, nil
|
||||
}
|
||||
return "", Instance{}, errors.New("map is empty")
|
||||
}
|
||||
|
||||
// GetOthers returns all instances but the one with the handed ID.
|
||||
func (i Instances) GetOthers(id string) Instances {
|
||||
others := make(Instances)
|
||||
for key, instance := range i {
|
||||
if key != id {
|
||||
others[key] = instance
|
||||
}
|
||||
}
|
||||
return others
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package ec2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIDs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testState := testInstances()
|
||||
wantIDs := []string{"id-9", "id-10", "id-11", "id-12"}
|
||||
assert.ElementsMatch(wantIDs, testState.IDs())
|
||||
}
|
||||
|
||||
func TestPublicIPs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testState := testInstances()
|
||||
wantIPs := []string{"192.0.2.1", "192.0.2.3", "192.0.2.5", "192.0.2.7"}
|
||||
assert.ElementsMatch(wantIPs, testState.PublicIPs())
|
||||
}
|
||||
|
||||
func TestPrivateIPs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testState := testInstances()
|
||||
wantIPs := []string{"192.0.2.2", "192.0.2.4", "192.0.2.6", "192.0.2.8"}
|
||||
assert.ElementsMatch(wantIPs, testState.PrivateIPs())
|
||||
}
|
||||
|
||||
func TestGetOne(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testState := testInstances()
|
||||
id, instance, err := testState.GetOne()
|
||||
assert.NoError(err)
|
||||
assert.Contains(testState, id)
|
||||
assert.Equal(testState[id], instance)
|
||||
}
|
||||
|
||||
func TestGetOthers(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testCases := testInstances().IDs()
|
||||
|
||||
for _, id := range testCases {
|
||||
others := testInstances().GetOthers(id)
|
||||
assert.NotContains(others, id)
|
||||
wantInstances := testInstances()
|
||||
delete(wantInstances, id)
|
||||
assert.ElementsMatch(others.IDs(), wantInstances.IDs())
|
||||
}
|
||||
}
|
||||
|
||||
func testInstances() Instances {
|
||||
return Instances{
|
||||
"id-9": {
|
||||
PublicIP: "192.0.2.1",
|
||||
PrivateIP: "192.0.2.2",
|
||||
},
|
||||
"id-10": {
|
||||
PublicIP: "192.0.2.3",
|
||||
PrivateIP: "192.0.2.4",
|
||||
},
|
||||
"id-11": {
|
||||
PublicIP: "192.0.2.5",
|
||||
PrivateIP: "192.0.2.6",
|
||||
},
|
||||
"id-12": {
|
||||
PublicIP: "192.0.2.7",
|
||||
PrivateIP: "192.0.2.8",
|
||||
},
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package ec2
|
||||
|
||||
import "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
|
||||
// InstanceTypes defines possible values for the SIZE positional argument.
|
||||
var InstanceTypes = map[string]types.InstanceType{
|
||||
"4xlarge": types.InstanceTypeC5a4xlarge,
|
||||
"8xlarge": types.InstanceTypeC5a8xlarge,
|
||||
"12xlarge": types.InstanceTypeC5a12xlarge,
|
||||
"16xlarge": types.InstanceTypeC5a16xlarge,
|
||||
"24xlarge": types.InstanceTypeC5a24xlarge,
|
||||
// shorthands
|
||||
"4xl": types.InstanceTypeC5a4xlarge,
|
||||
"8xl": types.InstanceTypeC5a8xlarge,
|
||||
"12xl": types.InstanceTypeC5a12xlarge,
|
||||
"16xl": types.InstanceTypeC5a16xlarge,
|
||||
"24xl": types.InstanceTypeC5a24xlarge,
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package ec2
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
)
|
||||
|
||||
// Tag is a ec2 tag. It consits of a key and a value.
|
||||
type Tag struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// Tags is a set of Tags.
|
||||
type Tags []Tag
|
||||
|
||||
// AWS returns a AWS representation of tags.
|
||||
func (t Tags) AWS() []types.Tag {
|
||||
var awsTags []types.Tag
|
||||
for _, tag := range t {
|
||||
awsTags = append(awsTags, types.Tag{
|
||||
Key: aws.String(tag.Key),
|
||||
Value: aws.String(tag.Value),
|
||||
})
|
||||
}
|
||||
return awsTags
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package ec2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTagsAws(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
testTags := Tags{
|
||||
{
|
||||
Key: "Name",
|
||||
Value: "Test",
|
||||
},
|
||||
{
|
||||
Key: "Foo",
|
||||
Value: "Bar",
|
||||
},
|
||||
}
|
||||
wantTags := []types.Tag{
|
||||
{
|
||||
Key: aws.String("Name"),
|
||||
Value: aws.String("Test"),
|
||||
},
|
||||
{
|
||||
Key: aws.String("Foo"),
|
||||
Value: aws.String("Bar"),
|
||||
},
|
||||
}
|
||||
|
||||
awsTags := testTags.AWS()
|
||||
assert.Equal(wantTags, awsTags)
|
||||
}
|
@ -13,8 +13,6 @@ import (
|
||||
|
||||
func GetScalingGroupsFromConfig(stat state.ConstellationState, config *configc.Config) (coordinators, nodes cmdc.ScalingGroup, err error) {
|
||||
switch {
|
||||
case len(stat.EC2Instances) != 0:
|
||||
return getAWSInstances(stat, config)
|
||||
case len(stat.GCPCoordinators) != 0:
|
||||
return getGCPInstances(stat, config)
|
||||
case len(stat.AzureCoordinators) != 0:
|
||||
@ -26,38 +24,6 @@ func GetScalingGroupsFromConfig(stat state.ConstellationState, config *configc.C
|
||||
}
|
||||
}
|
||||
|
||||
func getAWSInstances(stat state.ConstellationState, _ *configc.Config) (coordinators, nodes cmdc.ScalingGroup, err error) {
|
||||
coordinatorID, _, err := stat.EC2Instances.GetOne()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
coordinatorMap := stat.EC2Instances
|
||||
var coordinatorInstances cmdc.Instances
|
||||
for _, node := range coordinatorMap {
|
||||
coordinatorInstances = append(coordinatorInstances, cmdc.Instance(node))
|
||||
}
|
||||
// GroupID of coordinators is empty, since they currently do not scale.
|
||||
coordinators = cmdc.ScalingGroup{
|
||||
Instances: coordinatorInstances,
|
||||
GroupID: "",
|
||||
}
|
||||
nodeMap := stat.EC2Instances.GetOthers(coordinatorID)
|
||||
if len(nodeMap) == 0 {
|
||||
return cmdc.ScalingGroup{}, cmdc.ScalingGroup{}, errors.New("no nodes available, can't create Constellation with one instance")
|
||||
}
|
||||
|
||||
var nodeInstances cmdc.Instances
|
||||
for _, node := range nodeMap {
|
||||
nodeInstances = append(nodeInstances, cmdc.Instance(node))
|
||||
}
|
||||
|
||||
// TODO: make min / max configurable and abstract autoscaling for different cloud providers
|
||||
// TODO: GroupID of nodes is empty, since they currently do not scale.
|
||||
nodes = cmdc.ScalingGroup{Instances: nodeInstances}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getGCPInstances(stat state.ConstellationState, config *configc.Config) (coordinators, nodes cmdc.ScalingGroup, err error) {
|
||||
coordinatorMap := stat.GCPCoordinators
|
||||
if len(coordinatorMap) == 0 {
|
||||
|
@ -2,7 +2,6 @@ package state
|
||||
|
||||
import (
|
||||
"github.com/edgelesssys/constellation/cli/cloud/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/cli/ec2"
|
||||
)
|
||||
|
||||
// ConstellationState is the state of a Constellation.
|
||||
@ -11,9 +10,6 @@ type ConstellationState struct {
|
||||
UID string `json:"uid,omitempty"`
|
||||
CloudProvider string `json:"cloudprovider,omitempty"`
|
||||
|
||||
EC2Instances ec2.Instances `json:"ec2instances,omitempty"`
|
||||
EC2SecurityGroup string `json:"ec2securitygroup,omitempty"`
|
||||
|
||||
GCPNodes cloudtypes.Instances `json:"gcpnodes,omitempty"`
|
||||
GCPCoordinators cloudtypes.Instances `json:"gcpcoordinators,omitempty"`
|
||||
GCPNodeInstanceGroup string `json:"gcpnodeinstancegroup,omitempty"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user