func getParams(key string, taskInfo *mesos.TaskInfo) (params []mesos.Parameter) {
	for _, param := range taskInfo.Container.Docker.Parameters {
		if param.Key == "" || param.Key != key {
			continue
		}
		params = append(params, param)
	}
	return params
}
getParams fetches items by key from the Docker.Parameters slice
package container
import (
	"encoding/json"
	"fmt"
	"io"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	retry "github.com/avast/retry-go"
	docker "github.com/fsouza/go-dockerclient"
	mesos "github.com/mesos/mesos-go/api/v1/lib"
	"github.com/pborman/uuid"
	log "github.com/sirupsen/logrus"
)
const (
	PullImageNumRetries = 5
	defaultCpuPeriod = 50000  
)
var portProtocolsTokenizer = regexp.MustCompile(`,\s?`)
type DockerClient interface {
	CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error)
	InspectContainer(id string) (*docker.Container, error)
	ListContainers(opts docker.ListContainersOptions) ([]docker.APIContainers, error)
	ListImages(docker.ListImagesOptions) ([]docker.APIImages, error)
	Logs(opts docker.LogsOptions) error
	PullImage(docker.PullImageOptions, docker.AuthConfiguration) error
	StartContainer(id string, hostConfig *docker.HostConfig) error
	StopContainer(id string, timeout uint) error
}
func CheckImage(client DockerClient, taskInfo *mesos.TaskInfo) bool {
	images, err := client.ListImages(docker.ListImagesOptions{All: false})
	if err != nil {
		log.Errorf("Failure to list Docker images: %s", err.Error())
		return false
	}
	for _, img := range images {
		for _, tag := range img.RepoTags {
			if tag == taskInfo.Container.Docker.Image {
				return true
			}
		}
	}
	return false
}
func StopContainer(client DockerClient, containerId string, timeout uint) error {
	_ = client.StopContainer(containerId, timeout)
	cntr, err := client.InspectContainer(containerId)
	if err != nil {
		return err
	}
	if cntr.State.Status == "exited" {
		return nil  
	}
	err = client.StopContainer(containerId, timeout)
	if err != nil {
		return err
	}
	if cntr.State.Status != "exited" {
		return fmt.Errorf("Unable to kill container! %s", containerId)
	}
	return nil
}
func PullImage(client DockerClient, taskInfo *mesos.TaskInfo, authConfig *docker.AuthConfiguration) error {
	log.Infof("Pulling Docker image '%s'", taskInfo.Container.Docker.Image)
	var numRetries int
	err := retry.Do(func() error {
		numRetries = numRetries + 1
		err := client.PullImage(
			docker.PullImageOptions{
				Repository: taskInfo.Container.Docker.Image,
			},
			*authConfig,
		)
		if err != nil {
			log.Warnf("Pull failed (retry %d/%d): %s", numRetries, PullImageNumRetries, err)
			return err
		}
		log.Info("Pulled.")
		return nil
	},
		retry.Attempts(PullImageNumRetries),
	)
	return err
}
func GetLogs(client DockerClient, containerId string, since int64, stdout io.Writer, stderr io.Writer) {
	go func() {
		err := client.Logs(docker.LogsOptions{
			Container:    containerId,
			OutputStream: stdout,
			ErrorStream:  stderr,
			Since:        since,
			Stdout:       true,
			Stderr:       true,
		})
		if err != nil {
			log.Errorf("Failed to fetch logs for task: %s", err.Error())
		}
	}()
}
func FollowLogs(client DockerClient, containerId string, since int64, stdout io.Writer, stderr io.Writer) {
	go func() {
		err := client.Logs(docker.LogsOptions{
			Container:    containerId,
			OutputStream: stdout,
			ErrorStream:  stderr,
			Since:        since,
			Stdout:       true,
			Stderr:       true,
			Follow:       true,
		})
		if err != nil {
			log.Errorf("Failed to fetch logs for task: %s", err.Error())
		}
	}()
}
func ConfigForTask(taskInfo *mesos.TaskInfo, forceCpuLimit bool, forceMemoryLimit bool, useCpuShares bool, envVars []string) *docker.CreateContainerOptions {
	labels := LabelsForTask(taskInfo)
	var command []string
	if _, ok := labels["executor.ShellCommand"]; ok {
		command = strings.Split(labels["executor.ShellCommand"], " ")
		delete(labels, "executor.ShellCommand")
	}
	log.Infof("Launching task %s with command '%s'", taskInfo.GetName(), command)
	config := &docker.CreateContainerOptions{
		Name: GetContainerName(&taskInfo.TaskID),
		Config: &docker.Config{
			Env:          EnvForTask(taskInfo, labels, envVars),
			ExposedPorts: PortsForTask(taskInfo),
			Image:        taskInfo.Container.Docker.Image,
			Labels:       labels,
			Cmd:          command,
		},
		HostConfig: &docker.HostConfig{
			Binds:        BindsForTask(taskInfo),
			PortBindings: PortBindingsForTask(taskInfo),
			NetworkMode:  NetworkForTask(taskInfo),
			CapAdd:       CapAddForTask(taskInfo),
			CapDrop:      CapDropForTask(taskInfo),
			VolumeDriver: VolumeDriverForTask(taskInfo),
		},
	}
	setCpuLimit(config, taskInfo, forceCpuLimit, useCpuShares)
	memory := getResource("mem", taskInfo)
	if memory != nil && forceMemoryLimit {
		memoryLimit := int64(memory.Scalar.Value * float64(1024*1024))
		log.Infof("Memory limit set to %.0fMB [HostConfig.Memory=%d] ", memory.Scalar.Value, memoryLimit)
		config.HostConfig.Memory = int64(memoryLimit)
	}
	jsonTaskInfo, _ := json.Marshal(*taskInfo)
	log.Debugf("Mesos TaskInfo: %s", jsonTaskInfo)
	jsonConfig, _ := json.Marshal(config)
	log.Debugf("Final config: %s", jsonConfig)
	return config
}
func setCpuLimit(config *docker.CreateContainerOptions, taskInfo *mesos.TaskInfo, forceCpuLimit bool, useCpuShares bool) {
	cpus := getResource("cpus", taskInfo)
	if cpus == nil || !forceCpuLimit {
		return
	}
	if useCpuShares {
		multiplier := cpus.Scalar.Value / float64(runtime.NumCPU())
		if multiplier > 1.0 {
			log.Errorf("CPUShares enabled, but CPUs value is more than 100%%. Scaling down to 1.0")
			multiplier = 1.0
		}
		config.HostConfig.CPUShares = int64(1024 * multiplier)
		log.Infof("CPU Shares set [HostConfig.CPUShares=%d", config.HostConfig.CPUShares)
		return
	}
	config.HostConfig.CPUPeriod = defaultCpuPeriod
	config.HostConfig.CPUQuota = int64(cpus.Scalar.Value * float64(defaultCpuPeriod))
	log.Infof("CPU limit set [HostConfig.CPUQuota=%d, HostConfig.CPUPeriod=%d]  ", config.HostConfig.CPUQuota, defaultCpuPeriod)
}
func getPortProtocols(port mesos.ContainerInfo_DockerInfo_PortMapping) []string {
	matches := portProtocolsTokenizer.Split(port.GetProtocol(), -1)
	var protocols []string
	for _, protocol := range matches {
		if protocol == "" {
			return []string{"tcp"}
		}
		protocols = append(protocols, protocol)
	}
	return protocols
}
func PortsForTask(taskInfo *mesos.TaskInfo) map[docker.Port]struct{} {
	ports := make(map[docker.Port]struct{}, len(taskInfo.Container.Docker.PortMappings))
	for _, port := range taskInfo.Container.Docker.PortMappings {
		if port.ContainerPort == 0 {
			continue
		}
		for _, proto := range getPortProtocols(port) {
			portStr := docker.Port(strconv.Itoa(int(port.ContainerPort)) + "/" + proto)
			ports[portStr] = struct{}{}
		}
	}
	log.Debugf("Ports: %#v", ports)
	return ports
}