func (imageState *ImageState) MarshalJSON() ([]byte, error) {
	imageState.lock.Lock()
	defer imageState.lock.Unlock()

	return json.Marshal(&struct {
		Image         *Image
		PulledAt      time.Time
		LastUsedAt    time.Time
		PullSucceeded bool
	}{
		Image:         imageState.Image,
		PulledAt:      imageState.PulledAt,
		LastUsedAt:    imageState.LastUsedAt,
		PullSucceeded: imageState.PullSucceeded,
	})
}

func ( imageState * ImageState ) MarshalJSON ( ) ( [ ] byte , error ) { imageState . lock . Lock ( ) defer imageState . lock . Unlock ( ) return json . Marshal ( & struct { Image * Image PulledAt time . Time LastUsedAt time . Time PullSucceeded bool } { Image : imageState . Image , PulledAt : imageState . PulledAt , LastUsedAt : imageState . LastUsedAt , PullSucceeded : imageState . PullSucceeded , } ) }


func (ts *TaskStatus) UnmarshalJSON(b []byte) error {
	if strings.ToLower(string(b)) == "null" {
		*ts = TaskStatusNone
		return nil
	}
	if b[0] != '"' || b[len(b)-1] != '"' {
		*ts = TaskStatusNone
		return errors.New("TaskStatus must be a string or null")
	}
	strStatus := string(b[1 : len(b)-1])
	// 'UNKNOWN' and 'DEAD' for Compatibility with v1.0.0 state files
	if strStatus == "UNKNOWN" {
		*ts = TaskStatusNone
		return nil
	}
	if strStatus == "DEAD" {
		*ts = TaskStopped
		return nil
	}

	stat, ok := taskStatusMap[strStatus]
	if !ok {
		*ts = TaskStatusNone
		return errors.New("Unrecognized TaskStatus")
	}
	*ts = stat
	return nil
}

// UnmarshalJSON overrides the logic for parsing the JSON-encoded TaskStatus data

UnmarshalJSON overrides the logic for parsing the JSON - encoded TaskStatus data


func (ts *TaskStatus) MarshalJSON() ([]byte, error) {
	if ts == nil {
		return nil, nil
	}
	return []byte(`"` + ts.String() + `"`), nil
}

func ( ts * TaskStatus ) MarshalJSON ( ) ( [ ] byte , error ) { if ts == nil { return nil , nil } return [ ] byte ( `"` + ts . String ( ) + `"` ) , nil }

// MarshalJSON overrides the logic for JSON-encoding the TaskStatus type

MarshalJSON overrides the logic for JSON - encoding the TaskStatus type


func NewClient(cfg *Config) CNIClient {
	libcniConfig := &libcni.CNIConfig{
		Path: []string{cfg.PluginsPath},
	}

	return &cniClient{
		pluginsPath: cfg.PluginsPath,
		cniVersion:  cfg.MinSupportedCNIVersion,
		subnet:      ecsSubnet,
		libcni:      libcniConfig,
	}
}

func NewClient ( cfg * Config ) CNIClient { libcniConfig := & libcni . CNIConfig { Path : [ ] string { cfg . PluginsPath } , } return & cniClient { pluginsPath : cfg . PluginsPath , cniVersion : cfg . MinSupportedCNIVersion , subnet : ecsSubnet , libcni : libcniConfig , } }

// NewClient creates a client of ecscni which is used to invoke the plugin


func (client *cniClient) SetupNS(ctx context.Context,
	cfg *Config,
	timeout time.Duration) (*current.Result, error) {
	derivedCtx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	type output struct {
		result *current.Result
		err    error
	}
	response := make(chan output)
	go func(response chan output) {
		result, err := client.setupNS(cfg)
		response <- output{
			result: result,
			err:    err,
		}
	}(response)

	select {
	case <-derivedCtx.Done():
		return nil, errors.Wrap(derivedCtx.Err(), "cni setup: container namespace setup failed")
	case result := <-response:
		return result.result, result.err
	}
}

func ( client * cniClient ) SetupNS ( ctx context . Context , cfg * Config , timeout time . Duration ) ( * current . Result , error ) { derivedCtx , cancel := context . WithTimeout ( ctx , timeout ) defer cancel ( ) type output struct { result * current . Result err error } response := make ( chan output ) go func ( response chan output ) { result , err := client . setupNS ( cfg ) response <- output { result : result , err : err , } } ( response ) select { case <- derivedCtx . Done ( ) : return nil , errors . Wrap ( derivedCtx . Err ( ) , " " ) case result := <- response : return result . result , result . err } }

// SetupNS will set up the namespace of container, including create the bridge
// and the veth pair, move the eni to container namespace, setup the routes

SetupNS will set up the namespace of container including create the bridge and the veth pair move the eni to container namespace setup the routes


func (client *cniClient) CleanupNS(
	ctx context.Context,
	cfg *Config,
	timeout time.Duration) error {

	derivedCtx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	err := make(chan error)
	go func(err chan error) {
		err <- client.cleanupNS(cfg)
	}(err)

	select {
	case <-derivedCtx.Done():
		return errors.Wrap(derivedCtx.Err(), "cni cleanup: container namespace cleanup failed")
	case err := <-err:
		return err
	}
}

func ( client * cniClient ) CleanupNS ( ctx context . Context , cfg * Config , timeout time . Duration ) error { derivedCtx , cancel := context . WithTimeout ( ctx , timeout ) defer cancel ( ) err := make ( chan error ) go func ( err chan error ) { err <- client . cleanupNS ( cfg ) } ( err ) select { case <- derivedCtx . Done ( ) : return errors . Wrap ( derivedCtx . Err ( ) , " " ) case err := <- err : return err } }

// CleanupNS will clean up the container namespace, including remove the veth
// pair and stop the dhclient

CleanupNS will clean up the container namespace including remove the veth pair and stop the dhclient


func (client *cniClient) ReleaseIPResource(cfg *Config) error {
	runtimeConfig := libcni.RuntimeConf{
		ContainerID: cfg.ContainerID,
		NetNS:       fmt.Sprintf(netnsFormat, cfg.ContainerPID),
	}

	seelog.Debugf("[ECSCNI] Releasing the ip resource from ipam db, id: [%s], ip: [%v]", cfg.ID, cfg.IPAMV4Address)
	os.Setenv("ECS_CNI_LOGLEVEL", logger.GetLevel())
	defer os.Unsetenv("ECS_CNI_LOGLEVEL")
	return client.del(runtimeConfig, cfg, client.createIPAMNetworkConfig)
}

func ( client * cniClient ) ReleaseIPResource ( cfg * Config ) error { runtimeConfig := libcni . RuntimeConf { ContainerID : cfg . ContainerID , NetNS : fmt . Sprintf ( netnsFormat , cfg . ContainerPID ) , } seelog . Debugf ( " " , cfg . ID , cfg . IPAMV4Address ) os . Setenv ( " " , logger . GetLevel ( ) ) defer os . Unsetenv ( " " ) return client . del ( runtimeConfig , cfg , client . createIPAMNetworkConfig ) }

// ReleaseIPResource marks the ip available in the ipam db


func (client *cniClient) add(runtimeConfig libcni.RuntimeConf,
	cfg *Config,
	pluginConfigFunc func(*Config) (string, *libcni.NetworkConfig, error)) (cnitypes.Result, error) {

	deviceName, networkConfig, err := pluginConfigFunc(cfg)
	if err != nil {
		return nil, err
	}
	runtimeConfig.IfName = deviceName

	return client.libcni.AddNetwork(networkConfig, &runtimeConfig)
}

func ( client * cniClient ) add ( runtimeConfig libcni . RuntimeConf , cfg * Config , pluginConfigFunc func ( * Config ) ( string , * libcni . NetworkConfig , error ) ) ( cnitypes . Result , error ) { deviceName , networkConfig , err := pluginConfigFunc ( cfg ) if err != nil { return nil , err } runtimeConfig . IfName = deviceName return client . libcni . AddNetwork ( networkConfig , & runtimeConfig ) }

// add invokes the ADD command of the given plugin


func (client *cniClient) del(runtimeConfig libcni.RuntimeConf,
	cfg *Config,
	pluginConfigFunc func(*Config) (string, *libcni.NetworkConfig, error)) error {

	deviceName, networkConfig, err := pluginConfigFunc(cfg)
	if err != nil {
		return err
	}
	runtimeConfig.IfName = deviceName

	return client.libcni.DelNetwork(networkConfig, &runtimeConfig)
}

func ( client * cniClient ) del ( runtimeConfig libcni . RuntimeConf , cfg * Config , pluginConfigFunc func ( * Config ) ( string , * libcni . NetworkConfig , error ) ) error { deviceName , networkConfig , err := pluginConfigFunc ( cfg ) if err != nil { return err } runtimeConfig . IfName = deviceName return client . libcni . DelNetwork ( networkConfig , & runtimeConfig ) }

// del invokes the DEL command of the given plugin


func (client *cniClient) createBridgeNetworkConfigWithIPAM(cfg *Config) (string, *libcni.NetworkConfig, error) {
	// Create the bridge config first
	bridgeConfig := client.createBridgeConfig(cfg)

	// Create the ipam config
	ipamConfig, err := client.createIPAMConfig(cfg)
	if err != nil {
		return "", nil, errors.Wrap(err, "createBridgeNetworkConfigWithIPAM: create ipam configuration failed")
	}

	bridgeConfig.IPAM = ipamConfig

	networkConfig, err := client.constructNetworkConfig(bridgeConfig, ECSBridgePluginName)
	if err != nil {
		return "", nil, errors.Wrap(err, "createBridgeNetworkConfigWithIPAM: construct bridge and ipam network configuration failed")
	}
	return defaultVethName, networkConfig, nil
}

func
(
client
*
cniClient
)
createBridgeNetworkConfigWithIPAM
(
cfg
*
Config
)
(
string
,
*
libcni
.
NetworkConfig
,
error
)
{
// Create the bridge config first
bridgeConfig
:=
client
.
createBridgeConfig
(
cfg
)
// Create the ipam config
ipamConfig
,
err
:=
client
.
createIPAMConfig
(
cfg
)
if
err
!=
{
return
"
"
,
,
errors
.
Wrap
(
err
,
"
"
)
}
bridgeConfig
.
IPAM
=
ipamConfig
networkConfig
,
err
:=
client
.
constructNetworkConfig
(
bridgeConfig
,
ECSBridgePluginName
)
if
err
!=
{
return
"
"
,
,
errors
.
Wrap
(
err
,
"
"
)
}
return
defaultVethName
,
networkConfig
,
}

// createBridgeNetworkConfigWithIPAM creates the config of bridge for ADD command, where
// bridge plugin acquires the IP and route information from IPAM

createBridgeNetworkConfigWithIPAM creates the config of bridge for ADD command where bridge plugin acquires the IP and route information from IPAM


func (client *cniClient) createBridgeNetworkConfigWithoutIPAM(cfg *Config) (string, *libcni.NetworkConfig, error) {
	networkConfig, err := client.constructNetworkConfig(client.createBridgeConfig(cfg), ECSBridgePluginName)
	if err != nil {
		return "", nil, errors.Wrap(err, "createBridgeNetworkConfigWithoutIPAM: construct bridge network configuration failed")
	}
	return defaultVethName, networkConfig, nil
}

func ( client * cniClient ) createBridgeNetworkConfigWithoutIPAM ( cfg * Config ) ( string , * libcni . NetworkConfig , error ) { networkConfig , err := client . constructNetworkConfig ( client . createBridgeConfig ( cfg ) , ECSBridgePluginName ) if err != nil { return " " , nil , errors . Wrap ( err , " " ) } return defaultVethName , networkConfig , nil }

// createBridgeNetworkConfigWithoutIPAM creates the config of the bridge for removal


func (client *cniClient) constructNetworkConfig(cfg interface{}, plugin string) (*libcni.NetworkConfig, error) {
	configBytes, err := json.Marshal(cfg)
	if err != nil {
		seelog.Errorf("[ECSCNI] Marshal configuration for plugin %s failed, error: %v", plugin, err)
		return nil, err
	}
	networkConfig := &libcni.NetworkConfig{
		Network: &cnitypes.NetConf{
			Type: plugin,
		},
		Bytes: configBytes,
	}

	return networkConfig, nil
}

func ( client * cniClient ) constructNetworkConfig ( cfg interface { } , plugin string ) ( * libcni . NetworkConfig , error ) { configBytes , err := json . Marshal ( cfg ) if err != nil { seelog . Errorf ( " " , plugin , err ) return nil , err } networkConfig := & libcni . NetworkConfig { Network : & cnitypes . NetConf { Type : plugin , } , Bytes : configBytes , } return networkConfig , nil }

// constructNetworkConfig takes in the config from agent and construct the configuration
// that's accepted by the libcni

constructNetworkConfig takes in the config from agent and construct the configuration that s accepted by the libcni


