Skip to content

Commit

Permalink
Add unit test when IMDS mode is disabled
Browse files Browse the repository at this point in the history
Update README to reflect new behavior. Fix NodeMetadata initialization logic.
  • Loading branch information
snay2 committed Dec 5, 2022
1 parent 3850aa6 commit d2b2256
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ The `enableSqsTerminationDraining` must be set to false for these configuration
The Queue Processor Mode does not allow for fine-grained configuration of which events are handled through helm configuration keys. Instead, you can modify your Amazon EventBridge rules to not send certain types of events to the SQS Queue so that NTH does not process those events. All events when operating in Queue Processor mode are Cordoned and Drained unless the `cordon-only` flag is set to true.


The `enableSqsTerminationDraining` flag turns on Queue Processor Mode. When Queue Processor Mode is enabled, IMDS mode cannot be active. NTH cannot respond to queue events AND monitor IMDS paths. Queue Processor Mode still queries for node information on startup, but this information is not required for normal operation, so it is safe to disable IMDS for the NTH pod.
The `enableSqsTerminationDraining` flag turns on Queue Processor Mode. When Queue Processor Mode is enabled, IMDS mode will be disabled, even if you explicitly enabled any of the IMDS configuration keys. NTH cannot respond to queue events AND monitor IMDS paths. In this case, it is safe to disable IMDS for the NTH pod.

