diff --git a/Enable_clib_yml_api.patch b/Enable_clib_yml_api.patch new file mode 100644 index 0000000..ed8cf9f --- /dev/null +++ b/Enable_clib_yml_api.patch @@ -0,0 +1,636 @@ +From ad2bfa136290e72cdfd4b7877b49b3fc07203f9c Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 21 Feb 2023 16:26:22 +0800 +Subject: [PATCH] clib: Introduce YAML support + +Allowing both YAML and JSON input, the output format will matching input +format. + +For `nmstate_net_state_retrieve()`, user can use +`NMSTATE_FLAG_YAML_OUTPUT` flag to instruct the output to be YAML +format. + +Signed-off-by: Gris Ge +--- + rust/src/clib/Cargo.toml | 1 + + rust/src/clib/apply.rs | 2 +- + rust/src/clib/gen_conf.rs | 52 +++++++----- + rust/src/clib/nmstate.h.in | 55 +++++++------ + rust/src/clib/policy.rs | 57 ++++++++----- + rust/src/clib/query.rs | 49 ++++++++---- + .../{nmpolicy_test.c => nmpolicy_json_test.c} | 5 ++ + rust/src/clib/test/nmpolicy_yaml_test.c | 80 +++++++++++++++++++ + .../{nmstate_test.c => nmstate_json_test.c} | 5 ++ + rust/src/clib/test/nmstate_yaml_test.c | 34 ++++++++ + rust/src/lib/Cargo.toml | 3 + + rust/src/lib/net_state.rs | 14 +++- + 12 files changed, 274 insertions(+), 83 deletions(-) + rename rust/src/clib/test/{nmpolicy_test.c => nmpolicy_json_test.c} (96%) + create mode 100644 rust/src/clib/test/nmpolicy_yaml_test.c + rename rust/src/clib/test/{nmstate_test.c => nmstate_json_test.c} (87%) + create mode 100644 rust/src/clib/test/nmstate_yaml_test.c + +diff --git a/rust/src/clib/Cargo.toml b/rust/src/clib/Cargo.toml +index 97e4128c..ed391b3a 100644 +--- a/rust/src/clib/Cargo.toml ++++ b/rust/src/clib/Cargo.toml +@@ -16,6 +16,7 @@ crate-type = ["cdylib", "staticlib"] + nmstate = { path = "../lib", default-features = false } + libc = "0.2.74" + serde_json = "1.0" ++serde_yaml = "0.9" + log = "0.4.17" + serde = { version = "1.0.137", features = ["derive"] } + once_cell = "1.12.0" +diff --git a/rust/src/clib/apply.rs b/rust/src/clib/apply.rs +index 9a0d6fbc..67d39730 100644 +--- a/rust/src/clib/apply.rs ++++ b/rust/src/clib/apply.rs +@@ -74,7 +74,7 @@ pub extern "C" fn nmstate_net_state_apply( + }; + + let mut net_state = +- match nmstate::NetworkState::new_from_json(net_state_str) { ++ match nmstate::NetworkState::new_from_yaml(net_state_str) { + Ok(n) => n, + Err(e) => { + unsafe { +diff --git a/rust/src/clib/gen_conf.rs b/rust/src/clib/gen_conf.rs +index f63fb7b0..1ad7156b 100644 +--- a/rust/src/clib/gen_conf.rs ++++ b/rust/src/clib/gen_conf.rs +@@ -68,7 +68,7 @@ pub extern "C" fn nmstate_generate_configurations( + } + }; + +- let net_state = match nmstate::NetworkState::new_from_json(net_state_str) { ++ let net_state = match nmstate::NetworkState::new_from_yaml(net_state_str) { + Ok(n) => n, + Err(e) => { + unsafe { +@@ -80,28 +80,44 @@ pub extern "C" fn nmstate_generate_configurations( + } + }; + ++ let input_is_json = ++ serde_json::from_str::(net_state_str).is_ok(); + let result = net_state.gen_conf(); + unsafe { + *log = CString::new(logger.drain(now)).unwrap().into_raw(); + } + match result { +- Ok(s) => match serde_json::to_string(&s) { +- Ok(cfgs) => unsafe { +- *configs = CString::new(cfgs).unwrap().into_raw(); +- NMSTATE_PASS +- }, +- Err(e) => unsafe { +- *err_msg = +- CString::new(format!("serde_json::to_string failure: {e}")) +- .unwrap() +- .into_raw(); +- *err_kind = +- CString::new(format!("{}", nmstate::ErrorKind::Bug)) +- .unwrap() +- .into_raw(); +- NMSTATE_FAIL +- }, +- }, ++ Ok(s) => { ++ let serialize = if input_is_json { ++ serde_json::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to JSON: {e}"), ++ ) ++ }) ++ } else { ++ serde_yaml::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to YAML: {e}"), ++ ) ++ }) ++ }; ++ ++ match serialize { ++ Ok(cfgs) => unsafe { ++ *configs = CString::new(cfgs).unwrap().into_raw(); ++ NMSTATE_PASS ++ }, ++ Err(e) => unsafe { ++ *err_msg = ++ CString::new(e.msg().to_string()).unwrap().into_raw(); ++ *err_kind = ++ CString::new(e.kind().to_string()).unwrap().into_raw(); ++ NMSTATE_FAIL ++ }, ++ } ++ } + Err(e) => { + unsafe { + *err_msg = CString::new(e.msg()).unwrap().into_raw(); +diff --git a/rust/src/clib/nmstate.h.in b/rust/src/clib/nmstate.h.in +index 0879d47e..391477fd 100644 +--- a/rust/src/clib/nmstate.h.in ++++ b/rust/src/clib/nmstate.h.in +@@ -1,19 +1,4 @@ +-/* +- * Copyright 2021 Red Hat +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- ++// SPDX-License-Identifier: Apache-2.0 + + #ifndef _LIBNMSTATE_H_ + #define _LIBNMSTATE_H_ +@@ -44,6 +29,7 @@ extern "C" { + #define NMSTATE_FLAG_NO_COMMIT 1 << 5 + #define NMSTATE_FLAG_MEMORY_ONLY 1 << 6 + #define NMSTATE_FLAG_RUNNING_CONFIG_ONLY 1 << 7 ++#define NMSTATE_FLAG_YAML_OUTPUT 1 << 8 + + /** + * nmstate_net_state_retrieve - Retrieve network state +@@ -52,7 +38,7 @@ extern "C" { + * 0.1 + * + * Description: +- * Retrieve network state in the format of JSON. ++ * Retrieve network state in the format of JSON or YAML. + * + * @flags: + * Flags for special use cases: +@@ -60,6 +46,13 @@ extern "C" { + * No flag + * * NMSTATE_FLAG_KERNEL_ONLY + * Do not use external plugins, show kernel status only. ++ * * NMSTATE_FLAG_INCLUDE_SECRETS ++ * No not hide sercerts like password. ++ * * NMSTATE_FLAG_RUNNING_CONFIG_ONLY ++ * Only include running config excluding running status like auto ++ * IP addresses and routes, LLDP neighbors. ++ * * NMSTATE_FLAG_YAML_OUTPUT ++ * Show the state in YAML format + * @state: + * Output pointer of char array for network state in json format. + * The memory should be freed by nmstate_net_state_free(). +@@ -90,7 +83,7 @@ int nmstate_net_state_retrieve(uint32_t flags, char **state, char **log, + * 0.1 + * + * Description: +- * Apply network state in the format of JSON. ++ * Apply network state in the format of JSON or YAML. + * + * @flags: + * Flags for special use cases: +@@ -98,8 +91,12 @@ int nmstate_net_state_retrieve(uint32_t flags, char **state, char **log, + * No flag + * * NMSTATE_FLAG_KERNEL_ONLY + * Do not use external plugins, apply to kernel only. ++ * * NMSTATE_FLAG_NO_VERIFY ++ * Do not verify state after applied + * * NMSTATE_FLAG_NO_COMMIT + * Do not commit new state after verification ++ * * NMSTATE_FLAG_MEMORY_ONLY ++ * No not store network state to persistent. + * @state: + * Pointer of char array for network state in json format. + * @log: +@@ -119,7 +116,8 @@ int nmstate_net_state_retrieve(uint32_t flags, char **state, char **log, + * * NMSTATE_FAIL + * On failure. + */ +-int nmstate_net_state_apply(uint32_t flags, const char *state, uint32_t rollback_timeout, char **log, ++int nmstate_net_state_apply(uint32_t flags, const char *state, ++ uint32_t rollback_timeout, char **log, + char **err_kind, char **err_msg); + + /** +@@ -151,8 +149,8 @@ int nmstate_net_state_apply(uint32_t flags, const char *state, uint32_t rollback + * * NMSTATE_FAIL + * On failure. + */ +-int nmstate_checkpoint_commit(const char *checkpoint, char **log, char **err_kind, +- char **err_msg); ++int nmstate_checkpoint_commit(const char *checkpoint, char **log, ++ char **err_kind, char **err_msg); + + /** + * nmstate_checkpoint_rollback - Rollback the checkpoint +@@ -183,8 +181,8 @@ int nmstate_checkpoint_commit(const char *checkpoint, char **log, char **err_kin + * * NMSTATE_FAIL + * On failure. + */ +-int nmstate_checkpoint_rollback(const char *checkpoint, char **log, char **err_kind, +- char **err_msg); ++int nmstate_checkpoint_rollback(const char *checkpoint, char **log, ++ char **err_kind, char **err_msg); + + /** + * nmstate_generate_configurations - Generate network configurations +@@ -199,9 +197,10 @@ int nmstate_checkpoint_rollback(const char *checkpoint, char **log, char **err_k + * as value. + * + * @state: +- * Pointer of char array for network state in json format. ++ * Pointer of char array for network state in JSON or YAML format. + * @configs: +- * Output pointer of char array for network configures in json format. ++ * Output pointer of char array for network configures in JSON or ++ * YAML(depend on which format you use in @state) format. + * The memory should be freed by nmstate_net_state_free(). + * @log: + * Output pointer of char array for logging. +@@ -231,14 +230,14 @@ int nmstate_generate_configurations(const char *state, char **configs, + * 2.2 + * + * Description: +- * Generate new network state from policy again specifed state ++ * Generate new network state from policy again specified state + * + * @policy: +- * Pointer of char array for network policy in json format. ++ * Pointer of char array for network policy in JSON/YAML format. + * @current_state: + * Pointer of char array for current network state. + * @state: +- * Output pointer of char array for network state in json format. ++ * Output pointer of char array for network state in JSON/YAML format. + * The memory should be freed by nmstate_net_state_free(). + * @log: + * Output pointer of char array for logging. +diff --git a/rust/src/clib/policy.rs b/rust/src/clib/policy.rs +index ec8c46c1..ea7dd036 100644 +--- a/rust/src/clib/policy.rs ++++ b/rust/src/clib/policy.rs +@@ -67,6 +67,13 @@ pub extern "C" fn nmstate_net_state_from_policy( + } + }; + ++ let input_is_json = ++ if let Ok(policy_str) = unsafe { CStr::from_ptr(policy) }.to_str() { ++ serde_json::from_str::(policy_str).is_ok() ++ } else { ++ false ++ }; ++ + let mut policy = match deserilize_from_c_char::( + policy, err_kind, err_msg, + ) { +@@ -86,23 +93,37 @@ pub extern "C" fn nmstate_net_state_from_policy( + } + + match result { +- Ok(s) => match serde_json::to_string(&s) { +- Ok(state_str) => unsafe { +- *state = CString::new(state_str).unwrap().into_raw(); +- NMSTATE_PASS +- }, +- Err(e) => unsafe { +- *err_msg = +- CString::new(format!("serde_json::to_string failure: {e}")) +- .unwrap() +- .into_raw(); +- *err_kind = +- CString::new(format!("{}", nmstate::ErrorKind::Bug)) +- .unwrap() +- .into_raw(); +- NMSTATE_FAIL +- }, +- }, ++ Ok(s) => { ++ let serialize = if input_is_json { ++ serde_json::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to JSON: {e}"), ++ ) ++ }) ++ } else { ++ serde_yaml::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to YAML: {e}"), ++ ) ++ }) ++ }; ++ ++ match serialize { ++ Ok(state_str) => unsafe { ++ *state = CString::new(state_str).unwrap().into_raw(); ++ NMSTATE_PASS ++ }, ++ Err(e) => unsafe { ++ *err_msg = ++ CString::new(e.msg().to_string()).unwrap().into_raw(); ++ *err_kind = ++ CString::new(e.kind().to_string()).unwrap().into_raw(); ++ NMSTATE_FAIL ++ }, ++ } ++ } + Err(e) => { + unsafe { + *err_msg = CString::new(e.msg()).unwrap().into_raw(); +@@ -144,7 +165,7 @@ where + } + }; + +- match serde_json::from_str(content_str) { ++ match serde_yaml::from_str(content_str) { + Ok(n) => Some(n), + Err(e) => { + unsafe { +diff --git a/rust/src/clib/query.rs b/rust/src/clib/query.rs +index a24b9c83..12e44d05 100644 +--- a/rust/src/clib/query.rs ++++ b/rust/src/clib/query.rs +@@ -14,6 +14,7 @@ pub(crate) const NMSTATE_FLAG_INCLUDE_SECRETS: u32 = 1 << 4; + pub(crate) const NMSTATE_FLAG_NO_COMMIT: u32 = 1 << 5; + pub(crate) const NMSTATE_FLAG_MEMORY_ONLY: u32 = 1 << 6; + pub(crate) const NMSTATE_FLAG_RUNNING_CONFIG_ONLY: u32 = 1 << 7; ++pub(crate) const NMSTATE_FLAG_YAML_OUTPUT: u32 = 1 << 8; + + #[allow(clippy::not_unsafe_ptr_arg_deref)] + #[no_mangle] +@@ -72,23 +73,37 @@ pub extern "C" fn nmstate_net_state_retrieve( + } + + match result { +- Ok(s) => match serde_json::to_string(&s) { +- Ok(state_str) => unsafe { +- *state = CString::new(state_str).unwrap().into_raw(); +- NMSTATE_PASS +- }, +- Err(e) => unsafe { +- *err_msg = +- CString::new(format!("serde_json::to_string failure: {e}")) +- .unwrap() +- .into_raw(); +- *err_kind = +- CString::new(format!("{}", nmstate::ErrorKind::Bug)) +- .unwrap() +- .into_raw(); +- NMSTATE_FAIL +- }, +- }, ++ Ok(s) => { ++ let serialize = if (flags & NMSTATE_FLAG_YAML_OUTPUT) > 0 { ++ serde_yaml::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to YAML: {e}"), ++ ) ++ }) ++ } else { ++ serde_json::to_string(&s).map_err(|e| { ++ nmstate::NmstateError::new( ++ nmstate::ErrorKind::Bug, ++ format!("Failed to convert state {s:?} to JSON: {e}"), ++ ) ++ }) ++ }; ++ ++ match serialize { ++ Ok(state_str) => unsafe { ++ *state = CString::new(state_str).unwrap().into_raw(); ++ NMSTATE_PASS ++ }, ++ Err(e) => unsafe { ++ *err_msg = ++ CString::new(e.msg().to_string()).unwrap().into_raw(); ++ *err_kind = ++ CString::new(e.kind().to_string()).unwrap().into_raw(); ++ NMSTATE_FAIL ++ }, ++ } ++ } + Err(e) => { + unsafe { + *err_msg = CString::new(e.msg()).unwrap().into_raw(); +diff --git a/rust/src/clib/test/nmpolicy_test.c b/rust/src/clib/test/nmpolicy_json_test.c +similarity index 96% +rename from rust/src/clib/test/nmpolicy_test.c +rename to rust/src/clib/test/nmpolicy_json_test.c +index 7a71a5f5..8a0444d4 100644 +--- a/rust/src/clib/test/nmpolicy_test.c ++++ b/rust/src/clib/test/nmpolicy_json_test.c +@@ -1,3 +1,6 @@ ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include + #include + #include + #include +@@ -91,6 +94,8 @@ int main(void) { + rc = EXIT_FAILURE; + } + ++ assert(state[0] == '{'); ++ + nmstate_cstring_free(state); + nmstate_cstring_free(err_kind); + nmstate_cstring_free(err_msg); +diff --git a/rust/src/clib/test/nmpolicy_yaml_test.c b/rust/src/clib/test/nmpolicy_yaml_test.c +new file mode 100644 +index 00000000..7984f509 +--- /dev/null ++++ b/rust/src/clib/test/nmpolicy_yaml_test.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++int main(void) { ++ int rc = EXIT_SUCCESS; ++ const char *policy = "\ ++capture:\n\ ++ default-gw: override me with the cache\n\ ++ base-iface: >\n\ ++ interfaces.name == capture.default-gw.routes.running.0.next-hop-interface\n\ ++ base-iface-routes: >\n\ ++ routes.running.next-hop-interface ==\n\ ++ capture.default-gw.routes.running.0.next-hop-interface\n\ ++ bridge-routes: >\n\ ++ capture.base-iface-routes | routes.running.next-hop-interface:=\"br1\"\n\ ++desired:\n\ ++ interfaces:\n\ ++ - name: br1\n\ ++ description: Linux bridge with base interface as a port\n\ ++ type: linux-bridge\n\ ++ state: up\n\ ++ bridge:\n\ ++ options:\n\ ++ stp:\n\ ++ enabled: false\n\ ++ port:\n\ ++ - name: '{{ capture.base-iface.interfaces.0.name }}'\n\ ++ ipv4: '{{ capture.base-iface.interfaces.0.ipv4 }}'\n\ ++ routes:\n\ ++ config: '{{ capture.bridge-routes.routes.running }}'"; ++ const char *current_state = "\ ++interfaces:\n\ ++- name: eth1\n\ ++ type: ethernet\n\ ++ state: up\n\ ++ mac-address: 1c:c1:0c:32:3b:ff\n\ ++ ipv4:\n\ ++ address:\n\ ++ - ip: 192.0.2.251\n\ ++ prefix-length: 24\n\ ++ dhcp: false\n\ ++ enabled: true\n\ ++routes:\n\ ++ config:\n\ ++ - destination: 0.0.0.0/0\n\ ++ next-hop-address: 192.0.2.1\n\ ++ next-hop-interface: eth1\n\ ++ running:\n\ ++ - destination: 0.0.0.0/0\n\ ++ next-hop-address: 192.0.2.1\n\ ++ next-hop-interface: eth1"; ++ char *state = NULL; ++ char *err_kind = NULL; ++ char *err_msg = NULL; ++ char *log = NULL; ++ ++ if (nmstate_net_state_from_policy(policy, current_state, &state, &log, ++ &err_kind, &err_msg) == NMSTATE_PASS) ++ { ++ printf("%s\n", state); ++ } else { ++ printf("%s: %s\n", err_kind, err_msg); ++ rc = EXIT_FAILURE; ++ } ++ ++ assert(state[0] != '{'); ++ ++ nmstate_cstring_free(state); ++ nmstate_cstring_free(err_kind); ++ nmstate_cstring_free(err_msg); ++ nmstate_cstring_free(log); ++ exit(rc); ++} +diff --git a/rust/src/clib/test/nmstate_test.c b/rust/src/clib/test/nmstate_json_test.c +similarity index 87% +rename from rust/src/clib/test/nmstate_test.c +rename to rust/src/clib/test/nmstate_json_test.c +index 0e79cb15..1bfbcda7 100644 +--- a/rust/src/clib/test/nmstate_test.c ++++ b/rust/src/clib/test/nmstate_json_test.c +@@ -1,3 +1,6 @@ ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include + #include + #include + #include +@@ -21,6 +24,8 @@ int main(void) { + rc = EXIT_FAILURE; + } + ++ assert(state[0] == '{'); ++ + nmstate_cstring_free(state); + nmstate_cstring_free(err_kind); + nmstate_cstring_free(err_msg); +diff --git a/rust/src/clib/test/nmstate_yaml_test.c b/rust/src/clib/test/nmstate_yaml_test.c +new file mode 100644 +index 00000000..de0f2486 +--- /dev/null ++++ b/rust/src/clib/test/nmstate_yaml_test.c +@@ -0,0 +1,34 @@ ++// SPDX-License-Identifier: Apache-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++int main(void) { ++ int rc = EXIT_SUCCESS; ++ char *state = NULL; ++ char *err_kind = NULL; ++ char *err_msg = NULL; ++ char *log = NULL; ++ uint32_t flag = NMSTATE_FLAG_KERNEL_ONLY | NMSTATE_FLAG_YAML_OUTPUT; ++ ++ if (nmstate_net_state_retrieve(flag, &state, &log, &err_kind, &err_msg) ++ == NMSTATE_PASS) { ++ printf("%s\n", state); ++ } else { ++ printf("%s: %s\n", err_kind, err_msg); ++ rc = EXIT_FAILURE; ++ } ++ ++ assert(state[0] != '{'); ++ ++ nmstate_cstring_free(state); ++ nmstate_cstring_free(err_kind); ++ nmstate_cstring_free(err_msg); ++ nmstate_cstring_free(log); ++ exit(rc); ++} +diff --git a/rust/src/lib/Cargo.toml b/rust/src/lib/Cargo.toml +index a27d0e1a..0142026d 100644 +--- a/rust/src/lib/Cargo.toml ++++ b/rust/src/lib/Cargo.toml +@@ -15,6 +15,9 @@ edition = "2018" + [lib] + path = "lib.rs" + ++[dependencies] ++serde_yaml = "0.9" ++ + [dependencies.nispor] + version = "1.2.9" + optional = true +diff --git a/rust/src/lib/net_state.rs b/rust/src/lib/net_state.rs +index 8ab79642..fe5fea78 100644 +--- a/rust/src/lib/net_state.rs ++++ b/rust/src/lib/net_state.rs +@@ -274,7 +274,19 @@ impl NetworkState { + Ok(s) => Ok(s), + Err(e) => Err(NmstateError::new( + ErrorKind::InvalidArgument, +- format!("Invalid json string: {e}"), ++ format!("Invalid JSON string: {e}"), ++ )), ++ } ++ } ++ ++ /// Wrapping function of [serde_yaml::from_str()] with error mapped to ++ /// [NmstateError]. ++ pub fn new_from_yaml(net_state_yaml: &str) -> Result { ++ match serde_yaml::from_str(net_state_yaml) { ++ Ok(s) => Ok(s), ++ Err(e) => Err(NmstateError::new( ++ ErrorKind::InvalidArgument, ++ format!("Invalid YAML string: {e}"), + )), + } + } +-- +2.39.2 + diff --git a/nmstate.spec b/nmstate.spec index 7838405..90662c0 100644 --- a/nmstate.spec +++ b/nmstate.spec @@ -4,7 +4,7 @@ Name: nmstate Version: 1.4.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Declarative network manager API License: LGPLv2+ URL: https://github.com/%{srcname}/%{srcname} @@ -14,6 +14,7 @@ Source2: https://www.nmstate.io/nmstate.gpg Source3: %{url}/releases/download/v%{version}/%{srcname}-vendor-%{version}.tar.xz # Patches 0X are reserved to downstream only Patch0: BZ_2132570-nm-reverse-IPv6-order-before-adding-them-to-setting.patch +Patch11: Enable_clib_yml_api.patch BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: gnupg2 @@ -148,6 +149,9 @@ popd /sbin/ldconfig %changelog +* Wed Feb 22 2023 Gris Ge - 1.4.2-2 +- Enable YAML API in rust clib. + * Sat Feb 18 2023 Gris Ge - 1.4.2-1 - Upgrade to nmstate 1.4.2