From 7583e6aa1c3694519d106f29fb813233218e83a2 Mon Sep 17 00:00:00 2001 From: elmiko Date: Fri, 10 May 2024 15:22:02 -0400 Subject: [PATCH 1/4] remove managed fields from raw output this change was a little tricky and required marshaling the data out of the source yaml, removing the managed field section, and then unmarshaling back to a string. a new test file was added to account for the serialization choices that yaml-rust2 makes. --- src/manifest.rs | 27 ++++- ...0-0-1.control.plane.no-managed-fields.yaml | 101 ++++++++++++++++++ .../core/nodes/ip-10-0-0-1.control.plane.yaml | 2 +- 3 files changed, 126 insertions(+), 4 deletions(-) create mode 100755 testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml diff --git a/src/manifest.rs b/src/manifest.rs index 6462d3a..6ad3d2a 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -5,7 +5,7 @@ use crate::prelude::*; use std::fs; use std::path::PathBuf; use yaml_rust::yaml::Hash; -use yaml_rust::{Yaml, YamlLoader}; +use yaml_rust::{Yaml, YamlLoader, YamlEmitter}; #[derive(Debug, Clone)] pub struct Manifest { @@ -31,7 +31,7 @@ impl Manifest { return Err(anyhow!("Path is a directory {}", path.as_path().display())); } - let raw = fs::read_to_string(path.as_path())?; + let mut raw = fs::read_to_string(path.as_path())?; let mut docs = YamlLoader::load_from_str(&raw)?; if docs.is_empty() { @@ -55,7 +55,28 @@ impl Manifest { metadata.remove(&Yaml::String(String::from("managedFields"))); ycopy.remove(&Yaml::String(String::from("metadata"))); ycopy.insert(Yaml::String(String::from("metadata")), Yaml::Hash(metadata)); + + // we want to make sure that the display of the raw file is in a familiar format + // to accomplish that, we want the metadata field to appear first, then spec, then status + let spec = ycopy[&Yaml::String(String::from("spec"))] + .as_hash() + .unwrap_or(&Hash::new()) + .clone(); + ycopy.remove(&Yaml::String(String::from("spec"))); + ycopy.insert(Yaml::String(String::from("spec")), Yaml::Hash(spec)); + let status = ycopy[&Yaml::String(String::from("status"))] + .as_hash() + .unwrap_or(&Hash::new()) + .clone(); + ycopy.remove(&Yaml::String(String::from("status"))); + ycopy.insert(Yaml::String(String::from("status")), Yaml::Hash(status)); + yaml = Yaml::Hash(ycopy); + let mut out_str = String::new(); + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(&yaml).unwrap(); + out_str.push('\n'); + raw = out_str; } Ok(Manifest { name, raw, yaml }) } @@ -138,7 +159,7 @@ mod tests { #[test] fn test_manifest_as_raw() { let expected = include_str!( - "../testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml"); + "../testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml"); let manifest = Manifest::from(PathBuf::from( "testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml" )).unwrap(); diff --git a/testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml b/testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml new file mode 100755 index 0000000..3af0c70 --- /dev/null +++ b/testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: v1 +kind: Node +metadata: + annotations: + machine.openshift.io/machine: openshift-machine-api/control-plane1 + machineconfiguration.openshift.io/controlPlaneTopology: HighlyAvailable + machineconfiguration.openshift.io/currentConfig: rendered-master-0 + machineconfiguration.openshift.io/desiredConfig: rendered-master-0 + machineconfiguration.openshift.io/reason: "" + machineconfiguration.openshift.io/state: Done + nfd.node.kubernetes.io/master.version: "1.16" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2022-01-01T00:00:00Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/instance-type: xlarge + beta.kubernetes.io/os: linux + failure-domain.beta.kubernetes.io/region: region-1 + failure-domain.beta.kubernetes.io/zone: zone-1 + kubernetes.io/arch: amd64 + kubernetes.io/hostname: ip-10-0-0-1.control.plane + kubernetes.io/os: linux + node-role.kubernetes.io/master: "" + node.kubernetes.io/instance-type: xlarge + node.openshift.io/os_id: rhcos + topology.kubernetes.io/region: region-1 + topology.kubernetes.io/zone: zone-1 + name: ip-10-0-0-1.control.plane + resourceVersion: "89485" + uid: 00000000-0000-0000-0000-000000000000 +spec: + providerID: "fake://ip-10-0-0-1.control.plane" + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/master +status: + addresses: + - address: 10.0.0.1 + type: InternalIP + - address: ip-10-0-0-1.control.plane + type: Hostname + - address: ip-10-0-0-1.control.plane + type: InternalDNS + allocatable: + cpu: 3500m + ephemeral-storage: "115470533646" + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 14955324Ki + pods: "250" + capacity: + cpu: "4" + ephemeral-storage: 125293548Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 16106300Ki + pods: "250" + conditions: + - lastHeartbeatTime: "2022-01-01T00:00:00Z" + lastTransitionTime: "2022-01-01T00:00:00Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2022-01-01T00:00:00Z" + lastTransitionTime: "2022-01-01T00:00:00Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2022-01-01T00:00:00Z" + lastTransitionTime: "2022-01-01T00:00:00Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2022-01-01T00:00:00Z" + lastTransitionTime: "2022-01-01T00:00:00Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - quay.io/openshift-release-dev/ocp-v4.0-art-dev + sizeBytes: 1139449201 + nodeInfo: + architecture: amd64 + bootID: 00000000-0000-0000-0000-000000000000 + containerRuntimeVersion: "cri-o://1.24.alpha.fake" + kernelVersion: 5.fake + kubeProxyVersion: v1.24 + kubeletVersion: v1.24 + machineID: 493810f75ca55b6099ceec0c9373f2fe + operatingSystem: linux + osImage: Linux + systemUUID: 00000000-0000-0000-0000-000000000000 diff --git a/testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml b/testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml index eabd026..52aa03d 100755 --- a/testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml +++ b/testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml @@ -143,7 +143,7 @@ status: kernelVersion: 5.fake kubeProxyVersion: v1.24 kubeletVersion: v1.24 - machineID: 00000000000000000000000000000000 + machineID: 493810f75ca55b6099ceec0c9373f2fe operatingSystem: linux osImage: Linux systemUUID: 00000000-0000-0000-0000-000000000000 From 06770e24f9e286cd0f408a09e63844f9fdfa48c9 Mon Sep 17 00:00:00 2001 From: elmiko Date: Fri, 10 May 2024 16:11:33 -0400 Subject: [PATCH 2/4] update toolchain to nightly --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b78a8de..e8befcd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: Install toolchain - uses: dtolnay/rust-toolchain@v1 + uses: dtolnay/rust-toolchain@nightly with: toolchain: stable - name: Cache Dependencies @@ -37,7 +37,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: Install toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@nightly with: toolchain: stable components: rustfmt From 44671d34fd739ba7a1921ac580b8f7fe341c9c0e Mon Sep 17 00:00:00 2001 From: elmiko Date: Fri, 10 May 2024 16:18:05 -0400 Subject: [PATCH 3/4] fix fmt errors in manifest.rs --- src/manifest.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/manifest.rs b/src/manifest.rs index 6ad3d2a..28b3b26 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -5,7 +5,7 @@ use crate::prelude::*; use std::fs; use std::path::PathBuf; use yaml_rust::yaml::Hash; -use yaml_rust::{Yaml, YamlLoader, YamlEmitter}; +use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; #[derive(Debug, Clone)] pub struct Manifest { @@ -158,8 +158,7 @@ mod tests { #[test] fn test_manifest_as_raw() { - let expected = include_str!( - "../testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml"); + let expected = include_str!("../testdata/ip-10-0-0-1.control.plane.no-managed-fields.yaml"); let manifest = Manifest::from(PathBuf::from( "testdata/must-gather-valid/sample-openshift-release/cluster-scoped-resources/core/nodes/ip-10-0-0-1.control.plane.yaml" )).unwrap(); From a48ceb52e4730ddea02be8888f4208c97ec0b408 Mon Sep 17 00:00:00 2001 From: elmiko Date: Fri, 10 May 2024 17:11:11 -0400 Subject: [PATCH 4/4] add some error handling to ensure we don't panic if there is an issue dumping the mutated yaml, default to using the original raw string. --- src/manifest.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/manifest.rs b/src/manifest.rs index 28b3b26..aa95b1c 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -74,9 +74,14 @@ impl Manifest { yaml = Yaml::Hash(ycopy); let mut out_str = String::new(); let mut emitter = YamlEmitter::new(&mut out_str); - emitter.dump(&yaml).unwrap(); - out_str.push('\n'); - raw = out_str; + // if we have an error creating the string, default to using the original + raw = match emitter.dump(&yaml) { + Ok(()) => { + out_str.push('\n'); + out_str + } + Err(_) => raw, + }; } Ok(Manifest { name, raw, yaml }) }