Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --mac-address to podman play kube #10208

Merged
merged 1 commit into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cmd/podman/play/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pods

import (
"fmt"
"net"
"os"

"github.com/containers/common/pkg/auth"
Expand All @@ -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{}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-play-kube.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
37 changes: 25 additions & 12 deletions pkg/api/handlers/libpod/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/server/register_play.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions pkg/bindings/play/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions pkg/bindings/play/types_kube_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,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)
Expand Down
3 changes: 2 additions & 1 deletion pkg/domain/infra/tunnel/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 12 additions & 1 deletion test/e2e/play_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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()
Expand All @@ -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() {
Expand Down