Use Podman and Docker CLI for Container tests instead of Docker API (#415)
Signed-off-by: Nicholas-Daffern <Nicholas.Daffern@ibm.com>
This commit is contained in:
committed by
GitHub Enterprise
parent
e14ffb261a
commit
33566bed16
669
test/container/containerengine/containerengine.go
Normal file
669
test/container/containerengine/containerengine.go
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017, 2023
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License 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 containerengine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ContainerInterface interface {
|
||||
ContainerCreate(config *ContainerConfig, hostConfig *ContainerHostConfig, networkingConfig *ContainerNetworkSettings, containerName string) (string, error)
|
||||
ContainerStop(container string, timeout *time.Duration) error
|
||||
ContainerKill(container string, signal string) error
|
||||
ContainerRemove(container string, options ContainerRemoveOptions) error
|
||||
ContainerStart(container string, options ContainerStartOptions) error
|
||||
ContainerWait(ctx context.Context, container string, condition string) (<-chan int64, <-chan error)
|
||||
GetContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (string, error)
|
||||
CopyFromContainer(container, srcPath string) ([]byte, error)
|
||||
|
||||
GetContainerPort(ID string, hostPort int) (string, error)
|
||||
GetContainerIPAddress(ID string) (string, error)
|
||||
ContainerInspectWithFormat(format string, ID string) (string, error)
|
||||
ExecContainer(ID string, user string, cmd []string) (int, string)
|
||||
GetMQVersion(image string) (string, error)
|
||||
ContainerInspect(containerID string) (ContainerDetails, error)
|
||||
|
||||
NetworkCreate(name string, options NetworkCreateOptions) (string, error)
|
||||
NetworkRemove(network string) error
|
||||
|
||||
VolumeCreate(options VolumeCreateOptions) (string, error)
|
||||
VolumeRemove(volumeID string, force bool) error
|
||||
|
||||
ImageBuild(context io.Reader, tag string, dockerfilename string) (string, error)
|
||||
ImageRemove(image string, options ImageRemoveOptions) (bool, error)
|
||||
ImageInspectWithFormat(format string, ID string) (string, error)
|
||||
}
|
||||
|
||||
type ContainerClient struct {
|
||||
ContainerTool string
|
||||
Version string
|
||||
}
|
||||
|
||||
// objects
|
||||
var objVolume = "volume"
|
||||
var objImage = "image"
|
||||
var objPort = "port"
|
||||
var objNetwork = "network"
|
||||
|
||||
// verbs
|
||||
var listContainers = "ps"
|
||||
var listImages = "images"
|
||||
var create = "create"
|
||||
var startContainer = "start"
|
||||
var waitContainer = "wait"
|
||||
var execContainer = "exec"
|
||||
var getLogs = "logs"
|
||||
var stopContainer = "stop"
|
||||
var remove = "rm"
|
||||
var inspect = "inspect"
|
||||
var copyFile = "cp"
|
||||
var build = "build"
|
||||
var killContainer = "kill"
|
||||
|
||||
// args
|
||||
var argEntrypoint = "--entrypoint"
|
||||
var argUser = "--user"
|
||||
var argExpose = "--expose"
|
||||
var argVolume = "--volume"
|
||||
var argPublish = "--publish"
|
||||
var argPrivileged = "--privileged"
|
||||
var argAddCapability = "--cap-add"
|
||||
var argDropCapability = "--cap-drop"
|
||||
var argName = "--name"
|
||||
var argCondition = "--condition"
|
||||
var argEnvironmentVariable = "--env"
|
||||
var argTail = "--tail"
|
||||
var argForce = "--force"
|
||||
var argVolumes = "--volumes"
|
||||
var argHostname = "--hostname"
|
||||
var argDriver = "--driver"
|
||||
var argFile = "--file"
|
||||
var argQuiet = "--quiet"
|
||||
var argTag = "--tag"
|
||||
var argFormat = "--format"
|
||||
var argNetwork = "--network"
|
||||
var argSecurityOptions = "--security-opt"
|
||||
var argSignal = "--signal"
|
||||
|
||||
// generic
|
||||
var toolVersion = "version"
|
||||
var ContainerStateNotRunning = "not-running"
|
||||
var ContainerStateStopped = "stopped"
|
||||
|
||||
type ContainerConfig struct {
|
||||
Image string
|
||||
Hostname string
|
||||
User string
|
||||
Entrypoint []string
|
||||
Env []string
|
||||
ExposedPorts []string
|
||||
}
|
||||
|
||||
type ContainerDetails struct {
|
||||
ID string
|
||||
Name string
|
||||
Image string
|
||||
Path string
|
||||
Args []string
|
||||
Config ContainerConfig
|
||||
HostConfig ContainerHostConfig
|
||||
}
|
||||
|
||||
type ContainerDetailsLogging struct {
|
||||
ID string
|
||||
Name string
|
||||
Image string
|
||||
Path string
|
||||
Args []string
|
||||
CapAdd []string
|
||||
CapDrop []string
|
||||
User string
|
||||
Env []string
|
||||
}
|
||||
|
||||
type ContainerHostConfig struct {
|
||||
Binds []string // Bindings onto a volume
|
||||
PortBindings []PortBinding //Bindings from a container port to a port on the host
|
||||
Privileged bool // Give extended privileges to container
|
||||
CapAdd []string // Linux capabilities to add to the container
|
||||
CapDrop []string // Linux capabilities to drop from the container
|
||||
SecurityOpt []string
|
||||
}
|
||||
|
||||
type ContainerNetworkSettings struct {
|
||||
Networks []string // A list of networks to connect the container to
|
||||
}
|
||||
|
||||
type ContainerRemoveOptions struct {
|
||||
Force bool
|
||||
RemoveVolumes bool
|
||||
}
|
||||
|
||||
type ContainerStartOptions struct {
|
||||
}
|
||||
|
||||
type NetworkCreateOptions struct {
|
||||
}
|
||||
|
||||
type ContainerLogsOptions struct {
|
||||
}
|
||||
|
||||
type ImageRemoveOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
type VolumeCreateOptions struct {
|
||||
Name string
|
||||
Driver string
|
||||
}
|
||||
|
||||
// Binding from a container port to a port on the host
|
||||
type PortBinding struct {
|
||||
HostIP string
|
||||
HostPort string //Port to map to on the host
|
||||
ContainerPort string //Exposed port on the container
|
||||
}
|
||||
|
||||
// NewContainerClient returns a new container client
|
||||
// Defaults to using podman
|
||||
func NewContainerClient() ContainerClient {
|
||||
tool, set := os.LookupEnv("COMMAND")
|
||||
if !set {
|
||||
tool = "podman"
|
||||
}
|
||||
return ContainerClient{
|
||||
ContainerTool: tool,
|
||||
Version: GetContainerToolVersion(tool),
|
||||
}
|
||||
}
|
||||
|
||||
// GetContainerToolVersion returns the version of the container tool being used
|
||||
func GetContainerToolVersion(containerTool string) string {
|
||||
if containerTool == "docker" {
|
||||
args := []string{"version", "--format", "'{{.Client.Version}}'"}
|
||||
v, err := exec.Command("docker", args...).Output()
|
||||
if err != nil {
|
||||
return "0.0.0"
|
||||
}
|
||||
return string(v)
|
||||
} else if containerTool == "podman" {
|
||||
//Default to checking the version of podman
|
||||
args := []string{"version", "--format", "'{{.Version}}'"}
|
||||
v, err := exec.Command("podman", args...).Output()
|
||||
if err != nil {
|
||||
return "0.0.0"
|
||||
}
|
||||
return string(v)
|
||||
}
|
||||
return "0.0.0"
|
||||
}
|
||||
|
||||
// GetMQVersion returns the MQ version of a given container image
|
||||
func (cli ContainerClient) GetMQVersion(image string) (string, error) {
|
||||
v, err := cli.ImageInspectWithFormat("{{.Config.Labels.version}}", image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// ImageInspectWithFormat inspects an image with a given formatting string
|
||||
func (cli ContainerClient) ImageInspectWithFormat(format string, ID string) (string, error) {
|
||||
args := []string{
|
||||
objImage,
|
||||
inspect,
|
||||
ID,
|
||||
}
|
||||
if format != "" {
|
||||
args = append(args, []string{argFormat, format}...)
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// ContainerInspectWithFormat inspects a container with a given formatting string
|
||||
func (cli ContainerClient) ContainerInspectWithFormat(format string, ID string) (string, error) {
|
||||
args := []string{
|
||||
inspect,
|
||||
ID,
|
||||
}
|
||||
if format != "" {
|
||||
args = append(args, []string{argFormat, format}...)
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// GetContainerPort gets the ports on a container
|
||||
func (cli ContainerClient) GetContainerPort(ID string, hostPort int) (string, error) {
|
||||
args := []string{
|
||||
objPort,
|
||||
ID,
|
||||
strconv.Itoa(hostPort),
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
o := SanitizeString(string(output))
|
||||
return strings.Split((o), ":")[1], nil
|
||||
}
|
||||
|
||||
// GetContainerIPAddress gets the IP address of a container
|
||||
func (cli ContainerClient) GetContainerIPAddress(ID string) (string, error) {
|
||||
v, err := cli.ContainerInspectWithFormat("{{.NetworkSettings.IPAddress}}", ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// CopyFromContainer copies a file from a container and returns its contents
|
||||
func (cli ContainerClient) CopyFromContainer(container, srcPath string) ([]byte, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "tmp")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
args := []string{
|
||||
copyFile,
|
||||
container + ":" + srcPath,
|
||||
tmpDir + "/.",
|
||||
}
|
||||
_, err = exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//Get file name
|
||||
fname := filepath.Base(srcPath)
|
||||
data, err := os.ReadFile(filepath.Join(tmpDir, fname))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Remove the file
|
||||
err = os.Remove(filepath.Join(tmpDir, fname))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerInspect(containerID string) (ContainerDetails, error) {
|
||||
args := []string{
|
||||
inspect,
|
||||
containerID,
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return ContainerDetails{}, err
|
||||
}
|
||||
|
||||
var container ContainerDetails
|
||||
err = json.Unmarshal(output, &container)
|
||||
if err != nil {
|
||||
return ContainerDetails{}, err
|
||||
}
|
||||
return container, err
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerStop(container string, timeout *time.Duration) error {
|
||||
args := []string{
|
||||
stopContainer,
|
||||
container,
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerKill(container string, signal string) error {
|
||||
args := []string{
|
||||
killContainer,
|
||||
container,
|
||||
}
|
||||
if signal != "" {
|
||||
args = append(args, []string{argSignal, signal}...)
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerRemove(container string, options ContainerRemoveOptions) error {
|
||||
args := []string{
|
||||
remove,
|
||||
container,
|
||||
}
|
||||
if options.Force {
|
||||
args = append(args, argForce)
|
||||
}
|
||||
if options.RemoveVolumes {
|
||||
args = append(args, argVolumes)
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
//Silently error as the exit code 125 is present on sucessful deletion
|
||||
if strings.Contains(err.Error(), "125") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ExecContainer(ID string, user string, cmd []string) (int, string) {
|
||||
args := []string{
|
||||
execContainer,
|
||||
}
|
||||
if user != "" {
|
||||
args = append(args, []string{argUser, user}...)
|
||||
}
|
||||
args = append(args, ID)
|
||||
args = append(args, cmd...)
|
||||
ctx := context.Background()
|
||||
output, err := exec.CommandContext(ctx, cli.ContainerTool, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
if err.(*exec.ExitError) != nil {
|
||||
return err.(*exec.ExitError).ExitCode(), string(output)
|
||||
} else {
|
||||
return 9897, string(output)
|
||||
}
|
||||
}
|
||||
return 0, string(output)
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerStart(container string, options ContainerStartOptions) error {
|
||||
args := []string{
|
||||
startContainer,
|
||||
container,
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
// ContainerWait starts waiting for a container. It returns an int64 channel for receiving an exit code and an error channel for receiving errors.
|
||||
// The channels returned from this function should be used to receive the results from the wait command.
|
||||
func (cli ContainerClient) ContainerWait(ctx context.Context, container string, condition string) (<-chan int64, <-chan error) {
|
||||
args := []string{
|
||||
waitContainer,
|
||||
container,
|
||||
}
|
||||
if cli.ContainerTool == "podman" {
|
||||
if condition == ContainerStateNotRunning {
|
||||
condition = ContainerStateStopped
|
||||
}
|
||||
args = append(args, []string{argCondition, string(condition)}...)
|
||||
}
|
||||
|
||||
resultC := make(chan int64)
|
||||
errC := make(chan error, 1)
|
||||
|
||||
output, err := exec.CommandContext(ctx, cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return resultC, errC
|
||||
}
|
||||
|
||||
go func() {
|
||||
out := strings.TrimSuffix(string(output), "\n")
|
||||
exitCode, err := strconv.Atoi(out)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
resultC <- int64(exitCode)
|
||||
}()
|
||||
|
||||
return resultC, errC
|
||||
}
|
||||
|
||||
func (cli ContainerClient) GetContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (string, error) {
|
||||
args := []string{
|
||||
getLogs,
|
||||
container,
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) NetworkCreate(name string, options NetworkCreateOptions) (string, error) {
|
||||
args := []string{
|
||||
objNetwork,
|
||||
create,
|
||||
}
|
||||
netID, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
networkID := SanitizeString(string(netID))
|
||||
|
||||
return networkID, nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) NetworkRemove(network string) error {
|
||||
args := []string{
|
||||
objNetwork,
|
||||
remove,
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli ContainerClient) VolumeCreate(options VolumeCreateOptions) (string, error) {
|
||||
args := []string{
|
||||
objVolume,
|
||||
create,
|
||||
options.Name,
|
||||
}
|
||||
if options.Driver != "" {
|
||||
args = append(args, []string{argDriver, options.Driver}...)
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name := SanitizeString(string(output))
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) VolumeRemove(volumeID string, force bool) error {
|
||||
args := []string{
|
||||
objVolume,
|
||||
remove,
|
||||
volumeID,
|
||||
}
|
||||
if force {
|
||||
args = append(args, argForce)
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ImageBuild(context io.Reader, tag string, dockerfilename string) (string, error) {
|
||||
args := []string{
|
||||
objImage,
|
||||
build,
|
||||
}
|
||||
//dockerfilename includes the path to the dockerfile
|
||||
//When using podman use the full path including the name of the Dockerfile
|
||||
if cli.ContainerTool == "podman" {
|
||||
args = append(args, []string{argFile, dockerfilename}...)
|
||||
}
|
||||
if tag != "" {
|
||||
args = append(args, []string{argTag, tag}...)
|
||||
}
|
||||
args = append(args, argQuiet)
|
||||
//When using docker remove the name 'DockerFile' from the string
|
||||
if cli.ContainerTool == "docker" {
|
||||
dfn := strings.ReplaceAll(dockerfilename, "Dockerfile", "")
|
||||
args = append(args, dfn)
|
||||
}
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sha := SanitizeString(string(output))
|
||||
return sha, nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ImageRemove(image string, options ImageRemoveOptions) (bool, error) {
|
||||
args := []string{
|
||||
objImage,
|
||||
remove,
|
||||
image,
|
||||
}
|
||||
if options.Force {
|
||||
args = append(args, argForce)
|
||||
}
|
||||
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (cli ContainerClient) ContainerCreate(config *ContainerConfig, hostConfig *ContainerHostConfig, networkingConfig *ContainerNetworkSettings, containerName string) (string, error) {
|
||||
args := []string{
|
||||
create,
|
||||
argName,
|
||||
containerName,
|
||||
}
|
||||
args = getHostConfigArgs(args, hostConfig)
|
||||
args = getNetworkConfigArgs(args, networkingConfig)
|
||||
args = getContainerConfigArgs(args, config, cli.ContainerTool)
|
||||
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||
lines := strings.Split(strings.ReplaceAll(string(output), "\r\n", "\n"), "\n")
|
||||
if err != nil {
|
||||
return lines[0], err
|
||||
}
|
||||
return lines[0], nil
|
||||
}
|
||||
|
||||
// getContainerConfigArgs converts a ContainerConfig into a set of cli arguments
|
||||
func getContainerConfigArgs(args []string, config *ContainerConfig, toolName string) []string {
|
||||
argList := []string{}
|
||||
if config.Entrypoint != nil && toolName == "podman" {
|
||||
entrypoint := "[\""
|
||||
for i, commandPart := range config.Entrypoint {
|
||||
if i != len(config.Entrypoint)-1 {
|
||||
entrypoint += commandPart + "\",\""
|
||||
} else {
|
||||
//terminate list
|
||||
entrypoint += commandPart + "\"]"
|
||||
}
|
||||
}
|
||||
args = append(args, []string{argEntrypoint, entrypoint}...)
|
||||
}
|
||||
if config.Entrypoint != nil && toolName == "docker" {
|
||||
ep1 := ""
|
||||
for i, commandPart := range config.Entrypoint {
|
||||
if i == 0 {
|
||||
ep1 = commandPart
|
||||
} else {
|
||||
argList = append(argList, commandPart)
|
||||
}
|
||||
}
|
||||
args = append(args, []string{argEntrypoint, ep1}...)
|
||||
}
|
||||
if config.User != "" {
|
||||
args = append(args, []string{argUser, config.User}...)
|
||||
}
|
||||
if config.ExposedPorts != nil {
|
||||
for _, port := range config.ExposedPorts {
|
||||
args = append(args, []string{argExpose, port}...)
|
||||
}
|
||||
}
|
||||
if config.Hostname != "" {
|
||||
args = append(args, []string{argHostname, config.Hostname}...)
|
||||
}
|
||||
for _, env := range config.Env {
|
||||
args = append(args, []string{argEnvironmentVariable, env}...)
|
||||
}
|
||||
if config.Image != "" {
|
||||
args = append(args, config.Image)
|
||||
}
|
||||
if config.Entrypoint != nil && toolName == "docker" {
|
||||
args = append(args, argList...)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// getHostConfigArgs converts a ContainerHostConfig into a set of cli arguments
|
||||
func getHostConfigArgs(args []string, hostConfig *ContainerHostConfig) []string {
|
||||
if hostConfig.Binds != nil {
|
||||
for _, volume := range hostConfig.Binds {
|
||||
args = append(args, []string{argVolume, volume}...)
|
||||
}
|
||||
}
|
||||
if hostConfig.PortBindings != nil {
|
||||
for _, binding := range hostConfig.PortBindings {
|
||||
pub := binding.HostIP + ":" + binding.HostPort + ":" + binding.ContainerPort
|
||||
args = append(args, []string{argPublish, pub}...)
|
||||
}
|
||||
}
|
||||
if hostConfig.Privileged {
|
||||
args = append(args, []string{argPrivileged}...)
|
||||
}
|
||||
if hostConfig.CapAdd != nil {
|
||||
for _, capability := range hostConfig.CapAdd {
|
||||
args = append(args, []string{argAddCapability, string(capability)}...)
|
||||
}
|
||||
}
|
||||
if hostConfig.CapDrop != nil {
|
||||
for _, capability := range hostConfig.CapDrop {
|
||||
args = append(args, []string{argDropCapability, string(capability)}...)
|
||||
}
|
||||
}
|
||||
if hostConfig.SecurityOpt != nil {
|
||||
for _, securityOption := range hostConfig.SecurityOpt {
|
||||
args = append(args, []string{argSecurityOptions, string(securityOption)}...)
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// getNetworkConfigArgs converts a set of ContainerNetworkSettings into a set of cli arguments
|
||||
func getNetworkConfigArgs(args []string, networkingConfig *ContainerNetworkSettings) []string {
|
||||
if networkingConfig.Networks != nil {
|
||||
for _, netID := range networkingConfig.Networks {
|
||||
args = append(args, []string{argNetwork, netID}...)
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func SanitizeString(s string) string {
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
s = strings.Replace(s, "\t", "", -1)
|
||||
s = strings.Replace(s, "\n", "", -1)
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user