summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/play/kube.go15
-rw-r--r--docs/source/markdown/podman-play-kube.1.md4
-rw-r--r--pkg/api/handlers/libpod/play.go37
-rw-r--r--pkg/api/server/register_play.go6
-rw-r--r--pkg/bindings/play/types.go2
-rw-r--r--pkg/bindings/play/types_kube_options.go16
-rw-r--r--pkg/domain/entities/play.go2
-rw-r--r--pkg/domain/infra/abi/play.go10
-rw-r--r--pkg/domain/infra/tunnel/play.go3
-rw-r--r--pkg/rootless/rootless.go4
-rw-r--r--pkg/rootless/rootless_test.go57
-rw-r--r--test/e2e/play_kube_test.go13
12 files changed, 151 insertions, 18 deletions
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index 30d6d86f0..fe382bdfb 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -2,6 +2,7 @@ package pods
import (
"fmt"
+ "net"
"os"
"github.com/containers/common/pkg/auth"
@@ -27,6 +28,7 @@ type playKubeOptionsWrapper struct {
}
var (
+ macs []string
// https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
defaultSeccompRoot = "/var/lib/kubelet/seccomp"
kubeOptions = playKubeOptionsWrapper{}
@@ -61,6 +63,10 @@ func init() {
flags.StringVar(&kubeOptions.CredentialsCLI, credsFlagName, "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
_ = kubeCmd.RegisterFlagCompletionFunc(credsFlagName, completion.AutocompleteNone)
+ staticMACFlagName := "mac-address"
+ flags.StringSliceVar(&macs, staticMACFlagName, nil, "Static MAC addresses to assign to the pods")
+ _ = kubeCmd.RegisterFlagCompletionFunc(staticMACFlagName, completion.AutocompleteNone)
+
networkFlagName := "network"
flags.StringVar(&kubeOptions.Network, networkFlagName, "", "Connect pod to CNI network(s)")
_ = kubeCmd.RegisterFlagCompletionFunc(networkFlagName, common.AutocompleteNetworkFlag)
@@ -128,6 +134,15 @@ func kube(cmd *cobra.Command, args []string) error {
if yamlfile == "-" {
yamlfile = "/dev/stdin"
}
+
+ for _, mac := range macs {
+ m, err := net.ParseMAC(mac)
+ if err != nil {
+ return err
+ }
+ kubeOptions.StaticMACs = append(kubeOptions.StaticMACs, m)
+ }
+
report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), yamlfile, kubeOptions.PlayKubeOptions)
if err != nil {
return err
diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md
index 1074c27f8..ab2019139 100644
--- a/docs/source/markdown/podman-play-kube.1.md
+++ b/docs/source/markdown/podman-play-kube.1.md
@@ -70,6 +70,10 @@ Assign a static ip address to the pod. This option can be specified several time
Set logging driver for all created containers.
+#### **\-\-mac-address**=*MAC address*
+
+Assign a static mac address to the pod. This option can be specified several times when play kube creates more than one pod.
+
#### **\-\-network**=*networks*, **\-\-net**
A comma-separated list of the names of CNI networks the pod should join.
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index 96f572a8b..90332924c 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -21,11 +21,12 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Network string `schema:"network"`
- TLSVerify bool `schema:"tlsVerify"`
- LogDriver string `schema:"logDriver"`
- Start bool `schema:"start"`
- StaticIPs []string `schema:"staticIPs"`
+ Network string `schema:"network"`
+ TLSVerify bool `schema:"tlsVerify"`
+ LogDriver string `schema:"logDriver"`
+ Start bool `schema:"start"`
+ StaticIPs []string `schema:"staticIPs"`
+ StaticMACs []string `schema:"staticMACs"`
}{
TLSVerify: true,
Start: true,
@@ -48,6 +49,17 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
staticIPs = append(staticIPs, ip)
}
+ staticMACs := make([]net.HardwareAddr, 0, len(query.StaticMACs))
+ for _, macString := range query.StaticMACs {
+ mac, err := net.ParseMAC(macString)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ err)
+ return
+ }
+ staticMACs = append(staticMACs, mac)
+ }
+
// Fetch the K8s YAML file from the body, and copy it to a temp file.
tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
if err != nil {
@@ -78,13 +90,14 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.PlayKubeOptions{
- Authfile: authfile,
- Username: username,
- Password: password,
- Network: query.Network,
- Quiet: true,
- LogDriver: query.LogDriver,
- StaticIPs: staticIPs,
+ Authfile: authfile,
+ Username: username,
+ Password: password,
+ Network: query.Network,
+ Quiet: true,
+ LogDriver: query.LogDriver,
+ StaticIPs: staticIPs,
+ StaticMACs: staticMACs,
}
if _, found := r.URL.Query()["tlsVerify"]; found {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go
index da37abb70..c51301aa8 100644
--- a/pkg/api/server/register_play.go
+++ b/pkg/api/server/register_play.go
@@ -40,6 +40,12 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error {
// description: Static IPs used for the pods.
// items:
// type: string
+ // - in: query
+ // name: staticMACs
+ // type: array
+ // description: Static MACs used for the pods.
+ // items:
+ // type: string
// - in: body
// name: request
// description: Kubernetes YAML file.
diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go
index 6598ec3c2..52a72c7b6 100644
--- a/pkg/bindings/play/types.go
+++ b/pkg/bindings/play/types.go
@@ -27,6 +27,8 @@ type KubeOptions struct {
SeccompProfileRoot *string
// StaticIPs - Static IP address used by the pod(s).
StaticIPs *[]net.IP
+ // StaticMACs - Static MAC address used by the pod(s).
+ StaticMACs *[]net.HardwareAddr
// ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
ConfigMaps *[]string
// LogDriver for the container. For example: journald
diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go
index a1786f553..4cc7d6f21 100644
--- a/pkg/bindings/play/types_kube_options.go
+++ b/pkg/bindings/play/types_kube_options.go
@@ -181,6 +181,22 @@ func (o *KubeOptions) GetStaticIPs() []net.IP {
return *o.StaticIPs
}
+// WithStaticMACs
+func (o *KubeOptions) WithStaticMACs(value []net.HardwareAddr) *KubeOptions {
+ v := &value
+ o.StaticMACs = v
+ return o
+}
+
+// GetStaticMACs
+func (o *KubeOptions) GetStaticMACs() []net.HardwareAddr {
+ var staticMACs []net.HardwareAddr
+ if o.StaticMACs == nil {
+ return staticMACs
+ }
+ return *o.StaticMACs
+}
+
// WithConfigMaps
func (o *KubeOptions) WithConfigMaps(value []string) *KubeOptions {
v := &value
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index c69bb0867..89dfc08e9 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -30,6 +30,8 @@ type PlayKubeOptions struct {
SeccompProfileRoot string
// StaticIPs - Static IP address used by the pod(s).
StaticIPs []net.IP
+ // StaticMACs - Static MAC address used by the pod(s).
+ StaticMACs []net.HardwareAddr
// ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
ConfigMaps []string
// LogDriver for the container. For example: journald
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index d235c9ed8..64e7f208c 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -198,11 +198,17 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
if len(options.StaticIPs) > *ipIndex {
p.StaticIP = &options.StaticIPs[*ipIndex]
- *ipIndex++
} else if len(options.StaticIPs) > 0 {
- // only warn if the user has set at least one ip ip
+ // only warn if the user has set at least one ip
logrus.Warn("No more static ips left using a random one")
}
+ if len(options.StaticMACs) > *ipIndex {
+ p.StaticMAC = &options.StaticMACs[*ipIndex]
+ } else if len(options.StaticIPs) > 0 {
+ // only warn if the user has set at least one mac
+ logrus.Warn("No more static macs left using a random one")
+ }
+ *ipIndex++
// Create the Pod
pod, err := generate.MakePod(p, ic.Libpod)
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index e52e1a1f7..e66ff0308 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -11,7 +11,8 @@ import (
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
- options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot).WithStaticIPs(opts.StaticIPs)
+ options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot)
+ options.WithStaticIPs(opts.StaticIPs).WithStaticMACs(opts.StaticMACs)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
options.WithSkipTLSVerify(s == types.OptionalBoolTrue)
diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go
index 0b9d719a9..93b4e2e9f 100644
--- a/pkg/rootless/rootless.go
+++ b/pkg/rootless/rootless.go
@@ -137,7 +137,7 @@ func GetAvailableGids() (int64, error) {
// It assumes availableMappings is sorted by ID.
func findIDInMappings(id int64, availableMappings []user.IDMap) *user.IDMap {
i := sort.Search(len(availableMappings), func(i int) bool {
- return availableMappings[i].ID >= id
+ return availableMappings[i].ID <= id
})
if i < 0 || i >= len(availableMappings) {
return nil
@@ -157,7 +157,7 @@ func MaybeSplitMappings(mappings []spec.LinuxIDMapping, availableMappings []user
overflow.Size = 0
consumed := 0
sort.Slice(availableMappings, func(i, j int) bool {
- return availableMappings[i].ID < availableMappings[j].ID
+ return availableMappings[i].ID > availableMappings[j].ID
})
for {
cur := overflow
diff --git a/pkg/rootless/rootless_test.go b/pkg/rootless/rootless_test.go
index ef574099c..fe9b23cdf 100644
--- a/pkg/rootless/rootless_test.go
+++ b/pkg/rootless/rootless_test.go
@@ -98,4 +98,61 @@ func TestMaybeSplitMappings(t *testing.T) {
if !reflect.DeepEqual(newMappings, desiredMappings) {
t.Fatal("wrong mappings generated")
}
+
+ mappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 4,
+ },
+ }
+ desiredMappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 1,
+ },
+ {
+ ContainerID: 1,
+ HostID: 1,
+ Size: 1,
+ },
+ {
+ ContainerID: 2,
+ HostID: 2,
+ Size: 1,
+ },
+ {
+ ContainerID: 3,
+ HostID: 3,
+ Size: 1,
+ },
+ }
+ availableMappings = []user.IDMap{
+ {
+ ID: 0,
+ ParentID: 0,
+ Count: 1,
+ },
+ {
+ ID: 1,
+ ParentID: 1,
+ Count: 1,
+ },
+ {
+ ID: 2,
+ ParentID: 2,
+ Count: 1,
+ },
+ {
+ ID: 3,
+ ParentID: 3,
+ Count: 1,
+ },
+ }
+
+ newMappings = MaybeSplitMappings(mappings, availableMappings)
+ if !reflect.DeepEqual(newMappings, desiredMappings) {
+ t.Fatal("wrong mappings generated")
+ }
}
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index f89da4c05..836fbe1ee 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -1717,7 +1717,7 @@ spec:
}
})
- It("podman play kube --ip", func() {
+ It("podman play kube --ip and --mac-address", func() {
var i, numReplicas int32
numReplicas = 3
deployment := getDeployment(withReplicas(numReplicas))
@@ -1735,6 +1735,10 @@ spec:
for _, ip := range ips {
playArgs = append(playArgs, "--ip", ip)
}
+ macs := []string{"e8:d8:82:c9:80:40", "e8:d8:82:c9:80:50", "e8:d8:82:c9:80:60"}
+ for _, mac := range macs {
+ playArgs = append(playArgs, "--mac-address", mac)
+ }
kube := podmanTest.Podman(append(playArgs, kubeYaml))
kube.WaitWithDefaultTimeout()
@@ -1747,6 +1751,13 @@ spec:
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.OutputToString()).To(Equal(ips[i]))
}
+
+ for i = 0; i < numReplicas; i++ {
+ inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[i]), "--format", "{{ .NetworkSettings.Networks." + net + ".MacAddress }}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(Equal(macs[i]))
+ }
})
It("podman play kube test with network portbindings", func() {