Skip to content

Commit

Permalink
api: add Hostname, ExtraHosts for pause container
Browse files Browse the repository at this point in the history
This change adds Hostname and ExtraHosts to the pause container's docker
config and host config respectively. This allows awsvpc tasks to have
/etc/hosts entries for the ENI private ips
  • Loading branch information
adnxn committed Mar 20, 2018
1 parent 3b211fc commit ee83b9b
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 8 deletions.
3 changes: 2 additions & 1 deletion agent/acs/model/api/api-2.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@
"ipv4Addresses":{"shape":"IPv4AddressList"},
"ipv6Addresses":{"shape":"IPv6AddressList"},
"domainName":{"shape":"StringList"},
"domainNameServers":{"shape":"StringList"}
"domainNameServers":{"shape":"StringList"},
"privateDnsName":{"shape":"String"}
}
},
"ElasticNetworkInterfaceList":{
Expand Down
2 changes: 2 additions & 0 deletions agent/acs/model/ecsacs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ type ElasticNetworkInterface struct {
Ipv6Addresses []*IPv6AddressAssignment `locationName:"ipv6Addresses" type:"list"`

MacAddress *string `locationName:"macAddress" type:"string"`

PrivateDnsName *string `locationName:"privateDnsName" type:"string"`
}

// String returns the string representation
Expand Down
21 changes: 15 additions & 6 deletions agent/api/eni.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type ENI struct {
// DomainNameSearchList specifies the search list for the domain
// name lookup, for the eni
DomainNameSearchList []string `json:",omitempty"`

// PrivateDNSName is the dns name assigned by the vpc to this eni
PrivateDNSName string `json:",omitempty"`
}

// GetIPV4Addresses returns a list of ipv4 addresses allocated to the ENI
Expand All @@ -60,6 +63,11 @@ func (eni *ENI) GetIPV6Addresses() []string {
return addresses
}

// GetHostname returns the hostname assigned to the ENI
func (eni *ENI) GetHostname() string {
return eni.PrivateDNSName
}

// String returns a human readable version of the ENI object
func (eni *ENI) String() string {
var ipv4Addresses []string
Expand All @@ -71,8 +79,8 @@ func (eni *ENI) String() string {
ipv6Addresses = append(ipv6Addresses, addr.Address)
}
return fmt.Sprintf(
"eni id:%s, mac: %s, ipv4addresses: [%s], ipv6addresses: [%s], dns: [%s], dns search: [%s]",
eni.ID, eni.MacAddress, strings.Join(ipv4Addresses, ","), strings.Join(ipv6Addresses, ","),
"eni id:%s, mac: %s, hostname: %s, ipv4addresses: [%s], ipv6addresses: [%s], dns: [%s], dns search: [%s]",
eni.ID, eni.MacAddress, eni.GetHostname(), strings.Join(ipv4Addresses, ","), strings.Join(ipv6Addresses, ","),
strings.Join(eni.DomainNameServers, ","), strings.Join(eni.DomainNameSearchList, ","))
}

Expand Down Expand Up @@ -116,10 +124,11 @@ func ENIFromACS(acsenis []*ecsacs.ElasticNetworkInterface) (*ENI, error) {
}

eni := &ENI{
ID: aws.StringValue(acsenis[0].Ec2Id),
IPV4Addresses: ipv4,
IPV6Addresses: ipv6,
MacAddress: aws.StringValue(acsenis[0].MacAddress),
ID: aws.StringValue(acsenis[0].Ec2Id),
IPV4Addresses: ipv4,
IPV6Addresses: ipv6,
MacAddress: aws.StringValue(acsenis[0].MacAddress),
PrivateDNSName: aws.StringValue(acsenis[0].PrivateDnsName),
}
for _, nameserverIP := range acsenis[0].DomainNameServers {
eni.DomainNameServers = append(eni.DomainNameServers, aws.StringValue(nameserverIP))
Expand Down
2 changes: 2 additions & 0 deletions agent/api/eni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestENIFromACS(t *testing.T) {
MacAddress: aws.String("mac"),
DomainNameServers: []*string{aws.String(defaultDNS), aws.String(customDNS)},
DomainName: []*string{aws.String(customSearchDomain)},
PrivateDnsName: aws.String("ip.region.compute.internal"),
},
}

Expand All @@ -66,6 +67,7 @@ func TestENIFromACS(t *testing.T) {
assert.Equal(t, customDNS, eni.DomainNameServers[1])
assert.Len(t, eni.DomainNameSearchList, 1)
assert.Equal(t, customSearchDomain, eni.DomainNameSearchList[0])
assert.Equal(t, aws.StringValue(acsenis[0].PrivateDnsName), eni.PrivateDNSName)
}

// TestValidateENIFromACS tests the validation of enis from acs
Expand Down
51 changes: 51 additions & 0 deletions agent/api/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ func (task *Task) dockerConfig(container *Container, apiVersion dockerclient.Doc
config.Labels = make(map[string]string)
}

if container.Type == ContainerCNIPause {
// apply hostname to pause container's docker config
return task.applyENIHostname(config), nil
}

return config, nil
}

