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
```

Unit and integration test cases included.

Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
Gris Ge 2023-11-13 15:34:23 +08:00 committed by Fernando Fernández Mancera
parent 0ef80caba7
commit 75e2f04296
3 changed files with 102 additions and 14 deletions

View File

@ -7,14 +7,12 @@ use serde::{Deserialize, Serialize};
use crate::{ip::is_ipv6_addr, ErrorKind, MergedNetworkState, NmstateError};
const SUPPORTED_DNS_OPTIONS: [&str; 18] = [
"attempts",
const SUPPORTED_DNS_OPTS_NO_VALUE: [&str; 15] = [
"debug",
"edns0",
"inet6",
"ip6-bytestring",
"ip6-dotint",
"ndots",
"no-aaaa",
"no-check-names",
"no-ip6-dotint",
@ -23,11 +21,13 @@ const SUPPORTED_DNS_OPTIONS: [&str; 18] = [
"rotate",
"single-request",
"single-request-reopen",
"timeout",
"trust-ad",
"use-vc",
];
const SUPPORTED_DNS_OPTS_WITH_VALUE: [&str; 3] =
["ndots", "timeout", "attempts"];
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(deny_unknown_fields)]
@ -166,15 +166,37 @@ impl DnsClientState {
}
if let Some(opts) = self.options.as_ref() {
for opt in opts {
if !SUPPORTED_DNS_OPTIONS.contains(&opt.as_str()) {
return Err(NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Unsupported DNS option {opt}, \
only support: {}",
SUPPORTED_DNS_OPTIONS.join(", ")
),
));
match opt.find(':') {
Some(i) => {
let opt = &opt[..i];
if !SUPPORTED_DNS_OPTS_WITH_VALUE.contains(&opt) {
return Err(NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Option '{opt}' is not supported to hold \
a value, only support these without \
value: {} and these with values: {}:n",
SUPPORTED_DNS_OPTS_NO_VALUE.join(", "),
SUPPORTED_DNS_OPTS_WITH_VALUE.join(":n, ")
),
));
}
}
None => {
if !SUPPORTED_DNS_OPTS_NO_VALUE.contains(&opt.as_str())
{
return Err(NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Unsupported DNS option {opt}, \
only support these without value: {} \
and these with values: {}",
SUPPORTED_DNS_OPTS_NO_VALUE.join(", "),
SUPPORTED_DNS_OPTS_WITH_VALUE.join(":n, ")
),
));
}
}
}
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{DnsState, MergedDnsState};
use crate::{DnsState, ErrorKind, MergedDnsState};
#[test]
fn test_dns_verify_uncompressed_srvs() {
@ -50,3 +50,36 @@ fn test_dns_verify_uncompressed_srvs() {
merged.verify(&current).unwrap();
}
#[test]
fn test_dns_option_with_value() {
let mut desired: DnsState = serde_yaml::from_str(
r"---
config:
options:
- rotate
- ndots:9
",
)
.unwrap();
desired.sanitize().unwrap();
}
#[test]
fn test_invalid_dns_option_with_value() {
let mut desired: DnsState = serde_yaml::from_str(
r"---
config:
options:
- rotate
- ndot:9
",
)
.unwrap();
let result = desired.sanitize();
assert!(result.is_err());
if let Err(e) = result {
assert_eq!(e.kind(), ErrorKind::InvalidArgument);
}
}

View File

@ -540,3 +540,36 @@ def test_set_invalid_dns_options(static_dns):
)
with pytest.raises(NmstateValueError):
libnmstate.apply(desired_state)
def test_set_dns_option_with_value(static_dns):
desired_state = yaml.load(
"""---
dns-resolver:
config:
options:
- rotate
- debug
- ndots:9
""",
Loader=yaml.SafeLoader,
)
libnmstate.apply(desired_state)
current_state = libnmstate.show()
assert "ndots:9" in current_state[DNS.KEY][DNS.CONFIG][DNS.OPTIONS]
def test_invalid_dns_option_with_value(static_dns):
desired_state = yaml.load(
"""---
dns-resolver:
config:
options:
- rotate
- debug
- ndot:9
""",
Loader=yaml.SafeLoader,
)
with pytest.raises(NmstateValueError):
libnmstate.apply(desired_state)