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 --no-trunc flag to maintain original annotation length #19102

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
3 changes: 3 additions & 0 deletions cmd/podman/kube/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ func generateFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig) {
flags.Int32VarP(&generateOptions.Replicas, replicasFlagName, "r", 1, "Set the replicas number for Deployment kind")
_ = cmd.RegisterFlagCompletionFunc(replicasFlagName, completion.AutocompleteNone)

noTruncAnnotationsFlagName := "no-trunc"
flags.BoolVar(&generateOptions.UseLongAnnotations, noTruncAnnotationsFlagName, false, "Don't truncate annotations to Kubernetes length (63 chars)")

flags.SetNormalizeFunc(utils.AliasFlags)
}

Expand Down
5 changes: 4 additions & 1 deletion cmd/podman/kube/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ func playFlags(cmd *cobra.Command) {
flags.StringSliceVar(&playOptions.ConfigMaps, configmapFlagName, []string{}, "`Pathname` of a YAML file containing a kubernetes configmap")
_ = cmd.RegisterFlagCompletionFunc(configmapFlagName, completion.AutocompleteDefault)

noTruncFlagName := "no-trunc"
flags.BoolVar(&playOptions.UseLongAnnotations, noTruncFlagName, false, "Use annotations that are not truncated to the Kubernetes maximum length of 63 characters")

if !registry.IsRemote() {
certDirFlagName := "cert-dir"
flags.StringVar(&playOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys")
Expand Down Expand Up @@ -240,7 +243,7 @@ func play(cmd *cobra.Command, args []string) error {
playOptions.Annotations = make(map[string]string)
}
annotation := splitN[1]
if len(annotation) > define.MaxKubeAnnotation {
if len(annotation) > define.MaxKubeAnnotation && !playOptions.UseLongAnnotations {
return fmt.Errorf("annotation exceeds maximum size, %d, of kubernetes annotation: %s", define.MaxKubeAnnotation, annotation)
}
playOptions.Annotations[splitN[0]] = annotation
Expand Down
5 changes: 5 additions & 0 deletions docs/source/markdown/podman-kube-generate.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ Note that the generated Kubernetes YAML file can be used to re-run the deploymen

Output to the given file instead of STDOUT. If the file already exists, `kube generate` refuses to replace it and returns an error.

#### **--no-trunc**

Don't truncate annotations to the Kubernetes maximum length of 63 characters.
Note: enabling this flag means the generated YAML file is not Kubernetes compatible and can only be used with `podman kube play`

#### **--replicas**, **-r**=*replica count*

The value to set `replicas` to when generating a **Deployment** kind.
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-kube-play.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ When no network option is specified and *host* network mode is not configured in

This option conflicts with host added in the Kubernetes YAML.

#### **--no-trunc**

Use annotations that are not truncated to the Kubernetes maximum length of 63 characters

#### **--publish**=*[[ip:][hostPort]:]containerPort[/protocol]*

Define or override a port definition in the YAML file.
Expand Down
36 changes: 18 additions & 18 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ import (

// GenerateForKube takes a slice of libpod containers and generates
// one v1.Pod description that includes just a single container.
func GenerateForKube(ctx context.Context, ctrs []*Container, getService bool) (*v1.Pod, error) {
func GenerateForKube(ctx context.Context, ctrs []*Container, getService, useLongAnnotations bool) (*v1.Pod, error) {
// Generate the v1.Pod yaml description
return simplePodWithV1Containers(ctx, ctrs, getService)
return simplePodWithV1Containers(ctx, ctrs, getService, useLongAnnotations)
}

// GenerateForKube takes a slice of libpod containers and generates
// one v1.Pod description
func (p *Pod) GenerateForKube(ctx context.Context, getService bool) (*v1.Pod, []v1.ServicePort, error) {
func (p *Pod) GenerateForKube(ctx context.Context, getService, useLongAnnotations bool) (*v1.Pod, []v1.ServicePort, error) {
// Generate the v1.Pod yaml description
var (
ports []v1.ContainerPort
Expand Down Expand Up @@ -91,7 +91,7 @@ func (p *Pod) GenerateForKube(ctx context.Context, getService bool) (*v1.Pod, []
hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
hostUsers = infraContainer.IDMappings().HostUIDMapping && infraContainer.IDMappings().HostGIDMapping
}
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork, hostUsers, getService)
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork, hostUsers, getService, useLongAnnotations)
if err != nil {
return nil, servicePorts, err
}
Expand Down Expand Up @@ -370,9 +370,9 @@ func newServicePortState() servicePortState {
}
}

func TruncateKubeAnnotation(str string) string {
func truncateKubeAnnotation(str string, useLongAnnotations bool) string {
str = strings.TrimSpace(str)
if utf8.RuneCountInString(str) < define.MaxKubeAnnotation {
if useLongAnnotations || utf8.RuneCountInString(str) < define.MaxKubeAnnotation {
return str
}
trunc := string([]rune(str)[:define.MaxKubeAnnotation])
Expand Down Expand Up @@ -426,7 +426,7 @@ func containersToServicePorts(containers []v1.Container) ([]v1.ServicePort, erro
return sps, nil
}

func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork, hostUsers, getService bool) (*v1.Pod, error) {
func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork, hostUsers, getService, useLongAnnotations bool) (*v1.Pod, error) {
deDupPodVolumes := make(map[string]*v1.Volume)
first := true
podContainers := make([]v1.Container, 0, len(containers))
Expand All @@ -445,11 +445,11 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
if define.IsReservedAnnotation(k) || annotations.IsReservedAnnotation(k) {
continue
}
podAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = TruncateKubeAnnotation(v)
podAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = truncateKubeAnnotation(v, useLongAnnotations)
}
// Convert auto-update labels into kube annotations
for k, v := range getAutoUpdateAnnotations(ctr.Name(), ctr.Labels()) {
podAnnotations[k] = TruncateKubeAnnotation(v)
for k, v := range getAutoUpdateAnnotations(ctr.Name(), ctr.Labels(), useLongAnnotations) {
podAnnotations[k] = truncateKubeAnnotation(v, useLongAnnotations)
}
isInit := ctr.IsInitCtr()
// Since hostname is only set at pod level, set the hostname to the hostname of the first container we encounter
Expand All @@ -466,7 +466,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
return nil, err
}
for k, v := range annotations {
podAnnotations[define.BindMountPrefix] = TruncateKubeAnnotation(k + ":" + v)
podAnnotations[define.BindMountPrefix] = truncateKubeAnnotation(k+":"+v, useLongAnnotations)
}
// Since port bindings for the pod are handled by the
// infra container, wipe them here only if we are sharing the net namespace
Expand Down Expand Up @@ -574,7 +574,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta

// simplePodWithV1Containers is a function used by inspect when kube yaml needs to be generated
// for a single container. we "insert" that container description in a pod.
func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getService bool) (*v1.Pod, error) {
func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getService, useLongAnnotations bool) (*v1.Pod, error) {
kubeCtrs := make([]v1.Container, 0, len(ctrs))
kubeInitCtrs := []v1.Container{}
kubeVolumes := make([]v1.Volume, 0)
Expand All @@ -591,12 +591,12 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
if define.IsReservedAnnotation(k) || annotations.IsReservedAnnotation(k) {
continue
}
kubeAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = TruncateKubeAnnotation(v)
kubeAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = truncateKubeAnnotation(v, useLongAnnotations)
}

// Convert auto-update labels into kube annotations
for k, v := range getAutoUpdateAnnotations(ctr.Name(), ctr.Labels()) {
kubeAnnotations[k] = TruncateKubeAnnotation(v)
for k, v := range getAutoUpdateAnnotations(ctr.Name(), ctr.Labels(), useLongAnnotations) {
kubeAnnotations[k] = truncateKubeAnnotation(v, useLongAnnotations)
}

isInit := ctr.IsInitCtr()
Expand Down Expand Up @@ -643,7 +643,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
return nil, err
}
for k, v := range annotations {
kubeAnnotations[define.BindMountPrefix] = TruncateKubeAnnotation(k + ":" + v)
kubeAnnotations[define.BindMountPrefix] = truncateKubeAnnotation(k+":"+v, useLongAnnotations)
}
if isInit {
kubeInitCtrs = append(kubeInitCtrs, kubeCtr)
Expand Down Expand Up @@ -1266,7 +1266,7 @@ func removeUnderscores(s string) string {

// getAutoUpdateAnnotations searches for auto-update container labels
// and returns them as kube annotations
func getAutoUpdateAnnotations(ctrName string, ctrLabels map[string]string) map[string]string {
func getAutoUpdateAnnotations(ctrName string, ctrLabels map[string]string, useLongAnnotations bool) map[string]string {
autoUpdateLabel := "io.containers.autoupdate"
annotations := make(map[string]string)

Expand All @@ -1276,7 +1276,7 @@ func getAutoUpdateAnnotations(ctrName string, ctrLabels map[string]string) map[s
// since labels can variate between containers within a pod, they will be
// identified with the container name when converted into kube annotations
kc := fmt.Sprintf("%s/%s", k, ctrName)
annotations[kc] = TruncateKubeAnnotation(v)
annotations[kc] = truncateKubeAnnotation(v, useLongAnnotations)
}
}

Expand Down
8 changes: 7 additions & 1 deletion pkg/api/handlers/libpod/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) {
Service bool `schema:"service"`
Type string `schema:"type"`
Replicas int32 `schema:"replicas"`
NoTrunc bool `schema:"noTrunc"`
}{
// Defaults would go here.
Replicas: 1,
Expand All @@ -115,7 +116,12 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) {
}

containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.GenerateKubeOptions{Service: query.Service, Type: generateType, Replicas: query.Replicas}
options := entities.GenerateKubeOptions{
Service: query.Service,
Type: generateType,
Replicas: query.Replicas,
UseLongAnnotations: query.NoTrunc,
}
report, err := containerEngine.GenerateKube(r.Context(), query.Names, options)
if err != nil {
utils.Error(w, http.StatusInternalServerError, fmt.Errorf("generating YAML: %w", err))
Expand Down
32 changes: 17 additions & 15 deletions pkg/api/handlers/libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {
StaticMACs []string `schema:"staticMACs"`
NoHosts bool `schema:"noHosts"`
PublishPorts []string `schema:"publishPorts"`
NoTrunc bool `schema:"noTrunc"`
Wait bool `schema:"wait"`
ServiceContainer bool `schema:"serviceContainer"`
}{
Expand Down Expand Up @@ -85,21 +86,22 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {

containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.PlayKubeOptions{
Annotations: query.Annotations,
Authfile: authfile,
Username: username,
Password: password,
Networks: query.Network,
NoHosts: query.NoHosts,
Quiet: true,
LogDriver: logDriver,
LogOptions: query.LogOptions,
StaticIPs: staticIPs,
StaticMACs: staticMACs,
IsRemote: true,
PublishPorts: query.PublishPorts,
Wait: query.Wait,
ServiceContainer: query.ServiceContainer,
Annotations: query.Annotations,
Authfile: authfile,
Username: username,
Password: password,
Networks: query.Network,
NoHosts: query.NoHosts,
Quiet: true,
LogDriver: logDriver,
LogOptions: query.LogOptions,
StaticIPs: staticIPs,
StaticMACs: staticMACs,
IsRemote: true,
PublishPorts: query.PublishPorts,
Wait: query.Wait,
ServiceContainer: query.ServiceContainer,
UseLongAnnotations: query.NoTrunc,
}
if _, found := r.URL.Query()["tlsVerify"]; found {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
Expand Down
10 changes: 10 additions & 0 deletions pkg/api/server/register_kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error {
// type: boolean
// default: false
// description: Clean up all objects created when a SIGTERM is received or pods exit.
// - in: query
// name: noTrunc
// type: boolean
// default: false
// description: use annotations that are not truncated to the Kubernetes maximum length of 63 characters
// - in: body
// name: request
// description: Kubernetes YAML file.
Expand Down Expand Up @@ -125,6 +130,11 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error {
// format: int32
// default: 0
// description: Set the replica number for Deployment kind.
// - in: query
// name: noTrunc
// type: boolean
// default: false
// description: don't truncate annotations to the Kubernetes maximum length of 63 characters
// produces:
// - text/vnd.yaml
// - application/json
Expand Down
2 changes: 2 additions & 0 deletions pkg/bindings/generate/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ type KubeOptions struct {
Type *string
// Replicas - the value to set in the replicas field for a Deployment
Replicas *int32
// NoTrunc - don't truncate annotations to the Kubernetes maximum length of 63 characters
NoTrunc *bool
}

// SystemdOptions are optional options for generating systemd files
Expand Down
15 changes: 15 additions & 0 deletions pkg/bindings/generate/types_kube_options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/bindings/kube/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type PlayOptions struct {
LogOptions *[]string
// Start - don't start the pod if false
Start *bool
// NoTrunc - use annotations that were not truncated to the
// Kubernetes maximum of 63 characters
NoTrunc *bool
// Userns - define the user namespace to use.
Userns *string
// Force - remove volumes on --down
Expand Down
15 changes: 15 additions & 0 deletions pkg/bindings/kube/types_play_options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkg/domain/entities/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type GenerateKubeOptions struct {
Type string
// Replicas - the value to set in the replicas field for a Deployment
Replicas int32
// UseLongAnnotations - don't truncate annotations to the Kubernetes maximum length of 63 characters
UseLongAnnotations bool
}

type KubeGenerateOptions = GenerateKubeOptions
Expand Down
3 changes: 3 additions & 0 deletions pkg/domain/entities/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ type PlayKubeOptions struct {
Start types.OptionalBool
// ServiceContainer - creates a service container that is started before and is stopped after all pods.
ServiceContainer bool
// UseLongAnnotations - use annotations that were not truncated to the
// Kubernetes maximum length of 63 characters
UseLongAnnotations bool
// Userns - define the user namespace to use.
Userns string
// IsRemote - was the request triggered by running podman-remote
Expand Down
4 changes: 2 additions & 2 deletions pkg/domain/infra/abi/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,

// Generate the kube pods from containers.
if len(ctrs) >= 1 {
po, err := libpod.GenerateForKube(ctx, ctrs, options.Service)
po, err := libpod.GenerateForKube(ctx, ctrs, options.Service, options.UseLongAnnotations)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -273,7 +273,7 @@ func getKubePods(ctx context.Context, pods []*libpod.Pod, options entities.Gener
svcs := [][]byte{}

for _, p := range pods {
po, sp, err := p.GenerateForKube(ctx, options.Service)
po, sp, err := p.GenerateForKube(ctx, options.Service, options.UseLongAnnotations)
if err != nil {
return nil, nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
podTemplateSpec.Spec = podYAML.Spec
for name, val := range podYAML.Annotations {
if len(val) > define.MaxKubeAnnotation {
return nil, fmt.Errorf("invalid annotation %q=%q value length exceeds Kubernetetes max %d", name, val, define.MaxKubeAnnotation)
if len(val) > define.MaxKubeAnnotation && !options.UseLongAnnotations {
return nil, fmt.Errorf("annotation %q=%q value length exceeds Kubernetes max %d", name, val, define.MaxKubeAnnotation)
}
}
for name, val := range options.Annotations {
Expand Down
3 changes: 2 additions & 1 deletion pkg/domain/infra/tunnel/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
//
// Note: Caller is responsible for closing returned Reader
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, opts entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
options := new(generate.KubeOptions).WithService(opts.Service).WithType(opts.Type).WithReplicas(opts.Replicas)
options := new(generate.KubeOptions).WithService(opts.Service).WithType(opts.Type).WithReplicas(opts.Replicas).WithNoTrunc(opts.UseLongAnnotations)
return generate.Kube(ic.ClientCtx, nameOrIDs, options)
}

Expand All @@ -73,6 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, opts en
options.WithStart(start == types.OptionalBoolTrue)
}
options.WithPublishPorts(opts.PublishPorts)
options.WithNoTrunc(opts.UseLongAnnotations)
return play.KubeWithBody(ic.ClientCtx, body, options)
}

Expand Down
Loading