Compare commits

...

No commits in common. "c8" and "c8s" have entirely different histories.
c8 ... c8s

10 changed files with 935 additions and 303 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
SOURCES/nmstate-1.4.5.tar.gz
SOURCES/nmstate-vendor-1.4.5.tar.xz
SOURCES/nmstate-1.4.2.tar.gz
SOURCES/nmstate-vendor-1.4.2.tar.xz
SOURCES/nmstate.gpg

View File

@ -1,2 +1,3 @@
cd4f8e938eabaf7e70fb251c06e477ba3bc9d8c8 SOURCES/nmstate-1.4.5.tar.gz
4735ef08c31684624a7844832cc2ba20e67983f6 SOURCES/nmstate-vendor-1.4.5.tar.xz
165eba0069da41758442f1d2efa8cae180417882 SOURCES/nmstate-1.4.2.tar.gz
0815a374c7acca14db28b47347e43797d4b3d570 SOURCES/nmstate-vendor-1.4.2.tar.xz
5c1d9d65f9db4fedc9dc96e0fb6cac0a86749c88 SOURCES/nmstate.gpg

View File

@ -0,0 +1,66 @@
From d7d732332e486cd8969ff4b5ef95a24cb68b5441 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Mon, 27 Feb 2023 12:17:05 +0800
Subject: [PATCH] nm: Ignore error when creating profile if not desired
When a undesired interface holding `autoconf: true` and `dhcp: false`
for IPv6, nmstate will fail with error:
Autoconf without DHCP is not supported yet
This is caused by `nm/connection.py` try to create `NM.SimpleConnection`
for every interface even not desired.
This patch changed to:
* Only create new `NM.SimpleConnection` when desired or changed.
* Use current profile if exists when not desired or changed.
* Ignore error if not desired/changed.
Integration test case included.
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/nm/profile.py | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py
index ad1ad19f..1119cd1a 100644
--- a/libnmstate/nm/profile.py
+++ b/libnmstate/nm/profile.py
@@ -24,6 +24,7 @@ from distutils.version import StrictVersion
import logging
import time
+from libnmstate.error import NmstateError
from libnmstate.error import NmstateInternalError
from libnmstate.error import NmstateLibnmError
from libnmstate.error import NmstateNotSupportedError
@@ -321,9 +322,22 @@ class NmProfile:
# TODO: Use applied config as base profile
# Or even better remove the base profile argument as top level
# of nmstate should provide full/merged configure.
- self._nm_simple_conn = create_new_nm_simple_conn(
- self._iface, self._nm_profile
- )
+ if self._iface.is_changed or self._iface.is_desired:
+ self._nm_simple_conn = create_new_nm_simple_conn(
+ self._iface, self._nm_profile
+ )
+ elif self._nm_profile:
+ self._nm_simple_conn = NM.SimpleConnection.new_clone(
+ self._nm_profile
+ )
+ else:
+ try:
+ self._nm_simple_conn = create_new_nm_simple_conn(
+ self._iface, self._nm_profile
+ )
+ # No error for undesired interface
+ except NmstateError:
+ pass
def save_config(self, save_to_disk):
self._check_sriov_support()
--
2.39.2

View File

