Skip to content
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
24 changes: 24 additions & 0 deletions api/v1alpha1/oadp_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ type VeleroConfig struct {
// for the snaphandle
// +optional
EnableCSISnapshotEarlyFrequentPolling bool `json:"enableCSISnapshotEarlyFrequentPolling,omitempty"`
// ExtraArgs are additional arguments to append to the Velero server.
// Keys are flag names (without leading --), values are flag values.
// These are merged additively on top of operator defaults and Args.
// If the unsupported-args annotation is set, it takes highest precedence
// and completely overrides all other args including ExtraArgs.
// Precedence: operator defaults / Args < ExtraArgs < unsupported-args annotation.
// Keys are rejected at admission time if they don't match the pattern below.
// common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
// at runtime as a defensive fallback for CRs persisted before this validation existed.
// +optional
// +kubebuilder:validation:XValidation:rule="self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))",message="extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens"
ExtraArgs map[string]string `json:"extraArgs,omitempty"`
}

// PodConfig defines the pod configuration options
Expand Down Expand Up @@ -169,6 +181,18 @@ type NodeAgentConfig struct {
// +kubebuilder:validation:Enum=restic;kopia
// +kubebuilder:validation:Required
UploaderType string `json:"uploaderType"`
// ExtraArgs are additional arguments to append to the node-agent server.
// Keys are flag names (without leading --), values are flag values.
// These are merged additively on top of operator defaults.
// If the unsupported-args annotation is set, it takes highest precedence
// and completely overrides all other args including ExtraArgs.
// Precedence: operator defaults < ExtraArgs < unsupported-args annotation.
// Keys are rejected at admission time if they don't match the pattern below.
// common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
// at runtime as a defensive fallback for CRs persisted before this validation existed.
// +optional
// +kubebuilder:validation:XValidation:rule="self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))",message="extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens"
ExtraArgs map[string]string `json:"extraArgs,omitempty"`
}

// ResticConfig is the configuration for restic server
Expand Down
14 changes: 14 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