func (client *cniClient) createIPAMNetworkConfig(cfg *Config) (string, *libcni.NetworkConfig, error) {
	ipamConfig, err := client.createIPAMConfig(cfg)
	if err != nil {
		return defaultVethName, nil, errors.Wrap(err, "createIPAMNetworkConfig: create ipam network configuration failed")
	}

	ipamNetworkConfig := IPAMNetworkConfig{
		Name:       ECSIPAMPluginName,
		CNIVersion: client.cniVersion,
		IPAM:       ipamConfig,
	}

	networkConfig, err := client.constructNetworkConfig(ipamNetworkConfig, ECSIPAMPluginName)
	if err != nil {
		return "", nil, errors.Wrap(err, "createIPAMNetworkConfig: construct ipam network configuration failed")
	}
	return defaultVethName, networkConfig, nil
}

func ( client * cniClient ) createIPAMNetworkConfig ( cfg * Config ) ( string , * libcni . NetworkConfig , error ) { ipamConfig , err := client . createIPAMConfig ( cfg ) if err != nil { return defaultVethName , nil , errors . Wrap ( err , " " ) } ipamNetworkConfig := IPAMNetworkConfig { Name : ECSIPAMPluginName , CNIVersion : client . cniVersion , IPAM : ipamConfig , } networkConfig , err := client . constructNetworkConfig ( ipamNetworkConfig , ECSIPAMPluginName ) if err != nil { return " " , nil , errors . Wrap ( err , " " ) } return defaultVethName , networkConfig , nil }

// createIPAMNetworkConfig constructs the ipam configuration accepted by libcni


func (client *cniClient) Version(name string) (string, error) {
	file := filepath.Join(client.pluginsPath, name)

	// Check if the plugin file exists before executing it
	_, err := os.Stat(file)
	if err != nil {
		return "", err
	}

	cmd := exec.Command(file, versionCommand)
	versionInfo, err := cmd.Output()
	if err != nil {
		return "", err
	}

	version := &cniPluginVersion{}
	// versionInfo is of the format
	// {"version":"2017.06.0","dirty":true,"gitShortHash":"226db36"}
	// Unmarshal this
	err = json.Unmarshal(versionInfo, version)
	if err != nil {
		return "", errors.Wrapf(err, "ecscni: unmarshal version from string: %s", versionInfo)
	}

	return version.str(), nil
}

// Version returns the version of the plugin


func (client *cniClient) Capabilities(name string) ([]string, error) {
	file := filepath.Join(client.pluginsPath, name)

	// Check if the plugin file exists before executing it
	_, err := os.Stat(file)
	if err != nil {
		return nil, errors.Wrapf(err, "ecscni: unable to describe file info for '%s'", file)
	}

	cmd := exec.Command(file, capabilitiesCommand)
	capabilitiesInfo, err := cmd.Output()
	if err != nil {
		return nil, errors.Wrapf(err, "ecscni: failed invoking capabilities command for '%s'", name)
	}

	capabilities := &struct {
		Capabilities []string `json:"capabilities"`
	}{}
	err = json.Unmarshal(capabilitiesInfo, capabilities)
	if err != nil {
		return nil, errors.Wrapf(err, "ecscni: failed to unmarshal capabilities for '%s' from string: %s", name, capabilitiesInfo)
	}

	return capabilities.Capabilities, nil
}

// Capabilities returns the capabilities supported by a plugin


func New(ctx context.Context, primaryMAC string, udevwrap udevwrapper.Udev,
	state dockerstate.TaskEngineState, stateChangeEvents chan<- statechange.Event) *UdevWatcher {
	return newWatcher(ctx, primaryMAC, netlinkwrapper.New(), udevwrap, state, stateChangeEvents)
}

func New ( ctx context . Context , primaryMAC string , udevwrap udevwrapper . Udev , state dockerstate . TaskEngineState , stateChangeEvents chan <- statechange . Event ) * UdevWatcher { return newWatcher ( ctx , primaryMAC , netlinkwrapper . New ( ) , udevwrap , state , stateChangeEvents ) }

// New is used to return an instance of the UdevWatcher struct


func newWatcher(ctx context.Context,
	primaryMAC string,
	nlWrap netlinkwrapper.NetLink,
	udevWrap udevwrapper.Udev,
	state dockerstate.TaskEngineState,
	stateChangeEvents chan<- statechange.Event) *UdevWatcher {

	derivedContext, cancel := context.WithCancel(ctx)
	return &UdevWatcher{
		ctx:            derivedContext,
		cancel:         cancel,
		netlinkClient:  nlWrap,
		udevMonitor:    udevWrap,
		events:         make(chan *udev.UEvent),
		agentState:     state,
		eniChangeEvent: stateChangeEvents,
		primaryMAC:     primaryMAC,
	}
}

func newWatcher ( ctx context . Context , primaryMAC string , nlWrap netlinkwrapper . NetLink , udevWrap udevwrapper . Udev , state dockerstate . TaskEngineState , stateChangeEvents chan <- statechange . Event ) * UdevWatcher { derivedContext , cancel := context . WithCancel ( ctx ) return & UdevWatcher { ctx : derivedContext , cancel : cancel , netlinkClient : nlWrap , udevMonitor : udevWrap , events : make ( chan * udev . UEvent ) , agentState : state , eniChangeEvent : stateChangeEvents , primaryMAC : primaryMAC , } }

// newWatcher is used to nest the return of the UdevWatcher struct


func (udevWatcher *UdevWatcher) performPeriodicReconciliation(updateInterval time.Duration) {
	udevWatcher.updateIntervalTicker = time.NewTicker(updateInterval)
	for {
		select {
		case <-udevWatcher.updateIntervalTicker.C:
			if err := udevWatcher.reconcileOnce(); err != nil {
				log.Warnf("Udev watcher reconciliation failed: %v", err)
			}
		case <-udevWatcher.ctx.Done():
			udevWatcher.updateIntervalTicker.Stop()
			return
		}
	}
}

func ( udevWatcher * UdevWatcher ) performPeriodicReconciliation ( updateInterval time . Duration ) { udevWatcher . updateIntervalTicker = time . NewTicker ( updateInterval ) for { select { case <- udevWatcher . updateIntervalTicker . C : if err := udevWatcher . reconcileOnce ( ) ; err != nil { log . Warnf ( " " , err ) } case <- udevWatcher . ctx . Done ( ) : udevWatcher . updateIntervalTicker . Stop ( ) return } } }

// performPeriodicReconciliation is used to periodically invoke the
// reconciliation process based on a ticker

performPeriodicReconciliation is used to periodically invoke the reconciliation process based on a ticker


func (udevWatcher *UdevWatcher) reconcileOnce() error {
	links, err := udevWatcher.netlinkClient.LinkList()
	if err != nil {
		return errors.Wrapf(err, "udev watcher: unable to retrieve network interfaces")
	}

	// Return on empty list
	if len(links) == 0 {
		log.Info("Udev watcher reconciliation: no network interfaces discovered for reconciliation")
		return nil
	}

	currentState := udevWatcher.buildState(links)

	// NOTE: For correct semantics, this entire function needs to be locked.
	// As we postulate the netlinkClient.LinkList() call to be expensive, we allow
	// the race here. The state would be corrected during the next reconciliation loop.

	// Add new interfaces next
	for mac := range currentState {
		if err := udevWatcher.sendENIStateChange(mac); err != nil {
			log.Warnf("Udev watcher reconciliation: unable to send state change: %v", err)
		}
	}
	return nil
}

// reconcileOnce is used to reconcile the state of ENIs attached to the instance


func (udevWatcher *UdevWatcher) sendENIStateChange(mac string) error {
	if mac == "" {
		return errors.New("udev watcher send ENI state change: empty mac address")
	}
	// check if this is an eni required by a task
	eni, ok := udevWatcher.agentState.ENIByMac(mac)
	if !ok {
		return &unmanagedENIError{mac}
	}
	if eni.IsSent() {
		return errors.Errorf("udev watcher send ENI state change: eni status already sent: %s", eni.String())
	}
	if eni.HasExpired() {
		// Agent is aware of the ENI, but we decide not to ack it
		// as it's ack timeout has expired
		udevWatcher.agentState.RemoveENIAttachment(eni.MACAddress)
		return errors.Errorf(
			"udev watcher send ENI state change: eni status expired, no longer tracking it: %s",
			eni.String())
	}

	// We found an ENI, which has the expiration time set in future and
	// needs to be acknowledged as having been 'attached' to the Instance
	go func(eni *apieni.ENIAttachment) {
		eni.Status = apieni.ENIAttached
		log.Infof("Emitting ENI change event for: %s", eni.String())
		udevWatcher.eniChangeEvent <- api.TaskStateChange{
			TaskARN:    eni.TaskARN,
			Attachment: eni,
		}
	}(eni)
	return nil
}

// sendENIStateChange handles the eni event from udev or reconcile phase


func (udevWatcher *UdevWatcher) buildState(links []netlink.Link) map[string]string {
	state := make(map[string]string)
	for _, link := range links {
		if link.Type() != linkTypeDevice {
			// We only care about netlink.Device types. These are created
			// by udev like 'lo' and 'eth0'. Ignore other link types
			continue
		}
		if link.Attrs().EncapType == encapTypeLoopback {
			// Ignore localhost
			continue
		}
		macAddress := link.Attrs().HardwareAddr.String()
		if macAddress != "" && macAddress != udevWatcher.primaryMAC {
			state[macAddress] = link.Attrs().Name
		}
	}
	return state
}

// buildState is used to build a state of the system for reconciliation


func (udevWatcher *UdevWatcher) sendENIStateChangeWithRetries(parentCtx context.Context,
	macAddress string,
	timeout time.Duration) error {
	backoff := retry.NewExponentialBackoff(sendENIStateChangeBackoffMin, sendENIStateChangeBackoffMax,
		sendENIStateChangeBackoffJitter, sendENIStateChangeBackoffMultiple)
	ctx, cancel := context.WithTimeout(parentCtx, timeout)
	defer cancel()

	err := retry.RetryWithBackoffCtx(ctx, backoff, func() error {
		sendErr := udevWatcher.sendENIStateChange(macAddress)
		if sendErr != nil {
			if _, ok := sendErr.(*unmanagedENIError); ok {
				log.Debugf("Unable to send state change for unmanaged ENI: %v", sendErr)
				return sendErr
			}
			// Not unmanagedENIError. Stop retrying when this happens
			return apierrors.NewRetriableError(apierrors.NewRetriable(false), sendErr)
		}

		return nil
	})

	if err != nil {
		return err
	}
	// RetryWithBackoffCtx returns nil when the context is cancelled. Check if there was
	// a timeout here. TODO: Fix RetryWithBackoffCtx to return ctx.Err() on context Done()
	if err = ctx.Err(); err != nil {
		return errors.Wrapf(err,
			"udev watcher send ENI state change: timed out waiting for eni '%s' in state", macAddress)
	}

	return nil
}

// sendENIStateChangeWithRetries invokes the sendENIStateChange method, with backoff and
// retries. Retries are only effective if sendENIStateChange returns an unmanagedENIError.
// We're effectively waiting for the ENI attachment message from ACS for a network device
// at this point of time.

sendENIStateChangeWithRetries invokes the sendENIStateChange method with backoff and retries . Retries are only effective if sendENIStateChange returns an unmanagedENIError . We re effectively waiting for the ENI attachment message from ACS for a network device at this point of time .


func (cs *clientServer) Close() error {
	if cs.publishTicker != nil {
		cs.publishTicker.Stop()
	}
	if cs.publishHealthTicker != nil {
		cs.publishHealthTicker.Stop()
	}

	cs.cancel()
	return cs.Disconnect()
}

func ( cs * clientServer ) Close ( ) error { if cs . publishTicker != nil { cs . publishTicker . Stop ( ) } if cs . publishHealthTicker != nil { cs . publishHealthTicker . Stop ( ) } cs . cancel ( ) return cs . Disconnect ( ) }

// Close closes the underlying connection.

Close closes the underlying connection .


func signRequestFunc(url, region string, credentialProvider *credentials.Credentials) wsclient.MakeRequestHookFunc {
	return func(payload []byte) ([]byte, error) {
		reqBody := bytes.NewReader(payload)

		request, err := http.NewRequest("GET", url, reqBody)
		if err != nil {
			return nil, err
		}

		err = utils.SignHTTPRequest(request, region, "ecs", credentialProvider, reqBody)
		if err != nil {
			return nil, err
		}

		request.Header.Add("Host", request.Host)
		var dataBuffer bytes.Buffer
		request.Header.Write(&dataBuffer)
		io.WriteString(&dataBuffer, "\r\n")

		data := dataBuffer.Bytes()
		data = append(data, payload...)

		return data, nil
	}
}

func signRequestFunc ( url , region string , credentialProvider * credentials . Credentials ) wsclient . MakeRequestHookFunc { return func ( payload [ ] byte ) ( [ ] byte , error ) { reqBody := bytes . NewReader ( payload ) request , err := http . NewRequest ( " " , url , reqBody ) if err != nil { return nil , err } err = utils . SignHTTPRequest ( request , region , " " , credentialProvider , reqBody ) if err != nil { return nil , err } request . Header . Add ( " " , request . Host ) var dataBuffer bytes . Buffer request . Header . Write ( & dataBuffer ) io . WriteString ( & dataBuffer , " \r \n " ) data := dataBuffer . Bytes ( ) data = append ( data , payload ... ) return data , nil } }

