doc: update README.md with instructions on how to add a field in opnsense config.xml
This commit is contained in:
parent
3f77bc7aef
commit
a3a61c734f
139
README.md
139
README.md
@ -7,3 +7,142 @@ RUST_LOG=info cargo watch --ignore-nothing -w harmony -w private_repos/ -x 'run
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will run the nationtech bin (likely `private_repos/nationtech/src/main.rs`) on any change in the harmony or private_repos folders.
|
This will run the nationtech bin (likely `private_repos/nationtech/src/main.rs`) on any change in the harmony or private_repos folders.
|
||||||
|
|
||||||
|
## Supporting a new field in OPNSense `config.xml`
|
||||||
|
|
||||||
|
Two steps:
|
||||||
|
- Supporting the field in `opnsense-config-xml`
|
||||||
|
- Enabling Harmony to control the field
|
||||||
|
|
||||||
|
We'll use the `filename` field in the `dhcpcd` section of the file as an example.
|
||||||
|
|
||||||
|
### Supporting the field
|
||||||
|
|
||||||
|
As type checking if enforced, every field from `config.xml` must be known by the code. Each subsection of `config.xml` has its `.rs` file. For the `dhcpcd` section, we'll modify `opnsense-config-xml/src/data/dhcpd.rs`.
|
||||||
|
|
||||||
|
When a new field appears in the xml file, an error like this will be thrown and Harmony will panic :
|
||||||
|
```
|
||||||
|
Running `/home/stremblay/nt/dir/harmony/target/debug/example-nanodc`
|
||||||
|
Found unauthorized element filename
|
||||||
|
thread 'main' panicked at opnsense-config-xml/src/data/opnsense.rs:54:14:
|
||||||
|
OPNSense received invalid string, should be full XML: ()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Define the missing field (`filename`) in the `DhcpInterface` struct of `opnsense-config-xml/src/data/dhcpd.rs`:
|
||||||
|
```
|
||||||
|
pub struct DhcpInterface {
|
||||||
|
...
|
||||||
|
pub filename: Option<String>,
|
||||||
|
```
|
||||||
|
|
||||||
|
Harmony should now be fixed, build and run.
|
||||||
|
|
||||||
|
### Controlling the field
|
||||||
|
|
||||||
|
Define the `xml field setter` in `opnsense-config-xml/src/data/dhcpd.rs`.
|
||||||
|
```
|
||||||
|
impl<'a> DhcpConfig<'a> {
|
||||||
|
...
|
||||||
|
pub fn set_filename(&mut self, filename: &str) {
|
||||||
|
self.enable_netboot();
|
||||||
|
self.get_lan_dhcpd().filename = Some(filename.to_string());
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Define the `value setter` in the `DhcpServer trait` in `domain/topology/network.rs`
|
||||||
|
```
|
||||||
|
#[async_trait]
|
||||||
|
pub trait DhcpServer: Send + Sync {
|
||||||
|
...
|
||||||
|
async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError>;
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Implement the `value setter` in each `DhcpServer` implementation.
|
||||||
|
`infra/opnsense/dhcp.rs`:
|
||||||
|
```
|
||||||
|
#[async_trait]
|
||||||
|
impl DhcpServer for OPNSenseFirewall {
|
||||||
|
...
|
||||||
|
async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError> {
|
||||||
|
{
|
||||||
|
let mut writable_opnsense = self.opnsense_config.write().await;
|
||||||
|
writable_opnsense.dhcp().set_filename(filename);
|
||||||
|
debug!("OPNsense dhcp server set filename {filename}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
`domain/topology/ha_cluster.rs`
|
||||||
|
```
|
||||||
|
#[async_trait]
|
||||||
|
impl DhcpServer for DummyInfra {
|
||||||
|
...
|
||||||
|
async fn set_filename(&self, _filename: &str) -> Result<(), ExecutorError> {
|
||||||
|
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the new field to the DhcpScore in `modules/dhcp.rs`
|
||||||
|
```
|
||||||
|
pub struct DhcpScore {
|
||||||
|
...
|
||||||
|
pub filename: Option<String>,
|
||||||
|
```
|
||||||
|
|
||||||
|
Define it in its implementation in `modules/okd/dhcp.rs`
|
||||||
|
```
|
||||||
|
impl OKDDhcpScore {
|
||||||
|
...
|
||||||
|
Self {
|
||||||
|
dhcp_score: DhcpScore {
|
||||||
|
...
|
||||||
|
filename: Some("undionly.kpxe".to_string()),
|
||||||
|
```
|
||||||
|
|
||||||
|
Define it in its implementation in `modules/okd/bootstrap_dhcp.rs`
|
||||||
|
```
|
||||||
|
impl OKDDhcpScore {
|
||||||
|
...
|
||||||
|
Self {
|
||||||
|
dhcp_score: DhcpScore::new(
|
||||||
|
...
|
||||||
|
Some("undionly.kpxe".to_string()),
|
||||||
|
```
|
||||||
|
|
||||||
|
Update the interpret (function called by the `execute` fn of the interpret) so it now updates the `filename` field value in `modules/dhcp.rs`
|
||||||
|
```
|
||||||
|
impl DhcpInterpret {
|
||||||
|
...
|
||||||
|
let filename_outcome = match &self.score.filename {
|
||||||
|
Some(filename) => {
|
||||||
|
let dhcp_server = Arc::new(topology.dhcp_server.clone());
|
||||||
|
dhcp_server.set_filename(&filename).await?;
|
||||||
|
Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
format!("Dhcp Interpret Set filename to {filename}"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => Outcome::noop(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if next_server_outcome.status == InterpretStatus::NOOP
|
||||||
|
&& boot_filename_outcome.status == InterpretStatus::NOOP
|
||||||
|
&& filename_outcome.status == InterpretStatus::NOOP
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
Ok(Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
format!(
|
||||||
|
"Dhcp Interpret Set next boot to [{:?}], boot_filename to [{:?}], filename to [{:?}]",
|
||||||
|
self.score.boot_filename, self.score.boot_filename, self.score.filename
|
||||||
|
),
|
||||||
|
...
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user