Skip to content

Commit

Permalink
awsvpc: configure local routes with env var
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelkarp committed Sep 13, 2017
1 parent cb1c9ff commit 557658d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,10 @@ configure them as something other than the defaults.
| `ECS_IMAGE_MINIMUM_CLEANUP_AGE` | 30m | The minimum time interval between when an image is pulled and when it can be considered for automated image cleanup. | 1h | 1h |
| `ECS_NUM_IMAGES_DELETE_PER_CYCLE` | 5 | The maximum number of images to delete in a single automated image cleanup cycle. If set to less than 1, the value is ignored. | 5 | 5 |
| `ECS_INSTANCE_ATTRIBUTES` | `{"stack": "prod"}` | These attributes take effect only during initial registration. After the agent has joined an ECS cluster, use the PutAttributes API action to add additional attributes. For more information, see [Amazon ECS Container Agent Configuration](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-config.html) in the Amazon ECS Developer Guide.| `{}` | `{}` |
| `ECS_ENABLE_TASK_ENI` | `false` | Whether to enable task networking for task to be launched with its own network interface | `false` | `false` |
| `ECS_CNI_PLUGINS_PATH` | `/ecs/cni` | The path where the cni binary file is located | `/amazon-ecs-cni-plugins` | `/amazon-ecs-cni-plugins` |
| `ECS_AWSVPC_BLOCK_IMDS` | `true` | Whether to block access to [Instance Metdata](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) for Tasks started with `awsvpc` network mode | `false` | `false`|
| `ECS_ENABLE_TASK_ENI` | `false` | Whether to enable task networking for task to be launched with its own network interface | `false` | Not applicable |
| `ECS_CNI_PLUGINS_PATH` | `/ecs/cni` | The path where the cni binary file is located | `/amazon-ecs-cni-plugins` | Not applicable |
| `ECS_AWSVPC_BLOCK_IMDS` | `true` | Whether to block access to [Instance Metdata](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) for Tasks started with `awsvpc` network mode | `false` | Not applicable |
| `ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES` | `["10.0.15.0/24"]` | Additional routes that cause traffic to travel by the default ENI | `[]` | Not applicable |

### Persistence

Expand Down
12 changes: 12 additions & 0 deletions agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/aws/amazon-ecs-agent/agent/engine/dockerclient"
"github.com/aws/amazon-ecs-agent/agent/utils"
"github.com/cihub/seelog"
cnitypes "github.com/containernetworking/cni/pkg/types"
)