// signRequestFunc is a MakeRequestHookFunc that signs each generated request


func (cs *clientServer) publishMetrics() {
	if cs.publishTicker == nil {
		seelog.Debug("Skipping publishing metrics. Publish ticker is uninitialized")
		return
	}

	// Publish metrics immediately after we connect and wait for ticks. This makes
	// sure that there is no data loss when a scheduled metrics publishing fails
	// due to a connection reset.
	err := cs.publishMetricsOnce()
	if err != nil && err != stats.EmptyMetricsError {
		seelog.Warnf("Error publishing metrics: %v", err)
	}
	// don't simply range over the ticker since its channel doesn't ever get closed
	for {
		select {
		case <-cs.publishTicker.C:
			err := cs.publishMetricsOnce()
			if err != nil {
				seelog.Warnf("Error publishing metrics: %v", err)
			}
		case <-cs.ctx.Done():
			return
		}
	}
}

// publishMetrics invokes the PublishMetricsRequest on the clientserver object.

publishMetrics invokes the PublishMetricsRequest on the clientserver object .


func (cs *clientServer) publishMetricsOnce() error {
	// Get the list of objects to send to backend.
	requests, err := cs.metricsToPublishMetricRequests()
	if err != nil {
		return err
	}

	// Make the publish metrics request to the backend.
	for _, request := range requests {
		err = cs.MakeRequest(request)
		if err != nil {
			return err
		}
	}
	return nil
}

// publishMetricsOnce is invoked by the ticker to periodically publish metrics to backend.

publishMetricsOnce is invoked by the ticker to periodically publish metrics to backend .


func (cs *clientServer) metricsToPublishMetricRequests() ([]*ecstcs.PublishMetricsRequest, error) {
	metadata, taskMetrics, err := cs.statsEngine.GetInstanceMetrics()
	if err != nil {
		return nil, err
	}

	var requests []*ecstcs.PublishMetricsRequest
	if *metadata.Idle {
		metadata.Fin = aws.Bool(true)
		// Idle instance, we have only one request to send to backend.
		requests = append(requests, ecstcs.NewPublishMetricsRequest(metadata, taskMetrics))
		return requests, nil
	}
	var messageTaskMetrics []*ecstcs.TaskMetric
	numTasks := len(taskMetrics)

	for i, taskMetric := range taskMetrics {
		messageTaskMetrics = append(messageTaskMetrics, taskMetric)
		var requestMetadata *ecstcs.MetricsMetadata
		if (i + 1) == numTasks {
			// If this is the last task to send, set fin to true
			requestMetadata = copyMetricsMetadata(metadata, true)
		} else {
			requestMetadata = copyMetricsMetadata(metadata, false)
		}
		if (i+1)%tasksInMetricMessage == 0 {
			// Construct payload with tasksInMetricMessage number of task metrics and send to backend.
			requests = append(requests, ecstcs.NewPublishMetricsRequest(requestMetadata, copyTaskMetrics(messageTaskMetrics)))
			messageTaskMetrics = messageTaskMetrics[:0]
		}
	}

	if len(messageTaskMetrics) > 0 {
		// Create the new metadata object and set fin to true as this is the last message in the payload.
		requestMetadata := copyMetricsMetadata(metadata, true)
		// Create a request with remaining task metrics.
		requests = append(requests, ecstcs.NewPublishMetricsRequest(requestMetadata, messageTaskMetrics))
	}
	return requests, nil
}

// metricsToPublishMetricRequests gets task metrics and converts them to a list of PublishMetricRequest
// objects.

metricsToPublishMetricRequests gets task metrics and converts them to a list of PublishMetricRequest objects .


func (cs *clientServer) publishHealthMetrics() {
	if cs.publishTicker == nil {
		seelog.Debug("Skipping publishing health metrics. Publish ticker is uninitialized")
		return
	}

	// Publish metrics immediately after we connect and wait for ticks. This makes
	// sure that there is no data loss when a scheduled metrics publishing fails
	// due to a connection reset.
	err := cs.publishHealthMetricsOnce()
	if err != nil {
		seelog.Warnf("Unable to publish health metrics: %v", err)
	}
	for {
		select {
		case <-cs.publishHealthTicker.C:
			err := cs.publishHealthMetricsOnce()
			if err != nil {
				seelog.Warnf("Unable to publish health metrics: %v", err)
			}
		case <-cs.ctx.Done():
			return
		}
	}
}

// publishHealthMetrics send the container health information to backend


func (cs *clientServer) publishHealthMetricsOnce() error {
	// Get the list of health request to send to backend.
	requests, err := cs.createPublishHealthRequests()
	if err != nil {
		return err
	}
	// Make the publish metrics request to the backend.
	for _, request := range requests {
		err = cs.MakeRequest(request)
		if err != nil {
			return err
		}
	}
	return nil
}

// publishHealthMetricsOnce is invoked by the ticker to periodically publish metrics to backend.

publishHealthMetricsOnce is invoked by the ticker to periodically publish metrics to backend .


func (cs *clientServer) createPublishHealthRequests() ([]*ecstcs.PublishHealthRequest, error) {
	metadata, taskHealthMetrics, err := cs.statsEngine.GetTaskHealthMetrics()
	if err != nil {
		return nil, err
	}

	if metadata == nil || taskHealthMetrics == nil {
		seelog.Debug("No container health metrics to report")
		return nil, nil
	}

	var requests []*ecstcs.PublishHealthRequest
	var taskHealths []*ecstcs.TaskHealth
	numOfTasks := len(taskHealthMetrics)
	for i, taskHealth := range taskHealthMetrics {
		taskHealths = append(taskHealths, taskHealth)
		// create a request if the number of task reaches the maximum page size
		if (i+1)%tasksInHealthMessage == 0 {
			requestMetadata := copyHealthMetadata(metadata, (i+1) == numOfTasks)
			requestTaskHealth := copyTaskHealthMetrics(taskHealths)
			request := ecstcs.NewPublishHealthMetricsRequest(requestMetadata, requestTaskHealth)
			requests = append(requests, request)
			taskHealths = taskHealths[:0]
		}
	}

	// Put the rest of the metrics in another request
	if len(taskHealths) != 0 {
		requestMetadata := copyHealthMetadata(metadata, true)
		requests = append(requests, ecstcs.NewPublishHealthMetricsRequest(requestMetadata, taskHealths))
	}

	return requests, nil
}

// createPublishHealthRequests creates the requests to publish container health


func copyMetricsMetadata(metadata *ecstcs.MetricsMetadata, fin bool) *ecstcs.MetricsMetadata {
	return &ecstcs.MetricsMetadata{
		Cluster:           aws.String(*metadata.Cluster),
		ContainerInstance: aws.String(*metadata.ContainerInstance),
		Idle:              aws.Bool(*metadata.Idle),
		MessageId:         aws.String(*metadata.MessageId),
		Fin:               aws.Bool(fin),
	}
}

func copyMetricsMetadata ( metadata * ecstcs . MetricsMetadata , fin bool ) * ecstcs . MetricsMetadata { return & ecstcs . MetricsMetadata { Cluster : aws . String ( * metadata . Cluster ) , ContainerInstance : aws . String ( * metadata . ContainerInstance ) , Idle : aws . Bool ( * metadata . Idle ) , MessageId : aws . String ( * metadata . MessageId ) , Fin : aws . Bool ( fin ) , } }

// copyMetricsMetadata creates a new MetricsMetadata object from a given MetricsMetadata object.
// It copies all the fields from the source object to the new object and sets the 'Fin' field
// as specified by the argument.

copyMetricsMetadata creates a new MetricsMetadata object from a given MetricsMetadata object . It copies all the fields from the source object to the new object and sets the Fin field as specified by the argument .


func copyTaskMetrics(from []*ecstcs.TaskMetric) []*ecstcs.TaskMetric {
	to := make([]*ecstcs.TaskMetric, len(from))
	copy(to, from)
	return to
}

func copyTaskMetrics ( from [ ] * ecstcs . TaskMetric ) [ ] * ecstcs . TaskMetric { to := make ( [ ] * ecstcs . TaskMetric , len ( from ) ) copy ( to , from ) return to }

// copyTaskMetrics copies a slice of TaskMetric objects to another slice. This is needed as we
// reset the source slice after creating a new PublishMetricsRequest object.

copyTaskMetrics copies a slice of TaskMetric objects to another slice . This is needed as we reset the source slice after creating a new PublishMetricsRequest object .


func copyHealthMetadata(metadata *ecstcs.HealthMetadata, fin bool) *ecstcs.HealthMetadata {
	return &ecstcs.HealthMetadata{
		Cluster:           aws.String(aws.StringValue(metadata.Cluster)),
		ContainerInstance: aws.String(aws.StringValue(metadata.ContainerInstance)),
		Fin:               aws.Bool(fin),
		MessageId:         aws.String(aws.StringValue(metadata.MessageId)),
	}
}

func copyHealthMetadata ( metadata * ecstcs . HealthMetadata , fin bool ) * ecstcs . HealthMetadata { return & ecstcs . HealthMetadata { Cluster : aws . String ( aws . StringValue ( metadata . Cluster ) ) , ContainerInstance : aws . String ( aws . StringValue ( metadata . ContainerInstance ) ) , Fin : aws . Bool ( fin ) , MessageId : aws . String ( aws . StringValue ( metadata . MessageId ) ) , } }

// copyHealthMetadata performs a deep copy of HealthMetadata object


func copyTaskHealthMetrics(from []*ecstcs.TaskHealth) []*ecstcs.TaskHealth {
	to := make([]*ecstcs.TaskHealth, len(from))
	copy(to, from)
	return to
}

func copyTaskHealthMetrics ( from [ ] * ecstcs . TaskHealth ) [ ] * ecstcs . TaskHealth { to := make ( [ ] * ecstcs . TaskHealth , len ( from ) ) copy ( to , from ) return to }

// copyTaskHealthMetrics copies a slice of taskHealthMetrics to another slice


func (rm *ResourcesMap) UnmarshalJSON(data []byte) error {
	resources := make(map[string]json.RawMessage)
	err := json.Unmarshal(data, &resources)
	if err != nil {
		return err
	}
	result := make(map[string][]taskresource.TaskResource)
	for key, value := range resources {
		switch key {
		case CgroupKey:
			if unmarshlCgroup(key, value, result) != nil {
				return err
			}
		case DockerVolumeKey:
			if unmarshalDockerVolume(key, value, result) != nil {
				return err
			}
		case ASMAuthKey:
			if unmarshalASMAuthKey(key, value, result) != nil {
				return err
			}
		case SSMSecretKey:
			if unmarshalSSMSecretKey(key, value, result) != nil {
				return err
			}
		case ASMSecretKey:
			if unmarshalASMSecretKey(key, value, result) != nil {
				return err
			}
		default:
			return errors.New("Unsupported resource type")
		}
	}
	*rm = result
	return nil
}

func ( rm * ResourcesMap ) UnmarshalJSON ( data [ ] byte ) error { resources := make ( map [ string ] json . RawMessage ) err := json . Unmarshal ( data , & resources ) if err != nil { return err } result := make ( map [ string ] [ ] taskresource . TaskResource ) for key , value := range resources { switch key { case CgroupKey : if unmarshlCgroup ( key , value , result ) != nil { return err } case DockerVolumeKey : if unmarshalDockerVolume ( key , value , result ) != nil { return err } case ASMAuthKey : if unmarshalASMAuthKey ( key , value , result ) != nil { return err } case SSMSecretKey : if unmarshalSSMSecretKey ( key , value , result ) != nil { return err } case ASMSecretKey : if unmarshalASMSecretKey ( key , value , result ) != nil { return err } default : return errors . New ( " " ) } } * rm = result return nil }

// UnmarshalJSON unmarshals ResourcesMap object


func NewVolumeResource(ctx context.Context,
	name string,
	dockerVolumeName string,
	scope string,
	autoprovision bool,
	driver string,
	driverOptions map[string]string,
	labels map[string]string,
	client dockerapi.DockerClient) (*VolumeResource, error) {

	if scope == TaskScope && autoprovision {
		return nil, errors.Errorf("volume [%s] : task scoped volume could not be autoprovisioned", name)
	}

	v := &VolumeResource{
		Name: name,
		VolumeConfig: DockerVolumeConfig{
			Scope:            scope,
			Autoprovision:    autoprovision,
			Driver:           driver,
			DriverOpts:       driverOptions,
			Labels:           labels,
			DockerVolumeName: dockerVolumeName,
		},
		client: client,
		ctx:    ctx,
	}
	v.initStatusToTransitions()
	return v, nil
}

