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
58 changes: 45 additions & 13 deletions kustomizer/src/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,61 @@ fn merge_array(
patches: Vec<Value>,
schema: Option<&ArrayType>,
) -> anyhow::Result<()> {
// two values match if they have at least one common element and
// corresponding elements only differ if one is an empty string
fn keys_match<'a>(
keys: impl IntoIterator<Item = &'a str>,
base: &Value,
patch: &Value,
) -> bool {
let mut one_match = false;
for key in keys {
let base_value = base.get(key);
let patch_value = patch.get(key);
if base_value.is_some() && patch_value.is_some() {
if base_value == patch_value {
one_match = true;
} else if base_value.and_then(|v| v.as_str()) == Some("")
|| patch_value.and_then(|v| v.as_str()) == Some("")
{
continue;
} else {
return false;
}
}
}

one_match
}

match schema {
Some(schema) => match schema.list_map_keys.as_deref() {
Some(keys) => {
for patch in patches {
if let Some(pos) = bases.iter().position(|base| {
keys.iter()
.all(|key| base.get(key.as_str()) == patch.get(key.as_str()))
}) {
if let Some(pos) = bases
.iter()
.position(|base| keys_match(keys.iter().map(|s| s.as_str()), base, &patch))
{
merge(&mut bases[pos], patch, Some(&schema.items))?;
} else {
bases.push(patch);
}
}
}
None => {
if schema.patch_strategy == Some(PatchStrategy::Merge)
&& schema.list_type.is_none_or(|t| t != ListType::Atomic)
{
bases.extend(patches)
} else {
*bases = patches
}
}
None => match schema.patch_strategy {
Some(strategy) => match strategy {
PatchStrategy::Merge
if schema.list_type.is_none_or(|t| t != ListType::Atomic) =>
{
bases.extend(patches);
return Ok(());
}
PatchStrategy::Merge | PatchStrategy::Replace => *bases = patches,
PatchStrategy::RetainKeys => todo!("retainKeys"),
PatchStrategy::MergeRetainKeys => todo!("merge,retainKeys"),
},
None => *bases = patches,
},
},
_ => *bases = patches,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resources:
- service.yaml
patchesStrategicMerge:
- patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: web
labels:
service: web
spec:
ports:
- port: 30900
targetPort: 30900
protocol: TCP
type: NodePort
selector:
service: web
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: web
labels:
service: web
spec:
ports:
- port: 30900
targetPort: 30900
selector:
service: web
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: web
spec:
ports:
- port: 30900
targetPort: 30900
protocol: TCP
type: NodePort
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: success
# Ported from Go kustomize TestPatchPortHasNoProtocol in multiplepatch_test.go
# Tests that when patching a service port without protocol field, original protocol is preserved
Loading