34 changes: 34 additions & 0 deletions bundle/manifests/oadp.openshift.io_dataprotectionapplications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ spec:
enable defines a boolean pointer whether we want the daemonset to
exist or not
type: boolean
extraArgs:
additionalProperties:
type: string
description: |-
ExtraArgs are additional arguments to append to the node-agent server.
Keys are flag names (without leading --), values are flag values.
These are merged additively on top of operator defaults.
If the unsupported-args annotation is set, it takes highest precedence
and completely overrides all other args including ExtraArgs.
Precedence: operator defaults < ExtraArgs < unsupported-args annotation.
Keys are rejected at admission time if they don't match the pattern below.
common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
at runtime as a defensive fallback for CRs persisted before this validation existed.
type: object
x-kubernetes-validations:
- message: extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens
rule: self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))
podConfig:
description: Pod specific configuration
properties:
Expand Down Expand Up @@ -837,6 +854,23 @@ spec:
the 1-second polling interval for the first 10 seconds while waiting
for the snaphandle
type: boolean
extraArgs:
additionalProperties:
type: string
description: |-
ExtraArgs are additional arguments to append to the Velero server.
Keys are flag names (without leading --), values are flag values.
These are merged additively on top of operator defaults and Args.
If the unsupported-args annotation is set, it takes highest precedence
and completely overrides all other args including ExtraArgs.
Precedence: operator defaults / Args < ExtraArgs < unsupported-args annotation.
Keys are rejected at admission time if they don't match the pattern below.
common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
at runtime as a defensive fallback for CRs persisted before this validation existed.
type: object
x-kubernetes-validations:
- message: extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens
rule: self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))
featureFlags:
description: featureFlags defines the list of features to enable for Velero instance
items:
Expand Down
34 changes: 34 additions & 0 deletions config/crd/bases/oadp.openshift.io_dataprotectionapplications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ spec:
enable defines a boolean pointer whether we want the daemonset to
exist or not
type: boolean
extraArgs:
additionalProperties:
type: string
description: |-
ExtraArgs are additional arguments to append to the node-agent server.
Keys are flag names (without leading --), values are flag values.
These are merged additively on top of operator defaults.
If the unsupported-args annotation is set, it takes highest precedence
and completely overrides all other args including ExtraArgs.
Precedence: operator defaults < ExtraArgs < unsupported-args annotation.
Keys are rejected at admission time if they don't match the pattern below.
common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
at runtime as a defensive fallback for CRs persisted before this validation existed.
type: object
x-kubernetes-validations:
- message: extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens
rule: self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))
podConfig:
description: Pod specific configuration
properties:
Expand Down Expand Up @@ -837,6 +854,23 @@ spec:
the 1-second polling interval for the first 10 seconds while waiting
for the snaphandle
type: boolean
extraArgs:
additionalProperties:
type: string
description: |-
ExtraArgs are additional arguments to append to the Velero server.
Keys are flag names (without leading --), values are flag values.
These are merged additively on top of operator defaults and Args.
If the unsupported-args annotation is set, it takes highest precedence
and completely overrides all other args including ExtraArgs.
Precedence: operator defaults / Args < ExtraArgs < unsupported-args annotation.
Keys are rejected at admission time if they don't match the pattern below.
common.MergeExtraArgs additionally normalizes keys (strips leading dashes)
at runtime as a defensive fallback for CRs persisted before this validation existed.
type: object
x-kubernetes-validations:
- message: extraArgs keys must be flag names without a leading '-', containing only alphanumeric characters, dots, underscores, or hyphens
rule: self.all(key, key.matches('^[A-Za-z0-9][A-Za-z0-9_.-]*$'))
featureFlags:
description: featureFlags defines the list of features to enable for Velero instance
items:
Expand Down
4 changes: 4 additions & 0 deletions controllers/nodeagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ func (r *DPAReconciler) customizeNodeAgentDaemonset(dpa *oadpv1alpha1.DataProtec
nodeAgentContainer.ImagePullPolicy = imagePullPolicy
setContainerDefaults(nodeAgentContainer)

if len(dpa.Spec.Configuration.NodeAgent.ExtraArgs) > 0 {
nodeAgentContainer.Args = common.MergeExtraArgs(nodeAgentContainer.Args, dpa.Spec.Configuration.NodeAgent.ExtraArgs)
}

if configMapName, ok := dpa.Annotations[common.UnsupportedNodeAgentServerArgsAnnotation]; ok {
if configMapName != "" {
unsupportedServerArgsCM := corev1.ConfigMap{}
Expand Down
61 changes: 61 additions & 0 deletions controllers/nodeagent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,67 @@ func TestDPAReconciler_buildNodeAgentDaemonset(t *testing.T) {
nodeAgentDaemonSet: testNodeAgentDaemonSet.DeepCopy(),
errorMessage: "configmaps \"missing-unsupported-node-agent-server-args-cm\" not found",
},
{
name: "valid DPA CR with NodeAgent ExtraArgs, DaemonSet is built with extra args appended",
dpa: createTestDpaWith(
nil,
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{},
NodeAgent: &oadpv1alpha1.NodeAgentConfig{
NodeAgentCommonFields: oadpv1alpha1.NodeAgentCommonFields{},
UploaderType: "kopia",
ExtraArgs: map[string]string{
"custom-flag": "value1",
},
},
},
},
),
clientObjects: []client.Object{testGenericInfrastructure},
nodeAgentDaemonSet: testNodeAgentDaemonSet.DeepCopy(),
wantNodeAgentDaemonSet: createTestBuiltNodeAgentDaemonSet(TestBuiltNodeAgentDaemonSetOptions{
args: []string{
"--custom-flag=value1",
},
}),
},
{
name: "valid DPA CR with NodeAgent ExtraArgs and Unsupported Server Args, annotation takes priority",
dpa: createTestDpaWith(
map[string]string{common.UnsupportedNodeAgentServerArgsAnnotation: "unsupported-node-agent-server-args-cm"},
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{},
NodeAgent: &oadpv1alpha1.NodeAgentConfig{
NodeAgentCommonFields: oadpv1alpha1.NodeAgentCommonFields{},
UploaderType: "kopia",
ExtraArgs: map[string]string{
"custom-flag": "value1",
},
},
},
},
),
clientObjects: []client.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "unsupported-node-agent-server-args-cm",
Namespace: testNamespaceName,
},
Data: map[string]string{
"unsupported-arg": "value2",
},
},
testGenericInfrastructure,
},
nodeAgentDaemonSet: testNodeAgentDaemonSet.DeepCopy(),
wantNodeAgentDaemonSet: createTestBuiltNodeAgentDaemonSet(TestBuiltNodeAgentDaemonSetOptions{
args: []string{
"--unsupported-arg=value2",
},
}),
},
{
name: "valid DPA CR with NodeAgent resource allocations, NodeAgent DaemonSet is built with resource allocations",
dpa: createTestDpaWith(
Expand Down
3 changes: 3 additions & 0 deletions controllers/velero.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ func (r *DPAReconciler) customizeVeleroDeployment(dpa *oadpv1alpha1.DataProtecti
}
r.appendPluginSpecificSpecs(dpa, veleroDeployment, veleroContainer, providerNeedsDefaultCreds, hasCloudStorage)
setPodTemplateSpecDefaults(&veleroDeployment.Spec.Template)
if dpa.Spec.Configuration.Velero != nil && len(dpa.Spec.Configuration.Velero.ExtraArgs) > 0 {
veleroContainer.Args = common.MergeExtraArgs(veleroContainer.Args, dpa.Spec.Configuration.Velero.ExtraArgs)
}
if configMapName, ok := dpa.Annotations[common.UnsupportedVeleroServerArgsAnnotation]; ok {
if configMapName != "" {
unsupportedServerArgsCM := corev1.ConfigMap{}
Expand Down
113 changes: 113 additions & 0 deletions controllers/velero_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,119 @@ func TestDPAReconciler_buildVeleroDeployment(t *testing.T) {
veleroDeployment: testVeleroDeployment.DeepCopy(),
errorMessage: "configmaps \"missing-unsupported-server-args-cm\" not found",
},
{
name: "valid DPA CR with ExtraArgs, Velero Deployment is built with extra args appended",
dpa: createTestDpaWith(
nil,
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{
ExtraArgs: map[string]string{
"custom-timeout": "30m",
"another-flag": "value1",
},
},
},
},
),
veleroDeployment: testVeleroDeployment.DeepCopy(),
wantVeleroDeployment: createTestBuiltVeleroDeployment(TestBuiltVeleroDeploymentOptions{
args: []string{
defaultFileSystemBackupTimeout,
defaultRestoreResourcePriorities,
defaultDisableInformerCache,
"--another-flag=value1",
"--custom-timeout=30m",
},
}),
},
{
name: "valid DPA CR with ExtraArgs overriding a default, Velero Deployment is built with overridden value",
dpa: createTestDpaWith(
nil,
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{
ExtraArgs: map[string]string{
"fs-backup-timeout": "8h",
},
},
},
},
),
veleroDeployment: testVeleroDeployment.DeepCopy(),
wantVeleroDeployment: createTestBuiltVeleroDeployment(TestBuiltVeleroDeploymentOptions{
args: []string{
"--fs-backup-timeout=8h",
defaultRestoreResourcePriorities,
defaultDisableInformerCache,
},
}),
},
{
name: "valid DPA CR with ExtraArgs and Unsupported Server Args, annotation takes priority",
dpa: createTestDpaWith(
map[string]string{common.UnsupportedVeleroServerArgsAnnotation: "unsupported-server-args-cm"},
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{
ExtraArgs: map[string]string{
"custom-flag": "value1",
},
},
},
},
),
clientObjects: []client.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "unsupported-server-args-cm",
Namespace: testNamespaceName,
},
Data: map[string]string{
"unsupported-arg": "value2",
},
},
},
veleroDeployment: testVeleroDeployment.DeepCopy(),
wantVeleroDeployment: createTestBuiltVeleroDeployment(TestBuiltVeleroDeploymentOptions{
args: []string{
"--unsupported-arg=value2",
},
}),
},
{
name: "valid DPA CR with Args and ExtraArgs, ExtraArgs adds on top of Args",
dpa: createTestDpaWith(
nil,
oadpv1alpha1.DataProtectionApplicationSpec{
Configuration: &oadpv1alpha1.ApplicationConfig{
Velero: &oadpv1alpha1.VeleroConfig{
Args: &server.Args{
ServerConfig: server.ServerConfig{
MetricsAddress: fmt.Sprintf(":%v", argsMetricsPortTest),
},
},
ExtraArgs: map[string]string{
"custom-flag": "custom-value",
"disable-informer-cache": "true",
},
},
},
},
),
veleroDeployment: testVeleroDeployment.DeepCopy(),
wantVeleroDeployment: createTestBuiltVeleroDeployment(TestBuiltVeleroDeploymentOptions{
metricsPort: argsMetricsPortTest,
args: []string{
fmt.Sprintf("--metrics-address=:%v", argsMetricsPortTest),
"--fs-backup-timeout=4h0m0s",
defaultRestoreResourcePriorities,
"--disable-informer-cache=true",
"--custom-flag=custom-value",
},
}),
},
{
name: "valid DPA CR with ItemOperationSyncFrequency, Velero Deployment is built with ItemOperationSyncFrequency arg",
dpa: createTestDpaWith(
Expand Down
Loading
Loading