func NewVolumeResource ( ctx context . Context , name string , dockerVolumeName string , scope string , autoprovision bool , driver string , driverOptions map [ string ] string , labels map [ string ] string , client dockerapi . DockerClient ) ( * VolumeResource , error ) { if scope == TaskScope && autoprovision { return nil , errors . Errorf ( " " , name ) } v := & VolumeResource { Name : name , VolumeConfig : DockerVolumeConfig { Scope : scope , Autoprovision : autoprovision , Driver : driver , DriverOpts : driverOptions , Labels : labels , DockerVolumeName : dockerVolumeName , } , client : client , ctx : ctx , } v . initStatusToTransitions ( ) return v , nil }

// NewVolumeResource returns a docker volume wrapper object


func (vol *VolumeResource) KnownCreated() bool {
	vol.lock.RLock()
	defer vol.lock.RUnlock()

	return vol.knownStatusUnsafe == resourcestatus.ResourceStatus(VolumeCreated)
}

func ( vol * VolumeResource ) KnownCreated ( ) bool { vol . lock . RLock ( ) defer vol . lock . RUnlock ( ) return vol . knownStatusUnsafe == resourcestatus . ResourceStatus ( VolumeCreated ) }

// KnownCreated returns true if the volume's known status is CREATED

KnownCreated returns true if the volume s known status is CREATED


func (vol *VolumeResource) setMountPoint(mountPoint string) {
	vol.lock.Lock()
	defer vol.lock.Unlock()

	vol.VolumeConfig.Mountpoint = mountPoint
}

func ( vol * VolumeResource ) setMountPoint ( mountPoint string ) { vol . lock . Lock ( ) defer vol . lock . Unlock ( ) vol . VolumeConfig . Mountpoint = mountPoint }

// setMountPoint sets the mountpoint of the created volume.
// This is a read-only field, hence making this a private function.

setMountPoint sets the mountpoint of the created volume . This is a read - only field hence making this a private function .


func (vol *VolumeResource) GetMountPoint() string {
	vol.lock.RLock()
	defer vol.lock.RUnlock()

	return vol.VolumeConfig.Mountpoint
}

func ( vol * VolumeResource ) GetMountPoint ( ) string { vol . lock . RLock ( ) defer vol . lock . RUnlock ( ) return vol . VolumeConfig . Mountpoint }

// GetMountPoint gets the mountpoint of the created volume.

GetMountPoint gets the mountpoint of the created volume .


func (vol *VolumeResource) Create() error {
	seelog.Debugf("Creating volume with name %s using driver %s", vol.VolumeConfig.DockerVolumeName, vol.VolumeConfig.Driver)
	volumeResponse := vol.client.CreateVolume(
		vol.ctx,
		vol.VolumeConfig.DockerVolumeName,
		vol.VolumeConfig.Driver,
		vol.VolumeConfig.DriverOpts,
		vol.VolumeConfig.Labels,
		dockerclient.CreateVolumeTimeout)

	if volumeResponse.Error != nil {
		return volumeResponse.Error
	}

	// set readonly field after creation
	vol.setMountPoint(volumeResponse.DockerVolume.Name)
	return nil
}

func
(
vol
*
VolumeResource
)
Create
(
)
error
{
seelog
.
Debugf
(
"
"
,
vol
.
VolumeConfig
.
DockerVolumeName
,
vol
.
VolumeConfig
.
Driver
)
volumeResponse
:=
vol
.
client
.
CreateVolume
(
vol
.
ctx
,
vol
.
VolumeConfig
.
DockerVolumeName
,
vol
.
VolumeConfig
.
Driver
,
vol
.
VolumeConfig
.
DriverOpts
,
vol
.
VolumeConfig
.
Labels
,
dockerclient
.
CreateVolumeTimeout
)
if
volumeResponse
.
Error
!=
{
return
volumeResponse
.
Error
}
// set readonly field after creation
vol
.
setMountPoint
(
volumeResponse
.
DockerVolume
.
Name
)
return
}


func (vol *VolumeResource) Cleanup() error {
	// Enable volume clean up if it's task scoped
	if vol.VolumeConfig.Scope != TaskScope {
		seelog.Debugf("Volume [%s] is shared, not removing", vol.Name)
		return nil
	}

	seelog.Debugf("Removing volume with name %s", vol.Name)
	err := vol.client.RemoveVolume(vol.ctx, vol.VolumeConfig.DockerVolumeName, dockerclient.RemoveVolumeTimeout)

	if err != nil {
		return err
	}
	return nil
}


func (vol *VolumeResource) MarshalJSON() ([]byte, error) {
	if vol == nil {
		return nil, nil
	}
	return json.Marshal(volumeResourceJSON{
		vol.Name,
		vol.VolumeConfig,
		vol.GetCreatedAt(),
		func() *VolumeStatus { desiredState := VolumeStatus(vol.GetDesiredStatus()); return &desiredState }(),
		func() *VolumeStatus { knownState := VolumeStatus(vol.GetKnownStatus()); return &knownState }(),
	})
}

func ( vol * VolumeResource ) MarshalJSON ( ) ( [ ] byte , error ) { if vol == nil { return nil , nil } return json . Marshal ( volumeResourceJSON { vol . Name , vol . VolumeConfig , vol . GetCreatedAt ( ) , func ( ) * VolumeStatus { desiredState := VolumeStatus ( vol . GetDesiredStatus ( ) ) ; return & desiredState } ( ) , func ( ) * VolumeStatus { knownState := VolumeStatus ( vol . GetKnownStatus ( ) ) ; return & knownState } ( ) , } ) }

// MarshalJSON marshals VolumeResource object using duplicate struct VolumeResourceJSON


func (vol *VolumeResource) UnmarshalJSON(b []byte) error {
	temp := &volumeResourceJSON{}

	if err := json.Unmarshal(b, &temp); err != nil {
		return err
	}

	vol.Name = temp.Name
	vol.VolumeConfig = temp.VolumeConfig
	if temp.DesiredStatus != nil {
		vol.SetDesiredStatus(resourcestatus.ResourceStatus(*temp.DesiredStatus))
	}
	if temp.KnownStatus != nil {
		vol.SetKnownStatus(resourcestatus.ResourceStatus(*temp.KnownStatus))
	}
	return nil
}

func ( vol * VolumeResource ) UnmarshalJSON ( b [ ] byte ) error { temp := & volumeResourceJSON { } if err := json . Unmarshal ( b , & temp ) ; err != nil { return err } vol . Name = temp . Name vol . VolumeConfig = temp . VolumeConfig if temp . DesiredStatus != nil { vol . SetDesiredStatus ( resourcestatus . ResourceStatus ( * temp . DesiredStatus ) ) } if temp . KnownStatus != nil { vol . SetKnownStatus ( resourcestatus . ResourceStatus ( * temp . KnownStatus ) ) } return nil }

// UnmarshalJSON unmarshals VolumeResource object using duplicate struct VolumeResourceJSON


func NewMockClientCreator(ctrl *gomock.Controller) *MockClientCreator {
	mock := &MockClientCreator{ctrl: ctrl}
	mock.recorder = &MockClientCreatorMockRecorder{mock}
	return mock
}

func NewMockClientCreator ( ctrl * gomock . Controller ) * MockClientCreator { mock := & MockClientCreator { ctrl : ctrl } mock . recorder = & MockClientCreatorMockRecorder { mock } return mock }

// NewMockClientCreator creates a new mock instance


func (m *MockClientCreator) NewASMClient(arg0 string, arg1 credentials.IAMRoleCredentials) secretsmanageriface.SecretsManagerAPI {
	ret := m.ctrl.Call(m, "NewASMClient", arg0, arg1)
	ret0, _ := ret[0].(secretsmanageriface.SecretsManagerAPI)
	return ret0
}

func ( m * MockClientCreator ) NewASMClient ( arg0 string , arg1 credentials . IAMRoleCredentials ) secretsmanageriface . SecretsManagerAPI { ret := m . ctrl . Call ( m , " " , arg0 , arg1 ) ret0 , _ := ret [ 0 ] . ( secretsmanageriface . SecretsManagerAPI ) return ret0 }


func (mr *MockClientCreatorMockRecorder) NewASMClient(arg0, arg1 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewASMClient", reflect.TypeOf((*MockClientCreator)(nil).NewASMClient), arg0, arg1)
}

func ( mr * MockClientCreatorMockRecorder ) NewASMClient ( arg0 , arg1 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockClientCreator ) ( nil ) . NewASMClient ) , arg0 , arg1 ) }

// NewASMClient indicates an expected call of NewASMClient


func NewTransportProtocol(protocol string) (TransportProtocol, error) {
	switch protocol {
	case tcp:
		return TransportProtocolTCP, nil
	case udp:
		return TransportProtocolUDP, nil
	default:
		return TransportProtocolTCP, errors.New(protocol + " is not a recognized transport protocol")
	}
}

func NewTransportProtocol ( protocol string ) ( TransportProtocol , error ) { switch protocol { case tcp : return TransportProtocolTCP , nil case udp : return TransportProtocolUDP , nil default : return TransportProtocolTCP , errors . New ( protocol + " " ) } }

// NewTransportProtocol returns a TransportProtocol from a string in the task


func (tp *TransportProtocol) String() string {
	if tp == nil {
		return tcp
	}
	switch *tp {
	case TransportProtocolUDP:
		return udp
	case TransportProtocolTCP:
		return tcp
	default:
		seelog.Critical("Unknown TransportProtocol type!")
		return tcp
	}
}

func ( tp * TransportProtocol ) String ( ) string { if tp == nil { return tcp } switch * tp { case TransportProtocolUDP : return udp case TransportProtocolTCP : return tcp default : seelog . Critical ( " " ) return tcp } }

// String converts TransportProtocol to a string


func (tp *TransportProtocol) UnmarshalJSON(b []byte) error {
	if strings.ToLower(string(b)) == "null" {
		*tp = TransportProtocolTCP
		seelog.Warn("Unmarshalled nil TransportProtocol as TCP")
		return nil
	}
	switch string(b) {
	case `"tcp"`:
		*tp = TransportProtocolTCP
	case `"udp"`:
		*tp = TransportProtocolUDP
	default:
		*tp = TransportProtocolTCP
		return errors.New("TransportProtocol must be \"tcp\" or \"udp\"; Got " + string(b))
	}
	return nil
}

func ( tp * TransportProtocol ) UnmarshalJSON ( b [ ] byte ) error { if strings . ToLower ( string ( b ) ) == " " { * tp = TransportProtocolTCP seelog . Warn ( " " ) return nil } switch string ( b ) { case `"tcp"` : * tp = TransportProtocolTCP case `"udp"` : * tp = TransportProtocolUDP default : * tp = TransportProtocolTCP return errors . New ( " \" \" \" \" " + string ( b ) ) } return nil }

// UnmarshalJSON for TransportProtocol determines whether to use TCP or UDP,
// setting TCP as the zero-value but treating other unrecognized values as
// errors

UnmarshalJSON for TransportProtocol determines whether to use TCP or UDP setting TCP as the zero - value but treating other unrecognized values as errors


func (tp *TransportProtocol) MarshalJSON() ([]byte, error) {
	if tp == nil {
		return []byte("null"), nil
	}
	return []byte(`"` + tp.String() + `"`), nil
}

func ( tp * TransportProtocol ) MarshalJSON ( ) ( [ ] byte , error ) { if tp == nil { return [ ] byte ( " " ) , nil } return [ ] byte ( `"` + tp . String ( ) + `"` ) , nil }

// MarshalJSON overrides the logic for JSON-encoding the TransportProtocol type

MarshalJSON overrides the logic for JSON - encoding the TransportProtocol type


func NewMockManager(ctrl *gomock.Controller) *MockManager {
	mock := &MockManager{ctrl: ctrl}
	mock.recorder = &MockManagerMockRecorder{mock}
	return mock
}

func NewMockManager ( ctrl * gomock . Controller ) * MockManager { mock := & MockManager { ctrl : ctrl } mock . recorder = & MockManagerMockRecorder { mock } return mock }

// NewMockManager creates a new mock instance


func (m *MockManager) GetTaskCredentials(arg0 string) (credentials.TaskIAMRoleCredentials, bool) {
	ret := m.ctrl.Call(m, "GetTaskCredentials", arg0)
	ret0, _ := ret[0].(credentials.TaskIAMRoleCredentials)
	ret1, _ := ret[1].(bool)
	return ret0, ret1
}

func ( m * MockManager ) GetTaskCredentials ( arg0 string ) ( credentials . TaskIAMRoleCredentials , bool ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( credentials . TaskIAMRoleCredentials ) ret1 , _ := ret [ 1 ] . ( bool ) return ret0 , ret1 }


func (m *MockManager) RemoveCredentials(arg0 string) {
	m.ctrl.Call(m, "RemoveCredentials", arg0)
}

func ( m * MockManager ) RemoveCredentials ( arg0 string ) { m . ctrl . Call ( m , " " , arg0 ) }


func (m *MockManager) SetTaskCredentials(arg0 *credentials.TaskIAMRoleCredentials) error {
	ret := m.ctrl.Call(m, "SetTaskCredentials", arg0)
	ret0, _ := ret[0].(error)
	return ret0
}

