Skip to content

Instantly share code, notes, and snippets.

@alfredopalhares
Last active November 14, 2024 10:43
Show Gist options
  • Save alfredopalhares/0f071fc019aac0955ea34e2f21ff7087 to your computer and use it in GitHub Desktop.
Save alfredopalhares/0f071fc019aac0955ea34e2f21ff7087 to your computer and use it in GitHub Desktop.
Script to diff un-updatebale Statefulsets fiesl

List un-updatabale file Kubernetes Statefulset

https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#updating-statefulsets

There are some cases that you might be trying to update a statefulset and you get this error:

Error: cannot patch "my-statefulset" with kind StatefulSet: StatefulSet.apps "my-statefulset" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden && cannot patch "my-statefulset-tracking" with kind StatefulSet: StatefulSet.apps "my-statefulset-tracking" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden

And while you can diff a file manually beteween you update and the yaml that you can fecth: kubectl -n my-ns get sts my-statefulset -o yaml

So I makde the scritp that diff that also excluding the options, this will help you be faster on the system.

-> % k8s-diff-sts-upgrade.py template.yaml onserver.yaml
Differences in the 'spec' block:
- Field: revisionHistoryLimit
  - template: None
  - template: 10
- Field: serviceName
  - template: my-statefulset-v1
  - template: my-statefulset-v1-svc
- Field: podManagementPolicy
  - template: None
  - template: OrderedReady
#!/usr/bin/env python3
## This script compares two Kubernetes StatefulSet YAML files and prints the differences spec block
# This is useful for
import argparse
from pathlib import Path
import yaml
def get_file_path(file_path):
return Path(file_path).stem
def load_yaml(file_path):
with open(file_path, "r") as stream:
return yaml.safe_load(stream)
def compare_spec_blocks(yaml1, yaml2):
spec1 = yaml1.get("spec", {})
spec2 = yaml2.get("spec", {})
excluded_fields = {
"replicas",
"ordinals",
"template",
"updateStrategy",
"persistentVolumeClaimRetentionPolicy",
"minReadySeconds",
}
differences = {}
all_keys = set(spec1.keys()).union(set(spec2.keys()))
for key in all_keys:
if key in excluded_fields:
continue
value1 = spec1.get(key, None)
value2 = spec2.get(key, None)
if value1 != value2:
differences[key] = {"file1": value1, "file2": value2}
return differences
def main(file1, file2):
yaml1 = load_yaml(file1)
yaml2 = load_yaml(file2)
yaml1_name = get_file_path(file1)
yaml2_name = get_file_path(file1)
differences = compare_spec_blocks(yaml1, yaml2)
if differences:
print("Differences in the 'spec' block:")
for key, diff in differences.items():
print(f"- Field: {key}")
print(f" - {yaml1_name}: {diff['file1']}")
print(f" - {yaml2_name}: {diff['file2']}")
else:
print("No differences found in the 'spec' block (excluding specified fields).")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Compare 'spec' blocks of two YAML files, excluding specific fields."
)
parser.add_argument("file1", type=str, help="Path to the first YAML file")
parser.add_argument("file2", type=str, help="Path to the second YAML file")
args = parser.parse_args()
main(args.file1, args.file2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment