Add podman play kube --annotation

Allow users to add annotions in the podman play kube command.
This PR Also fixes the fact that annotations in the pod spec were
not being passed down to containers.

Fixes: https://github.com/containers/podman/issues/12968

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2022-03-09 17:30:01 -05:00
parent acfcecf2ae
commit feaa1a134a
10 changed files with 93 additions and 19 deletions

View File

@ -4,6 +4,7 @@ import (
"fmt"
"net"
"os"
"strings"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
@ -31,7 +32,8 @@ type playKubeOptionsWrapper struct {
}
var (
macs []string
annotations []string
macs []string
// https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
defaultSeccompRoot = "/var/lib/kubelet/seccomp"
kubeOptions = playKubeOptionsWrapper{}
@ -61,6 +63,13 @@ func init() {
flags := kubeCmd.Flags()
flags.SetNormalizeFunc(utils.AliasFlags)
annotationFlagName := "annotation"
flags.StringSliceVar(
&annotations,
annotationFlagName, []string{},
"Add annotations to pods (key=value)",
)
_ = kubeCmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone)
credsFlagName := "creds"
flags.StringVar(&kubeOptions.CredentialsCLI, credsFlagName, "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
_ = kubeCmd.RegisterFlagCompletionFunc(credsFlagName, completion.AutocompleteNone)
@ -161,6 +170,16 @@ func kube(cmd *cobra.Command, args []string) error {
kubeOptions.Password = creds.Password
}
for _, annotation := range annotations {
splitN := strings.SplitN(annotation, "=", 2)
if len(splitN) > 2 {
return errors.Errorf("annotation %q must include an '=' sign", annotation)
}
if kubeOptions.Annotations == nil {
kubeOptions.Annotations = make(map[string]string)
}
kubeOptions.Annotations[splitN[0]] = splitN[1]
}
yamlfile := args[0]
if yamlfile == "-" {
yamlfile = "/dev/stdin"

View File

@ -105,6 +105,11 @@ and as a result environment variable `FOO` will be set to `bar` for container `c
## OPTIONS
#### **--annotation**=*key=value*
Add an annotation to the container or pod. The format is key=value.
The **--annotation** option can be set multiple times.
#### **--authfile**=*path*
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.

View File

@ -23,14 +23,15 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
Network []string `schema:"network"`
TLSVerify bool `schema:"tlsVerify"`
LogDriver string `schema:"logDriver"`
LogOptions []string `schema:"logOptions"`
Start bool `schema:"start"`
StaticIPs []string `schema:"staticIPs"`
StaticMACs []string `schema:"staticMACs"`
NoHosts bool `schema:"noHosts"`
Annotations map[string]string `schema:"annotations"`
Network []string `schema:"network"`
TLSVerify bool `schema:"tlsVerify"`
LogDriver string `schema:"logDriver"`
LogOptions []string `schema:"logOptions"`
Start bool `schema:"start"`
StaticIPs []string `schema:"staticIPs"`
StaticMACs []string `schema:"staticMACs"`
NoHosts bool `schema:"noHosts"`
}{
TLSVerify: true,
Start: true,
@ -97,16 +98,17 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.PlayKubeOptions{
Authfile: authfile,
Username: username,
Password: password,
Networks: query.Network,
NoHosts: query.NoHosts,
Quiet: true,
LogDriver: query.LogDriver,
LogOptions: query.LogOptions,
StaticIPs: staticIPs,
StaticMACs: staticMACs,
Annotations: query.Annotations,
Authfile: authfile,
Username: username,
Password: password,
Networks: query.Network,
NoHosts: query.NoHosts,
Quiet: true,
LogDriver: query.LogDriver,
LogOptions: query.LogOptions,
StaticIPs: staticIPs,
StaticMACs: staticMACs,
}
if _, found := r.URL.Query()["tlsVerify"]; found {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)

View File

@ -7,6 +7,8 @@ import (
//go:generate go run ../generator/generator.go KubeOptions
// KubeOptions are optional options for replaying kube YAML files
type KubeOptions struct {
// Annotations - Annotations to add to Pods
Annotations map[string]string
// Authfile - path to an authentication file.
Authfile *string
// CertDir - to a directory containing TLS certifications and keys.

View File

@ -18,6 +18,21 @@ func (o *KubeOptions) ToParams() (url.Values, error) {
return util.ToParams(o)
}
// WithAnnotations set field Annotations to given value
func (o *KubeOptions) WithAnnotations(value map[string]string) *KubeOptions {
o.Annotations = value
return o
}
// GetAnnotations returns value of field Annotations
func (o *KubeOptions) GetAnnotations() map[string]string {
if o.Annotations == nil {
var z map[string]string
return z
}
return o.Annotations
}
// WithAuthfile set field Authfile to given value
func (o *KubeOptions) WithAuthfile(value string) *KubeOptions {
o.Authfile = &value

View File

@ -8,6 +8,8 @@ import (
// PlayKubeOptions controls playing kube YAML files.
type PlayKubeOptions struct {
// Annotations - Annotations to add to Pods
Annotations map[string]string
// Authfile - path to an authentication file.
Authfile string
// Indicator to build all images with Containerfile or Dockerfile

View File

@ -79,6 +79,13 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
podTemplateSpec.Spec = podYAML.Spec
for name, val := range options.Annotations {
if podYAML.Annotations == nil {
podYAML.Annotations = make(map[string]string)
}
podYAML.Annotations[name] = val
}
r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options, &ipIndex, podYAML.Annotations, configMaps)
if err != nil {
return nil, err

View File

@ -16,6 +16,9 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit
if len(opts.LogOptions) > 0 {
options.WithLogOptions(opts.LogOptions)
}
if opts.Annotations != nil {
options.WithAnnotations(opts.Annotations)
}
options.WithNoHosts(opts.NoHosts)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
options.WithSkipTLSVerify(s == types.OptionalBoolTrue)

View File

@ -277,7 +277,13 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
}
annotations := make(map[string]string)
if opts.Annotations != nil {
annotations = opts.Annotations
}
if opts.PodInfraID != "" {
if annotations == nil {
}
annotations[ann.SandboxID] = opts.PodInfraID
annotations[ann.ContainerType] = ann.ContainerTypeContainer
}

View File

@ -220,3 +220,16 @@ _EOF
run_podman pod rm -t 0 -f test_pod
run_podman rmi -f userimage:latest
}
@test "podman play --annotation" {
TESTDIR=$PODMAN_TMPDIR/testdir
RANDOMSTRING=$(random_string 15)
mkdir -p $TESTDIR
echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml
run_podman play kube --annotation "name=$RANDOMSTRING" $PODMAN_TMPDIR/test.yaml
run_podman inspect --format "{{ .Config.Annotations }}" test_pod-test
is "$output" ".*name:$RANDOMSTRING" "Annotation should be added to pod"
run_podman stop -a -t 0
run_podman pod rm -t 0 -f test_pod
}