func ( m * MockManager ) SetTaskCredentials ( arg0 * credentials . TaskIAMRoleCredentials ) error { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( error ) return ret0 }


func GetDockerAuthFromASM(secretID string, client secretsmanageriface.SecretsManagerAPI) (types.AuthConfig, error) {
	in := &secretsmanager.GetSecretValueInput{
		SecretId: aws.String(secretID),
	}

	out, err := client.GetSecretValue(in)
	if err != nil {
		return types.AuthConfig{}, errors.Wrapf(err,
			"asm fetching secret from the service for %s", secretID)
	}

	return extractASMValue(out)
}

func GetDockerAuthFromASM ( secretID string , client secretsmanageriface . SecretsManagerAPI ) ( types . AuthConfig , error ) { in := & secretsmanager . GetSecretValueInput { SecretId : aws . String ( secretID ) , } out , err := client . GetSecretValue ( in ) if err != nil { return types . AuthConfig { } , errors . Wrapf ( err , " " , secretID ) } return extractASMValue ( out ) }

// GetDockerAuthFromASM makes the api call to the AWS Secrets Manager service to
// retrieve the docker auth data

GetDockerAuthFromASM makes the api call to the AWS Secrets Manager service to retrieve the docker auth data


func GetSecretFromASM(secretID string, client secretsmanageriface.SecretsManagerAPI) (string, error) {
	in := &secretsmanager.GetSecretValueInput{
		SecretId: aws.String(secretID),
	}

	out, err := client.GetSecretValue(in)
	if err != nil {
		return "", errors.Wrapf(err, "secret %s", secretID)
	}

	return aws.StringValue(out.SecretString), nil
}

func GetSecretFromASM ( secretID string , client secretsmanageriface . SecretsManagerAPI ) ( string , error ) { in := & secretsmanager . GetSecretValueInput { SecretId : aws . String ( secretID ) , } out , err := client . GetSecretValue ( in ) if err != nil { return " " , errors . Wrapf ( err , " " , secretID ) } return aws . StringValue ( out . SecretString ) , nil }

// GetSecretFromASM makes the api call to the AWS Secrets Manager service to
// retrieve the secret value

GetSecretFromASM makes the api call to the AWS Secrets Manager service to retrieve the secret value


func NewMockCgroupFactory(ctrl *gomock.Controller) *MockCgroupFactory {
	mock := &MockCgroupFactory{ctrl: ctrl}
	mock.recorder = &MockCgroupFactoryMockRecorder{mock}
	return mock
}

func NewMockCgroupFactory ( ctrl * gomock . Controller ) * MockCgroupFactory { mock := & MockCgroupFactory { ctrl : ctrl } mock . recorder = & MockCgroupFactoryMockRecorder { mock } return mock }

// NewMockCgroupFactory creates a new mock instance


func (m *MockCgroupFactory) Load(arg0 cgroups.Hierarchy, arg1 cgroups.Path) (cgroups.Cgroup, error) {
	ret := m.ctrl.Call(m, "Load", arg0, arg1)
	ret0, _ := ret[0].(cgroups.Cgroup)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockCgroupFactory ) Load ( arg0 cgroups . Hierarchy , arg1 cgroups . Path ) ( cgroups . Cgroup , error ) { ret := m . ctrl . Call ( m , " " , arg0 , arg1 ) ret0 , _ := ret [ 0 ] . ( cgroups . Cgroup ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (mr *MockCgroupFactoryMockRecorder) Load(arg0, arg1 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Load", reflect.TypeOf((*MockCgroupFactory)(nil).Load), arg0, arg1)
}

func ( mr * MockCgroupFactoryMockRecorder ) Load ( arg0 , arg1 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockCgroupFactory ) ( nil ) . Load ) , arg0 , arg1 ) }

// Load indicates an expected call of Load


func (*loader) LoadImage(ctx context.Context, cfg *config.Config, dockerClient dockerapi.DockerClient) (*types.ImageInspect, error) {
	log.Debugf("Loading pause container tarball: %s", cfg.PauseContainerTarballPath)
	if err := loadFromFile(ctx, cfg.PauseContainerTarballPath, dockerClient, os.Default); err != nil {
		return nil, err
	}

	return getPauseContainerImage(
		config.DefaultPauseContainerImageName, config.DefaultPauseContainerTag, dockerClient)
}

func ( * loader ) LoadImage ( ctx context . Context , cfg * config . Config , dockerClient dockerapi . DockerClient ) ( * types . ImageInspect , error ) { log . Debugf ( " " , cfg . PauseContainerTarballPath ) if err := loadFromFile ( ctx , cfg . PauseContainerTarballPath , dockerClient , os . Default ) ; err != nil { return nil , err } return getPauseContainerImage ( config . DefaultPauseContainerImageName , config . DefaultPauseContainerTag , dockerClient ) }

// LoadImage helps load the pause container image for the agent


func NewCgroupResource(taskARN string,
	control control.Control,
	ioutil ioutilwrapper.IOUtil,
	cgroupRoot string,
	cgroupMountPath string,
	resourceSpec specs.LinuxResources) *CgroupResource {
	c := &CgroupResource{
		taskARN:         taskARN,
		control:         control,
		ioutil:          ioutil,
		cgroupRoot:      cgroupRoot,
		cgroupMountPath: cgroupMountPath,
		resourceSpec:    resourceSpec,
	}
	c.initializeResourceStatusToTransitionFunction()
	return c
}

// NewCgroupResource is used to return an object that implements the Resource interface


func (cgroup *CgroupResource) Create() error {
	err := cgroup.setupTaskCgroup()
	if err != nil {
		seelog.Criticalf("Cgroup resource [%s]: unable to setup cgroup root: %v", cgroup.taskARN, err)
		return err
	}
	return nil
}

func ( cgroup * CgroupResource ) Create ( ) error { err := cgroup . setupTaskCgroup ( ) if err != nil { seelog . Criticalf ( " " , cgroup . taskARN , err ) return err } return nil }

// Create creates cgroup root for the task


func (cgroup *CgroupResource) Cleanup() error {
	err := cgroup.control.Remove(cgroup.cgroupRoot)
	// Explicitly handle cgroup deleted error
	if err != nil {
		if err == cgroups.ErrCgroupDeleted {
			seelog.Warnf("Cgroup at %s has already been removed: %v", cgroup.cgroupRoot, err)
			return nil
		}
		return errors.Wrapf(err, "resource: cleanup cgroup: unable to remove cgroup at %s", cgroup.cgroupRoot)
	}
	return nil
}

// Cleanup removes the cgroup root created for the task


func (cgroup *CgroupResource) MarshalJSON() ([]byte, error) {
	if cgroup == nil {
		return nil, errors.New("cgroup resource is nil")
	}
	return json.Marshal(cgroupResourceJSON{
		cgroup.cgroupRoot,
		cgroup.cgroupMountPath,
		cgroup.GetCreatedAt(),
		func() *CgroupStatus {
			desiredState := cgroup.GetDesiredStatus()
			status := CgroupStatus(desiredState)
			return &status
		}(),
		func() *CgroupStatus {
			knownState := cgroup.GetKnownStatus()
			status := CgroupStatus(knownState)
			return &status
		}(),
		cgroup.resourceSpec,
	})
}

func ( cgroup * CgroupResource ) MarshalJSON ( ) ( [ ] byte , error ) { if cgroup == nil { return nil , errors . New ( " " ) } return json . Marshal ( cgroupResourceJSON { cgroup . cgroupRoot , cgroup . cgroupMountPath , cgroup . GetCreatedAt ( ) , func ( ) * CgroupStatus { desiredState := cgroup . GetDesiredStatus ( ) status := CgroupStatus ( desiredState ) return & status } ( ) , func ( ) * CgroupStatus { knownState := cgroup . GetKnownStatus ( ) status := CgroupStatus ( knownState ) return & status } ( ) , cgroup . resourceSpec , } ) }

// MarshalJSON marshals CgroupResource object using duplicate struct CgroupResourceJSON


func (cgroup *CgroupResource) UnmarshalJSON(b []byte) error {
	temp := cgroupResourceJSON{}

	if err := json.Unmarshal(b, &temp); err != nil {
		return err
	}

	cgroup.cgroupRoot = temp.CgroupRoot
	cgroup.cgroupMountPath = temp.CgroupMountPath
	cgroup.resourceSpec = temp.LinuxSpec
	if temp.DesiredStatus != nil {
		cgroup.SetDesiredStatus(resourcestatus.ResourceStatus(*temp.DesiredStatus))
	}
	if temp.KnownStatus != nil {
		cgroup.SetKnownStatus(resourcestatus.ResourceStatus(*temp.KnownStatus))
	}
	return nil
}

func ( cgroup * CgroupResource ) UnmarshalJSON ( b [ ] byte ) error { temp := cgroupResourceJSON { } if err := json . Unmarshal ( b , & temp ) ; err != nil { return err } cgroup . cgroupRoot = temp . CgroupRoot cgroup . cgroupMountPath = temp . CgroupMountPath cgroup . resourceSpec = temp . LinuxSpec if temp . DesiredStatus != nil { cgroup . SetDesiredStatus ( resourcestatus . ResourceStatus ( * temp . DesiredStatus ) ) } if temp . KnownStatus != nil { cgroup . SetKnownStatus ( resourcestatus . ResourceStatus ( * temp . KnownStatus ) ) } return nil }

// UnmarshalJSON unmarshals CgroupResource object using duplicate struct CgroupResourceJSON


func (cgroup *CgroupResource) GetCgroupRoot() string {
	cgroup.lock.RLock()
	defer cgroup.lock.RUnlock()
	return cgroup.cgroupRoot
}

func ( cgroup * CgroupResource ) GetCgroupRoot ( ) string { cgroup . lock . RLock ( ) defer cgroup . lock . RUnlock ( ) return cgroup . cgroupRoot }

// GetCgroupRoot returns cgroup root of the resource


func (cgroup *CgroupResource) GetCgroupMountPath() string {
	cgroup.lock.RLock()
	defer cgroup.lock.RUnlock()
	return cgroup.cgroupMountPath
}

func ( cgroup * CgroupResource ) GetCgroupMountPath ( ) string { cgroup . lock . RLock ( ) defer cgroup . lock . RUnlock ( ) return cgroup . cgroupMountPath }

// GetCgroupMountPath returns cgroup mount path of the resource


func (cgroup *CgroupResource) Initialize(resourceFields *taskresource.ResourceFields,
	taskKnownStatus status.TaskStatus,
	taskDesiredStatus status.TaskStatus) {
	cgroup.lock.Lock()
	defer cgroup.lock.Unlock()

	cgroup.initializeResourceStatusToTransitionFunction()
	cgroup.ioutil = resourceFields.IOUtil
	cgroup.control = resourceFields.Control
}

// Initialize initializes the resource fileds in cgroup


func (*loader) LoadImage(ctx context.Context, cfg *config.Config, dockerClient dockerapi.DockerClient) (*types.ImageInspect, error) {
	return nil, NewUnsupportedPlatformError(errors.Errorf(
		"pause container load: unsupported platform: %s/%s",
		runtime.GOOS, runtime.GOARCH))
}

func ( * loader ) LoadImage ( ctx context . Context , cfg * config . Config , dockerClient dockerapi . DockerClient ) ( * types . ImageInspect , error ) { return nil , NewUnsupportedPlatformError ( errors . Errorf ( " " , runtime . GOOS , runtime . GOARCH ) ) }

// LoadImage returns UnsupportedPlatformError on the unsupported platform


func NewECRFactory(acceptInsecureCert bool) ECRFactory {
	return &ecrFactory{
		httpClient: httpclient.New(roundtripTimeout, acceptInsecureCert),
	}
}

func NewECRFactory ( acceptInsecureCert bool ) ECRFactory { return & ecrFactory { httpClient : httpclient . New ( roundtripTimeout , acceptInsecureCert ) , } }

// NewECRFactory returns an ECRFactory capable of producing ECRSDK clients


func (factory *ecrFactory) GetClient(authData *apicontainer.ECRAuthData) (ECRClient, error) {
	clientConfig, err := getClientConfig(factory.httpClient, authData)
	if err != nil {
		return &ecrClient{}, err
	}

	return factory.newClient(clientConfig), nil
}

func ( factory * ecrFactory ) GetClient ( authData * apicontainer . ECRAuthData ) ( ECRClient , error ) { clientConfig , err := getClientConfig ( factory . httpClient , authData ) if err != nil { return & ecrClient { } , err } return factory . newClient ( clientConfig ) , nil }

// GetClient creates the ECR SDK client based on the authdata


func getClientConfig(httpClient *http.Client, authData *apicontainer.ECRAuthData) (*aws.Config, error) {
	cfg := aws.NewConfig().WithRegion(authData.Region).WithHTTPClient(httpClient)
	if authData.EndpointOverride != "" {
		cfg.Endpoint = aws.String(authData.EndpointOverride)
	}

	if authData.UseExecutionRole {
		if authData.GetPullCredentials() == (credentials.IAMRoleCredentials{}) {
			return nil, fmt.Errorf("container uses execution credentials, but the credentials are empty")
		}
		creds := awscreds.NewStaticCredentials(authData.GetPullCredentials().AccessKeyID,
			authData.GetPullCredentials().SecretAccessKey,
			authData.GetPullCredentials().SessionToken)
		cfg = cfg.WithCredentials(creds)
	}

	return cfg, nil
}