<details opened>
<summary>AWS Node Termination Handler - IMDS Processor</summary>
Expand Down
57 changes: 23 additions & 34 deletions pkg/ec2metadata/ec2metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,42 +326,31 @@ func retry(attempts int, sleep time.Duration, httpReq func() (*http.Response, er

// GetNodeMetadata attempts to gather additional ec2 instance information from the metadata service
func (e *Service) GetNodeMetadata(imdsDisabled bool) NodeMetadata {
var metadata NodeMetadata
if (!imdsDisabled) {
identityDoc, err := e.GetMetadataInfo(IdentityDocPath)
if err != nil {
log.Err(err).Msg("Unable to fetch metadata from IMDS")
return metadata
}
err = json.NewDecoder(strings.NewReader(identityDoc)).Decode(&metadata)
if err != nil {
log.Warn().Msg("Unable to fetch instance identity document from ec2 metadata")
metadata.InstanceID, _ = e.GetMetadataInfo(InstanceIDPath)
metadata.InstanceType, _ = e.GetMetadataInfo(InstanceTypePath)
metadata.LocalIP, _ = e.GetMetadataInfo(LocalIPPath)
metadata.AvailabilityZone, _ = e.GetMetadataInfo(AZPlacementPath)
if len(metadata.AvailabilityZone) > 1 {
metadata.Region = metadata.AvailabilityZone[0 : len(metadata.AvailabilityZone)-1]
metadata := NodeMetadata{}
if !imdsDisabled {
identityDoc, err := e.GetMetadataInfo(IdentityDocPath)
if err != nil {
log.Err(err).Msg("Unable to fetch metadata from IMDS")
return metadata
}
}
metadata.InstanceLifeCycle, _ = e.GetMetadataInfo(InstanceLifeCycle)
metadata.LocalHostname, _ = e.GetMetadataInfo(LocalHostnamePath)
metadata.PublicHostname, _ = e.GetMetadataInfo(PublicHostnamePath)
metadata.PublicIP, _ = e.GetMetadataInfo(PublicIPPath)
err = json.NewDecoder(strings.NewReader(identityDoc)).Decode(&metadata)
if err != nil {
log.Warn().Msg("Unable to fetch instance identity document from ec2 metadata")
metadata.InstanceID, _ = e.GetMetadataInfo(InstanceIDPath)
metadata.InstanceType, _ = e.GetMetadataInfo(InstanceTypePath)
metadata.LocalIP, _ = e.GetMetadataInfo(LocalIPPath)
metadata.AvailabilityZone, _ = e.GetMetadataInfo(AZPlacementPath)
if len(metadata.AvailabilityZone) > 1 {
metadata.Region = metadata.AvailabilityZone[0 : len(metadata.AvailabilityZone)-1]
}
}
metadata.InstanceLifeCycle, _ = e.GetMetadataInfo(InstanceLifeCycle)
metadata.LocalHostname, _ = e.GetMetadataInfo(LocalHostnamePath)
metadata.PublicHostname, _ = e.GetMetadataInfo(PublicHostnamePath)
metadata.PublicIP, _ = e.GetMetadataInfo(PublicIPPath)

log.Info().Interface("metadata", metadata).Msg("Startup Metadata Retrieved")
} else {
metadata.AccountId = ""
metadata.InstanceID = ""
metadata.InstanceLifeCycle = ""
metadata.InstanceType = ""
metadata.PublicHostname = ""
metadata.PublicIP = ""
metadata.LocalHostname = ""
metadata.LocalIP = ""
metadata.AvailabilityZone = ""
metadata.Region = ""
}
log.Info().Interface("metadata", metadata).Msg("Startup Metadata Retrieved")
}

return metadata
}
25 changes: 25 additions & 0 deletions pkg/ec2metadata/ec2metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,11 +582,36 @@ func TestGetNodeMetadata(t *testing.T) {
imds := ec2metadata.New(server.URL, 1)
nodeMetadata := imds.GetNodeMetadata(false)

h.Assert(t, nodeMetadata.AccountId == "", `AccountId should be empty string (only present in SQS events)`)
h.Assert(t, nodeMetadata.InstanceID == `metadata`, `Missing required NodeMetadata field InstanceID`)
h.Assert(t, nodeMetadata.InstanceLifeCycle == `metadata`, `Missing required NodeMetadata field InstanceLifeCycle`)
h.Assert(t, nodeMetadata.InstanceType == `metadata`, `Missing required NodeMetadata field InstanceType`)
h.Assert(t, nodeMetadata.LocalHostname == `metadata`, `Missing required NodeMetadata field LocalHostname`)
h.Assert(t, nodeMetadata.LocalIP == `metadata`, `Missing required NodeMetadata field LocalIP`)
h.Assert(t, nodeMetadata.PublicHostname == `metadata`, `Missing required NodeMetadata field PublicHostname`)
h.Assert(t, nodeMetadata.PublicIP == `metadata`, `Missing required NodeMetadata field PublicIP`)
h.Assert(t, nodeMetadata.AvailabilityZone == `metadata`, `Missing required NodeMetadata field AvailabilityZone`)
h.Assert(t, nodeMetadata.Region == `metadat`, `Region should equal AvailabilityZone with the final character truncated`)
}

func TestGetNodeMetadataWithIMDSDisabled(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
h.Ok(t, fmt.Errorf("IMDS was called when using Queue Processor mode"))
}))
defer server.Close()

// Use URL from our local test server that throws errors when called
imds := ec2metadata.New(server.URL, 1)
nodeMetadata := imds.GetNodeMetadata(true)

h.Assert(t, nodeMetadata.AccountId == "", "AccountId should be empty string")
h.Assert(t, nodeMetadata.InstanceID == "", "InstanceID should be empty string")
h.Assert(t, nodeMetadata.InstanceLifeCycle == "", "InstanceLifeCycle should be empty string")
h.Assert(t, nodeMetadata.InstanceType == "", "InstanceType should be empty string")
h.Assert(t, nodeMetadata.PublicHostname == "", "PublicHostname should be empty string")
h.Assert(t, nodeMetadata.PublicIP == "", "PublicIP should be empty string")
h.Assert(t, nodeMetadata.LocalHostname == "", "LocalHostname should be empty string")
h.Assert(t, nodeMetadata.LocalIP == "", "LocalIP should be empty string")
h.Assert(t, nodeMetadata.AvailabilityZone == "", "AvailabilityZone should be empty string")
h.Assert(t, nodeMetadata.Region == "", "Region should be empty string")
}

0 comments on commit d2b2256

Please sign in to comment.