-
Notifications
You must be signed in to change notification settings - Fork 613
/
container.go
1608 lines (1331 loc) · 53.2 KB
/
container.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// 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 container
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
resourcestatus "github.com/aws/amazon-ecs-agent/agent/taskresource/status"
referenceutil "github.com/aws/amazon-ecs-agent/agent/utils/reference"
"github.com/aws/amazon-ecs-agent/ecs-agent/api/container/restart"
apicontainerstatus "github.com/aws/amazon-ecs-agent/ecs-agent/api/container/status"
apierrors "github.com/aws/amazon-ecs-agent/ecs-agent/api/errors"
"github.com/aws/amazon-ecs-agent/ecs-agent/credentials"
"github.com/aws/amazon-ecs-agent/ecs-agent/logger"
"github.com/aws/amazon-ecs-agent/ecs-agent/logger/field"
"github.com/aws/aws-sdk-go/aws"
"github.com/cihub/seelog"
"github.com/docker/docker/api/types"
dockercontainer "github.com/docker/docker/api/types/container"
)
const (
// defaultContainerSteadyStateStatus defines the container status at
// which the container is assumed to be in steady state. It is set
// to 'ContainerRunning' unless overridden
defaultContainerSteadyStateStatus = apicontainerstatus.ContainerRunning
// awslogsAuthExecutionRole is the string value passed in the task payload
// that specifies that the log driver should be authenticated using the
// execution role
awslogsAuthExecutionRole = "ExecutionRole"
// DockerHealthCheckType is the type of container health check provided by docker
DockerHealthCheckType = "docker"
// AuthTypeECR is to use image pull auth over ECR
AuthTypeECR = "ecr"
// AuthTypeASM is to use image pull auth over AWS Secrets Manager
AuthTypeASM = "asm"
// MetadataURIEnvironmentVariableName defines the name of the environment
// variable in containers' config, which can be used by the containers to access the
// v3 metadata endpoint
MetadataURIEnvironmentVariableName = "ECS_CONTAINER_METADATA_URI"
// MetadataURIEnvVarNameV4 defines the name of the environment
// variable in containers' config, which can be used by the containers to access the
// v4 metadata endpoint
MetadataURIEnvVarNameV4 = "ECS_CONTAINER_METADATA_URI_V4"
// MetadataURIFormatV4 defines the URI format for v4 metadata endpoint
MetadataURIFormatV4 = "http://169.254.170.2/v4/%s"
// AgentURIEnvVarName defines the name of the environment variable
// injected into containers that contains the Agent endpoints.
AgentURIEnvVarName = "ECS_AGENT_URI"
// AgentURIFormat defines the URI format for Agent endpoints
AgentURIFormat = "http://169.254.170.2/api/%s"
// SecretProviderSSM is to show secret provider being SSM
SecretProviderSSM = "ssm"
// SecretProviderASM is to show secret provider being ASM
SecretProviderASM = "asm"
// SecretTypeEnv is to show secret type being ENVIRONMENT_VARIABLE
SecretTypeEnv = "ENVIRONMENT_VARIABLE"
// SecretTargetLogDriver is to show secret target being "LOG_DRIVER", the default will be "CONTAINER"
SecretTargetLogDriver = "LOG_DRIVER"
// neuronVisibleDevicesEnvVar is the env which indicates that the container wants to use inferentia devices.
neuronVisibleDevicesEnvVar = "AWS_NEURON_VISIBLE_DEVICES"
credentialSpecPrefix = "credentialspec"
credentialSpecDomainlessPrefix = credentialSpecPrefix + "domainless"
)
var (
// MetadataURIFormat defines the URI format for v3 metadata endpoint. Made as a var to be able to
// overwrite it in test.
MetadataURIFormat = "http://169.254.170.2/v3/%s"
)
// DockerConfig represents additional metadata about a container to run. It's
// remodeled from the `ecsacs` api model file. Eventually it should not exist
// once this remodeling is refactored out.
type DockerConfig struct {
// Config is the configuration used to create container
Config *string `json:"config"`
// HostConfig is the configuration of container related to host resource
HostConfig *string `json:"hostConfig"`
// Version specifies the docker client API version to use
Version *string `json:"version"`
}
// HealthStatus contains the health check result returned by docker
type HealthStatus struct {
// Status is the container health status
Status apicontainerstatus.ContainerHealthStatus `json:"status,omitempty"`
// Since is the timestamp when container health status changed
Since *time.Time `json:"statusSince,omitempty"`
// ExitCode is the exitcode of health check if failed
ExitCode int `json:"exitCode,omitempty"`
// Output is the output of health check
Output string `json:"output,omitempty"`
}
type ManagedAgentState struct {
// ID of this managed agent state
ID string `json:"id,omitempty"`
// TODO: [ecs-exec] Change variable name from Status to KnownStatus in future PR to avoid noise
// Status is the managed agent health status
Status apicontainerstatus.ManagedAgentStatus `json:"status,omitempty"`
// SentStatus is the managed agent sent status
SentStatus apicontainerstatus.ManagedAgentStatus `json:"sentStatus,omitempty"`
// Reason is a placeholder for failure messaging
Reason string `json:"reason,omitempty"`
// LastStartedAt is the timestamp when the status last went from PENDING->RUNNING
LastStartedAt time.Time `json:"lastStartedAt,omitempty"`
// Metadata holds metadata about the managed agent
Metadata map[string]interface{} `json:"metadata,omitempty"`
// InitFailed indicates if exec agent initialization failed
InitFailed bool `json:"initFailed,omitempty"`
}
type ManagedAgent struct {
ManagedAgentState
// Name is the name of this managed agent. This name is streamed down from ACS.
Name string `json:"name,omitempty"`
// Properties of this managed agent. Properties are streamed down from ACS.
Properties map[string]string `json:"properties,omitempty"`
}
// Container is the internal representation of a container in the ECS agent
type Container struct {
// Name is the name of the container specified in the task definition
Name string
// RuntimeID is the docker id of the container
RuntimeID string
// TaskARNUnsafe is the task ARN of the task that the container belongs to. Access should be
// protected by lock i.e. via GetTaskARN and SetTaskARN.
TaskARNUnsafe string `json:"taskARN"`
// DependsOnUnsafe is the field which specifies the ordering for container startup and shutdown.
DependsOnUnsafe []DependsOn `json:"dependsOn,omitempty"`
// ManagedAgentsUnsafe presently contains only the executeCommandAgent
ManagedAgentsUnsafe []ManagedAgent `json:"managedAgents,omitempty"`
// V3EndpointID is a container identifier used to construct v3 metadata endpoint; it's unique among
// all the containers managed by the agent
V3EndpointID string
// Image is the image name specified in the task definition
Image string
// ImageID is the local ID of the image used in the container
ImageID string
// ImageDigest is the sha-256 digest of the container image as pulled from the repository
ImageDigest string
// Command is the command to run in the container which is specified in the task definition
Command []string
// CPU is the cpu limitation of the container which is specified in the task definition
CPU uint `json:"Cpu"`
// GPUIDs is the list of GPU ids for a container
GPUIDs []string
// Memory is the memory limitation of the container which is specified in the task definition
Memory uint
// Links contains a list of containers to link, corresponding to docker option: --link
Links []string
// FirelensConfig contains configuration for a Firelens container
FirelensConfig *FirelensConfig `json:"firelensConfiguration"`
// VolumesFrom contains a list of container's volume to use, corresponding to docker option: --volumes-from
VolumesFrom []VolumeFrom `json:"volumesFrom"`
// MountPoints contains a list of volume mount paths
MountPoints []MountPoint `json:"mountPoints"`
// Ports contains a list of ports binding configuration
Ports []PortBinding `json:"portMappings"`
// Secrets contains a list of secret
Secrets []Secret `json:"secrets"`
// Essential denotes whether the container is essential or not
Essential bool
// EntryPoint is entrypoint of the container, corresponding to docker option: --entrypoint
EntryPoint *[]string
// Environment is the environment variable set in the container
Environment map[string]string `json:"environment"`
// EnvironmentFiles is the list of environmentFile used to populate environment variables
EnvironmentFiles []EnvironmentFile `json:"environmentFiles"`
// Overrides contains the configuration to override of a container
Overrides ContainerOverrides `json:"overrides"`
// DockerConfig is the configuration used to create the container
DockerConfig DockerConfig `json:"dockerConfig"`
// CredentialSpecs is the configuration used for configuring gMSA authentication for the container
CredentialSpecs []string `json:"credentialSpecs,omitempty"`
// RegistryAuthentication is the auth data used to pull image
RegistryAuthentication *RegistryAuthenticationData `json:"registryAuthentication"`
// HealthCheckType is the mechanism to use for the container health check
// currently it only supports 'DOCKER'
HealthCheckType string `json:"healthCheckType,omitempty"`
// Health contains the health check information of container health check
Health HealthStatus `json:"-"`
// LogsAuthStrategy specifies how the logs driver for the container will be
// authenticated
LogsAuthStrategy string
// StartTimeout specifies the time value after which if a container has a dependency
// on another container and the dependency conditions are 'SUCCESS', 'COMPLETE', 'HEALTHY',
// then that dependency will not be resolved.
StartTimeout uint
// StopTimeout specifies the time value to be passed as StopContainer api call
StopTimeout uint
// lock is used for fields that are accessed and updated concurrently
lock sync.RWMutex
// DesiredStatusUnsafe represents the state where the container should go. Generally,
// the desired status is informed by the ECS backend as a result of either
// API calls made to ECS or decisions made by the ECS service scheduler,
// though the agent may also set the DesiredStatusUnsafe if a different "essential"
// container in the task exits. The DesiredStatus is almost always either
// ContainerRunning or ContainerStopped.
// NOTE: Do not access DesiredStatusUnsafe directly. Instead, use `GetDesiredStatus`
// and `SetDesiredStatus`.
// TODO DesiredStatusUnsafe should probably be private with appropriately written
// setter/getter. When this is done, we need to ensure that the UnmarshalJSON
// is handled properly so that the state storage continues to work.
DesiredStatusUnsafe apicontainerstatus.ContainerStatus `json:"desiredStatus"`
// KnownStatusUnsafe represents the state where the container is.
// NOTE: Do not access `KnownStatusUnsafe` directly. Instead, use `GetKnownStatus`
// and `SetKnownStatus`.
// TODO KnownStatusUnsafe should probably be private with appropriately written
// setter/getter. When this is done, we need to ensure that the UnmarshalJSON
// is handled properly so that the state storage continues to work.
KnownStatusUnsafe apicontainerstatus.ContainerStatus `json:"KnownStatus"`
// TransitionDependenciesMap is a map of the dependent container status to other
// dependencies that must be satisfied in order for this container to transition.
TransitionDependenciesMap TransitionDependenciesMap `json:"TransitionDependencySet"`
// SteadyStateDependencies is a list of containers that must be in "steady state" before
// this one is created
// Note: Current logic requires that the containers specified here are run
// before this container can even be pulled.
//
// Deprecated: Use TransitionDependencySet instead. SteadyStateDependencies is retained for compatibility with old
// state files.
SteadyStateDependencies []string `json:"RunDependencies"`
// Type specifies the container type. Except the 'Normal' type, all other types
// are not directly specified by task definitions, but created by the agent. The
// JSON tag is retained as this field's previous name 'IsInternal' for maintaining
// backwards compatibility. Please see JSON parsing hooks for this type for more
// details
Type ContainerType `json:"IsInternal"`
// AppliedStatus is the status that has been "applied" (e.g., we've called Pull,
// Create, Start, or Stop) but we don't yet know that the application was successful.
// No need to save it in the state file, as agent will synchronize the container status
// on restart and for some operation eg: pull, it has to be recalled again.
AppliedStatus apicontainerstatus.ContainerStatus `json:"-"`
// ApplyingError is an error that occurred trying to transition the container
// to its desired state. It is propagated to the backend in the form
// 'Name: ErrorString' as the 'reason' field.
ApplyingError *apierrors.DefaultNamedError
// SentStatusUnsafe represents the last KnownStatusUnsafe that was sent to the ECS
// SubmitContainerStateChange API.
// TODO SentStatusUnsafe should probably be private with appropriately written
// setter/getter. When this is done, we need to ensure that the UnmarshalJSON is
// handled properly so that the state storage continues to work.
SentStatusUnsafe apicontainerstatus.ContainerStatus `json:"SentStatus"`
// MetadataFileUpdated is set to true when we have completed updating the
// metadata file
MetadataFileUpdated bool `json:"metadataFileUpdated"`
// KnownExitCodeUnsafe specifies the exit code for the container.
// It is exposed outside the package so that it's marshalled/unmarshalled in
// the JSON body while saving the state.
// NOTE: Do not access KnownExitCodeUnsafe directly. Instead, use `GetKnownExitCode`
// and `SetKnownExitCode`.
KnownExitCodeUnsafe *int `json:"KnownExitCode"`
// KnownPortBindingsUnsafe is an array of port bindings for the container.
KnownPortBindingsUnsafe []PortBinding `json:"KnownPortBindings"`
// VolumesUnsafe is an array of volume mounts in the container.
VolumesUnsafe []types.MountPoint `json:"-"`
// NetworkModeUnsafe is the network mode in which the container is started
NetworkModeUnsafe string `json:"-"`
// NetworksUnsafe denotes the Docker Network Settings in the container.
NetworkSettingsUnsafe *types.NetworkSettings `json:"-"`
// SteadyStateStatusUnsafe specifies the steady state status for the container
// If uninitialized, it's assumed to be set to 'ContainerRunning'. Even though
// it's not only supposed to be set when the container is being created, it's
// exposed outside the package so that it's marshalled/unmarshalled in the
// JSON body while saving the state
SteadyStateStatusUnsafe *apicontainerstatus.ContainerStatus `json:"SteadyStateStatus,omitempty"`
// ContainerArn is the Arn of this container.
ContainerArn string `json:"ContainerArn,omitempty"`
// ContainerTornDownUnsafe is set to true when we have cleaned up this container. For now this is only used for the
// pause container
ContainerTornDownUnsafe bool `json:"containerTornDown"`
createdAt time.Time
// StartedAtUnsafe specifies the started at time of the container.
// It is exposed outside this container package so that it is marshalled/unmarshalled in JSON body while
// saving state.
// NOTE: Do not access StartedAtUnsafe directly. Instead, use `GetStartedAt` and `SetStartedAt`.
StartedAtUnsafe time.Time `json:"startedAt,omitempty"`
// setStartedAtOnce is used to set the value of the container's started at time only the first time SetStartedAt is
// invoked.
setStartedAtOnce sync.Once
finishedAt time.Time
labels map[string]string
// ContainerHasPortRange is set to true when the container has at least 1 port range requested.
ContainerHasPortRange bool
// ContainerPortSet is a set of singular container ports that don't belong to a containerPortRange request
ContainerPortSet map[int]struct{}
// ContainerPortRangeMap is a map of containerPortRange to its associated hostPortRange
ContainerPortRangeMap map[string]string
// RestartPolicy is an object representing the restart policy of the container
RestartPolicy *restart.RestartPolicy `json:"restartPolicy,omitempty"`
// RestartTracker tracks this container's restart policy metadata, such
// as restart count and last restart time. This is only initialized if the container
// has a restart policy defined and enabled.
RestartTracker *restart.RestartTracker `json:"restartTracker,omitempty"`
// RestartAggregationDataForStatsUnsafe specifies the restart aggregation data used for stats of the container.
// It is exposed outside this container package so that it is marshalled/unmarshalled in JSON body while
// saving state.
// NOTE: Do not access RestartAggregationDataForStatsUnsafe directly. Instead, use
// `GetRestartAggregationDataForStats` and `SetRestartAggregationDataForStats`.
RestartAggregationDataForStatsUnsafe ContainerRestartAggregationDataForStats `json:"RestartAggregationDataForStats,omitempty"`
}
type DependsOn struct {
ContainerName string `json:"containerName"`
Condition string `json:"condition"`
}
type ContainerRestartAggregationDataForStats struct {
LastRestartDetectedAt time.Time `json:"LastRestartDetectedAt,omitempty"`
LastStatBeforeLastRestart types.StatsJSON `json:"LastStatBeforeLastRestart,omitempty"`
}
// DockerContainer is a mapping between containers-as-docker-knows-them and
// containers-as-we-know-them.
// This is primarily used in DockerState, but lives here such that tasks and
// containers know how to convert themselves into Docker's desired config format
type DockerContainer struct {
DockerID string `json:"DockerId"`
DockerName string // needed for linking
Container *Container
}
type EnvironmentFile struct {
Value string `json:"value"`
Type string `json:"type"`
}
// MountPoint describes the in-container location of a Volume and references
// that Volume by name.
type MountPoint struct {
SourceVolume string `json:"sourceVolume"`
ContainerPath string `json:"containerPath"`
ReadOnly bool `json:"readOnly"`
}
// FirelensConfig describes the type and options of a Firelens container.
type FirelensConfig struct {
Type string `json:"type"`
Options map[string]string `json:"options"`
}
// VolumeFrom is a volume which references another container as its source.
type VolumeFrom struct {
SourceContainer string `json:"sourceContainer"`
ReadOnly bool `json:"readOnly"`
}
// Secret contains all essential attributes needed for ECS secrets vending as environment variables/tmpfs files
type Secret struct {
Name string `json:"name"`
ValueFrom string `json:"valueFrom"`
Region string `json:"region"`
ContainerPath string `json:"containerPath"`
Type string `json:"type"`
Provider string `json:"provider"`
Target string `json:"target"`
}
// GetSecretResourceCacheKey returns the key required to access the secret
// from the ssmsecret resource
func (s *Secret) GetSecretResourceCacheKey() string {
return s.ValueFrom + "_" + s.Region
}
// String returns a human-readable string representation of DockerContainer
func (dc *DockerContainer) String() string {
if dc == nil {
return "nil"
}
return fmt.Sprintf("Id: %s, Name: %s, Container: %s", dc.DockerID, dc.DockerName, dc.Container.String())
}
// NewContainerWithSteadyState creates a new Container object with the specified
// steady state. Containers that need the non default steady state set will
// use this method instead of setting it directly
func NewContainerWithSteadyState(steadyState apicontainerstatus.ContainerStatus) *Container {
steadyStateStatus := steadyState
return &Container{
SteadyStateStatusUnsafe: &steadyStateStatus,
}
}
// KnownTerminal returns true if the container's known status is STOPPED
func (c *Container) KnownTerminal() bool {
return c.GetKnownStatus().Terminal()
}
// DesiredTerminal returns true if the container's desired status is STOPPED
func (c *Container) DesiredTerminal() bool {
return c.GetDesiredStatus().Terminal()
}
// GetKnownStatus returns the known status of the container
func (c *Container) GetKnownStatus() apicontainerstatus.ContainerStatus {
c.lock.RLock()
defer c.lock.RUnlock()
return c.KnownStatusUnsafe
}
// SetKnownStatus sets the known status of the container and update the container
// applied status
func (c *Container) SetKnownStatus(status apicontainerstatus.ContainerStatus) {
c.lock.Lock()
defer c.lock.Unlock()
c.KnownStatusUnsafe = status
c.updateAppliedStatusUnsafe(status)
}
// GetDesiredStatus gets the desired status of the container
func (c *Container) GetDesiredStatus() apicontainerstatus.ContainerStatus {
c.lock.RLock()
defer c.lock.RUnlock()
return c.DesiredStatusUnsafe
}
// SetDesiredStatus sets the desired status of the container
func (c *Container) SetDesiredStatus(status apicontainerstatus.ContainerStatus) {
c.lock.Lock()
defer c.lock.Unlock()
c.DesiredStatusUnsafe = status
}
// GetSentStatus safely returns the SentStatusUnsafe of the container
func (c *Container) GetSentStatus() apicontainerstatus.ContainerStatus {
c.lock.RLock()
defer c.lock.RUnlock()
return c.SentStatusUnsafe
}
// SetSentStatus safely sets the SentStatusUnsafe of the container
func (c *Container) SetSentStatus(status apicontainerstatus.ContainerStatus) {
c.lock.Lock()
defer c.lock.Unlock()
c.SentStatusUnsafe = status
}
// SetKnownExitCode sets exit code field in container struct
func (c *Container) SetKnownExitCode(i *int) {
c.lock.Lock()
defer c.lock.Unlock()
c.KnownExitCodeUnsafe = i
}
// GetKnownExitCode returns the container exit code
func (c *Container) GetKnownExitCode() *int {
c.lock.RLock()
defer c.lock.RUnlock()
return c.KnownExitCodeUnsafe
}
// SetRegistryAuthCredentials sets the credentials for pulling image from ECR
func (c *Container) SetRegistryAuthCredentials(credential credentials.IAMRoleCredentials) {
c.lock.Lock()
defer c.lock.Unlock()
c.RegistryAuthentication.ECRAuthData.SetPullCredentials(credential)
}
// ShouldPullWithExecutionRole returns whether this container has its own ECR credentials
func (c *Container) ShouldPullWithExecutionRole() bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.RegistryAuthentication != nil &&
c.RegistryAuthentication.Type == AuthTypeECR &&
c.RegistryAuthentication.ECRAuthData != nil &&
c.RegistryAuthentication.ECRAuthData.UseExecutionRole
}
// String returns a human-readable string representation of this object
func (c *Container) String() string {
ret := fmt.Sprintf("%s(%s) (%s->%s)", c.Name, c.Image,
c.GetKnownStatus().String(), c.GetDesiredStatus().String())
if c.GetKnownExitCode() != nil {
ret += " - Exit: " + strconv.Itoa(*c.GetKnownExitCode())
}
return ret
}
func (c *Container) Fields() logger.Fields {
exitCode := "nil"
if c.GetKnownExitCode() != nil {
exitCode = strconv.Itoa(*c.GetKnownExitCode())
}
return logger.Fields{
field.ContainerName: c.Name,
field.ContainerImage: c.Image,
"containerKnownStatus": c.GetKnownStatus().String(),
"containerDesiredStatus": c.GetDesiredStatus().String(),
field.ContainerExitCode: exitCode,
}
}
// GetSteadyStateStatus returns the steady state status for the container. If
// Container.steadyState is not initialized, the default steady state status
// defined by `defaultContainerSteadyStateStatus` is returned. In awsvpc, the 'pause'
// container's steady state differs from that of other containers, as the
// 'pause' container can reach its steady state once networking resources
// have been provisioned for it, which is done in the `ContainerResourcesProvisioned`
// state. In bridge mode, pause containers are currently used exclusively for
// supporting service-connect tasks. Those pause containers will have steady state
// status "ContainerRunning" as the actual network provisioning is done by ServiceConnect
// container (aka Appnet agent)
func (c *Container) GetSteadyStateStatus() apicontainerstatus.ContainerStatus {
if c.SteadyStateStatusUnsafe == nil {
return defaultContainerSteadyStateStatus
}
return *c.SteadyStateStatusUnsafe
}
// SetSteadyStateStatusUnsafe allows setting container steady state status after they
// are initially created.
// In bridge mode, this is used by overriding the ServiceConnect container steady
// status to ContainerResourcesProvisioned because it comes with ACS task payload and will
// get ContainerRunning by default during unmarshalling. We need ServiceConnect container
// to provision network resources to support SC bridge mode
func (c *Container) SetSteadyStateStatusUnsafe(steadyState apicontainerstatus.ContainerStatus) {
c.SteadyStateStatusUnsafe = &steadyState
}
// IsKnownSteadyState returns true if the `KnownState` of the container equals
// the `steadyState` defined for the container
func (c *Container) IsKnownSteadyState() bool {
knownStatus := c.GetKnownStatus()
return knownStatus == c.GetSteadyStateStatus()
}
// GetNextKnownStateProgression returns the state that the container should
// progress to based on its `KnownState`. The progression is
// incremental until the container reaches its steady state. From then on,
// it transitions to `ContainerStopped`.
//
// For example:
// a. if the steady state of the container is defined as `ContainerRunning`,
// the progression is:
// Container: None -> Pulled -> Created -> Running* -> Stopped -> Zombie
//
// b. if the steady state of the container is defined as `ContainerResourcesProvisioned`,
// the progression is:
// Container: None -> Pulled -> Created -> Running -> Provisioned* -> Stopped -> Zombie
//
// c. if the steady state of the container is defined as `ContainerCreated`,
// the progression is:
// Container: None -> Pulled -> Created* -> Stopped -> Zombie
func (c *Container) GetNextKnownStateProgression() apicontainerstatus.ContainerStatus {
if c.IsKnownSteadyState() {
return apicontainerstatus.ContainerStopped
}
return c.GetKnownStatus() + 1
}
// IsInternal returns true if the container type is `ContainerCNIPause`
// or `ContainerNamespacePause`. It returns false otherwise
func (c *Container) IsInternal() bool {
return c.Type != ContainerNormal
}
// IsRunning returns true if the container's known status is either RUNNING
// or RESOURCES_PROVISIONED. It returns false otherwise
func (c *Container) IsRunning() bool {
return c.GetKnownStatus().IsRunning()
}
// IsMetadataFileUpdated returns true if the metadata file has been once the
// metadata file is ready and will no longer change
func (c *Container) IsMetadataFileUpdated() bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.MetadataFileUpdated
}
// SetMetadataFileUpdated sets the container's MetadataFileUpdated status to true
func (c *Container) SetMetadataFileUpdated() {
c.lock.Lock()
defer c.lock.Unlock()
c.MetadataFileUpdated = true
}
// IsEssential returns whether the container is an essential container or not
func (c *Container) IsEssential() bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.Essential
}
// RestartPolicyEnabled returns whether the restart policy is defined and enabled
func (c *Container) RestartPolicyEnabled() bool {
c.lock.RLock()
defer c.lock.RUnlock()
if c.RestartPolicy == nil {
return false
}
return c.RestartPolicy.Enabled
}
// AWSLogAuthExecutionRole returns true if the auth is by execution role
func (c *Container) AWSLogAuthExecutionRole() bool {
return c.LogsAuthStrategy == awslogsAuthExecutionRole
}
// SetCreatedAt sets the timestamp for container's creation time
func (c *Container) SetCreatedAt(createdAt time.Time) {
if createdAt.IsZero() {
return
}
c.lock.Lock()
defer c.lock.Unlock()
c.createdAt = createdAt
}
// SetStartedAt sets the timestamp for container's start time
func (c *Container) SetStartedAt(startedAt time.Time) {
if startedAt.IsZero() {
return
}
c.lock.Lock()
defer c.lock.Unlock()
c.setStartedAtOnce.Do(func() {
if c.StartedAtUnsafe.IsZero() {
c.StartedAtUnsafe = startedAt
}
})
}
// SetFinishedAt sets the timestamp for container's stopped time
func (c *Container) SetFinishedAt(finishedAt time.Time) {
if finishedAt.IsZero() {
return
}
c.lock.Lock()
defer c.lock.Unlock()
c.finishedAt = finishedAt
}
// GetCreatedAt sets the timestamp for container's creation time
func (c *Container) GetCreatedAt() time.Time {
c.lock.RLock()
defer c.lock.RUnlock()
return c.createdAt
}
// GetStartedAt sets the timestamp for container's start time
func (c *Container) GetStartedAt() time.Time {
c.lock.RLock()
defer c.lock.RUnlock()
return c.StartedAtUnsafe
}
// GetFinishedAt sets the timestamp for container's stopped time
func (c *Container) GetFinishedAt() time.Time {
c.lock.RLock()
defer c.lock.RUnlock()
return c.finishedAt
}
// SetLabels sets the labels for a container
func (c *Container) SetLabels(labels map[string]string) {
c.lock.Lock()
defer c.lock.Unlock()
c.labels = labels
}
// SetRuntimeID sets the DockerID for a container
func (c *Container) SetRuntimeID(RuntimeID string) {
c.lock.Lock()
defer c.lock.Unlock()
c.RuntimeID = RuntimeID
}
// GetRuntimeID gets the DockerID for a container
func (c *Container) GetRuntimeID() string {
c.lock.RLock()
defer c.lock.RUnlock()
return c.RuntimeID
}
// SetImageDigest sets the ImageDigest for a container
func (c *Container) SetImageDigest(ImageDigest string) {
c.lock.Lock()
defer c.lock.Unlock()
c.ImageDigest = ImageDigest
}
// GetImageDigest gets the ImageDigest for a container
func (c *Container) GetImageDigest() string {
c.lock.RLock()
defer c.lock.RUnlock()
return c.ImageDigest
}
// GetLabels gets the labels for a container
func (c *Container) GetLabels() map[string]string {
c.lock.RLock()
defer c.lock.RUnlock()
return c.labels
}
// SetKnownPortBindings sets the ports for a container
func (c *Container) SetKnownPortBindings(ports []PortBinding) {
c.lock.Lock()
defer c.lock.Unlock()
c.KnownPortBindingsUnsafe = ports
}
// GetKnownPortBindings gets the ports for a container
func (c *Container) GetKnownPortBindings() []PortBinding {
c.lock.RLock()
defer c.lock.RUnlock()
return c.KnownPortBindingsUnsafe
}
// GetManagedAgents returns the managed agents configured for this container
func (c *Container) GetManagedAgents() []ManagedAgent {
c.lock.RLock()
defer c.lock.RUnlock()
return c.ManagedAgentsUnsafe
}
// SetVolumes sets the volumes mounted in a container
func (c *Container) SetVolumes(volumes []types.MountPoint) {
c.lock.Lock()
defer c.lock.Unlock()
c.VolumesUnsafe = volumes
}
// GetVolumes returns the volumes mounted in a container
func (c *Container) GetVolumes() []types.MountPoint {
c.lock.RLock()
defer c.lock.RUnlock()
return c.VolumesUnsafe
}
// SetNetworkSettings sets the networks field in a container
func (c *Container) SetNetworkSettings(networks *types.NetworkSettings) {
c.lock.Lock()
defer c.lock.Unlock()
c.NetworkSettingsUnsafe = networks
}
// GetNetworkSettings returns the networks field in a container
func (c *Container) GetNetworkSettings() *types.NetworkSettings {
c.lock.RLock()
defer c.lock.RUnlock()
return c.NetworkSettingsUnsafe
}
// SetNetworkMode sets the network mode of the container
func (c *Container) SetNetworkMode(networkMode string) {
c.lock.Lock()
defer c.lock.Unlock()
c.NetworkModeUnsafe = networkMode
}
// GetNetworkMode returns the network mode of the container
func (c *Container) GetNetworkMode() string {
c.lock.RLock()
defer c.lock.RUnlock()
return c.NetworkModeUnsafe
}
// HealthStatusShouldBeReported returns true if the health check is defined in
// the task definition
func (c *Container) HealthStatusShouldBeReported() bool {
return c.HealthCheckType == DockerHealthCheckType
}
// SetHealthStatus sets the container health status
func (c *Container) SetHealthStatus(health HealthStatus) {
c.lock.Lock()
defer c.lock.Unlock()
if c.Health.Status == health.Status {
return
}
c.Health.Status = health.Status
c.Health.Since = aws.Time(time.Now())
c.Health.Output = health.Output
// Set the health exit code if the health check failed
if c.Health.Status == apicontainerstatus.ContainerUnhealthy {
c.Health.ExitCode = health.ExitCode
}
}
// GetHealthStatus returns the container health information
func (c *Container) GetHealthStatus() HealthStatus {
c.lock.RLock()
defer c.lock.RUnlock()
// Copy the pointer to avoid race condition
copyHealth := c.Health
if c.Health.Since != nil {
copyHealth.Since = aws.Time(aws.TimeValue(c.Health.Since))
}
return copyHealth
}
// BuildContainerDependency adds a new dependency container and satisfied status
// to the dependent container
func (c *Container) BuildContainerDependency(contName string,
satisfiedStatus apicontainerstatus.ContainerStatus,
dependentStatus apicontainerstatus.ContainerStatus) {
contDep := ContainerDependency{
ContainerName: contName,
SatisfiedStatus: satisfiedStatus,
}
if _, ok := c.TransitionDependenciesMap[dependentStatus]; !ok {
c.TransitionDependenciesMap[dependentStatus] = TransitionDependencySet{}
}
deps := c.TransitionDependenciesMap[dependentStatus]
deps.ContainerDependencies = append(deps.ContainerDependencies, contDep)
c.TransitionDependenciesMap[dependentStatus] = deps
}
// BuildResourceDependency adds a new resource dependency by taking in the required status
// of the resource that satisfies the dependency and the dependent container status,
// whose transition is dependent on the resource.
// example: if container's PULLED transition is dependent on volume resource's
// CREATED status, then RequiredStatus=VolumeCreated and dependentStatus=ContainerPulled
func (c *Container) BuildResourceDependency(resourceName string,
requiredStatus resourcestatus.ResourceStatus,
dependentStatus apicontainerstatus.ContainerStatus) {
resourceDep := ResourceDependency{
Name: resourceName,
RequiredStatus: requiredStatus,
}
if _, ok := c.TransitionDependenciesMap[dependentStatus]; !ok {
c.TransitionDependenciesMap[dependentStatus] = TransitionDependencySet{}
}
deps := c.TransitionDependenciesMap[dependentStatus]
deps.ResourceDependencies = append(deps.ResourceDependencies, resourceDep)
c.TransitionDependenciesMap[dependentStatus] = deps
}
// updateAppliedStatusUnsafe updates the container transitioning status
func (c *Container) updateAppliedStatusUnsafe(knownStatus apicontainerstatus.ContainerStatus) {
if c.AppliedStatus == apicontainerstatus.ContainerStatusNone {
return
}
// Check if the container transition has already finished
if c.AppliedStatus <= knownStatus {
c.AppliedStatus = apicontainerstatus.ContainerStatusNone
}
}
// SetAppliedStatus sets the applied status of container and returns whether
// the container is already in a transition
func (c *Container) SetAppliedStatus(status apicontainerstatus.ContainerStatus) bool {
c.lock.Lock()
defer c.lock.Unlock()
if c.AppliedStatus != apicontainerstatus.ContainerStatusNone {
// return false to indicate the set operation failed
return false
}
c.AppliedStatus = status
return true
}
// GetAppliedStatus returns the transitioning status of container
func (c *Container) GetAppliedStatus() apicontainerstatus.ContainerStatus {
c.lock.RLock()
defer c.lock.RUnlock()
return c.AppliedStatus
}
// ShouldPullWithASMAuth returns true if this container needs to retrieve
// private registry authentication data from ASM
func (c *Container) ShouldPullWithASMAuth() bool {
c.lock.RLock()
defer c.lock.RUnlock()
return c.RegistryAuthentication != nil &&
c.RegistryAuthentication.Type == AuthTypeASM &&
c.RegistryAuthentication.ASMAuthData != nil
}
// SetASMDockerAuthConfig add the docker auth config data to the
// RegistryAuthentication struct held by the container, this is then passed down
// to the docker client to pull the image
func (c *Container) SetASMDockerAuthConfig(dac types.AuthConfig) {
c.RegistryAuthentication.ASMAuthData.SetDockerAuthConfig(dac)
}
// SetV3EndpointID sets the v3 endpoint id of container
func (c *Container) SetV3EndpointID(v3EndpointID string) {
c.lock.Lock()
defer c.lock.Unlock()
c.V3EndpointID = v3EndpointID
}
// GetV3EndpointID returns the v3 endpoint id of container
func (c *Container) GetV3EndpointID() string {
c.lock.RLock()
defer c.lock.RUnlock()
return c.V3EndpointID
}
// InjectV3MetadataEndpoint injects the v3 metadata endpoint as an environment variable for a container