@@ -19,6 +19,7 @@ import (
19
19
"path/filepath"
20
20
"runtime"
21
21
"strings"
22
+ "sync"
22
23
23
24
"github.com/aws/amazon-ecs-agent/agent/config"
24
25
"github.com/cihub/seelog"
@@ -36,10 +37,98 @@ const (
36
37
37
38
var cpuShareScaleFactor = runtime .NumCPU () * cpuSharesPerCore
38
39
40
+ // Task is the internal representation of a task in the ECS agent
41
+ // TODO: there are some fields which are not related to Windows. Remove them.
42
+ type Task struct {
43
+ // Arn is the unique identifer for the task
44
+ Arn string
45
+ // Overrides are the overrides applied to a task
46
+ Overrides TaskOverrides `json:"-"`
47
+ // Family is the name of the task definition family
48
+ Family string
49
+ // Version is the version of the task definition
50
+ Version string
51
+ // Containers are the containers for the task
52
+ Containers []* Container
53
+ // Volumes are the volumes for the task
54
+ Volumes []TaskVolume `json:"volumes"`
55
+ // CPU is a task-level limit for compute resources. A value of 1 means that
56
+ // the task may access 100% of 1 vCPU on the instance
57
+ CPU float64 `json:"Cpu,omitempty"`
58
+ // Memory is a task-level limit for memory resources in bytes
59
+ Memory int64 `json:"Memory,omitempty"`
60
+ // DesiredStatusUnsafe represents the state where the task should go. Generally,
61
+ // the desired status is informed by the ECS backend as a result of either
62
+ // API calls made to ECS or decisions made by the ECS service scheduler.
63
+ // The DesiredStatusUnsafe is almost always either TaskRunning or TaskStopped.
64
+ // NOTE: Do not access DesiredStatusUnsafe directly. Instead, use `UpdateStatus`,
65
+ // `UpdateDesiredStatus`, `SetDesiredStatus`, and `SetDesiredStatus`.
66
+ // TODO DesiredStatusUnsafe should probably be private with appropriately written
67
+ // setter/getter. When this is done, we need to ensure that the UnmarshalJSON
68
+ // is handled properly so that the state storage continues to work.
69
+ DesiredStatusUnsafe TaskStatus `json:"DesiredStatus"`
70
+
71
+ // KnownStatusUnsafe represents the state where the task is. This is generally
72
+ // the minimum of equivalent status types for the containers in the task;
73
+ // if one container is at ContainerRunning and another is at ContainerPulled,
74
+ // the task KnownStatusUnsafe would be TaskPulled.
75
+ // NOTE: Do not access KnownStatusUnsafe directly. Instead, use `UpdateStatus`,
76
+ // and `GetKnownStatus`.
77
+ // TODO KnownStatusUnsafe should probably be private with appropriately written
78
+ // setter/getter. When this is done, we need to ensure that the UnmarshalJSON
79
+ // is handled properly so that the state storage continues to work.
80
+ KnownStatusUnsafe TaskStatus `json:"KnownStatus"`
81
+ // KnownStatusTimeUnsafe captures the time when the KnownStatusUnsafe was last updated.
82
+ // NOTE: Do not access KnownStatusTime directly, instead use `GetKnownStatusTime`.
83
+ KnownStatusTimeUnsafe time.Time `json:"KnownTime"`
84
+
85
+ // PullStartedAtUnsafe is the timestamp when the task start pulling the first container,
86
+ // it won't be set if the pull never happens
87
+ PullStartedAtUnsafe time.Time `json:"PullStartedAt"`
88
+ // PullStoppedAtUnsafe is the timestamp when the task finished pulling the last container,
89
+ // it won't be set if the pull never happens
90
+ PullStoppedAtUnsafe time.Time `json:"PullStoppedAt"`
91
+ // ExecutionStoppedAtUnsafe is the timestamp when the task desired status moved to stopped,
92
+ // which is when the any of the essential containers stopped
93
+ ExecutionStoppedAtUnsafe time.Time `json:"ExecutionStoppedAt"`
94
+
95
+ // SentStatusUnsafe represents the last KnownStatusUnsafe that was sent to the ECS SubmitTaskStateChange API.
96
+ // TODO(samuelkarp) SentStatusUnsafe needs a lock and setters/getters.
97
+ // TODO SentStatusUnsafe should probably be private with appropriately written
98
+ // setter/getter. When this is done, we need to ensure that the UnmarshalJSON
99
+ // is handled properly so that the state storage continues to work.
100
+ SentStatusUnsafe TaskStatus `json:"SentStatus"`
101
+
102
+ StartSequenceNumber int64
103
+ StopSequenceNumber int64
104
+
105
+ // ExecutionCredentialsID is the ID of credentials that are used by agent to
106
+ // perform some action at the task level, such as pulling image from ECR
107
+ ExecutionCredentialsID string `json:"executionCredentialsID"`
108
+
109
+ // credentialsID is used to set the CredentialsId field for the
110
+ // IAMRoleCredentials object associated with the task. This id can be
111
+ // used to look up the credentials for task in the credentials manager
112
+ credentialsID string
113
+
114
+ // ENI is the elastic network interface specified by this task
115
+ ENI * ENI
116
+
117
+ // MemoryCPULimitsEnabled to determine if task supports CPU, memory limits
118
+ MemoryCPULimitsEnabled bool `json:"MemoryCPULimitsEnabled,omitempty"`
119
+
120
+ // cpuUnboundedEnabled determines whether a mix of unbounded and bounded CPU tasks
121
+ // are allowed to run in the instance
122
+ cpuUnboundedEnabled bool
123
+
124
+ // lock is for protecting all fields in the task struct
125
+ lock sync.RWMutex
126
+ }
127
+
39
128
// adjustForPlatform makes Windows-specific changes to the task after unmarshal
40
129
func (task * Task ) adjustForPlatform (cfg * config.Config ) {
41
130
task .downcaseAllVolumePaths ()
42
- task .cpuUnboundedWindowsEnabled = cfg .CPUUnboundedWindowsEnabled
131
+ task .cpuUnboundedEnabled = cfg .CPUUnboundedWindowsEnabled
43
132
}
44
133
45
134
// downcaseAllVolumePaths forces all volume paths (host path and container path)
@@ -70,14 +159,12 @@ func (task *Task) platformHostConfigOverride(hostConfig *docker.HostConfig) erro
70
159
task .overrideDefaultMemorySwappiness (hostConfig )
71
160
// Convert the CPUShares to CPUPercent
72
161
hostConfig .CPUPercent = hostConfig .CPUShares * percentageFactor / int64 (cpuShareScaleFactor )
73
- if hostConfig .CPUPercent == 0 {
162
+ if hostConfig .CPUPercent == 0 && hostConfig . CPUShares != 0 {
74
163
// if CPU percent is too low, we set it to the minimum(linux and some windows tasks).
75
164
// if the CPU is explicitly set to zero or not set at all, and CPU unbounded
76
165
// tasks are allowed for windows, let CPU percent be zero.
77
166
// this is a workaround to allow CPU unbounded tasks(https://github.com/aws/amazon-ecs-agent/issues/1127)
78
- if hostConfig .CPUShares != 0 {
79
- hostConfig .CPUPercent = minimumCPUPercent
80
- }
167
+ hostConfig .CPUPercent = minimumCPUPercent
81
168
}
82
169
hostConfig .CPUShares = 0
83
170
return nil
@@ -98,7 +185,7 @@ func (task *Task) overrideDefaultMemorySwappiness(hostConfig *docker.HostConfig)
98
185
// want. Instead, we convert 0 to 2 to be closer to expected behavior. The
99
186
// reason for 2 over 1 is that 1 is an invalid value (Linux's choice, not Docker's).
100
187
func (task * Task ) dockerCPUShares (containerCPU uint ) int64 {
101
- if containerCPU <= 1 && ! task .cpuUnboundedWindowsEnabled {
188
+ if containerCPU <= 1 && ! task .cpuUnboundedEnabled {
102
189
seelog .Debugf (
103
190
"Converting CPU shares to allowed minimum of 2 for task arn: [%s] and cpu shares: %d" ,
104
191
task .Arn , containerCPU )
0 commit comments