func getClientConfig ( httpClient * http . Client , authData * apicontainer . ECRAuthData ) ( * aws . Config , error ) { cfg := aws . NewConfig ( ) . WithRegion ( authData . Region ) . WithHTTPClient ( httpClient ) if authData . EndpointOverride != " " { cfg . Endpoint = aws . String ( authData . EndpointOverride ) } if authData . UseExecutionRole { if authData . GetPullCredentials ( ) == ( credentials . IAMRoleCredentials { } ) { return nil , fmt . Errorf ( " " ) } creds := awscreds . NewStaticCredentials ( authData . GetPullCredentials ( ) . AccessKeyID , authData . GetPullCredentials ( ) . SecretAccessKey , authData . GetPullCredentials ( ) . SessionToken ) cfg = cfg . WithCredentials ( creds ) } return cfg , nil }

// getClientConfig returns the config for the ecr client based on authData


func NewMockAuditLogger(ctrl *gomock.Controller) *MockAuditLogger {
	mock := &MockAuditLogger{ctrl: ctrl}
	mock.recorder = &MockAuditLoggerMockRecorder{mock}
	return mock
}

func NewMockAuditLogger ( ctrl * gomock . Controller ) * MockAuditLogger { mock := & MockAuditLogger { ctrl : ctrl } mock . recorder = & MockAuditLoggerMockRecorder { mock } return mock }

// NewMockAuditLogger creates a new mock instance


func (m *MockAuditLogger) GetContainerInstanceArn() string {
	ret := m.ctrl.Call(m, "GetContainerInstanceArn")
	ret0, _ := ret[0].(string)
	return ret0
}

func ( m * MockAuditLogger ) GetContainerInstanceArn ( ) string { ret := m . ctrl . Call ( m , " " ) ret0 , _ := ret [ 0 ] . ( string ) return ret0 }

// GetContainerInstanceArn mocks base method


func (mr *MockAuditLoggerMockRecorder) GetContainerInstanceArn() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainerInstanceArn", reflect.TypeOf((*MockAuditLogger)(nil).GetContainerInstanceArn))
}

func ( mr * MockAuditLoggerMockRecorder ) GetContainerInstanceArn ( ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockAuditLogger ) ( nil ) . GetContainerInstanceArn ) ) }

// GetContainerInstanceArn indicates an expected call of GetContainerInstanceArn


func (m *MockAuditLogger) Log(arg0 request.LogRequest, arg1 int, arg2 string) {
	m.ctrl.Call(m, "Log", arg0, arg1, arg2)
}

func ( m * MockAuditLogger ) Log ( arg0 request . LogRequest , arg1 int , arg2 string ) { m . ctrl . Call ( m , " " , arg0 , arg1 , arg2 ) }


func (mr *MockAuditLoggerMockRecorder) Log(arg0, arg1, arg2 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockAuditLogger)(nil).Log), arg0, arg1, arg2)
}

func ( mr * MockAuditLoggerMockRecorder ) Log ( arg0 , arg1 , arg2 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockAuditLogger ) ( nil ) . Log ) , arg0 , arg1 , arg2 ) }

// Log indicates an expected call of Log


func NewMockInfoLogger(ctrl *gomock.Controller) *MockInfoLogger {
	mock := &MockInfoLogger{ctrl: ctrl}
	mock.recorder = &MockInfoLoggerMockRecorder{mock}
	return mock
}

func NewMockInfoLogger ( ctrl * gomock . Controller ) * MockInfoLogger { mock := & MockInfoLogger { ctrl : ctrl } mock . recorder = & MockInfoLoggerMockRecorder { mock } return mock }

// NewMockInfoLogger creates a new mock instance


func (m *MockInfoLogger) Info(arg0 ...interface{}) {
	varargs := []interface{}{}
	for _, a := range arg0 {
		varargs = append(varargs, a)
	}
	m.ctrl.Call(m, "Info", varargs...)
}

func ( m * MockInfoLogger ) Info ( arg0 ... interface { } ) { varargs := [ ] interface { } { } for _ , a := range arg0 { varargs = append ( varargs , a ) } m . ctrl . Call ( m , " " , varargs ... ) }


func (mr *MockInfoLoggerMockRecorder) Info(arg0 ...interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockInfoLogger)(nil).Info), arg0...)
}

func ( mr * MockInfoLoggerMockRecorder ) Info ( arg0 ... interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockInfoLogger ) ( nil ) . Info ) , arg0 ... ) }

// Info indicates an expected call of Info


func (event *sendableEvent) taskShouldBeSent() bool {
	event.lock.RLock()
	defer event.lock.RUnlock()

	if event.isContainerEvent {
		return false
	}
	tevent := event.taskChange
	if event.taskSent {
		return false // redundant event
	}

	// task and container change event should have task != nil
	if tevent.Task == nil {
		return false
	}

	// Task event should be sent
	if tevent.Task.GetSentStatus() < tevent.Status {
		return true
	}

	// Container event should be sent
	for _, containerStateChange := range tevent.Containers {
		container := containerStateChange.Container
		if container.GetSentStatus() < container.GetKnownStatus() {
			// We found a container that needs its state
			// change to be sent to ECS.
			return true
		}
	}

	return false
}

// taskShouldBeSent checks whether the event should be sent, this includes
// both task state change and container state change events

taskShouldBeSent checks whether the event should be sent this includes both task state change and container state change events


func (event *sendableEvent) send(
	sendStatusToECS sendStatusChangeToECS,
	setChangeSent setStatusSent,
	eventType string,
	client api.ECSClient,
	eventToSubmit *list.Element,
	stateSaver statemanager.Saver,
	backoff retry.Backoff,
	taskEvents *taskSendableEvents) error {

	seelog.Infof("TaskHandler: Sending %s change: %s", eventType, event.toString())
	// Try submitting the change to ECS
	if err := sendStatusToECS(client, event); err != nil {
		seelog.Errorf("TaskHandler: Unretriable error submitting %s state change [%s]: %v",
			eventType, event.toString(), err)
		return err
	}
	// submitted; ensure we don't retry it
	event.setSent()
	// Mark event as sent
	setChangeSent(event)
	// Update the state file
	stateSaver.Save()
	seelog.Debugf("TaskHandler: Submitted task state change: %s", event.toString())
	taskEvents.events.Remove(eventToSubmit)
	backoff.Reset()
	return nil
}

func
(
event
*
sendableEvent
)
send
(
sendStatusToECS
sendStatusChangeToECS
,
setChangeSent
setStatusSent
,
eventType
string
,
client
api
.
ECSClient
,
eventToSubmit
*
list
.
Element
,
stateSaver
statemanager
.
Saver
,
backoff
retry
.
Backoff
,
taskEvents
*
taskSendableEvents
)
error
{
seelog
.
Infof
(
"
"
,
eventType
,
event
.
toString
(
)
)
// Try submitting the change to ECS
if
err
:=
sendStatusToECS
(
client
,
event
)
;
err
!=
{
seelog
.
Errorf
(
"
"
,
eventType
,
event
.
toString
(
)
,
err
)
return
err
}
// submitted; ensure we don't retry it
event
.
setSent
(
)
// Mark event as sent
setChangeSent
(
event
)
// Update the state file
stateSaver
.
Save
(
)
seelog
.
Debugf
(
"
"
,
event
.
toString
(
)
)
taskEvents
.
events
.
Remove
(
eventToSubmit
)
backoff
.
Reset
(
)
return
}

// send tries to send an event, specified by 'eventToSubmit', of type
// 'eventType' to ECS

send tries to send an event specified by eventToSubmit of type eventType to ECS


func sendContainerStatusToECS(client api.ECSClient, event *sendableEvent) error {
	return client.SubmitContainerStateChange(event.containerChange)
}

func sendContainerStatusToECS ( client api . ECSClient , event * sendableEvent ) error { return client . SubmitContainerStateChange ( event . containerChange ) }

// sendContainerStatusToECS invokes the SubmitContainerStateChange API to send a
// container status change to ECS

sendContainerStatusToECS invokes the SubmitContainerStateChange API to send a container status change to ECS


func sendTaskStatusToECS(client api.ECSClient, event *sendableEvent) error {
	return client.SubmitTaskStateChange(event.taskChange)
}

func sendTaskStatusToECS ( client api . ECSClient , event * sendableEvent ) error { return client . SubmitTaskStateChange ( event . taskChange ) }

// sendTaskStatusToECS invokes the SubmitTaskStateChange API to send a task
// status change to ECS

sendTaskStatusToECS invokes the SubmitTaskStateChange API to send a task status change to ECS


func setContainerChangeSent(event *sendableEvent) {
	containerChangeStatus := event.containerChange.Status
	container := event.containerChange.Container
	if container != nil && container.GetSentStatus() < containerChangeStatus {
		container.SetSentStatus(containerChangeStatus)
	}
}

func setContainerChangeSent ( event * sendableEvent ) { containerChangeStatus := event . containerChange . Status container := event . containerChange . Container if container != nil && container . GetSentStatus ( ) < containerChangeStatus { container . SetSentStatus ( containerChangeStatus ) } }

// setContainerChangeSent sets the event's container change object as sent

setContainerChangeSent sets the event s container change object as sent


func setTaskChangeSent(event *sendableEvent) {
	taskChangeStatus := event.taskChange.Status
	task := event.taskChange.Task
	if task != nil && task.GetSentStatus() < taskChangeStatus {
		task.SetSentStatus(taskChangeStatus)
	}
	for _, containerStateChange := range event.taskChange.Containers {
		container := containerStateChange.Container
		containerChangeStatus := containerStateChange.Status
		if container.GetSentStatus() < containerChangeStatus {
			container.SetSentStatus(containerStateChange.Status)
		}
	}
}

func setTaskChangeSent ( event * sendableEvent ) { taskChangeStatus := event . taskChange . Status task := event . taskChange . Task if task != nil && task . GetSentStatus ( ) < taskChangeStatus { task . SetSentStatus ( taskChangeStatus ) } for _ , containerStateChange := range event . taskChange . Containers { container := containerStateChange . Container containerChangeStatus := containerStateChange . Status if container . GetSentStatus ( ) < containerChangeStatus { container . SetSentStatus ( containerStateChange . Status ) } } }

// setTaskChangeSent sets the event's task change object as sent

setTaskChangeSent sets the event s task change object as sent


func setTaskAttachmentSent(event *sendableEvent) {
	if event.taskChange.Attachment != nil {
		event.taskChange.Attachment.SetSentStatus()
		event.taskChange.Attachment.StopAckTimer()
	}
}

func setTaskAttachmentSent ( event * sendableEvent ) { if event . taskChange . Attachment != nil { event . taskChange . Attachment . SetSentStatus ( ) event . taskChange . Attachment . StopAckTimer ( ) } }

// setTaskAttachmentSent sets the event's task attachment object as sent

setTaskAttachmentSent sets the event s task attachment object as sent


func GetSecretsFromSSM(names []string, client SSMClient) (map[string]string, error) {
	var secretNames []*string
	for _, name := range names {
		secretNames = append(secretNames, aws.String(name))
	}

	in := &ssm.GetParametersInput{
		Names:          secretNames,
		WithDecryption: aws.Bool(true),
	}

	out, err := client.GetParameters(in)
	if err != nil {
		return nil, err
	}

	return extractSSMValues(out)
}

func GetSecretsFromSSM ( names [ ] string , client SSMClient ) ( map [ string ] string , error ) { var secretNames [ ] * string for _ , name := range names { secretNames = append ( secretNames , aws . String ( name ) ) } in := & ssm . GetParametersInput { Names : secretNames , WithDecryption : aws . Bool ( true ) , } out , err := client . GetParameters ( in ) if err != nil { return nil , err } return extractSSMValues ( out ) }

// GetSecretFromSSM makes the api call to the AWS SSM parameter store to
// retrieve secrets value in batches

GetSecretFromSSM makes the api call to the AWS SSM parameter store to retrieve secrets value in batches


func main() {

	versionStr, _ := ioutil.ReadFile(filepath.Join("..", "..", "VERSION"))

	// default values
	info := versionInfo{
		Version: strings.TrimSpace(string(versionStr)),
		Dirty:   true,
		Hash:    "UNKNOWN",
	}

	if strings.TrimSpace(os.Getenv("ECS_RELEASE")) == "cleanbuild" {
		// 'clean' release; all other releases assumed dirty
		info.Dirty = gitDirty()
	}
	if os.Getenv("ECS_UNKNOWN_VERSION") == "" {
		// When the version file is updated, the above is set
		// Setting UNKNOWN version allows the version committed in git to never
		// have a commit hash so that it does not churn with every commit. This
		// env var should not be set when building, and go generate should be
		// run before any build, such that the commithash will be set correctly.
		info.Hash = gitHash()
	}

	outFile, err := os.Create("version.go")
	if err != nil {
		log.Fatalf("Unable to create output version file: %v", err)
	}
	t := template.Must(template.New("version").Parse(versiongoTemplate))

	err = t.Execute(outFile, info)
	if err != nil {
		log.Fatalf("Error applying template: %v", err)
	}
}

