/
types.go
177 lines (161 loc) · 7.17 KB
/
types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package containermetadata
import (
"context"
"encoding/json"
"fmt"
"time"
apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container"
"github.com/docker/docker/api/types"
)
const (
// MetadataInitial is the initial state of the metadata file which
// contains metadata provided by the ECS Agent
MetadataInitialText = "INITIAL"
// MetadataReady is the final state of the metadata file which indicates
// it has acquired all the data it needs (Currently from the Agent and Docker)
MetadataReadyText = "READY"
)
const (
MetadataInitial MetadataStatus = iota
MetadataReady
)
// MetadataStatus specifies the current update status of the metadata file.
// The purpose of this status is for users to check if the metadata file has
// reached the stage they need before they read the rest of the file to avoid
// race conditions (Since the final stage will need to be after the container
// starts up
// In the future the metadata may require multiple stages of update and these
// statuses should amended/appended accordingly.
type MetadataStatus int32
func (status MetadataStatus) MarshalText() (text []byte, err error) {
switch status {
case MetadataInitial:
text = []byte(MetadataInitialText)
case MetadataReady:
text = []byte(MetadataReadyText)
default:
return nil, fmt.Errorf("failed marshalling MetadataStatus %v", status)
}
return
}
func (status *MetadataStatus) UnmarshalText(text []byte) error {
t := string(text)
switch t {
case MetadataInitialText:
*status = MetadataInitial
case MetadataReadyText:
*status = MetadataReady
default:
return fmt.Errorf("failed unmarshalling MetadataStatus %s", text)
}
return nil
}
// DockerMetadataClient is a wrapper for the docker interface functions we need
// We use this as a dummy type to be able to pass in dockerapi.DockerClient to
// our functions without creating import cycles
// We make it exported because we need to use it for testing (Using the MockDockerClient
// in engine package leads to import cycles)
// The problems described above are indications dockerapi.DockerClient needs to be moved
// outside the engine package
type DockerMetadataClient interface {
InspectContainer(context.Context, string, time.Duration) (*types.ContainerJSON, error)
}
// Network is a struct that keeps track of metadata of a network interface
type Network struct {
NetworkMode string `json:"NetworkMode,omitempty"`
IPv4Addresses []string `json:"IPv4Addresses,omitempty"`
IPv6Addresses []string `json:"IPv6Addresses,omitempty"`
}
// NetworkMetadata keeps track of the data we parse from the Network Settings
// in docker containers. While most information is redundant with the internal
// Network struct, we keeps this wrapper in case we wish to add data specifically
// from the NetworkSettings
type NetworkMetadata struct {
networks []Network
}
// DockerContainerMetadata keeps track of all metadata acquired from Docker inspection
// Has redundancies with dockerapi.DockerContainerMetadata but this packages all
// docker metadata we want in the service so we can change features easily
type DockerContainerMetadata struct {
containerID string
dockerContainerName string
imageID string
imageName string
ports []apicontainer.PortBinding
networkInfo NetworkMetadata
}
// TaskMetadata keeps track of all metadata associated with a task
// provided by AWS, does not depend on the creation of the container
type TaskMetadata struct {
containerName string
taskARN string
taskDefinitionFamily string
taskDefinitionRevision string
}
// Metadata packages all acquired metadata and is used to format it
// into JSON to write to the metadata file. We have it flattened, rather
// than simply containing the previous three structures to simplify JSON
// parsing and avoid exposing those structs in the final metadata file.
type Metadata struct {
cluster string
taskMetadata TaskMetadata
dockerContainerMetadata DockerContainerMetadata
containerInstanceARN string
metadataStatus MetadataStatus
availabilityZone string
hostPrivateIPv4Address string
hostPublicIPv4Address string
}
// metadataSerializer is an intermediate struct that converts the information
// in Metadata into information to encode into JSON
type metadataSerializer struct {
Cluster string `json:"Cluster,omitempty"`
ContainerInstanceARN string `json:"ContainerInstanceARN,omitempty"`
TaskARN string `json:"TaskARN,omitempty"`
TaskDefinitionFamily string `json:"TaskDefinitionFamily,omitempty"`
TaskDefinitionRevision string `json:"TaskDefinitionRevision,omitempty"`
ContainerID string `json:"ContainerID,omitempty"`
ContainerName string `json:"ContainerName,omitempty"`
DockerContainerName string `json:"DockerContainerName,omitempty"`
ImageID string `json:"ImageID,omitempty"`
ImageName string `json:"ImageName,omitempty"`
Ports []apicontainer.PortBinding `json:"PortMappings,omitempty"`
Networks []Network `json:"Networks,omitempty"`
MetadataFileStatus MetadataStatus `json:"MetadataFileStatus,omitempty"`
AvailabilityZone string `json:"AvailabilityZone,omitempty"`
HostPrivateIPv4Address string `json:"HostPrivateIPv4Address,omitempty"`
HostPublicIPv4Address string `json:"HostPublicIPv4Address,omitempty"`
}
func (m Metadata) MarshalJSON() ([]byte, error) {
return json.Marshal(
metadataSerializer{
Cluster: m.cluster,
ContainerInstanceARN: m.containerInstanceARN,
TaskARN: m.taskMetadata.taskARN,
TaskDefinitionFamily: m.taskMetadata.taskDefinitionFamily,
TaskDefinitionRevision: m.taskMetadata.taskDefinitionRevision,
ContainerID: m.dockerContainerMetadata.containerID,
ContainerName: m.taskMetadata.containerName,
DockerContainerName: m.dockerContainerMetadata.dockerContainerName,
ImageID: m.dockerContainerMetadata.imageID,
ImageName: m.dockerContainerMetadata.imageName,
Ports: m.dockerContainerMetadata.ports,
Networks: m.dockerContainerMetadata.networkInfo.networks,
MetadataFileStatus: m.metadataStatus,
AvailabilityZone: m.availabilityZone,
HostPrivateIPv4Address: m.hostPrivateIPv4Address,
HostPublicIPv4Address: m.hostPublicIPv4Address,
})
}