summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_create.go9
-rw-r--r--pkg/api/handlers/compat/images.go42
-rw-r--r--pkg/api/handlers/compat/networks.go8
-rw-r--r--pkg/api/handlers/libpod/pods.go6
-rw-r--r--pkg/api/server/register_images.go25
-rw-r--r--pkg/domain/entities/play.go2
-rw-r--r--pkg/domain/infra/abi/containers.go6
-rw-r--r--pkg/domain/infra/abi/network.go176
-rw-r--r--pkg/domain/infra/abi/play.go89
-rw-r--r--pkg/domain/infra/abi/play_test.go254
-rw-r--r--pkg/domain/infra/abi/pods.go6
-rw-r--r--pkg/network/config.go130
-rw-r--r--pkg/network/devices.go63
-rw-r--r--pkg/network/files.go174
-rw-r--r--pkg/network/ip.go19
-rw-r--r--pkg/network/netconflist.go155
-rw-r--r--pkg/network/netconflist_test.go38
-rw-r--r--pkg/network/network.go219
-rw-r--r--pkg/network/network_test.go35
-rw-r--r--pkg/network/subnet.go78
-rw-r--r--pkg/network/subnet_test.go35
-rw-r--r--pkg/parallel/ctr/ctr.go (renamed from pkg/parallel/parallel_linux.go)45
-rw-r--r--pkg/parallel/parallel.go30
-rw-r--r--pkg/varlinkapi/pods.go7
24 files changed, 479 insertions, 1172 deletions
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index a24dbaa47..4ce31cc83 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -14,8 +14,10 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/namespaces"
+ "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/signal"
createconfig "github.com/containers/podman/v2/pkg/spec"
+ "github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -134,6 +136,11 @@ func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input
Sysctl: input.HostConfig.Sysctls,
}
+ var netmode namespaces.NetworkMode
+ if rootless.IsRootless() {
+ netmode = namespaces.NetworkMode(specgen.Slirp)
+ }
+
network := createconfig.NetworkConfig{
DNSOpt: input.HostConfig.DNSOptions,
DNSSearch: input.HostConfig.DNSSearch,
@@ -144,7 +151,7 @@ func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input
IPAddress: "",
LinkLocalIP: nil, // docker-only
MacAddress: input.MacAddress,
- // NetMode: nil,
+ NetMode: netmode,
Network: input.HostConfig.NetworkMode.NetworkName(),
NetworkAlias: nil, // docker-only now
PortBindings: input.HostConfig.PortBindings,
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 9d8bc497a..f49ce59da 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -55,6 +55,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
return
}
+ defer os.Remove(tmpfile.Name())
if err := tmpfile.Close(); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
@@ -69,7 +70,6 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
return
}
defer rdr.Close()
- defer os.Remove(tmpfile.Name())
utils.WriteResponse(w, http.StatusOK, rdr)
}
@@ -398,3 +398,43 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
Stream: fmt.Sprintf("Loaded image: %s\n", id),
})
}
+
+func ExportImages(w http.ResponseWriter, r *http.Request) {
+ // 200 OK
+ // 500 Error
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ Names string `schema:"names"`
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ images := make([]string, 0)
+ images = append(images, strings.Split(query.Names, ",")...)
+ tmpfile, err := ioutil.TempFile("", "api.tar")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
+ return
+ }
+ defer os.Remove(tmpfile.Name())
+ if err := tmpfile.Close(); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
+ return
+ }
+ if err := runtime.ImageRuntime().SaveImages(r.Context(), images, "docker-archive", tmpfile.Name(), false); err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ rdr, err := os.Open(tmpfile.Name())
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile"))
+ return
+ }
+ defer rdr.Close()
+ utils.WriteResponse(w, http.StatusOK, rdr)
+}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index c5387b1e9..a46784a6c 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -12,10 +12,10 @@ import (
"github.com/containernetworking/cni/libcni"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
- "github.com/containers/podman/v2/pkg/network"
"github.com/docker/docker/api/types"
dockerNetwork "github.com/docker/docker/api/types/network"
"github.com/gorilla/schema"
@@ -210,6 +210,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
report, err := getNetworkResourceByName(name, runtime)
if err != nil {
utils.InternalServerError(w, err)
+ return
}
reports = append(reports, report)
}
@@ -267,9 +268,9 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
}
}
ce := abi.ContainerEngine{Libpod: runtime}
- _, err := ce.NetworkCreate(r.Context(), name, ncOptions)
- if err != nil {
+ if _, err := ce.NetworkCreate(r.Context(), name, ncOptions); err != nil {
utils.InternalServerError(w, err)
+ return
}
report := types.NetworkCreate{
CheckDuplicate: networkCreate.CheckDuplicate,
@@ -307,6 +308,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
}
if err := network.RemoveNetwork(config, name); err != nil {
utils.InternalServerError(w, err)
+ return
}
utils.WriteResponse(w, http.StatusNoContent, "")
}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 3aa554171..5422411cf 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -270,7 +270,7 @@ func PodPause(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
- responses, err := pod.Pause()
+ responses, err := pod.Pause(r.Context())
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
@@ -294,7 +294,7 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
- responses, err := pod.Unpause()
+ responses, err := pod.Unpause(r.Context())
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
utils.Error(w, "failed to pause pod", http.StatusInternalServerError, err)
return
@@ -402,7 +402,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
return
}
- responses, err := pod.Kill(uint(sig))
+ responses, err := pod.Kill(r.Context(), uint(sig))
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
utils.Error(w, "failed to kill pod", http.StatusInternalServerError, err)
return
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index cb0d26d1e..ad779203d 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -275,6 +275,31 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
r.Handle(VersionedPath("/images/{name:.*}/get"), s.APIHandler(compat.ExportImage)).Methods(http.MethodGet)
// Added non version path to URI to support docker non versioned paths
r.Handle("/images/{name:.*}/get", s.APIHandler(compat.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/get compat get
+ // ---
+ // tags:
+ // - images (compat)
+ // summary: Export several images
+ // description: Get a tarball containing all images and metadata for several image repositories
+ // parameters:
+ // - in: query
+ // name: names
+ // type: string
+ // required: true
+ // description: one or more image names or IDs comma separated
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // description: no error
+ // schema:
+ // type: string
+ // format: binary
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/get"), s.APIHandler(compat.ExportImages)).Methods(http.MethodGet)
+ // Added non version path to URI to support docker non versioned paths
+ r.Handle("/images/get", s.APIHandler(compat.ExportImages)).Methods(http.MethodGet)
// swagger:operation GET /images/{name:.*}/history compat imageHistory
// ---
// tags:
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index 2ba369b83..356e6869d 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -24,6 +24,8 @@ type PlayKubeOptions struct {
// SeccompProfileRoot - path to a directory containing seccomp
// profiles.
SeccompProfileRoot string
+ // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
+ ConfigMaps []string
}
// PlayKubePod represents a single pod and associated containers created by play kube
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index d92911e0c..0107e18c4 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -23,7 +23,7 @@ import (
"github.com/containers/podman/v2/pkg/checkpoint"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
- "github.com/containers/podman/v2/pkg/parallel"
+ parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
"github.com/containers/podman/v2/pkg/ps"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/signal"
@@ -157,7 +157,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
return nil, err
}
- errMap, err := parallel.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
+ errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
var err error
if options.Timeout != nil {
err = c.StopWithTimeout(*options.Timeout)
@@ -321,7 +321,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return reports, nil
}
- errMap, err := parallel.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
+ errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
if err != nil {
if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 5acfea853..f40df828a 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -2,19 +2,13 @@ package abi
import (
"context"
- "encoding/json"
"fmt"
- "io/ioutil"
- "os"
- "path/filepath"
"strings"
"github.com/containernetworking/cni/libcni"
- cniversion "github.com/containernetworking/cni/pkg/version"
- "github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/containers/podman/v2/pkg/network"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
)
@@ -111,173 +105,7 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
}
func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
- var (
- err error
- fileName string
- )
- if len(options.MacVLAN) > 0 {
- fileName, err = createMacVLAN(ic.Libpod, name, options)
- } else {
- fileName, err = createBridge(ic.Libpod, name, options)
- }
- if err != nil {
- return nil, err
- }
- return &entities.NetworkCreateReport{Filename: fileName}, nil
-}
-
-// createBridge creates a CNI network
-func createBridge(r *libpod.Runtime, name string, options entities.NetworkCreateOptions) (string, error) {
- isGateway := true
- ipMasq := true
- subnet := &options.Subnet
- ipRange := options.Range
- runtimeConfig, err := r.GetConfig()
- if err != nil {
- return "", err
- }
- // if range is provided, make sure it is "in" network
- if subnet.IP != nil {
- // if network is provided, does it conflict with existing CNI or live networks
- err = network.ValidateUserNetworkIsAvailable(runtimeConfig, subnet)
- } else {
- // if no network is provided, figure out network
- subnet, err = network.GetFreeNetwork(runtimeConfig)
- }
- if err != nil {
- return "", err
- }
- gateway := options.Gateway
- if gateway == nil {
- // if no gateway is provided, provide it as first ip of network
- gateway = network.CalcGatewayIP(subnet)
- }
- // if network is provided and if gateway is provided, make sure it is "in" network
- if options.Subnet.IP != nil && options.Gateway != nil {
- if !subnet.Contains(gateway) {
- return "", errors.Errorf("gateway %s is not in valid for subnet %s", gateway.String(), subnet.String())
- }
- }
- if options.Internal {
- isGateway = false
- ipMasq = false
- }
-
- // if a range is given, we need to ensure it is "in" the network range.
- if options.Range.IP != nil {
- if options.Subnet.IP == nil {
- return "", errors.New("you must define a subnet range to define an ip-range")
- }
- firstIP, err := network.FirstIPInSubnet(&options.Range)
- if err != nil {
- return "", err
- }
- lastIP, err := network.LastIPInSubnet(&options.Range)
- if err != nil {
- return "", err
- }
- if !subnet.Contains(firstIP) || !subnet.Contains(lastIP) {
- return "", errors.Errorf("the ip range %s does not fall within the subnet range %s", options.Range.String(), subnet.String())
- }
- }
- bridgeDeviceName, err := network.GetFreeDeviceName(runtimeConfig)
- if err != nil {
- return "", err
- }
-
- if len(name) > 0 {
- netNames, err := network.GetNetworkNamesFromFileSystem(runtimeConfig)
- if err != nil {
- return "", err
- }
- if util.StringInSlice(name, netNames) {
- return "", errors.Errorf("the network name %s is already used", name)
- }
- } else {
- // If no name is given, we give the name of the bridge device
- name = bridgeDeviceName
- }
-
- ncList := network.NewNcList(name, cniversion.Current())
- var plugins []network.CNIPlugins
- var routes []network.IPAMRoute
-
- defaultRoute, err := network.NewIPAMDefaultRoute(network.IsIPv6(subnet.IP))
- if err != nil {
- return "", err
- }
- routes = append(routes, defaultRoute)
- ipamConfig, err := network.NewIPAMHostLocalConf(subnet, routes, ipRange, gateway)
- if err != nil {
- return "", err
- }
-
- // TODO need to iron out the role of isDefaultGW and IPMasq
- bridge := network.NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, ipamConfig)
- plugins = append(plugins, bridge)
- plugins = append(plugins, network.NewPortMapPlugin())
- plugins = append(plugins, network.NewFirewallPlugin())
- // if we find the dnsname plugin, we add configuration for it
- if network.HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) && !options.DisableDNS {
- // Note: in the future we might like to allow for dynamic domain names
- plugins = append(plugins, network.NewDNSNamePlugin(network.DefaultPodmanDomainName))
- }
- ncList["plugins"] = plugins
- b, err := json.MarshalIndent(ncList, "", " ")
- if err != nil {
- return "", err
- }
- if err := os.MkdirAll(network.GetCNIConfDir(runtimeConfig), 0755); err != nil {
- return "", err
- }
- cniPathName := filepath.Join(network.GetCNIConfDir(runtimeConfig), fmt.Sprintf("%s.conflist", name))
- err = ioutil.WriteFile(cniPathName, b, 0644)
- return cniPathName, err
-}
-
-func createMacVLAN(r *libpod.Runtime, name string, options entities.NetworkCreateOptions) (string, error) {
- var (
- plugins []network.CNIPlugins
- )
- liveNetNames, err := network.GetLiveNetworkNames()
- if err != nil {
- return "", err
- }
-
- config, err := r.GetConfig()
- if err != nil {
- return "", err
- }
-
- // Make sure the host-device exists
- if !util.StringInSlice(options.MacVLAN, liveNetNames) {
- return "", errors.Errorf("failed to find network interface %q", options.MacVLAN)
- }
- if len(name) > 0 {
- netNames, err := network.GetNetworkNamesFromFileSystem(config)
- if err != nil {
- return "", err
- }
- if util.StringInSlice(name, netNames) {
- return "", errors.Errorf("the network name %s is already used", name)
- }
- } else {
- name, err = network.GetFreeDeviceName(config)
- if err != nil {
- return "", err
- }
- }
- ncList := network.NewNcList(name, cniversion.Current())
- macvlan := network.NewMacVLANPlugin(options.MacVLAN)
- plugins = append(plugins, macvlan)
- ncList["plugins"] = plugins
- b, err := json.MarshalIndent(ncList, "", " ")
- if err != nil {
- return "", err
- }
- cniPathName := filepath.Join(network.GetCNIConfDir(config), fmt.Sprintf("%s.conflist", name))
- err = ioutil.WriteFile(cniPathName, b, 0644)
- return cniPathName, err
+ return network.Create(name, options, ic.Libpod)
}
func ifPassesFilterTest(netconf *libcni.NetworkConfigList, filter []string) bool {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 40edc1ae3..2de98d8f5 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -311,6 +311,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
ctrRestartPolicy = libpod.RestartPolicyAlways
}
+ configMaps := []v1.ConfigMap{}
+ for _, p := range options.ConfigMaps {
+ f, err := os.Open(p)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ cm, err := readConfigMapFromFile(f)
+ if err != nil {
+ return nil, errors.Wrapf(err, "%q", p)
+ }
+
+ configMaps = append(configMaps, cm)
+ }
+
containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
for _, container := range podYAML.Spec.Containers {
pullPolicy := util.PullImageMissing
@@ -334,7 +350,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
- conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, seccompPaths)
+ conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths)
if err != nil {
return nil, err
}
@@ -447,7 +463,7 @@ func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfi
}
// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
-func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
+func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
var (
containerConfig createconfig.CreateConfig
pidConfig createconfig.PidConfig
@@ -572,8 +588,17 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
}
envs = imageEnv
}
- for _, e := range containerYAML.Env {
- envs[e.Name] = e.Value
+ for _, env := range containerYAML.Env {
+ value := envVarValue(env, configMaps)
+
+ envs[env.Name] = value
+ }
+ for _, envFrom := range containerYAML.EnvFrom {
+ cmEnvs := envVarsFromConfigMap(envFrom, configMaps)
+
+ for k, v := range cmEnvs {
+ envs[k] = v
+ }
}
containerConfig.Env = envs
@@ -594,6 +619,62 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return &containerConfig, nil
}
+// readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag
+func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
+ var cm v1.ConfigMap
+
+ content, err := ioutil.ReadAll(r)
+ if err != nil {
+ return cm, errors.Wrapf(err, "unable to read ConfigMap YAML content")
+ }
+
+ if err := yaml.Unmarshal(content, &cm); err != nil {
+ return cm, errors.Wrapf(err, "unable to read YAML as Kube ConfigMap")
+ }
+
+ if cm.Kind != "ConfigMap" {
+ return cm, errors.Errorf("invalid YAML kind: %q. [ConfigMap] is the only supported by --configmap", cm.Kind)
+ }
+
+ return cm, nil
+}
+
+// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container
+func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string {
+ envs := map[string]string{}
+
+ if envFrom.ConfigMapRef != nil {
+ cmName := envFrom.ConfigMapRef.Name
+
+ for _, c := range configMaps {
+ if cmName == c.Name {
+ envs = c.Data
+ break
+ }
+ }
+ }
+
+ return envs
+}
+
+// envVarValue returns the environment variable value configured within the container's env setting.
+// It gets the value from a configMap if specified, otherwise returns env.Value
+func envVarValue(env v1.EnvVar, configMaps []v1.ConfigMap) string {
+ for _, c := range configMaps {
+ if env.ValueFrom != nil {
+ if env.ValueFrom.ConfigMapKeyRef != nil {
+ if env.ValueFrom.ConfigMapKeyRef.Name == c.Name {
+ if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok {
+ return value
+ }
+ }
+ }
+ }
+ }
+
+ return env.Value
+}
+
// kubeSeccompPaths holds information about a pod YAML's seccomp configuration
// it holds both container and pod seccomp paths
type kubeSeccompPaths struct {
diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go
new file mode 100644
index 000000000..5595476c3
--- /dev/null
+++ b/pkg/domain/infra/abi/play_test.go
@@ -0,0 +1,254 @@
+package abi
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var configMapList = []v1.ConfigMap{
+ {
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "bar",
+ },
+ Data: map[string]string{
+ "myvar": "bar",
+ },
+ },
+ {
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string]string{
+ "myvar": "foo",
+ },
+ },
+}
+
+func TestReadConfigMapFromFile(t *testing.T) {
+ tests := []struct {
+ name string
+ configMapContent string
+ expectError bool
+ expectedErrorMsg string
+ expected v1.ConfigMap
+ }{
+ {
+ "ValidConfigMap",
+ `
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: foo
+data:
+ myvar: foo
+`,
+ false,
+ "",
+ v1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ConfigMap",
+ APIVersion: "v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string]string{
+ "myvar": "foo",
+ },
+ },
+ },
+ {
+ "InvalidYAML",
+ `
+Invalid YAML
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: foo
+data:
+ myvar: foo
+`,
+ true,
+ "unable to read YAML as Kube ConfigMap",
+ v1.ConfigMap{},
+ },
+ {
+ "InvalidKind",
+ `
+apiVersion: v1
+kind: InvalidKind
+metadata:
+ name: foo
+data:
+ myvar: foo
+`,
+ true,
+ "invalid YAML kind",
+ v1.ConfigMap{},
+ },
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ buf := bytes.NewBufferString(test.configMapContent)
+ cm, err := readConfigMapFromFile(buf)
+
+ if test.expectError {
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), test.expectedErrorMsg)
+ } else {
+ assert.NoError(t, err)
+ assert.Equal(t, test.expected, cm)
+ }
+ })
+ }
+}
+
+func TestEnvVarsFromConfigMap(t *testing.T) {
+ tests := []struct {
+ name string
+ envFrom v1.EnvFromSource
+ configMapList []v1.ConfigMap
+ expected map[string]string
+ }{
+ {
+ "ConfigMapExists",
+ v1.EnvFromSource{
+ ConfigMapRef: &v1.ConfigMapEnvSource{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "foo",
+ },
+ },
+ },
+ configMapList,
+ map[string]string{
+ "myvar": "foo",
+ },
+ },
+ {
+ "ConfigMapDoesNotExist",
+ v1.EnvFromSource{
+ ConfigMapRef: &v1.ConfigMapEnvSource{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "doesnotexist",
+ },
+ },
+ },
+ configMapList,
+ map[string]string{},
+ },
+ {
+ "EmptyConfigMapList",
+ v1.EnvFromSource{
+ ConfigMapRef: &v1.ConfigMapEnvSource{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "foo",
+ },
+ },
+ },
+ []v1.ConfigMap{},
+ map[string]string{},
+ },
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ result := envVarsFromConfigMap(test.envFrom, test.configMapList)
+ assert.Equal(t, test.expected, result)
+ })
+ }
+}
+
+func TestEnvVarValue(t *testing.T) {
+ tests := []struct {
+ name string
+ envVar v1.EnvVar
+ configMapList []v1.ConfigMap
+ expected string
+ }{
+ {
+ "ConfigMapExists",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ConfigMapKeyRef: &v1.ConfigMapKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "foo",
+ },
+ Key: "myvar",
+ },
+ },
+ },
+ configMapList,
+ "foo",
+ },
+ {
+ "ContainerKeyDoesNotExistInConfigMap",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ConfigMapKeyRef: &v1.ConfigMapKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "foo",
+ },
+ Key: "doesnotexist",
+ },
+ },
+ },
+ configMapList,
+ "",
+ },
+ {
+ "ConfigMapDoesNotExist",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ConfigMapKeyRef: &v1.ConfigMapKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "doesnotexist",
+ },
+ Key: "myvar",
+ },
+ },
+ },
+ configMapList,
+ "",
+ },
+ {
+ "EmptyConfigMapList",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ConfigMapKeyRef: &v1.ConfigMapKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "foo",
+ },
+ Key: "myvar",
+ },
+ },
+ },
+ []v1.ConfigMap{},
+ "",
+ },
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ result := envVarValue(test.envVar, test.configMapList)
+ assert.Equal(t, test.expected, result)
+ })
+ }
+}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 747da9fd4..258640a81 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -66,7 +66,7 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
for _, p := range pods {
report := entities.PodKillReport{Id: p.ID()}
- conErrs, err := p.Kill(uint(sig))
+ conErrs, err := p.Kill(ctx, uint(sig))
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
reports = append(reports, &report)
@@ -92,7 +92,7 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
}
for _, p := range pods {
report := entities.PodPauseReport{Id: p.ID()}
- errs, err := p.Pause()
+ errs, err := p.Pause(ctx)
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
continue
@@ -117,7 +117,7 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
}
for _, p := range pods {
report := entities.PodUnpauseReport{Id: p.ID()}
- errs, err := p.Unpause()
+ errs, err := p.Unpause(ctx)
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
report.Errs = []error{err}
continue
diff --git a/pkg/network/config.go b/pkg/network/config.go
deleted file mode 100644
index 0115433e1..000000000
--- a/pkg/network/config.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package network
-
-import (
- "encoding/json"
- "net"
-)
-
-// TODO once the containers.conf file stuff is worked out, this should be modified
-// to honor defines in the containers.conf as well as overrides?
-
-const (
- // CNIConfigDir is the path where CNI config files exist
- CNIConfigDir = "/etc/cni/net.d"
- // CNIDeviceName is the default network device name and in
- // reality should have an int appended to it (cni-podman4)
- CNIDeviceName = "cni-podman"
- // DefaultPodmanDomainName is used for the dnsname plugin to define
- // a localized domain name for a created network
- DefaultPodmanDomainName = "dns.podman"
-)
-
-// GetDefaultPodmanNetwork outputs the default network for podman
-func GetDefaultPodmanNetwork() (*net.IPNet, error) {
- _, n, err := net.ParseCIDR("10.88.1.0/24")
- return n, err
-}
-
-// CNIPlugins is a way of marshalling a CNI network configuration to disk
-type CNIPlugins interface {
- Bytes() ([]byte, error)
-}
-
-// HostLocalBridge describes a configuration for a bridge plugin
-// https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge#network-configuration-reference
-type HostLocalBridge struct {
- PluginType string `json:"type"`
- BrName string `json:"bridge,omitempty"`
- IsGW bool `json:"isGateway"`
- IsDefaultGW bool `json:"isDefaultGateway,omitempty"`
- ForceAddress bool `json:"forceAddress,omitempty"`
- IPMasq bool `json:"ipMasq,omitempty"`
- MTU int `json:"mtu,omitempty"`
- HairpinMode bool `json:"hairpinMode,omitempty"`
- PromiscMode bool `json:"promiscMode,omitempty"`
- Vlan int `json:"vlan,omitempty"`
- IPAM IPAMHostLocalConf `json:"ipam"`
-}
-
-// Bytes outputs []byte
-func (h *HostLocalBridge) Bytes() ([]byte, error) {
- return json.MarshalIndent(h, "", "\t")
-}
-
-// IPAMHostLocalConf describes an IPAM configuration
-// https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local#network-configuration-reference
-type IPAMHostLocalConf struct {
- PluginType string `json:"type"`
- Routes []IPAMRoute `json:"routes,omitempty"`
- ResolveConf string `json:"resolveConf,omitempty"`
- DataDir string `json:"dataDir,omitempty"`
- Ranges [][]IPAMLocalHostRangeConf `json:"ranges,omitempty"`
-}
-
-// IPAMLocalHostRangeConf describes the new style IPAM ranges
-type IPAMLocalHostRangeConf struct {
- Subnet string `json:"subnet"`
- RangeStart string `json:"rangeStart,omitempty"`
- RangeEnd string `json:"rangeEnd,omitempty"`
- Gateway string `json:"gateway,omitempty"`
-}
-
-// Bytes outputs the configuration as []byte
-func (i IPAMHostLocalConf) Bytes() ([]byte, error) {
- return json.MarshalIndent(i, "", "\t")
-}
-
-// IPAMRoute describes a route in an ipam config
-type IPAMRoute struct {
- Dest string `json:"dst"`
-}
-
-// PortMapConfig describes the default portmapping config
-type PortMapConfig struct {
- PluginType string `json:"type"`
- Capabilities map[string]bool `json:"capabilities"`
-}
-
-// Bytes outputs the configuration as []byte
-func (p PortMapConfig) Bytes() ([]byte, error) {
- return json.MarshalIndent(p, "", "\t")
-}
-
-// IPAMDHCP describes the ipamdhcp config
-type IPAMDHCP struct {
- DHCP string `json:"type"`
-}
-
-// MacVLANConfig describes the macvlan config
-type MacVLANConfig struct {
- PluginType string `json:"type"`
- Master string `json:"master"`
- IPAM IPAMDHCP `json:"ipam"`
-}
-
-// Bytes outputs the configuration as []byte
-func (p MacVLANConfig) Bytes() ([]byte, error) {
- return json.MarshalIndent(p, "", "\t")
-}
-
-// FirewallConfig describes the firewall plugin
-type FirewallConfig struct {
- PluginType string `json:"type"`
- Backend string `json:"backend"`
-}
-
-// Bytes outputs the configuration as []byte
-func (f FirewallConfig) Bytes() ([]byte, error) {
- return json.MarshalIndent(f, "", "\t")
-}
-
-// DNSNameConfig describes the dns container name resolution plugin config
-type DNSNameConfig struct {
- PluginType string `json:"type"`
- DomainName string `json:"domainName"`
-}
-
-// Bytes outputs the configuration as []byte
-func (d DNSNameConfig) Bytes() ([]byte, error) {
- return json.MarshalIndent(d, "", "\t")
-}
diff --git a/pkg/network/devices.go b/pkg/network/devices.go
deleted file mode 100644
index a5d23fae4..000000000
--- a/pkg/network/devices.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package network
-
-import (
- "fmt"
- "os/exec"
-
- "github.com/containers/common/pkg/config"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/containers/podman/v2/utils"
- "github.com/sirupsen/logrus"
-)
-
-// GetFreeDeviceName returns a device name that is unused; used when no network
-// name is provided by user
-func GetFreeDeviceName(config *config.Config) (string, error) {
- var (
- deviceNum uint
- deviceName string
- )
- networkNames, err := GetNetworkNamesFromFileSystem(config)
- if err != nil {
- return "", err
- }
- liveNetworksNames, err := GetLiveNetworkNames()
- if err != nil {
- return "", err
- }
- bridgeNames, err := GetBridgeNamesFromFileSystem(config)
- if err != nil {
- return "", err
- }
- for {
- deviceName = fmt.Sprintf("%s%d", CNIDeviceName, deviceNum)
- logrus.Debugf("checking if device name %q exists in other cni networks", deviceName)
- if util.StringInSlice(deviceName, networkNames) {
- deviceNum++
- continue
- }
- logrus.Debugf("checking if device name %q exists in live networks", deviceName)
- if util.StringInSlice(deviceName, liveNetworksNames) {
- deviceNum++
- continue
- }
- logrus.Debugf("checking if device name %q already exists as a bridge name ", deviceName)
- if !util.StringInSlice(deviceName, bridgeNames) {
- break
- }
- deviceNum++
- }
- return deviceName, nil
-}
-
-// RemoveInterface removes an interface by the given name
-func RemoveInterface(interfaceName string) error {
- // Make sure we have the ip command on the system
- ipPath, err := exec.LookPath("ip")
- if err != nil {
- return err
- }
- // Delete the network interface
- _, err = utils.ExecCmd(ipPath, []string{"link", "del", interfaceName}...)
- return err
-}
diff --git a/pkg/network/files.go b/pkg/network/files.go
deleted file mode 100644
index a2090491f..000000000
--- a/pkg/network/files.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package network
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "sort"
- "strings"
-
- "github.com/containernetworking/cni/libcni"
- "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
- "github.com/containers/common/pkg/config"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/pkg/errors"
-)
-
-func GetCNIConfDir(configArg *config.Config) string {
- if len(configArg.Network.NetworkConfigDir) < 1 {
- dc, err := config.DefaultConfig()
- if err != nil {
- // Fallback to hard-coded dir
- return CNIConfigDir
- }
- return dc.Network.NetworkConfigDir
- }
- return configArg.Network.NetworkConfigDir
-}
-
-// LoadCNIConfsFromDir loads all the CNI configurations from a dir
-func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
- files, err := libcni.ConfFiles(dir, []string{".conflist"})
- if err != nil {
- return nil, err
- }
- sort.Strings(files)
-
- configs := make([]*libcni.NetworkConfigList, 0, len(files))
- for _, confFile := range files {
- conf, err := libcni.ConfListFromFile(confFile)
- if err != nil {
- return nil, errors.Wrapf(err, "in %s", confFile)
- }
- configs = append(configs, conf)
- }
- return configs, nil
-}
-
-// GetCNIConfigPathByName finds a CNI network by name and
-// returns its configuration file path
-func GetCNIConfigPathByName(config *config.Config, name string) (string, error) {
- files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"})
- if err != nil {
- return "", err
- }
- for _, confFile := range files {
- conf, err := libcni.ConfListFromFile(confFile)
- if err != nil {
- return "", errors.Wrapf(err, "in %s", confFile)
- }
- if conf.Name == name {
- return confFile, nil
- }
- }
- return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name))
-}
-
-// ReadRawCNIConfByName reads the raw CNI configuration for a CNI
-// network by name
-func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) {
- confFile, err := GetCNIConfigPathByName(config, name)
- if err != nil {
- return nil, err
- }
- b, err := ioutil.ReadFile(confFile)
- return b, err
-}
-
-// GetCNIPlugins returns a list of plugins that a given network
-// has in the form of a string
-func GetCNIPlugins(list *libcni.NetworkConfigList) string {
- plugins := make([]string, 0, len(list.Plugins))
- for _, plug := range list.Plugins {
- plugins = append(plugins, plug.Network.Type)
- }
- return strings.Join(plugins, ",")
-}
-
-// GetNetworksFromFilesystem gets all the networks from the cni configuration
-// files
-func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) {
- var cniNetworks []*allocator.Net
-
- networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
- if err != nil {
- return nil, err
- }
- for _, n := range networks {
- for _, cniplugin := range n.Plugins {
- if cniplugin.Network.Type == "bridge" {
- ipamConf := allocator.Net{}
- if err := json.Unmarshal(cniplugin.Bytes, &ipamConf); err != nil {
- return nil, err
- }
- cniNetworks = append(cniNetworks, &ipamConf)
- break
- }
- }
- }
- return cniNetworks, nil
-}
-
-// GetNetworkNamesFromFileSystem gets all the names from the cni network
-// configuration files
-func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) {
- networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
- if err != nil {
- return nil, err
- }
- networkNames := []string{}
- for _, n := range networks {
- networkNames = append(networkNames, n.Name)
- }
- return networkNames, nil
-}
-
-// GetInterfaceNameFromConfig returns the interface name for the bridge plugin
-func GetInterfaceNameFromConfig(path string) (string, error) {
- var name string
- conf, err := libcni.ConfListFromFile(path)
- if err != nil {
- return "", err
- }
- for _, cniplugin := range conf.Plugins {
- if cniplugin.Network.Type == "bridge" {
- plugin := make(map[string]interface{})
- if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
- return "", err
- }
- name = plugin["bridge"].(string)
- break
- }
- }
- if len(name) == 0 {
- return "", errors.New("unable to find interface name for network")
- }
- return name, nil
-}
-
-// GetBridgeNamesFromFileSystem is a convenience function to get all the bridge
-// names from the configured networks
-func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) {
- networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
- if err != nil {
- return nil, err
- }
-
- bridgeNames := []string{}
- for _, n := range networks {
- var name string
- // iterate network conflists
- for _, cniplugin := range n.Plugins {
- // iterate plugins
- if cniplugin.Network.Type == "bridge" {
- plugin := make(map[string]interface{})
- if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
- continue
- }
- name = plugin["bridge"].(string)
- }
- }
- bridgeNames = append(bridgeNames, name)
- }
- return bridgeNames, nil
-}
diff --git a/pkg/network/ip.go b/pkg/network/ip.go
deleted file mode 100644
index ba93a0d05..000000000
--- a/pkg/network/ip.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package network
-
-import (
- "net"
-
- "github.com/containernetworking/plugins/pkg/ip"
-)
-
-// CalcGatewayIP takes a network and returns the first IP in it.
-func CalcGatewayIP(ipn *net.IPNet) net.IP {
- // taken from cni bridge plugin as it is not exported
- nid := ipn.IP.Mask(ipn.Mask)
- return ip.NextIP(nid)
-}
-
-// IsIPv6 returns if netIP is IPv6.
-func IsIPv6(netIP net.IP) bool {
- return netIP != nil && netIP.To4() == nil
-}
diff --git a/pkg/network/netconflist.go b/pkg/network/netconflist.go
deleted file mode 100644
index 8187fdb39..000000000
--- a/pkg/network/netconflist.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package network
-
-import (
- "net"
- "os"
- "path/filepath"
-)
-
-const (
- defaultIPv4Route = "0.0.0.0/0"
- defaultIPv6Route = "::/0"
-)
-
-// NcList describes a generic map
-type NcList map[string]interface{}
-
-// NewNcList creates a generic map of values with string
-// keys and adds in version and network name
-func NewNcList(name, version string) NcList {
- n := NcList{}
- n["cniVersion"] = version
- n["name"] = name
- return n
-}
-
-// NewHostLocalBridge creates a new LocalBridge for host-local
-func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, ipamConf IPAMHostLocalConf) *HostLocalBridge {
- hostLocalBridge := HostLocalBridge{
- PluginType: "bridge",
- BrName: name,
- IPMasq: ipMasq,
- HairpinMode: true,
- IPAM: ipamConf,
- }
- if isGateWay {
- hostLocalBridge.IsGW = true
- }
- if isDefaultGW {
- hostLocalBridge.IsDefaultGW = true
- }
- return &hostLocalBridge
-}
-
-// NewIPAMHostLocalConf creates a new IPAMHostLocal configfuration
-func NewIPAMHostLocalConf(subnet *net.IPNet, routes []IPAMRoute, ipRange net.IPNet, gw net.IP) (IPAMHostLocalConf, error) {
- var ipamRanges [][]IPAMLocalHostRangeConf
- ipamConf := IPAMHostLocalConf{
- PluginType: "host-local",
- Routes: routes,
- // Possible future support ? Leaving for clues
- //ResolveConf: "",
- //DataDir: ""
- }
- IPAMRange, err := newIPAMLocalHostRange(subnet, &ipRange, &gw)
- if err != nil {
- return ipamConf, err
- }
- ipamRanges = append(ipamRanges, IPAMRange)
- ipamConf.Ranges = ipamRanges
- return ipamConf, nil
-}
-
-func newIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw *net.IP) ([]IPAMLocalHostRangeConf, error) { //nolint:interfacer
- var ranges []IPAMLocalHostRangeConf
- hostRange := IPAMLocalHostRangeConf{
- Subnet: subnet.String(),
- }
- // an user provided a range, we add it here
- if ipRange.IP != nil {
- first, err := FirstIPInSubnet(ipRange)
- if err != nil {
- return nil, err
- }
- last, err := LastIPInSubnet(ipRange)
- if err != nil {
- return nil, err
- }
- hostRange.RangeStart = first.String()
- hostRange.RangeEnd = last.String()
- }
- if gw != nil {
- hostRange.Gateway = gw.String()
- }
- ranges = append(ranges, hostRange)
- return ranges, nil
-}
-
-// NewIPAMRoute creates a new IPAM route configuration
-func NewIPAMRoute(r *net.IPNet) IPAMRoute { //nolint:interfacer
- return IPAMRoute{Dest: r.String()}
-}
-
-// NewIPAMDefaultRoute creates a new IPAMDefault route of
-// 0.0.0.0/0 for IPv4 or ::/0 for IPv6
-func NewIPAMDefaultRoute(isIPv6 bool) (IPAMRoute, error) {
- route := defaultIPv4Route
- if isIPv6 {
- route = defaultIPv6Route
- }
- _, n, err := net.ParseCIDR(route)
- if err != nil {
- return IPAMRoute{}, err
- }
- return NewIPAMRoute(n), nil
-}
-
-// NewPortMapPlugin creates a predefined, default portmapping
-// configuration
-func NewPortMapPlugin() PortMapConfig {
- caps := make(map[string]bool)
- caps["portMappings"] = true
- p := PortMapConfig{
- PluginType: "portmap",
- Capabilities: caps,
- }
- return p
-}
-
-// NewFirewallPlugin creates a generic firewall plugin
-func NewFirewallPlugin() FirewallConfig {
- return FirewallConfig{
- PluginType: "firewall",
- }
-}
-
-// NewDNSNamePlugin creates the dnsname config with a given
-// domainname
-func NewDNSNamePlugin(domainName string) DNSNameConfig {
- return DNSNameConfig{
- PluginType: "dnsname",
- DomainName: domainName,
- }
-}
-
-// HasDNSNamePlugin looks to see if the dnsname cni plugin is present
-func HasDNSNamePlugin(paths []string) bool {
- for _, p := range paths {
- if _, err := os.Stat(filepath.Join(p, "dnsname")); err == nil {
- return true
- }
- }
- return false
-}
-
-// NewMacVLANPlugin creates a macvlanconfig with a given device name
-func NewMacVLANPlugin(device string) MacVLANConfig {
- i := IPAMDHCP{DHCP: "dhcp"}
-
- m := MacVLANConfig{
- PluginType: "macvlan",
- Master: device,
- IPAM: i,
- }
- return m
-}
diff --git a/pkg/network/netconflist_test.go b/pkg/network/netconflist_test.go
deleted file mode 100644
index 5893bf985..000000000
--- a/pkg/network/netconflist_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package network
-
-import (
- "reflect"
- "testing"
-)
-
-func TestNewIPAMDefaultRoute(t *testing.T) {
-
- tests := []struct {
- name string
- isIPv6 bool
- want IPAMRoute
- }{
- {
- name: "IPv4 default route",
- isIPv6: false,
- want: IPAMRoute{defaultIPv4Route},
- },
- {
- name: "IPv6 default route",
- isIPv6: true,
- want: IPAMRoute{defaultIPv6Route},
- },
- }
- for _, tt := range tests {
- tt := tt
- t.Run(tt.name, func(t *testing.T) {
- got, err := NewIPAMDefaultRoute(tt.isIPv6)
- if err != nil {
- t.Errorf("no error expected: %v", err)
- }
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("NewIPAMDefaultRoute() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/pkg/network/network.go b/pkg/network/network.go
deleted file mode 100644
index c4c1ff67f..000000000
--- a/pkg/network/network.go
+++ /dev/null
@@ -1,219 +0,0 @@
-package network
-
-import (
- "encoding/json"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
- "github.com/containers/common/pkg/config"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// DefaultNetworkDriver is the default network type used
-var DefaultNetworkDriver = "bridge"
-
-// SupportedNetworkDrivers describes the list of supported drivers
-var SupportedNetworkDrivers = []string{DefaultNetworkDriver}
-
-// IsSupportedDriver checks if the user provided driver is supported
-func IsSupportedDriver(driver string) error {
- if util.StringInSlice(driver, SupportedNetworkDrivers) {
- return nil
- }
- return errors.Errorf("driver '%s' is not supported", driver)
-}
-
-// GetLiveNetworks returns a slice of networks representing what the system
-// has defined as network interfaces
-func GetLiveNetworks() ([]*net.IPNet, error) {
- addrs, err := net.InterfaceAddrs()
- if err != nil {
- return nil, err
- }
- nets := make([]*net.IPNet, 0, len(addrs))
- for _, address := range addrs {
- _, n, err := net.ParseCIDR(address.String())
- if err != nil {
- return nil, err
- }
- nets = append(nets, n)
- }
- return nets, nil
-}
-
-// GetLiveNetworkNames returns a list of network interfaces on the system
-func GetLiveNetworkNames() ([]string, error) {
- liveInterfaces, err := net.Interfaces()
- if err != nil {
- return nil, err
- }
- interfaceNames := make([]string, 0, len(liveInterfaces))
- for _, i := range liveInterfaces {
- interfaceNames = append(interfaceNames, i.Name)
- }
- return interfaceNames, nil
-}
-
-// GetFreeNetwork looks for a free network according to existing cni configuration
-// files and network interfaces.
-func GetFreeNetwork(config *config.Config) (*net.IPNet, error) {
- networks, err := GetNetworksFromFilesystem(config)
- if err != nil {
- return nil, err
- }
- liveNetworks, err := GetLiveNetworks()
- if err != nil {
- return nil, err
- }
- nextNetwork, err := GetDefaultPodmanNetwork()
- if err != nil {
- return nil, err
- }
- logrus.Debugf("default network is %s", nextNetwork.String())
- for {
- newNetwork, err := NextSubnet(nextNetwork)
- if err != nil {
- return nil, err
- }
- logrus.Debugf("checking if network %s intersects with other cni networks", nextNetwork.String())
- if intersectsConfig, _ := networkIntersectsWithNetworks(newNetwork, allocatorToIPNets(networks)); intersectsConfig {
- logrus.Debugf("network %s is already being used by a cni configuration", nextNetwork.String())
- nextNetwork = newNetwork
- continue
- }
- logrus.Debugf("checking if network %s intersects with any network interfaces", nextNetwork.String())
- if intersectsLive, _ := networkIntersectsWithNetworks(newNetwork, liveNetworks); !intersectsLive {
- break
- }
- logrus.Debugf("network %s is being used by a network interface", nextNetwork.String())
- nextNetwork = newNetwork
- }
- return nextNetwork, nil
-}
-
-func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet {
- var nets []*net.IPNet
- for _, network := range networks {
- if len(network.IPAM.Ranges) > 0 {
- // this is the new IPAM range style
- // append each subnet from ipam the rangeset
- for _, r := range network.IPAM.Ranges[0] {
- nets = append(nets, newIPNetFromSubnet(r.Subnet))
- }
- } else {
- // looks like the old, deprecated style
- nets = append(nets, newIPNetFromSubnet(network.IPAM.Subnet))
- }
- }
- return nets
-}
-
-func newIPNetFromSubnet(subnet types.IPNet) *net.IPNet {
- n := net.IPNet{
- IP: subnet.IP,
- Mask: subnet.Mask,
- }
- return &n
-}
-
-func networkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) (bool, *net.IPNet) {
- for _, nw := range networklist {
- if networkIntersect(n, nw) {
- return true, nw
- }
- }
- return false, nil
-}
-
-func networkIntersect(n1, n2 *net.IPNet) bool {
- return n2.Contains(n1.IP) || n1.Contains(n2.IP)
-}
-
-// ValidateUserNetworkIsAvailable returns via an error if a network is available
-// to be used
-func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) error {
- if len(userNet.IP) == 0 || len(userNet.Mask) == 0 {
- return errors.Errorf("network %s's ip or mask cannot be empty", userNet.String())
- }
-
- ones, bit := userNet.Mask.Size()
- if ones == 0 || bit == 0 {
- return errors.Errorf("network %s's mask is invalid", userNet.String())
- }
-
- networks, err := GetNetworksFromFilesystem(config)
- if err != nil {
- return err
- }
- liveNetworks, err := GetLiveNetworks()
- if err != nil {
- return err
- }
- logrus.Debugf("checking if network %s exists in cni networks", userNet.String())
- if intersectsConfig, _ := networkIntersectsWithNetworks(userNet, allocatorToIPNets(networks)); intersectsConfig {
- return errors.Errorf("network %s is already being used by a cni configuration", userNet.String())
- }
- logrus.Debugf("checking if network %s exists in any network interfaces", userNet.String())
- if intersectsLive, _ := networkIntersectsWithNetworks(userNet, liveNetworks); intersectsLive {
- return errors.Errorf("network %s is being used by a network interface", userNet.String())
- }
- return nil
-}
-
-// RemoveNetwork removes a given network by name. If the network has container associated with it, that
-// must be handled outside the context of this.
-func RemoveNetwork(config *config.Config, name string) error {
- cniPath, err := GetCNIConfigPathByName(config, name)
- if err != nil {
- return err
- }
- // Before we delete the configuration file, we need to make sure we can read and parse
- // it to get the network interface name so we can remove that too
- interfaceName, err := GetInterfaceNameFromConfig(cniPath)
- if err != nil {
- return errors.Wrapf(err, "failed to find network interface name in %q", cniPath)
- }
- liveNetworkNames, err := GetLiveNetworkNames()
- if err != nil {
- return errors.Wrapf(err, "failed to get live network names")
- }
- if util.StringInSlice(interfaceName, liveNetworkNames) {
- if err := RemoveInterface(interfaceName); err != nil {
- return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName)
- }
- }
- // Remove the configuration file
- if err := os.Remove(cniPath); err != nil {
- return errors.Wrapf(err, "failed to remove network configuration file %q", cniPath)
- }
- return nil
-}
-
-// InspectNetwork reads a CNI config and returns its configuration
-func InspectNetwork(config *config.Config, name string) (map[string]interface{}, error) {
- b, err := ReadRawCNIConfByName(config, name)
- if err != nil {
- return nil, err
- }
- rawList := make(map[string]interface{})
- err = json.Unmarshal(b, &rawList)
- return rawList, err
-}
-
-// Exists says whether a given network exists or not; it meant
-// specifically for restful responses so 404s can be used
-func Exists(config *config.Config, name string) (bool, error) {
- _, err := ReadRawCNIConfByName(config, name)
- if err != nil {
- if errors.Cause(err) == define.ErrNoSuchNetwork {
- return false, nil
- }
- return false, err
- }
- return true, nil
-}
diff --git a/pkg/network/network_test.go b/pkg/network/network_test.go
deleted file mode 100644
index 1969e792c..000000000
--- a/pkg/network/network_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package network
-
-import (
- "net"
- "testing"
-)
-
-func parseCIDR(n string) *net.IPNet {
- _, parsedNet, _ := net.ParseCIDR(n)
- return parsedNet
-}
-
-func Test_networkIntersect(t *testing.T) {
- type args struct {
- n1 *net.IPNet
- n2 *net.IPNet
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {"16 and 24 intersects", args{n1: parseCIDR("192.168.0.0/16"), n2: parseCIDR("192.168.1.0/24")}, true},
- {"24 and 25 intersects", args{n1: parseCIDR("192.168.1.0/24"), n2: parseCIDR("192.168.1.0/25")}, true},
- {"Two 24s", args{n1: parseCIDR("192.168.1.0/24"), n2: parseCIDR("192.168.2.0/24")}, false},
- }
- for _, tt := range tests {
- test := tt
- t.Run(tt.name, func(t *testing.T) {
- if got := networkIntersect(test.args.n1, test.args.n2); got != test.want {
- t.Errorf("networkIntersect() = %v, want %v", got, test.want)
- }
- })
- }
-}
diff --git a/pkg/network/subnet.go b/pkg/network/subnet.go
deleted file mode 100644
index 90f0cdfce..000000000
--- a/pkg/network/subnet.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package network
-
-/*
- The code in this was kindly contributed by Dan Williams(dcbw@redhat.com). Many thanks
- for his contributions.
-*/
-
-import (
- "fmt"
- "net"
-)
-
-func incByte(subnet *net.IPNet, idx int, shift uint) error {
- if idx < 0 {
- return fmt.Errorf("no more subnets left")
- }
- if subnet.IP[idx] == 255 {
- subnet.IP[idx] = 0
- return incByte(subnet, idx-1, 0)
- }
- subnet.IP[idx] += 1 << shift
- return nil
-}
-
-// NextSubnet returns subnet incremented by 1
-func NextSubnet(subnet *net.IPNet) (*net.IPNet, error) {
- newSubnet := &net.IPNet{
- IP: subnet.IP,
- Mask: subnet.Mask,
- }
- ones, bits := newSubnet.Mask.Size()
- if ones == 0 {
- return nil, fmt.Errorf("%s has only one subnet", subnet.String())
- }
- zeroes := uint(bits - ones)
- shift := zeroes % 8
- idx := ones/8 - 1
- if idx < 0 {
- idx = 0
- }
- if err := incByte(newSubnet, idx, shift); err != nil {
- return nil, err
- }
- return newSubnet, nil
-}
-
-// LastIPInSubnet gets the last IP in a subnet
-func LastIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
- // re-parse to ensure clean network address
- _, cidr, err := net.ParseCIDR(addr.String())
- if err != nil {
- return nil, err
- }
-
- ones, bits := cidr.Mask.Size()
- if ones == bits {
- return FirstIPInSubnet(cidr)
- }
- hostStart := ones / 8
- // Handle the first host byte
- cidr.IP[hostStart] |= 0xff & cidr.Mask[hostStart]
- // Fill the rest with ones
- for i := hostStart; i < len(cidr.IP); i++ {
- cidr.IP[i] = 0xff
- }
- return cidr.IP, nil
-}
-
-// FirstIPInSubnet gets the first IP in a subnet
-func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
- // re-parse to ensure clean network address
- _, cidr, err := net.ParseCIDR(addr.String())
- if err != nil {
- return nil, err
- }
- cidr.IP[len(cidr.IP)-1]++
- return cidr.IP, nil
-}
diff --git a/pkg/network/subnet_test.go b/pkg/network/subnet_test.go
deleted file mode 100644
index 917c3be88..000000000
--- a/pkg/network/subnet_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package network
-
-import (
- "net"
- "reflect"
- "testing"
-)
-
-func TestNextSubnet(t *testing.T) {
- type args struct {
- subnet *net.IPNet
- }
- tests := []struct {
- name string
- args args
- want *net.IPNet
- wantErr bool
- }{
- {"class b", args{subnet: parseCIDR("192.168.0.0/16")}, parseCIDR("192.169.0.0/16"), false},
- {"class c", args{subnet: parseCIDR("192.168.1.0/24")}, parseCIDR("192.168.2.0/24"), false},
- }
- for _, tt := range tests {
- test := tt
- t.Run(test.name, func(t *testing.T) {
- got, err := NextSubnet(test.args.subnet)
- if (err != nil) != test.wantErr {
- t.Errorf("NextSubnet() error = %v, wantErr %v", err, test.wantErr)
- return
- }
- if !reflect.DeepEqual(got, test.want) {
- t.Errorf("NextSubnet() got = %v, want %v", got, test.want)
- }
- })
- }
-}
diff --git a/pkg/parallel/parallel_linux.go b/pkg/parallel/ctr/ctr.go
index 442db1502..e8c1292b8 100644
--- a/pkg/parallel/parallel_linux.go
+++ b/pkg/parallel/ctr/ctr.go
@@ -1,11 +1,10 @@
-package parallel
+package ctr
import (
"context"
- "sync"
"github.com/containers/podman/v2/libpod"
- "github.com/pkg/errors"
+ "github.com/containers/podman/v2/pkg/parallel"
"github.com/sirupsen/logrus"
)
@@ -14,44 +13,28 @@ import (
// If no error is returned, each container specified in ctrs will have an entry
// in the resulting map; containers with no error will be set to nil.
func ContainerOp(ctx context.Context, ctrs []*libpod.Container, applyFunc func(*libpod.Container) error) (map[*libpod.Container]error, error) {
- jobControlLock.RLock()
- defer jobControlLock.RUnlock()
-
// We could use a sync.Map but given Go's lack of generic I'd rather
// just use a lock on a normal map...
// The expectation is that most of the time is spent in applyFunc
// anyways.
var (
- errMap = make(map[*libpod.Container]error)
- errLock sync.Mutex
- allDone sync.WaitGroup
+ errMap = make(map[*libpod.Container]<-chan error)
)
for _, ctr := range ctrs {
- // Block until a thread is available
- if err := jobControl.Acquire(ctx, 1); err != nil {
- return nil, errors.Wrapf(err, "error acquiring job control semaphore")
- }
-
- allDone.Add(1)
-
c := ctr
- go func() {
- logrus.Debugf("Launching job on container %s", c.ID())
-
- err := applyFunc(c)
- errLock.Lock()
- errMap[c] = err
- errLock.Unlock()
-
- allDone.Done()
- jobControl.Release(1)
- }()
+ logrus.Debugf("Starting parallel job on container %s", c.ID())
+ errChan := parallel.Enqueue(ctx, func() error {
+ return applyFunc(c)
+ })
+ errMap[c] = errChan
}
- allDone.Wait()
+ finalErr := make(map[*libpod.Container]error)
+ for ctr, errChan := range errMap {
+ err := <-errChan
+ finalErr[ctr] = err
+ }
- return errMap, nil
+ return finalErr, nil
}
-
-// TODO: Add an Enqueue() function that returns a promise
diff --git a/pkg/parallel/parallel.go b/pkg/parallel/parallel.go
index c9e4da50d..4da7e0f89 100644
--- a/pkg/parallel/parallel.go
+++ b/pkg/parallel/parallel.go
@@ -1,6 +1,7 @@
package parallel
import (
+ "context"
"sync"
"github.com/pkg/errors"
@@ -42,3 +43,32 @@ func SetMaxThreads(threads uint) error {
func GetMaxThreads() uint {
return numThreads
}
+
+// Enqueue adds a single function to the parallel jobs queue. This function will
+// be run when an unused thread is available.
+// Returns a receive-only error channel that will return the error (if any) from
+// the provided function fn when fn has finished executing. The channel will be
+// closed after this.
+func Enqueue(ctx context.Context, fn func() error) <-chan error {
+ retChan := make(chan error)
+
+ go func() {
+ jobControlLock.RLock()
+ defer jobControlLock.RUnlock()
+
+ defer close(retChan)
+
+ if err := jobControl.Acquire(ctx, 1); err != nil {
+ retChan <- errors.Wrapf(err, "error acquiring job control semaphore")
+ return
+ }
+
+ err := fn()
+
+ jobControl.Release(1)
+
+ retChan <- err
+ }()
+
+ return retChan
+}
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index 189434780..6d03afb7a 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -3,6 +3,7 @@
package varlinkapi
import (
+ "context"
"encoding/json"
"fmt"
"strconv"
@@ -207,7 +208,7 @@ func (i *VarlinkAPI) KillPod(call iopodman.VarlinkCall, name string, signal int6
if err != nil {
return call.ReplyPodNotFound(name, err.Error())
}
- ctrErrs, err := pod.Kill(killSignal)
+ ctrErrs, err := pod.Kill(context.TODO(), killSignal)
callErr := handlePodCall(call, pod, ctrErrs, err)
if callErr != nil {
return err
@@ -221,7 +222,7 @@ func (i *VarlinkAPI) PausePod(call iopodman.VarlinkCall, name string) error {
if err != nil {
return call.ReplyPodNotFound(name, err.Error())
}
- ctrErrs, err := pod.Pause()
+ ctrErrs, err := pod.Pause(context.TODO())
callErr := handlePodCall(call, pod, ctrErrs, err)
if callErr != nil {
return err
@@ -235,7 +236,7 @@ func (i *VarlinkAPI) UnpausePod(call iopodman.VarlinkCall, name string) error {
if err != nil {
return call.ReplyPodNotFound(name, err.Error())
}
- ctrErrs, err := pod.Unpause()
+ ctrErrs, err := pod.Unpause(context.TODO())
callErr := handlePodCall(call, pod, ctrErrs, err)
if callErr != nil {
return err