// version-gen is a simple program that generates the agent's version file,
// containing information about the agent's version, commit hash, and repository
// cleanliness.

version - gen is a simple program that generates the agent s version file containing information about the agent s version commit hash and repository cleanliness .


func (err CannotStopContainerError) IsRetriableError() bool {
	if _, ok := err.FromError.(NoSuchContainerError); ok {
		return false
	}

	return true
}

func ( err CannotStopContainerError ) IsRetriableError ( ) bool { if _ , ok := err . FromError . ( NoSuchContainerError ) ; ok { return false } return true }

// IsRetriableError returns a boolean indicating whether the call that
// generated the error can be retried.
// When stopping a container, most errors that we can get should be
// considered retriable. However, in the case where the container is
// already stopped or doesn't exist at all, there's no sense in
// retrying.

IsRetriableError returns a boolean indicating whether the call that generated the error can be retried . When stopping a container most errors that we can get should be considered retriable . However in the case where the container is already stopped or doesn t exist at all there s no sense in retrying .


func NewMockFile(ctrl *gomock.Controller) *MockFile {
	mock := &MockFile{ctrl: ctrl}
	mock.recorder = &MockFileMockRecorder{mock}
	return mock
}

func NewMockFile ( ctrl * gomock . Controller ) * MockFile { mock := & MockFile { ctrl : ctrl } mock . recorder = & MockFileMockRecorder { mock } return mock }

// NewMockFile creates a new mock instance


func (m *MockFile) Chmod(arg0 os.FileMode) error {
	ret := m.ctrl.Call(m, "Chmod", arg0)
	ret0, _ := ret[0].(error)
	return ret0
}

func ( m * MockFile ) Chmod ( arg0 os . FileMode ) error { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( error ) return ret0 }


func (mr *MockFileMockRecorder) Chmod(arg0 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chmod", reflect.TypeOf((*MockFile)(nil).Chmod), arg0)
}

func ( mr * MockFileMockRecorder ) Chmod ( arg0 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockFile ) ( nil ) . Chmod ) , arg0 ) }

// Chmod indicates an expected call of Chmod


func (m *MockFile) Write(arg0 []byte) (int, error) {
	ret := m.ctrl.Call(m, "Write", arg0)
	ret0, _ := ret[0].(int)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockFile ) Write ( arg0 [ ] byte ) ( int , error ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( int ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func NewMockOS(ctrl *gomock.Controller) *MockOS {
	mock := &MockOS{ctrl: ctrl}
	mock.recorder = &MockOSMockRecorder{mock}
	return mock
}

func NewMockOS ( ctrl * gomock . Controller ) * MockOS { mock := & MockOS { ctrl : ctrl } mock . recorder = & MockOSMockRecorder { mock } return mock }

// NewMockOS creates a new mock instance


func (mr *MockOSMockRecorder) Create(arg0 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockOS)(nil).Create), arg0)
}

func ( mr * MockOSMockRecorder ) Create ( arg0 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockOS ) ( nil ) . Create ) , arg0 ) }

// Create indicates an expected call of Create


func (m *MockOS) IsNotExist(arg0 error) bool {
	ret := m.ctrl.Call(m, "IsNotExist", arg0)
	ret0, _ := ret[0].(bool)
	return ret0
}

func ( m * MockOS ) IsNotExist ( arg0 error ) bool { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( bool ) return ret0 }


func (m *MockOS) OpenFile(arg0 string, arg1 int, arg2 os.FileMode) (oswrapper.File, error) {
	ret := m.ctrl.Call(m, "OpenFile", arg0, arg1, arg2)
	ret0, _ := ret[0].(oswrapper.File)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockOS ) OpenFile ( arg0 string , arg1 int , arg2 os . FileMode ) ( oswrapper . File , error ) { ret := m . ctrl . Call ( m , " " , arg0 , arg1 , arg2 ) ret0 , _ := ret [ 0 ] . ( oswrapper . File ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (m *MockOS) RemoveAll(arg0 string) error {
	ret := m.ctrl.Call(m, "RemoveAll", arg0)
	ret0, _ := ret[0].(error)
	return ret0
}

func ( m * MockOS ) RemoveAll ( arg0 string ) error { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( error ) return ret0 }


func NewMockSSMClientCreator(ctrl *gomock.Controller) *MockSSMClientCreator {
	mock := &MockSSMClientCreator{ctrl: ctrl}
	mock.recorder = &MockSSMClientCreatorMockRecorder{mock}
	return mock
}

func NewMockSSMClientCreator ( ctrl * gomock . Controller ) * MockSSMClientCreator { mock := & MockSSMClientCreator { ctrl : ctrl } mock . recorder = & MockSSMClientCreatorMockRecorder { mock } return mock }

// NewMockSSMClientCreator creates a new mock instance


func (m *MockSSMClientCreator) NewSSMClient(arg0 string, arg1 credentials.IAMRoleCredentials) ssm.SSMClient {
	ret := m.ctrl.Call(m, "NewSSMClient", arg0, arg1)
	ret0, _ := ret[0].(ssm.SSMClient)
	return ret0
}

func ( m * MockSSMClientCreator ) NewSSMClient ( arg0 string , arg1 credentials . IAMRoleCredentials ) ssm . SSMClient { ret := m . ctrl . Call ( m , " " , arg0 , arg1 ) ret0 , _ := ret [ 0 ] . ( ssm . SSMClient ) return ret0 }


func (mr *MockSSMClientCreatorMockRecorder) NewSSMClient(arg0, arg1 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewSSMClient", reflect.TypeOf((*MockSSMClientCreator)(nil).NewSSMClient), arg0, arg1)
}

func ( mr * MockSSMClientCreatorMockRecorder ) NewSSMClient ( arg0 , arg1 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockSSMClientCreator ) ( nil ) . NewSSMClient ) , arg0 , arg1 ) }

// NewSSMClient indicates an expected call of NewSSMClient


func NewMockEC2MetadataClient(ctrl *gomock.Controller) *MockEC2MetadataClient {
	mock := &MockEC2MetadataClient{ctrl: ctrl}
	mock.recorder = &MockEC2MetadataClientMockRecorder{mock}
	return mock
}

func NewMockEC2MetadataClient ( ctrl * gomock . Controller ) * MockEC2MetadataClient { mock := & MockEC2MetadataClient { ctrl : ctrl } mock . recorder = & MockEC2MetadataClientMockRecorder { mock } return mock }

// NewMockEC2MetadataClient creates a new mock instance


func (m *MockEC2MetadataClient) DefaultCredentials() (*ec2.RoleCredentials, error) {
	ret := m.ctrl.Call(m, "DefaultCredentials")
	ret0, _ := ret[0].(*ec2.RoleCredentials)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockEC2MetadataClient ) DefaultCredentials ( ) ( * ec2 . RoleCredentials , error ) { ret := m . ctrl . Call ( m , " " ) ret0 , _ := ret [ 0 ] . ( * ec2 . RoleCredentials ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (mr *MockEC2MetadataClientMockRecorder) DefaultCredentials() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultCredentials", reflect.TypeOf((*MockEC2MetadataClient)(nil).DefaultCredentials))
}

func ( mr * MockEC2MetadataClientMockRecorder ) DefaultCredentials ( ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockEC2MetadataClient ) ( nil ) . DefaultCredentials ) ) }

// DefaultCredentials indicates an expected call of DefaultCredentials