Expand Down Expand Up @@ -625,6 +630,12 @@ func (task *Task) dockerHostConfig(container *Container, dockerContainerMap map[
hostConfig.NetworkMode = networkMode
// Override 'awsvpc' parameters if needed
if container.Type == ContainerCNIPause {

// apply ExtraHosts to HostConfig for pause container
if hosts := task.generateENIExtraHosts(); hosts != nil {
hostConfig.ExtraHosts = append(hostConfig.ExtraHosts, hosts...)
}

// Override the DNS settings for the pause container if ENI has custom
// DNS settings
return task.overrideDNS(hostConfig), nil
Expand Down Expand Up @@ -695,6 +706,46 @@ func (task *Task) overrideDNS(hostConfig *docker.HostConfig) *docker.HostConfig
return hostConfig
}

// applyENIHostname adds the hostname provided by the ENI message to the
// container's docker config. At the time of implmentation, we are only using it
// to configure the pause container for awsvpc tasks
func (task *Task) applyENIHostname(dockerConfig *docker.Config) *docker.Config {
eni := task.GetTaskENI()
if eni == nil {
return dockerConfig
}

hostname := eni.GetHostname()
if hostname == "" {
return dockerConfig
}

dockerConfig.Hostname = hostname
return dockerConfig
}

// generateENIExtraHosts returns a slice of strings of the form "hostname:ip"
// that is generated using the hostname and ip addresses allocated to the ENI
func (task *Task) generateENIExtraHosts() []string {
eni := task.GetTaskENI()
if eni == nil {
return nil
}

hostname := eni.GetHostname()
if hostname == "" {
return nil
}

extraHosts := []string{}

for _, ip := range eni.GetIPV4Addresses() {
host := fmt.Sprintf("%s:%s", hostname, ip)
extraHosts = append(extraHosts, host)
}
return extraHosts
}

func (task *Task) dockerLinks(container *Container, dockerContainerMap map[string]*DockerContainer) ([]string, error) {
dockerLinkArr := make([]string, len(container.Links))
for i, link := range container.Links {
Expand Down
15 changes: 15 additions & 0 deletions agent/api/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,21 @@ func TestDockerHostConfigPauseContainer(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, []string{"169.254.169.253"}, config.DNS)
assert.Equal(t, []string{"us-west-2.compute.internal"}, config.DNSSearch)

// Verify eni ExtraHosts added to HostConfig for "pause" container
ipaddr := &ENIIPV4Address{Primary: true, Address: "10.0.1.1"}
testTask.ENI.IPV4Addresses = []*ENIIPV4Address{ipaddr}
testTask.ENI.PrivateDNSName = "eni.ip.region.compute.internal"

config, err = testTask.DockerHostConfig(testTask.Containers[2], dockerMap(testTask), defaultDockerClientAPIVersion)
assert.Nil(t, err)
assert.Equal(t, []string{"eni.ip.region.compute.internal:10.0.1.1"}, config.ExtraHosts)

// Verify eni Hostname is added to DockerConfig for "pause" container
dockerconfig, dockerConfigErr := testTask.DockerConfig(testTask.Containers[2], defaultDockerClientAPIVersion)
assert.Nil(t, dockerConfigErr)
assert.Equal(t, "eni.ip.region.compute.internal", dockerconfig.Hostname)

}

func TestBadDockerHostConfigRawConfig(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion agent/statemanager/state_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ const (
// d) Added task cgroup related fields ('CPU', 'Memory', 'MemoryCPULimitsEnabled') to 'api.Task'
// 9) Add 'ipToTask' map to state file
// 10) Add 'healthCheckType' field in 'api.Container'
ECSDataVersion = 10
// 11) Add 'PrivateDNSName' field to 'api.ENI'
ECSDataVersion = 11

// ecsDataFile specifies the filename in the ECS_DATADIR
ecsDataFile = "ecs_agent_data.json"
Expand Down

0 comments on commit ee83b9b

Please sign in to comment.