//go:build windows // +build windows // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package ecscni import ( "context" "os" "path/filepath" "strings" "sync" "time" "github.com/cihub/seelog" "github.com/containernetworking/cni/libcni" cniTypes "github.com/containernetworking/cni/pkg/types" cniTypesCurrent "github.com/containernetworking/cni/pkg/types/100" "github.com/pkg/errors" "github.com/aws/amazon-ecs-agent/agent/utils" "github.com/aws/amazon-ecs-agent/ecs-agent/utils/retry" ) var ( // vpcCNIPluginPath is the path of the cni plugin's log file. // The default value of log file is C:\ProgramData\Amazon\ECS\log\cni\vpc-eni.log vpcCNIPluginPath = filepath.Join(utils.DefaultIfBlank(os.Getenv("ProgramData"), `C:\ProgramData`), `Amazon\ECS\log\cni\vpc-eni.log`) ) // newCNIGuard returns a new instance of CNI guard for the CNI client. func newCNIGuard() cniGuard { return &guard{ mutex: &sync.Mutex{}, } } // setupNS is the called by SetupNS to setup the task namespace by invoking ADD for given CNI configurations. // For Windows, we will retry the setup before conceding error. func (client *cniClient) setupNS(ctx context.Context, cfg *Config) (*cniTypesCurrent.Result, error) { var result *cniTypesCurrent.Result var err error backoff := retry.NewExponentialBackoff(setupNSBackoffMin, setupNSBackoffMax, setupNSBackoffJitter, setupNSBackoffMultiple) for count := 0; count < setupNSMaxRetryCount; count++ { result, err = client.doSetupNS(ctx, cfg) if err == nil { return result, nil } if count < setupNSMaxRetryCount-1 { time.Sleep(backoff.Duration()) } seelog.Errorf("[ECSCNI] Namespace setup failed due to error: %v. Retry count is %d.", err, count) } return nil, err } // doSetupNS invokes the CNI plugins to setup the task network namespace. func (client *cniClient) doSetupNS(ctx context.Context, cfg *Config) (*cniTypesCurrent.Result, error) { seelog.Debugf("[ECSCNI] Setting up the container namespace %s", cfg.ContainerID) var ecsBridgeResult cniTypes.Result runtimeConfig := libcni.RuntimeConf{ ContainerID: cfg.ContainerID, NetNS: cfg.ContainerNetNS, } // Execute all CNI network configurations serially, in the given order. for _, networkConfig := range cfg.NetworkConfigs { cniNetworkConfig := networkConfig.CNINetworkConfig seelog.Debugf("[ECSCNI] Adding network %s type %s in the container namespace %s", cniNetworkConfig.Network.Name, cniNetworkConfig.Network.Type, cfg.ContainerID) runtimeConfig.IfName = networkConfig.IfName result, err := client.libcni.AddNetwork(ctx, cniNetworkConfig, &runtimeConfig) if err != nil { return nil, errors.Wrap(err, "add network failed") } // We save the result from ecs-bridge setup invocation of the plugin. if strings.EqualFold(ECSBridgeNetworkName, cniNetworkConfig.Network.Name) && cniNetworkConfig.Network.Type == ECSVPCENIPluginExecutable { ecsBridgeResult = result } seelog.Debugf("[ECSCNI] Completed adding network %s type %s in the container namespace %s", cniNetworkConfig.Network.Name, cniNetworkConfig.Network.Type, cfg.ContainerID) } seelog.Debugf("[ECSCNI] Completed setting up the container namespace: %s", cfg.ContainerID) return cniTypesCurrent.GetResult(ecsBridgeResult) } // ReleaseIPResource marks the ip available in the ipam db // This method is not required in Windows. HNS takes care of IP management. func (client *cniClient) ReleaseIPResource(ctx context.Context, cfg *Config, timeout time.Duration) error { return nil } // Version is the version number of the repository. // GitShortHash is the short hash of the Git HEAD. // Built is the build time stamp. type cniPluginVersion struct { Version string `json:"version"` GitShortHash string `json:"gitShortHash"` Built string `json:"built"` } // str generates a string version of the CNI plugin version func (version *cniPluginVersion) str() string { return version.GitShortHash + "-" + version.Version }