func (m *MockEC2MetadataClient) GetDynamicData(arg0 string) (string, error) {
	ret := m.ctrl.Call(m, "GetDynamicData", arg0)
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockEC2MetadataClient ) GetDynamicData ( arg0 string ) ( string , error ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( string ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (m *MockEC2MetadataClient) InstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) {
	ret := m.ctrl.Call(m, "InstanceIdentityDocument")
	ret0, _ := ret[0].(ec2metadata.EC2InstanceIdentityDocument)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockEC2MetadataClient ) InstanceIdentityDocument ( ) ( ec2metadata . EC2InstanceIdentityDocument , error ) { ret := m . ctrl . Call ( m , " " ) ret0 , _ := ret [ 0 ] . ( ec2metadata . EC2InstanceIdentityDocument ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }

// InstanceIdentityDocument mocks base method


func NewMockHttpClient(ctrl *gomock.Controller) *MockHttpClient {
	mock := &MockHttpClient{ctrl: ctrl}
	mock.recorder = &MockHttpClientMockRecorder{mock}
	return mock
}

func NewMockHttpClient ( ctrl * gomock . Controller ) * MockHttpClient { mock := & MockHttpClient { ctrl : ctrl } mock . recorder = & MockHttpClientMockRecorder { mock } return mock }

// NewMockHttpClient creates a new mock instance


func (m *MockHttpClient) GetInstanceIdentityDocument() (ec2metadata.EC2InstanceIdentityDocument, error) {
	ret := m.ctrl.Call(m, "GetInstanceIdentityDocument")
	ret0, _ := ret[0].(ec2metadata.EC2InstanceIdentityDocument)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockHttpClient ) GetInstanceIdentityDocument ( ) ( ec2metadata . EC2InstanceIdentityDocument , error ) { ret := m . ctrl . Call ( m , " " ) ret0 , _ := ret [ 0 ] . ( ec2metadata . EC2InstanceIdentityDocument ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }

// GetInstanceIdentityDocument mocks base method


func (m *MockHttpClient) GetUserData() (string, error) {
	ret := m.ctrl.Call(m, "GetUserData")
	ret0, _ := ret[0].(string)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockHttpClient ) GetUserData ( ) ( string , error ) { ret := m . ctrl . Call ( m , " " ) ret0 , _ := ret [ 0 ] . ( string ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (mr *MockHttpClientMockRecorder) GetUserData() *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserData", reflect.TypeOf((*MockHttpClient)(nil).GetUserData))
}

func ( mr * MockHttpClientMockRecorder ) GetUserData ( ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockHttpClient ) ( nil ) . GetUserData ) ) }

// GetUserData indicates an expected call of GetUserData


func NewMockClient(ctrl *gomock.Controller) *MockClient {
	mock := &MockClient{ctrl: ctrl}
	mock.recorder = &MockClientMockRecorder{mock}
	return mock
}

func NewMockClient ( ctrl * gomock . Controller ) * MockClient { mock := & MockClient { ctrl : ctrl } mock . recorder = & MockClientMockRecorder { mock } return mock }

// NewMockClient creates a new mock instance


func (m *MockClient) DescribeECSTagsForInstance(arg0 string) ([]*ecs.Tag, error) {
	ret := m.ctrl.Call(m, "DescribeECSTagsForInstance", arg0)
	ret0, _ := ret[0].([]*ecs.Tag)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockClient ) DescribeECSTagsForInstance ( arg0 string ) ( [ ] * ecs . Tag , error ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( [ ] * ecs . Tag ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }

// DescribeECSTagsForInstance mocks base method


func NewMockClientSDK(ctrl *gomock.Controller) *MockClientSDK {
	mock := &MockClientSDK{ctrl: ctrl}
	mock.recorder = &MockClientSDKMockRecorder{mock}
	return mock
}

func NewMockClientSDK ( ctrl * gomock . Controller ) * MockClientSDK { mock := & MockClientSDK { ctrl : ctrl } mock . recorder = & MockClientSDKMockRecorder { mock } return mock }

// NewMockClientSDK creates a new mock instance


func (m *MockClientSDK) CreateTags(arg0 *ec20.CreateTagsInput) (*ec20.CreateTagsOutput, error) {
	ret := m.ctrl.Call(m, "CreateTags", arg0)
	ret0, _ := ret[0].(*ec20.CreateTagsOutput)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockClientSDK ) CreateTags ( arg0 * ec20 . CreateTagsInput ) ( * ec20 . CreateTagsOutput , error ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( * ec20 . CreateTagsOutput ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (m *MockClientSDK) DescribeTags(arg0 *ec20.DescribeTagsInput) (*ec20.DescribeTagsOutput, error) {
	ret := m.ctrl.Call(m, "DescribeTags", arg0)
	ret0, _ := ret[0].(*ec20.DescribeTagsOutput)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func ( m * MockClientSDK ) DescribeTags ( arg0 * ec20 . DescribeTagsInput ) ( * ec20 . DescribeTagsOutput , error ) { ret := m . ctrl . Call ( m , " " , arg0 ) ret0 , _ := ret [ 0 ] . ( * ec20 . DescribeTagsOutput ) ret1 , _ := ret [ 1 ] . ( error ) return ret0 , ret1 }


func (mr *MockClientSDKMockRecorder) DescribeTags(arg0 interface{}) *gomock.Call {
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTags", reflect.TypeOf((*MockClientSDK)(nil).DescribeTags), arg0)
}

func ( mr * MockClientSDKMockRecorder ) DescribeTags ( arg0 interface { } ) * gomock . Call { return mr . mock . ctrl . RecordCallWithMethodType ( mr . mock , " " , reflect . TypeOf ( ( * MockClientSDK ) ( nil ) . DescribeTags ) , arg0 ) }

// DescribeTags indicates an expected call of DescribeTags


func NewStateManager(cfg *config.Config, options ...Option) (StateManager, error) {
	fi, err := os.Stat(cfg.DataDir)
	if err != nil {
		return nil, err
	}
	if !fi.IsDir() {
		return nil, errors.New("State manager DataDir must exist")
	}

	state := &state{
		Data:    make(saveableState),
		Version: ECSDataVersion,
	}
	manager := &basicStateManager{
		statePath: cfg.DataDir,
		state:     state,
	}

	for _, option := range options {
		option(manager)
	}

	manager.platformDependencies = newPlatformDependencies()

	return manager, nil
}

func NewStateManager ( cfg * config . Config , options ... Option ) ( StateManager , error ) { fi , err := os . Stat ( cfg . DataDir ) if err != nil { return nil , err } if ! fi . IsDir ( ) { return nil , errors . New ( " " ) } state := & state { Data : make ( saveableState ) , Version : ECSDataVersion , } manager := & basicStateManager { statePath : cfg . DataDir , state : state , } for _ , option := range options { option ( manager ) } manager . platformDependencies = newPlatformDependencies ( ) return manager , nil }

// NewStateManager constructs a new StateManager which saves data at the
// location specified in cfg and operates under the given options.
// The returned StateManager will not save more often than every 10 seconds and
// will not reliably return errors with Save, but will log them appropriately.

NewStateManager constructs a new StateManager which saves data at the location specified in cfg and operates under the given options . The returned StateManager will not save more often than every 10 seconds and will not reliably return errors with Save but will log them appropriately .


func (manager *basicStateManager) Save() error {
	defer metrics.MetricsEngineGlobal.RecordStateManagerMetric("SAVE")()
	manager.saveTimesLock.Lock()
	defer manager.saveTimesLock.Unlock()
	if time.Since(manager.lastSave) >= minSaveInterval {
		// we can just save
		err := manager.ForceSave()
		manager.lastSave = time.Now()
		manager.nextPlannedSave = time.Time{} // re-zero it; assume all pending desires to save are fulfilled
		return err
	} else if manager.nextPlannedSave.IsZero() {
		// No save planned yet, we should plan one.
		next := manager.lastSave.Add(minSaveInterval)
		manager.nextPlannedSave = next
		go func() {
			time.Sleep(next.Sub(time.Now()))
			manager.Save()
		}()
	}
	// else nextPlannedSave wasn't Zero so there's a save planned elsewhere that'll
	// fulfill this
	return nil
}

// Save triggers a save to file, though respects a minimum save interval to wait
// between saves.

Save triggers a save to file though respects a minimum save interval to wait between saves .


func (manager *basicStateManager) Load() error {
	s := manager.state
	log.Info("Loading state!")
	data, err := manager.readFile()
	if err != nil {
		log.Error("Error reading existing state file", "err", err)
		return err
	}
	if data == nil {
		return nil
	}
	// Dry-run to make sure this is a version we can understand
	err = manager.dryRun(data)
	if err != nil {
		return err
	}
	// Now load it into the actual state. The reason we do this with the
	// intermediate state is that we *must* unmarshal directly into the
	// "saveable" pointers we were given in AddSaveable; if we unmarshal
	// directly into a map with values of pointers, those pointers are lost.
	// We *must* unmarshal this way because the existing pointers could have
	// semi-initialized data (and are actually expected to)

	var intermediate intermediateState
	err = json.Unmarshal(data, &intermediate)
	if err != nil {
		log.Debug("Could not unmarshal into intermediate")
		return err
	}

	for key, rawJSON := range intermediate.Data {
		actualPointer, ok := manager.state.Data[key]
		if !ok {
			log.Error("Loading state: potentially malformed json key of " + key)
			continue
		}
		err = json.Unmarshal(rawJSON, actualPointer)
		if err != nil {
			log.Debug("Could not unmarshal into actual")
			return err
		}
	}

	log.Debug("Loaded state!", "state", s)
	return nil
}

// Load reads state off the disk from the well-known filepath and loads it into
// the passed State object.

Load reads state off the disk from the well - known filepath and loads it into the passed State object .


func ValidDependencies(task *apitask.Task) bool {
	unresolved := make([]*apicontainer.Container, len(task.Containers))
	resolved := make([]*apicontainer.Container, 0, len(task.Containers))

	copy(unresolved, task.Containers)

OuterLoop:
	for len(unresolved) > 0 {
		for i, tryResolve := range unresolved {
			if dependenciesCanBeResolved(tryResolve, resolved) {
				resolved = append(resolved, tryResolve)
				unresolved = append(unresolved[:i], unresolved[i+1:]...)
				// Break out of the inner loop now that we modified the slice
				// we're looping over
				continue OuterLoop
			}
		}
		log.Warnf("Could not resolve some containers: [%v] for task %v", unresolved, task)
		return false
	}

	return true
}

// ValidDependencies takes a task and verifies that it is possible to allow all
// containers within it to reach the desired status by proceeding in some
// order.

ValidDependencies takes a task and verifies that it is possible to allow all containers within it to reach the desired status by proceeding in some order .


func dependenciesCanBeResolved(target *apicontainer.Container, by []*apicontainer.Container) bool {
	nameMap := make(map[string]*apicontainer.Container)
	for _, cont := range by {
		nameMap[cont.Name] = cont
	}

	if _, err := verifyContainerOrderingStatusResolvable(target, nameMap, containerOrderingDependenciesCanResolve); err != nil {
		return false
	}
	return verifyStatusResolvable(target, nameMap, target.SteadyStateDependencies, onSteadyStateCanResolve)
}

func dependenciesCanBeResolved ( target * apicontainer . Container , by [ ] * apicontainer . Container ) bool { nameMap := make ( map [ string ] * apicontainer . Container ) for _ , cont := range by { nameMap [ cont . Name ] = cont } if _ , err := verifyContainerOrderingStatusResolvable ( target , nameMap , containerOrderingDependenciesCanResolve ) ; err != nil { return false } return verifyStatusResolvable ( target , nameMap , target . SteadyStateDependencies , onSteadyStateCanResolve ) }

// DependenciesCanBeResolved verifies that it's possible to transition a `target`
// given a group of already handled containers, `by`. Essentially, it asks "is
// `target` resolved by `by`". It assumes that everything in `by` has reached
// DesiredStatus and that `target` is also trying to get there
//
// This function is used for verifying that a state should be resolvable, not
// for actually deciding what to do. `DependenciesAreResolved` should be used for
// that purpose instead.

DependenciesCanBeResolved verifies that it s possible to transition a target given a group of already handled containers by . Essentially it asks is target resolved by by . It assumes that everything in by has reached DesiredStatus and that target is also trying to get there This function is used for verifying that a state should be resolvable not for actually deciding what to do . DependenciesAreResolved should be used for that purpose instead .


func onSteadyStateIsResolved(target *apicontainer.Container, run *apicontainer.Container) bool {
	return target.GetDesiredStatus() >= apicontainerstatus.ContainerCreated &&
		run.GetKnownStatus() >= run.GetSteadyStateStatus()
}

func onSteadyStateIsResolved ( target * apicontainer . Container , run * apicontainer . Container ) bool { return target . GetDesiredStatus ( ) >= apicontainerstatus . ContainerCreated && run . GetKnownStatus ( ) >= run . GetSteadyStateStatus ( ) }

// onSteadyStateIsResolved defines a relationship where a target cannot be
// created until 'dependency' has reached the steady state. Transitions include pulling.

onSteadyStateIsResolved defines a relationship where a target cannot be created until dependency has reached the steady state . Transitions include pulling .


func newAgent(
	ctx context.Context,
	blackholeEC2Metadata bool,
	acceptInsecureCert *bool) (agent, error) {

	ec2MetadataClient := ec2.NewEC2MetadataClient(nil)
	if blackholeEC2Metadata {
		ec2MetadataClient = ec2.NewBlackholeEC2MetadataClient()
	}

	seelog.Info("Loading configuration")
	cfg, err := config.NewConfig(ec2MetadataClient)
	if err != nil {
		// All required config values can be inferred from EC2 Metadata,
		// so this error could be transient.
		seelog.Criticalf("Error loading config: %v", err)
		return nil, err
	}
	cfg.AcceptInsecureCert = aws.BoolValue(acceptInsecureCert)
	if cfg.AcceptInsecureCert {
		seelog.Warn("SSL certificate verification disabled. This is not recommended.")
	}
	seelog.Infof("Amazon ECS agent Version: %s, Commit: %s", version.Version, version.GitShortHash)
	seelog.Debugf("Loaded config: %s", cfg.String())

	ec2Client := ec2.NewClientImpl(cfg.AWSRegion)
	dockerClient, err := dockerapi.NewDockerGoClient(sdkclientfactory.NewFactory(ctx, cfg.DockerEndpoint), cfg, ctx)

	if err != nil {
		// This is also non terminal in the current config
		seelog.Criticalf("Error creating Docker client: %v", err)
		return nil, err
	}

	var metadataManager containermetadata.Manager
	if cfg.ContainerMetadataEnabled {
		// We use the default API client for the metadata inspect call. This version has some information
		// missing which means if we need those fields later we will need to change this client to
		// the appropriate version
		metadataManager = containermetadata.NewManager(dockerClient, cfg)
	}

	return &ecsAgent{
		ctx:               ctx,
		ec2MetadataClient: ec2MetadataClient,
		ec2Client:         ec2Client,
		cfg:               cfg,
		dockerClient:      dockerClient,
		// We instantiate our own credentialProvider for use in acs/tcs. This tries
		// to mimic roughly the way it's instantiated by the SDK for a default
		// session.
		credentialProvider:    defaults.CredChain(defaults.Config(), defaults.Handlers()),
		stateManagerFactory:   factory.NewStateManager(),
		saveableOptionFactory: factory.NewSaveableOption(),
		pauseLoader:           pause.New(),
		cniClient: ecscni.NewClient(&ecscni.Config{
			PluginsPath:            cfg.CNIPluginsPath,
			MinSupportedCNIVersion: config.DefaultMinSupportedCNIVersion,
		}),
		os:                 oswrapper.New(),
		metadataManager:    metadataManager,
		terminationHandler: sighandlers.StartDefaultTerminationHandler,
		mobyPlugins:        mobypkgwrapper.NewPlugins(),
	}, nil
}

// newAgent returns a new ecsAgent object, but does not start anything

newAgent returns a new ecsAgent object but does not start anything


func (agent *ecsAgent) printECSAttributes() int {
	capabilities, err := agent.capabilities()
	if err != nil {
		seelog.Warnf("Unable to obtain capabilities: %v", err)
		return exitcodes.ExitError
	}
	for _, attr := range capabilities {
		fmt.Printf("%s\t%s\n", aws.StringValue(attr.Name), aws.StringValue(attr.Value))
	}
	return exitcodes.ExitSuccess
}

func ( agent * ecsAgent ) printECSAttributes ( ) int { capabilities , err := agent . capabilities ( ) if err != nil { seelog . Warnf ( " " , err ) return exitcodes . ExitError } for _ , attr := range capabilities { fmt . Printf ( " \t \n " , aws . StringValue ( attr . Name ) , aws . StringValue ( attr . Value ) ) } return exitcodes . ExitSuccess }

// printECSAttributes prints the Agent's ECS Attributes based on its
// environment

printECSAttributes prints the Agent s ECS Attributes based on its environment


func (agent *ecsAgent) start() int {
	sighandlers.StartDebugHandler()

	containerChangeEventStream := eventstream.NewEventStream(containerChangeEventStreamName, agent.ctx)
	credentialsManager := credentials.NewManager()
	state := dockerstate.NewTaskEngineState()
	imageManager := engine.NewImageManager(agent.cfg, agent.dockerClient, state)
	client := ecsclient.NewECSClient(agent.credentialProvider, agent.cfg, agent.ec2MetadataClient)

	agent.initializeResourceFields(credentialsManager)
	return agent.doStart(containerChangeEventStream, credentialsManager, state, imageManager, client)
}

func ( agent * ecsAgent ) start ( ) int { sighandlers . StartDebugHandler ( ) containerChangeEventStream := eventstream . NewEventStream ( containerChangeEventStreamName , agent . ctx ) credentialsManager := credentials . NewManager ( ) state := dockerstate . NewTaskEngineState ( ) imageManager := engine . NewImageManager ( agent . cfg , agent . dockerClient , state ) client := ecsclient . NewECSClient ( agent . credentialProvider , agent . cfg , agent . ec2MetadataClient ) agent . initializeResourceFields ( credentialsManager ) return agent . doStart ( containerChangeEventStream , credentialsManager , state , imageManager , client ) }