@ -0,0 +1,206 @@
From d410b928c8f2a22d42d1974b62ab5b3164861184 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Thu, 23 Feb 2023 13:06:01 +0800
Subject: [PATCH] nm: Fix error on SR-IOV
When SR-IOV VF naming scheme is like `ens1f0v0`, nmstate will delete
the VF NM connection when applying this state:
```yml
---
interfaces:
- name: ens1f0
type: ethernet
state: up
ethernet:
sr-iov:
total-vfs: 1
- name: ens1f0v0
type: ethernet
state: up
ipv4:
enabled: false
ipv6:
enabled: false
```
This is because `delete_other_profiles()` is checking
`self._nm_profile()` from active NM profile instead of newly created
one. The fix is using newly created profile `self._nm_simple_conn`.
We also have race problem when activating PF along with VF, PF
activation might delete VF NIC which cause VF activation failed. To
workaround that, we activate PF first via `NmProfile.ACTION_SRIOV_PF`
and wait on it before start VF activation.
Also problem found during SR-IOV investigations is we do extra
un-required modification to `NM.SettingOvsExternalIDs` even it is not
mentioned in desired. We skip overriding `NM.SettingOvsExternalIDs` when
not desired.
Existing test case can cover the use cases.
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/ifaces/ifaces.py | 18 +++++++++++++++++-
libnmstate/netapplier.py | 20 +++++++++++---------
libnmstate/nm/connection.py | 2 +-
libnmstate/nm/profile.py | 12 ++++++++++--
4 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
index 828ff578..470dc0e6 100644
--- a/libnmstate/ifaces/ifaces.py
+++ b/libnmstate/ifaces/ifaces.py
@@ -157,6 +157,23 @@ class Ifaces:
def has_vf_count_change_and_missing_eth(self):
return self._has_vf_count_change() and self._has_missing_veth()
+ def has_sriov_iface(self):
+ for iface in self.all_kernel_ifaces.values():
+ if (iface.is_desired or iface.is_changed) and iface.is_up:
+ cur_iface = self._cur_kernel_ifaces.get(iface.name)
+ if (
+ cur_iface
+ and cur_iface.raw.get(Ethernet.CONFIG_SUBTREE, {}).get(
+ Ethernet.SRIOV_SUBTREE, {}
+ )
+ ) or iface.original_desire_dict.get(
+ Ethernet.CONFIG_SUBTREE, {}
+ ).get(
+ Ethernet.SRIOV_SUBTREE, {}
+ ):
+ return True
+ return False
+
def _has_vf_count_change(self):
for iface in self.all_kernel_ifaces.values():
cur_iface = self._cur_kernel_ifaces.get(iface.name)
@@ -664,7 +681,6 @@ class Ifaces:
return None
def get_cur_iface(self, iface_name, iface_type):
-
iface = self._cur_kernel_ifaces.get(iface_name)
if iface and iface_type in (None, InterfaceType.UNKNOWN, iface.type):
return iface
diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py
index ae909126..50a70a9c 100644
--- a/libnmstate/netapplier.py
+++ b/libnmstate/netapplier.py
@@ -104,7 +104,7 @@ def apply(
pf_net_state,
verify_change,
save_to_disk,
- has_sriov_pf=True,
+ VERIFY_RETRY_COUNT_SRIOV,
)
# Refresh the current state
current_state = show_with_plugins(
@@ -120,8 +120,16 @@ def apply(
current_state,
save_to_disk,
)
+
+ if net_state.ifaces.has_sriov_iface():
+ # If SR-IOV is present, the verification timeout is being increased
+ # to avoid timeouts due to slow drivers like i40e.
+ verify_retry = VERIFY_RETRY_COUNT_SRIOV
+ else:
+ verify_retry = VERIFY_RETRY_COUNT
+
_apply_ifaces_state(
- plugins, net_state, verify_change, save_to_disk, has_sriov_pf=False
+ plugins, net_state, verify_change, save_to_disk, verify_retry
)
if commit:
destroy_checkpoints(plugins, checkpoints)
@@ -154,7 +162,7 @@ def rollback(*, checkpoint=None):
def _apply_ifaces_state(
- plugins, net_state, verify_change, save_to_disk, has_sriov_pf=False
+ plugins, net_state, verify_change, save_to_disk, verify_retry
):
for plugin in plugins:
# Do not allow plugin to modify the net_state for future verification
@@ -163,12 +171,6 @@ def _apply_ifaces_state(
verified = False
if verify_change:
- if has_sriov_pf:
- # If SR-IOV is present, the verification timeout is being increased
- # to avoid timeouts due to slow drivers like i40e.
- verify_retry = VERIFY_RETRY_COUNT_SRIOV
- else:
- verify_retry = VERIFY_RETRY_COUNT
for _ in range(verify_retry):
try:
_verify_change(plugins, net_state)
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
index 1fbb380b..6448e372 100644
--- a/libnmstate/nm/connection.py
+++ b/libnmstate/nm/connection.py
@@ -240,7 +240,7 @@ def create_new_nm_simple_conn(iface, nm_profile):
InterfaceType.OVS_PORT,
)
or iface.type == InterfaceType.OVS_BRIDGE
- ):
+ ) and OvsDB.OVS_DB_SUBTREE in iface.original_desire_dict:
nm_setting = create_ovsdb_external_ids_setting(
iface_info.get(OvsDB.OVS_DB_SUBTREE, {})
)
diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py
index 53eaebed..ad1ad19f 100644
--- a/libnmstate/nm/profile.py
+++ b/libnmstate/nm/profile.py
@@ -56,6 +56,7 @@ ROUTE_REMOVED = "_route_removed"
class NmProfile:
# For unmanged iface and desired to down
ACTION_ACTIVATE_FIRST = "activate_first"
+ ACTION_SRIOV_PF = "activate_sriov_pf"
ACTION_DEACTIVATE = "deactivate"
ACTION_DEACTIVATE_FIRST = "deactivate_first"
ACTION_DELETE_DEVICE = "delete_device"
@@ -77,6 +78,7 @@ class NmProfile:
ACTION_ACTIVATE_FIRST,
ACTION_DEACTIVATE_FIRST,
ACTION_TOP_CONTROLLER,
+ ACTION_SRIOV_PF,
ACTION_NEW_IFACES,
ACTION_OTHER_CONTROLLER,
ACTION_NEW_OVS_PORT,
@@ -181,6 +183,11 @@ class NmProfile:
else:
self._add_action(NmProfile.ACTION_NEW_IFACES)
else:
+ if (
+ self._nm_dev.props.capabilities
+ & NM.DeviceCapabilities.SRIOV
+ ):
+ self._add_action(NmProfile.ACTION_SRIOV_PF)
if self._iface.type == InterfaceType.OVS_PORT:
self._add_action(NmProfile.ACTION_MODIFIED_OVS_PORT)
if self._iface.type == InterfaceType.OVS_INTERFACE:
@@ -462,6 +469,7 @@ class NmProfile:
def do_action(self, action):
if action in (
+ NmProfile.ACTION_SRIOV_PF,
NmProfile.ACTION_MODIFIED,
NmProfile.ACTION_MODIFIED_OVS_PORT,
NmProfile.ACTION_MODIFIED_OVS_IFACE,
@@ -559,8 +567,8 @@ class NmProfile:
or nm_profile.get_connection_type() == self._nm_iface_type
)
and (
- self._nm_profile is None
- or nm_profile.get_uuid() != self._nm_profile.get_uuid()
+ self._nm_simple_conn is None
+ or nm_profile.get_uuid() != self._nm_simple_conn.get_uuid()
)
):
ProfileDelete(
--
2.39.2

View File

@ -0,0 +1,636 @@
From ad2bfa136290e72cdfd4b7877b49b3fc07203f9c Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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::<serde_json::Value>(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::<serde_json::Value>(policy_str).is_ok()
+ } else {
+ false
+ };
+
let mut policy = match deserilize_from_c_char::<NetworkPolicy>(
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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -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 <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <nmstate.h>
+
+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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -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 <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <nmstate.h>
+
+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<Self, NmstateError> {
+ 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

View File

@ -1,157 +0,0 @@
From c95e26154cfe105faedb6fe6187e89da658e6d02 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Tue, 14 Nov 2023 16:08:35 +0800
Subject: [PATCH 1/2] dns: Fix DNS option `ndots`, `timeout` and `attempts`
The `ndots`, `timeout` and `attempts` DNS options are allowed to
hold a integer value in the format of `<opt_name>:<int>`. Previously,
nmstate is treating them as invalid DNS option. This patch fix it.
Now this YAML is supported:
```yml
dns-resolver:
config:
options:
- rotate
- ndots:9
```
Integration test cases included.
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/dns.py | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/libnmstate/dns.py b/libnmstate/dns.py
index f792b896..5bb512e8 100644
--- a/libnmstate/dns.py
+++ b/libnmstate/dns.py
@@ -19,14 +19,12 @@ EMPTY_DNS = {
REMOVE_DNS_CONFIG = {DNS.CONFIG: EMPTY_DNS}
-SUPPORTED_DNS_OPTIONS = [
- "attempts",
+SUPPORTED_DNS_OPTS_NO_VALUE = [
"debug",
"edns0",
"inet6",
"ip6-bytestring",
"ip6-dotint",
- "ndots",
"no-aaaa",
"no-check-names",
"no-ip6-dotint",
@@ -35,11 +33,16 @@ SUPPORTED_DNS_OPTIONS = [
"rotate",
"single-request",
"single-request-reopen",
- "timeout",
"trust-ad",
"use-vc",
]
+SUPPORTED_DNS_OPTS_WITH_VALUE = [
+ "ndots",
+ "timeout",
+ "attempts",
+]
+
class DnsState:
PRIORITY_METADATA = "_priority"
@@ -73,10 +76,24 @@ class DnsState:
def _canonicalize_dns_options(self):
for opt in self.config_options:
- if opt not in SUPPORTED_DNS_OPTIONS:
+ if opt.find(":") > 0:
+ opt = opt[: opt.find(":")]
+ if opt not in SUPPORTED_DNS_OPTS_WITH_VALUE:
+ raise NmstateValueError(
+ "Option '{}' is not supported to hold "
+ "a value, only support these without "
+ "value: {} and these with values: {}:n",
+ opt,
+ ", ".join(SUPPORTED_DNS_OPTS_NO_VALUE),
+ ":n, ".join(SUPPORTED_DNS_OPTS_WITH_VALUE),
+ )
+ elif opt not in SUPPORTED_DNS_OPTS_NO_VALUE:
raise NmstateValueError(
- f"Unsupported DNS option {opt}, only support: "
- f"{', '.join(SUPPORTED_DNS_OPTIONS)}",
+ "Option '{}' is not supported, only support these "
+ "without value: {} and these with values: {}:n",
+ opt,
+ ", ".join(SUPPORTED_DNS_OPTS_NO_VALUE),
+ ":n, ".join(SUPPORTED_DNS_OPTS_WITH_VALUE),
)
@property
--
2.42.1
From af07271ec5044ec092a3b66c0955636819ccde04 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Tue, 14 Nov 2023 16:16:53 +0800
Subject: [PATCH 2/2] dns: Fix purging DNS config
When user desires:
```yml
---
dns-resolver:
config:
search: []
```
It means user want to remove all search but preserve servers and
options, current nmstate incorrectly treat this as purge also.
This patch only treat these two as purge.
```yml
dns-resolver:
config: {}
```
and
```yml
dns-resolver:
config:
server: []
search: []
options: []
```
Integration test cases included.
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/nm/dns.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libnmstate/nm/dns.py b/libnmstate/nm/dns.py
index 60ebbba7..b811fdb2 100644
--- a/libnmstate/nm/dns.py
+++ b/libnmstate/nm/dns.py
@@ -158,7 +158,11 @@ def get_dns_config_iface_names(acs_and_ipv4_profiles, acs_and_ipv6_profiles):
for nm_ac, ip_profile in chain(
acs_and_ipv6_profiles, acs_and_ipv4_profiles
):
- if ip_profile.props.dns or ip_profile.props.dns_search:
+ if (
+ ip_profile.props.dns
+ or ip_profile.props.dns_search
+ or ip_profile.props.dns_options
+ ):
try:
iface_name = nm_ac.get_devices()[0].get_iface()
iface_names.append(iface_name)
--
2.42.1

View File

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE8f1XsqXpyNthgIbGbM3lj+QeKP8FAmPwSo0ACgkQbM3lj+Qe
KP/P7A/8DLoHZkeuCsDjCYQ5yk0pWSuEqDMZT4Qqk6khBJOtvx5L14oImlrpmOVr
iw3pclF/fl8wxcpPYwcVn2odJWryaZxKw3vNPfth47vEtk3RVZpIqHLsgcCOEcX1
/czFbA4EJLZV67Qu4gEfrfjbTKEmcakXLI5qUbMDw0nwqx5BI/66iF5kZD4IGJui
MDVbe61wAatcOl5RU8Y0rFI6fz4a9PXVJEijHJC8ZMg/Vq4Q/aBErUZAQ9RKJmi7
Uu2TLYv4JTMiWX/xspH+CJX7bbaJ9N7P/Z3NzEOKVlDGMmG7TN9QtpnuSF46Jv5K
LTLdr7mBSK3dnQ9vIwcmM8m/MWU2w9dxf7Oh8YCkjwlLk1ANnANHz+xBMx+qIM5e
uNB2iPL2nHTDLFVbOMp1dcZzvndgm3a5oS9L4nglVojvNqGTmkjeJaM5bk80HvxJ
i/onHNmNRnQeHn8xUT7EcBQXUBUCORExygTyJ1dsw+BwbncwV2lOSan7OJY53Os2
Lm7kHRBtOPeJNK7NbF55eo+N2+1+n9XP7oiCaj//FwWXN6vh97afi7fp5men2MKr
xbBPtYP5BV5LT7/DxKW+AunL2UUtlYoeCI0wm16kDzL8VW1u1Arv5NtdQsSnONk9
PChrlhPnITjIZ0o2+GrYYOROZPbMSl4oQtO0hTiUub2Vrf3sPIc=
=zl4m
-----END PGP SIGNATURE-----

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEESP1vrlFad7SENoIch4lWe4cVzrwFAmVDid0ACgkQh4lWe4cV
zrx26BAAqv8ec7UMDkJ7MGAXwRpMZrLQ+zjPIDlVH0HVmdvZY2g8Lx2iK9g0xHeL
YGdVk3aL3UwQE/5Tt6qtzQ8sk76dWyveS1XxxNDLZa+TKvcGqDbxnmvOAIBJwrlD
4Q6MNWqudJDsboGotKSAoI/xHJafFzWfHU+SSp4AHtf2xHa2KFZqmaZW5gVdYq9j
/Zhepz8OQ+1s8/frVw1JEqKaTcw5gc0/2xNzh0MkC714Lkk4dhITHP6zh1HF/2i8
LPIdVHMI8Ze7w4imiamr38+G3XzCQJ/6A/N6couFyJXrLgCn0Jm7Zv8t3TLW69JA
QD/YHcFgeZmh3QRHVoNIOunG7X7eczLjy61VVXMp3F38+GWSLxK2f7DMRyzRvIxF
uBrd9yBZ4qkSEqIG2tEBIZOPg4deDADaesyD3d5c0JROsmxkmhl9SEBk03qWtJEY
kWhCF4tGvVp1r+W7AjS6QpqAtFXJcBQdj1qs49fgRxVGjmw2ljMQdLT6O/oSFNpS
wzjvGhh8WvMcmStCQ0crTOeihYTyJu2PPqJ3c373EnE9xPN3cJVh+AGwV5kcpxkk
bJF8qooJDq7MAuNqiKdXORGzG0ht16TzJ4aE+1vGFAErYZitCzU13rkW3dKIU19h
KgFqlKXUHCS6J3KzJQszDpn+Hw8WOvcCQQ1LivcyLKHlvmTQPi4=
=51yt
-----END PGP SIGNATURE-----

View File

@ -1,99 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
i2QY7dEEs/uMRtq8C8kSWg==
=259x
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -3,8 +3,8 @@
%define libname libnmstate
Name: nmstate
Version: 1.4.5
Release: 2%{?dist}
Version: 1.4.2
Release: 4%{?dist}
Summary: Declarative network manager API
License: LGPLv2+
URL: https://github.com/%{srcname}/%{srcname}
@ -14,7 +14,9 @@ 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
Patch10: RHEL-13936-dns-opt-fix.patch
Patch11: Enable_clib_yml_api.patch
Patch12: BZ_2160416-fix-SRIOV.patch
Patch13: BZ_2160416-Ignore-error-when-creating-profile-if-not-desired.patch
BuildRequires: python3-devel
BuildRequires: python3-setuptools
BuildRequires: gnupg2
@ -149,30 +151,6 @@ popd
/sbin/ldconfig
%changelog
* Wed Nov 15 2023 Gris Ge <fge@redhat.com> - 1.4.5-2
- Fix use case on purging DNS option. RHEL-13936
* Thu Nov 02 2023 Gris Ge <fge@redhat.com> - 1.4.5-1
- Support DNS option. RHEL-13936
* Wed Oct 04 2023 Wen Liang <wenliang@redhat.com> - 1.4.4-5
- Support treating string as int for address prefix-length. RHEL-3358
* Wed Aug 30 2023 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.4.4-4
- Fix issue with ovs-bridge and ovs-interface with same name. RHBZ#2231843
* Tue May 30 2023 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.4.4-3
- Support static route with auto-ip. RHBZ#2203277
* Mon Apr 24 2023 Gris Ge <fge@redhat.com> - 1.4.4-2
- Enable CI gating.
* Sun Apr 23 2023 Gris Ge <fge@redhat.com> - 1.4.4-1
- Upgrade to nmstate 1.4.4
* Wed Mar 29 2023 Gris Ge <fge@redhat.com> - 1.4.3-1
- Upgrade to nmstate 1.4.3. RHBZ#2179899
* Mon Feb 27 2023 Gris Ge <fge@redhat.com> - 1.4.2-4
- Ignore undesired iface config. RHBZ#2160416