feat(crd): add dual-format Args field supporting map and list

Add a custom Args type that accepts both a key-value map and a flat
CLI-style list, normalizing internally to []string so downstream code
requires no changes.

- Args: new []string alias with UnmarshalJSON (map + list) and
  MarshalJSON (map) — keys are sorted for deterministic ordering
- CRD schema: switch args from typed array to
  x-kubernetes-preserve-unknown-fields to accept either shape
- Bump go-flink-client to v0.2.2 (fix: programArgsList → programArg
  query parameter name for Flink REST API)

Args can now be written as:
  args:
    kafka-host: broker:9092
    kafka-group-id: my-group

Or the existing list format:
  args:
    - "--kafka-host"
    - broker:9092
This commit is contained in:
2026-07-23 15:25:08 +03:30
parent 7fb18cd45f
commit 91c10c89da
6 changed files with 68 additions and 8 deletions

View File

@@ -44,9 +44,8 @@ spec:
jarURIBasicAuthPassword: jarURIBasicAuthPassword:
type: string type: string
args: args:
type: array description: "Program arguments. Accepts a list of strings (--key, value, ...) or a map of key-value pairs."
items: x-kubernetes-preserve-unknown-fields: true
type: string
savepointInterval: savepointInterval:
type: string type: string
format: duration format: duration

View File

@@ -11,6 +11,17 @@ spec:
jarUri: "https://git.logicamp.tech/api/packages/logiline/generic/facility-enrichment/1.0.0/facility-enrichment.jar" jarUri: "https://git.logicamp.tech/api/packages/logiline/generic/facility-enrichment/1.0.0/facility-enrichment.jar"
jarURIBasicAuthUsername: logiline-actrunner jarURIBasicAuthUsername: logiline-actrunner
jarURIBasicAuthPassword: daeweeb7ohpaiw3oojiCoong jarURIBasicAuthPassword: daeweeb7ohpaiw3oojiCoong
# args accepts two formats:
# Map (recommended):
args:
kafka-host: kafka.pg-release:9092
kafka-group-id: batch-sales-config-dedup-processor
# List (also valid):
# args:
# - "--kafka-host"
# - kafka.pg-release:9092
# - "--kafka-group-id"
# - batch-sales-config-dedup-processor
flinkConfiguration: flinkConfiguration:
taskmanager.numberOfTaskSlots: "1" taskmanager.numberOfTaskSlots: "1"
parallelism.default: "1" parallelism.default: "1"

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.23.2
require ( require (
github.com/danielgtaylor/huma/v2 v2.27.0 github.com/danielgtaylor/huma/v2 v2.27.0
github.com/gofiber/fiber/v2 v2.52.6 github.com/gofiber/fiber/v2 v2.52.6
github.com/logi-camp/go-flink-client v0.2.1 github.com/logi-camp/go-flink-client v0.2.2
github.com/samber/lo v1.47.0 github.com/samber/lo v1.47.0
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
k8s.io/apimachinery v0.31.3 k8s.io/apimachinery v0.31.3

4
go.sum
View File

@@ -62,8 +62,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/logi-camp/go-flink-client v0.2.1 h1:STfKamFm9+2SxxfZO3ysdFsb5MViQdThB4UHbnkUOE8= github.com/logi-camp/go-flink-client v0.2.2 h1:aWqibzcJiv02Myf/WowZafI0hhHp5x7BJGRCmI6PT20=
github.com/logi-camp/go-flink-client v0.2.1/go.mod h1:A79abedX6wGQI0FoICdZI7SRoGHj15QwMwWowgsKYFI= github.com/logi-camp/go-flink-client v0.2.2/go.mod h1:A79abedX6wGQI0FoICdZI7SRoGHj15QwMwWowgsKYFI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=

View File

@@ -11,7 +11,7 @@ image:
# This sets the pull policy for images. # This sets the pull policy for images.
pullPolicy: Always pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion. # Overrides the image tag whose default is the chart appVersion.
tag: v1.3.0 tag: v1.3.1
# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ # This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
imagePullSecrets: [] imagePullSecrets: []

View File

@@ -1,7 +1,10 @@
package v1alpha1 package v1alpha1
import ( import (
"encoding/json"
"errors" "errors"
"sort"
"strings"
"time" "time"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -9,6 +12,53 @@ import (
//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen object paths=$GOFILE //go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen object paths=$GOFILE
// Args is a list of program arguments passed to the Flink job.
// It accepts two formats in JSON/YAML:
//
// List: ["--kafka-host", "broker:9092", "--kafka-group-id", "my-group"]
// Map: {kafka-host: "broker:9092", kafka-group-id: "my-group"}
//
// Map keys are automatically prefixed with "--" and expanded into alternating
// key/value pairs. The internal representation is always a flat []string.
type Args []string
// UnmarshalJSON implements dual-format deserialization.
func (a *Args) UnmarshalJSON(data []byte) error {
// Try map format first: {"key": "value", ...}
var m map[string]string
if err := json.Unmarshal(data, &m); err == nil {
*a = make(Args, 0, len(m)*2)
// Sort keys for deterministic ordering.
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
*a = append(*a, "--"+k, m[k])
}
return nil
}
// Fall back to list format: ["--key", "value", ...]
var s []string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*a = Args(s)
return nil
}
// MarshalJSON serializes Args in the compact map format.
func (a Args) MarshalJSON() ([]byte, error) {
m := make(map[string]string, len(a)/2)
for i := 0; i < len(a)-1; i += 2 {
key := strings.TrimPrefix(a[i], "--")
m[key] = a[i+1]
}
return json.Marshal(m)
}
type FlinkJobSpec struct { type FlinkJobSpec struct {
Key string `json:"key"` Key string `json:"key"`
Name string `json:"name"` Name string `json:"name"`
@@ -19,7 +69,7 @@ type FlinkJobSpec struct {
JarURIBasicAuthPassword *string `json:"jarURIBasicAuthPassword"` JarURIBasicAuthPassword *string `json:"jarURIBasicAuthPassword"`
SavepointInterval metaV1.Duration `json:"savepointInterval"` SavepointInterval metaV1.Duration `json:"savepointInterval"`
EntryClass string `json:"entryClass"` EntryClass string `json:"entryClass"`
Args []string `json:"args"` Args Args `json:"args,omitempty"`
} }
type FlinkJobStatus struct { type FlinkJobStatus struct {