const (
Expand Down Expand Up @@ -343,6 +344,16 @@ func environmentConfig() (Config, error) {
seelog.Debugf("Setting instance attribute %v: %v", attributeKey, attributeValue)
}

var additionalLocalRoutes []cnitypes.IPNet
additionalLocalRoutesEnv := os.Getenv("ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES")
if additionalLocalRoutesEnv != "" {
err := json.Unmarshal([]byte(additionalLocalRoutesEnv), &additionalLocalRoutes)
if err != nil {
seelog.Warnf("Invalid format for ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES, expected a json array of CIDRs: %v", err)
errs = append(errs, err)
}
}

if len(errs) > 0 {
err = utils.NewMultiError(errs...)
} else {
Expand Down Expand Up @@ -381,6 +392,7 @@ func environmentConfig() (Config, error) {
InstanceAttributes: instanceAttributes,
CNIPluginsPath: cniPluginsPath,
AWSVPCBlockInstanceMetdata: awsVPCBlockInstanceMetadata,
AWSVPCAdditionalLocalRoutes: additionalLocalRoutes,
}, err
}

Expand Down
70 changes: 62 additions & 8 deletions agent/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package config

import (
"encoding/json"
"errors"
"os"
"reflect"
Expand Down Expand Up @@ -80,53 +81,75 @@ func TestBrokenEC2MetadataEndpoint(t *testing.T) {
}

func TestEnvironmentConfig(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_CLUSTER", "myCluster")
defer os.Unsetenv("ECS_CLUSTER")
os.Setenv("ECS_RESERVED_PORTS_UDP", "[42,99]")
defer os.Unsetenv("ECS_RESERVED_PORTS_UDP")
os.Setenv("ECS_RESERVED_MEMORY", "20")
defer os.Unsetenv("ECS_RESERVED_MEMORY")
os.Setenv("ECS_CONTAINER_STOP_TIMEOUT", "60s")
defer os.Unsetenv("ECS_CONTAINER_STOP_TIMEOUT")
os.Setenv("ECS_AVAILABLE_LOGGING_DRIVERS", "[\""+string(dockerclient.SyslogDriver)+"\"]")
defer os.Unsetenv("ECS_AVAILABLE_LOGGING_DRIVERS")
os.Setenv("ECS_SELINUX_CAPABLE", "true")
defer os.Unsetenv("ECS_SELINUX_CAPABLE")
os.Setenv("ECS_APPARMOR_CAPABLE", "true")
defer os.Unsetenv("ECS_APPARMOR_CAPABLE")
os.Setenv("ECS_DISABLE_PRIVILEGED", "true")
defer os.Unsetenv("ECS_DISABLE_PRIVILEGED")
os.Setenv("ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION", "90s")
defer os.Unsetenv("ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION")
os.Setenv("ECS_ENABLE_TASK_IAM_ROLE", "true")
defer os.Unsetenv("ECS_ENABLE_TASK_IAM_ROLE")
os.Setenv("ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST", "true")
defer os.Unsetenv("ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST")
os.Setenv("ECS_DISABLE_IMAGE_CLEANUP", "true")
defer os.Unsetenv("ECS_DISABLE_IMAGE_CLEANUP")
os.Setenv("ECS_IMAGE_CLEANUP_INTERVAL", "2h")
defer os.Unsetenv("ECS_IMAGE_CLEANUP_INTERVAL")
os.Setenv("ECS_IMAGE_MINIMUM_CLEANUP_AGE", "30m")
defer os.Unsetenv("ECS_IMAGE_MINIMUM_CLEANUP_AGE")
os.Setenv("ECS_NUM_IMAGES_DELETE_PER_CYCLE", "2")
defer os.Unsetenv("ECS_NUM_IMAGES_DELETE_PER_CYCLE")
os.Setenv("ECS_INSTANCE_ATTRIBUTES", "{\"my_attribute\": \"testing\"}")
defer os.Unsetenv("ECS_INSTANCE_ATTRIBUTES")
os.Setenv("ECS_ENABLE_TASK_ENI", "true")
defer os.Unsetenv("ECS_ENABLE_TASK_ENI")
additionalLocalRoutesJSON := `["1.2.3.4/22","5.6.7.8/32"]`
os.Setenv("ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES", additionalLocalRoutesJSON)

conf, err := environmentConfig()
assert.Nil(t, err)
assert.NoError(t, err)
assert.Equal(t, "myCluster", conf.Cluster)
assert.Equal(t, 2, len(conf.ReservedPortsUDP))
assert.Contains(t, conf.ReservedPortsUDP, uint16(42))
assert.Contains(t, conf.ReservedPortsUDP, uint16(99))
assert.Equal(t, uint16(20), conf.ReservedMemory)

expectedDuration, _ := time.ParseDuration("60s")
assert.Equal(t, expectedDuration, conf.DockerStopTimeout)

assert.Equal(t, []dockerclient.LoggingDriver{dockerclient.SyslogDriver}, conf.AvailableLoggingDrivers)

assert.True(t, conf.PrivilegedDisabled)
assert.True(t, conf.SELinuxCapable, "Wrong value for SELinuxCapable")
assert.True(t, conf.AppArmorCapable, "Wrong value for AppArmorCapable")
assert.True(t, conf.TaskIAMRoleEnabled, "Wrong value for TaskIAMRoleEnabled")
assert.True(t, conf.TaskIAMRoleEnabledForNetworkHost, "Wrong value for TaskIAMRoleEnabledForNetworkHost")
assert.True(t, conf.ImageCleanupDisabled, "Wrong value for ImageCleanupDisabled")
assert.True(t, conf.TaskENIEnabled, "Wrong value for TaskNetwork")

assert.Equal(t, (30 * time.Minute), conf.MinimumImageDeletionAge)
assert.Equal(t, (2 * time.Hour), conf.ImageCleanupInterval)
assert.Equal(t, 30*time.Minute, conf.MinimumImageDeletionAge)
assert.Equal(t, 2*time.Hour, conf.ImageCleanupInterval)
assert.Equal(t, 2, conf.NumImagesToDeletePerCycle)
assert.Equal(t, "testing", conf.InstanceAttributes["my_attribute"])
assert.Equal(t, (90 * time.Second), conf.TaskCleanupWaitDuration)
assert.Equal(t, 90*time.Second, conf.TaskCleanupWaitDuration)
serializedAdditionalLocalRoutesJSON, err := json.Marshal(conf.AWSVPCAdditionalLocalRoutes)
assert.NoError(t, err, "should marshal additional local routes")
assert.Equal(t, additionalLocalRoutesJSON, string(serializedAdditionalLocalRoutesJSON))
}

func TestTrimWhitespace(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_CLUSTER", "default \r")
os.Setenv("ECS_ENGINE_AUTH_TYPE", "dockercfg\r")

Expand All @@ -153,6 +176,8 @@ func TestTrimWhitespace(t *testing.T) {
}

func TestConfigBoolean(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_DISABLE_METRICS", "true")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand Down Expand Up @@ -253,6 +278,8 @@ func TestValidFormatParseEnvVariableDuration(t *testing.T) {
}

func TestInvalidTaskCleanupTimeout(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION", "1s")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -267,6 +294,8 @@ func TestInvalidTaskCleanupTimeout(t *testing.T) {
}

func TestTaskCleanupTimeout(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION", "10m")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -281,6 +310,8 @@ func TestTaskCleanupTimeout(t *testing.T) {
}

func TestInvalidReservedMemory(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_RESERVED_MEMORY", "-1")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -295,6 +326,8 @@ func TestInvalidReservedMemory(t *testing.T) {
}

func TestReservedMemory(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_RESERVED_MEMORY", "1")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -309,6 +342,8 @@ func TestReservedMemory(t *testing.T) {
}

func TestTaskIAMRoleEnabled(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_ENABLE_TASK_IAM_ROLE", "true")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -321,6 +356,8 @@ func TestTaskIAMRoleEnabled(t *testing.T) {
}

func TestTaskIAMRoleForHostNetworkEnabled(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST", "true")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -333,6 +370,8 @@ func TestTaskIAMRoleForHostNetworkEnabled(t *testing.T) {
}

func TestCredentialsAuditLogFile(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
dummyLocation := "/foo/bar.log"
os.Setenv("ECS_AUDIT_LOGFILE", dummyLocation)
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
Expand All @@ -346,6 +385,8 @@ func TestCredentialsAuditLogFile(t *testing.T) {
}

func TestCredentialsAuditLogDisabled(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_AUDIT_LOGFILE_DISABLED", "true")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -358,6 +399,8 @@ func TestCredentialsAuditLogDisabled(t *testing.T) {
}

func TestImageCleanupMinimumInterval(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_IMAGE_CLEANUP_INTERVAL", "1m")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -370,6 +413,8 @@ func TestImageCleanupMinimumInterval(t *testing.T) {
}

func TestImageCleanupMinimumNumImagesToDeletePerCycle(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_NUM_IMAGES_DELETE_PER_CYCLE", "-1")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
if err != nil {
Expand All @@ -382,9 +427,18 @@ func TestImageCleanupMinimumNumImagesToDeletePerCycle(t *testing.T) {
}

func TestAWSVPCBlockInstanceMetadata(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Setenv("ECS_AWSVPC_BLOCK_IMDS", "true")
defer os.Unsetenv("ECS_AWSVPC_BLOCK_IMDS")
cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
assert.NoError(t, err)
assert.True(t, cfg.AWSVPCBlockInstanceMetdata)
}

func TestInvalidAWSVPCAdditionalLocalRoutes(t *testing.T) {
os.Setenv("ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES", `["300.300.300.300/64"]`)
defer os.Unsetenv("ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES")
_, err := environmentConfig()
assert.Error(t, err)
}
4 changes: 3 additions & 1 deletion agent/config/config_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import (
)

func TestConfigDefault(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "foo-bar-1")
defer os.Unsetenv("AWS_DEFAULT_REGION")
os.Unsetenv("ECS_DISABLE_METRICS")
os.Unsetenv("ECS_RESERVED_PORTS")
os.Unsetenv("ECS_RESERVED_MEMORY")
Expand All @@ -49,7 +51,7 @@ func TestConfigDefault(t *testing.T) {
os.Unsetenv("ECS_AWSVPC_BLOCK_IMDS")

cfg, err := NewConfig(ec2.NewBlackholeEC2MetadataClient())
assert.Nil(t, err)
assert.NoError(t, err)

assert.Equal(t, "unix:///var/run/docker.sock", cfg.DockerEndpoint, "Default docker endpoint set incorrectly")
assert.Equal(t, "/data/", cfg.DataDir, "Default datadir set incorrectly")
Expand Down

0 comments on commit 557658d

Please sign in to comment.