Skip to content

Commit

Permalink
Add fault-injection capability (#4325)
Browse files Browse the repository at this point in the history
  • Loading branch information
harishxr authored Sep 11, 2024
1 parent 9ddccf9 commit 8e3ac0a
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 0 deletions.
14 changes: 14 additions & 0 deletions agent/app/agent_capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const (
capabilityGpuDriverVersion = "gpu-driver-version"
capabilityEBSTaskAttach = "storage.ebs-task-volume-attach"
capabilityContainerRestartPolicy = "container-restart-policy"
capabilityFaultInjection = "fault-injection"

// network capabilities, going forward, please append "network." prefix to any new networking capability we introduce
networkCapabilityPrefix = "network."
Expand Down Expand Up @@ -198,6 +199,7 @@ var (
// ecs.capability.service-connect-v1
// ecs.capability.network.container-port-range
// ecs.capability.container-restart-policy
// ecs.capability.fault-injection
func (agent *ecsAgent) capabilities() ([]*ecs.Attribute, error) {
var capabilities []*ecs.Attribute

Expand Down Expand Up @@ -312,6 +314,9 @@ func (agent *ecsAgent) capabilities() ([]*ecs.Attribute, error) {
capabilities = removeAttributesByNames(capabilities, externalUnsupportedCapabilities)
}

// add fault-injection capabilities if applicable
capabilities = agent.appendFaultInjectionCapabilities(capabilities)

return capabilities, nil
}

Expand Down Expand Up @@ -538,6 +543,15 @@ func (agent *ecsAgent) appendEBSTaskAttachCapabilities(capabilities []*ecs.Attri
return capabilities
}

func (agent *ecsAgent) appendFaultInjectionCapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute {
if isFaultInjectionToolingAvailable() {
capabilities = appendNameOnlyAttribute(capabilities, attributePrefix+capabilityFaultInjection)
} else {
seelog.Warn("Fault injection capability not enabled: Required network tools (iptables, tc) are missing")
}
return capabilities
}

func defaultGetSubDirectories(path string) ([]string, error) {
var subDirectories []string

Expand Down
24 changes: 24 additions & 0 deletions agent/app/agent_capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1558,3 +1558,27 @@ func TestAppendGMSADomainlessCapabilitiesFalse(t *testing.T) {

assert.Equal(t, len(expectedCapabilities), len(capabilities))
}

func TestAppendFaultInjectionCapabilities(t *testing.T) {
originalIsFaultInjectionToolingAvailable := isFaultInjectionToolingAvailable
defer func() { isFaultInjectionToolingAvailable = originalIsFaultInjectionToolingAvailable }()
t.Run("Fault Injection Capability Available", func(t *testing.T) {
// Test case where required tooling is available
isFaultInjectionToolingAvailable = func() bool { return true }
capabilities := []*ecs.Attribute{}
agent := &ecsAgent{}
capabilities = agent.appendFaultInjectionCapabilities(capabilities)
// Check that the only capability is "ecs.capability.fault-injection"
require.Len(t, capabilities, 1)
assert.Equal(t, "ecs.capability.fault-injection", aws.StringValue(capabilities[0].Name))
})
t.Run("Fault Injection Capability Not Available", func(t *testing.T) {
// Test case where required tooling is not available
isFaultInjectionToolingAvailable = func() bool { return false }
capabilities := []*ecs.Attribute{}
agent := &ecsAgent{}
capabilities = agent.appendFaultInjectionCapabilities(capabilities)
// Check that no capability is added
assert.Empty(t, capabilities)
})
}
20 changes: 20 additions & 0 deletions agent/app/agent_capability_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package app

import (
"os/exec"
"path/filepath"
"strings"

Expand Down Expand Up @@ -236,3 +237,22 @@ func (agent *ecsAgent) getTaskENIPluginVersionAttribute() (*ecs.Attribute, error
func defaultIsPlatformExecSupported() (bool, error) {
return true, nil
}

// var to allow mocking for checkNetworkTooling
var isFaultInjectionToolingAvailable = checkFaultInjectionTooling

// wrapper around exec.LookPath
var lookPathFunc = exec.LookPath

// checkFaultInjectionTooling checks for the required network packages like iptables, tc
// to be available on the host before ecs.capability.fault-injection can be advertised
func checkFaultInjectionTooling() bool {
tools := []string{"iptables", "tc"}
for _, tool := range tools {
if _, err := lookPathFunc(tool); err != nil {
seelog.Warnf("Failed to find network tool %s: %v", tool, err)
return false
}
}
return true
}
23 changes: 23 additions & 0 deletions agent/app/agent_capability_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"os"
"os/exec"
"path/filepath"
"testing"

Expand Down Expand Up @@ -972,3 +973,25 @@ func TestAppendFSxWindowsFileServerCapabilities(t *testing.T) {
assert.Equal(t, len(inputCapabilities), len(capabilities))
assert.EqualValues(t, capabilities, inputCapabilities)
}

func TestCheckNetworkTooling(t *testing.T) {
originalLookPath := exec.LookPath
defer func() {
lookPathFunc = originalLookPath
}()

// Test case: All tools are available
lookPathFunc = func(file string) (string, error) {
return "/usr/bin" + file, nil
}
assert.True(t, checkFaultInjectionTooling(), "Expected checkNetworkTooling to return true when all tools are available")

// Test case: One tool is missing
lookPathFunc = func(file string) (string, error) {
if file == "iptables" {
return "", exec.ErrNotFound
}
return "/usr/bin" + file, nil
}
assert.False(t, checkFaultInjectionTooling(), "Expected checkNetworkTooling to return false when a tool is missing")
}
9 changes: 9 additions & 0 deletions agent/app/agent_capability_unspecified.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,12 @@ func (agent *ecsAgent) getTaskENIPluginVersionAttribute() (*ecs.Attribute, error
func defaultIsPlatformExecSupported() (bool, error) {
return false, nil
}

// var to allow mocking for checkNetworkTooling
var isFaultInjectionToolingAvailable = checkFaultInjectionTooling

// checkFaultInjectionTooling checks for the required network packages like iptables, tc
// to be available on the host before ecs.capability.fault-injection can be advertised
func checkFaultInjectionTooling() bool {
return false
}
10 changes: 10 additions & 0 deletions agent/app/agent_capability_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,13 @@ func defaultIsPlatformExecSupported() (bool, error) {
}
return true, nil
}

// var to allow mocking for checkNetworkTooling
var isFaultInjectionToolingAvailable = checkFaultInjectionTooling

// checkFaultInjectionTooling checks for the required network packages like iptables, tc
// to be available on the host before ecs.capability.fault-injection can be advertised
func checkFaultInjectionTooling() bool {
seelog.Warnf("Fault injection tooling is not supported on windows")
return false
}

0 comments on commit 8e3ac0a

Please sign in to comment.