Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 0 additions & 75 deletions docs/example-config.yaml

This file was deleted.

2 changes: 2 additions & 0 deletions docs/example-config/dns/hetzner-domains.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
provider_name: Hetzner1
domains: []
2 changes: 2 additions & 0 deletions docs/example-config/dns/nitrado-domains.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
provider_name: Nitrado1
domains: []
3 changes: 3 additions & 0 deletions docs/example-config/providers/hetzner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: Hetzner1
api_key: your_api_key
api_base_url: https://dns.hetzner.com/api/v1
3 changes: 3 additions & 0 deletions docs/example-config/providers/nitrado.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: Nitrado1
api_key: your_api_key
api_base_url: https://api.nitrado.net
6 changes: 6 additions & 0 deletions docs/example-config/resolver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ipv4:
url: https://ip.cancom.io
type: Raw
ipv6:
url: https://ipv6.cancom.io
type: Raw
1 change: 1 addition & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod auto;
pub mod command;
pub mod generate_config;
pub mod get;

use std::future::Future;
Expand Down
10 changes: 9 additions & 1 deletion src/cli/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use thiserror::Error;

use crate::{
Config,
cli::{ExecutableCommand, auto, get},
cli::{ExecutableCommand, auto, generate_config, get},
};

#[derive(Debug, ClapSubcommand)]
#[command(version, about, long_about = None)]
pub enum Subcommand<'a> {
Auto(auto::Command<'a>),
Get(get::Command<'a>),
GenerateConfig(generate_config::Command<'a>),
}

#[derive(Debug)]
Expand All @@ -27,6 +28,9 @@ pub enum Error {

#[error("Failed to execute get subcommand: {0}")]
Get(#[from] get::Error),

#[error("Failed to execute generate-config subcommand: {0}")]
GenerateConfig(#[from] generate_config::Error),
}

/// dnrs
Expand Down Expand Up @@ -62,6 +66,10 @@ impl<'command> ExecutableCommand<'command> for Command<'command> {
let input = get::Input { config, reqwest };
subcommand.execute(&input).await?;
}
Subcommand::GenerateConfig(subcommand) => {
let input = generate_config::Input { config };
subcommand.execute(&input).await?;
}
}

Ok(())
Expand Down
63 changes: 63 additions & 0 deletions src/cli/generate_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::{io, marker::PhantomData};

use clap::Parser;
use lum_log::info;
use thiserror::Error;

use crate::{Config, cli::ExecutableCommand};

#[derive(Debug)]
pub struct Input<'config> {
pub config: &'config Config,
}

#[derive(Debug, Error)]
pub enum Error {
#[error("IO error: {0}")]
Io(#[from] io::Error),

#[error("YAML serialization error: {0}")]
Yaml(#[from] serde_yaml_ng::Error),

#[error("Config error: {0}")]
Config(#[from] anyhow::Error),
}

/// Generate configuration directory structure
#[derive(Debug, Parser)]
#[command(version, about, long_about = None, propagate_version = true)]
pub struct Command<'command> {
#[clap(skip)]
_phantom: PhantomData<&'command ()>,

/// Output directory path (defaults to ./config)
#[clap(short, long, default_value = "config")]
pub output: String,

/// Force overwrite existing files
#[clap(short, long, default_value = "false")]
pub force: bool,
}

impl<'command> ExecutableCommand<'command> for Command<'command> {
type I = Input<'command>;
type R = Result<(), Error>;

async fn execute(&self, _input: &'command Self::I) -> Self::R {
let config_dir = std::path::Path::new(&self.output);

if config_dir.exists() && !self.force {
info!(
"Configuration directory {:?} already exists. Use --force to overwrite.",
config_dir
);
return Ok(());
}

Config::create_example_structure(config_dir)?;

info!("Configuration structure created in {:?}", config_dir);

Ok(())
}
}
45 changes: 37 additions & 8 deletions src/cli/get.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use std::marker::PhantomData;

use clap::{Args, Parser};
use lum_log::{error, info};
use thiserror::Error;

use crate::{
Config,
cli::ExecutableCommand,
config::provider::Provider as ProviderConfig,
provider::{GetAllRecordsInput, GetRecordsInput, Provider, nitrado::NitradoProvider},
provider::{
GetAllRecordsInput, GetRecordsInput, Provider, hetzner::HetznerProvider,
netcup::NetcupProvider, nitrado::NitradoProvider,
},
};

#[derive(Debug)]
Expand All @@ -25,15 +29,14 @@ pub enum Error {
ProviderError(#[from] anyhow::Error),
}

//TODO: Fix order of usage message (provider should come first)
#[derive(Debug, Args)]
#[group(required = true, multiple = false)]
pub struct SubdomainArgs {
/// Subdomains to get records for
#[clap(display_order = 3)]
subdomains: Vec<String>,

/// Get all records
#[clap(short, long, default_value = "false")]
#[clap(short, long, default_value = "false", display_order = 3)]
pub all: bool,
}

Expand All @@ -45,9 +48,11 @@ pub struct Command<'command> {
_phantom: PhantomData<&'command ()>,

/// Name of the provider to get records from
#[clap(display_order = 1)]
provider: String,

/// Domain to get records for
#[clap(display_order = 2)]
domain: String,

#[command(flatten)]
Expand All @@ -59,13 +64,23 @@ fn get_provider<'config>(
name: &str,
config: &'config Config,
) -> Option<Box<dyn Provider + 'config>> {
for provider_file_config in config.providers.iter() {
match &provider_file_config.provider {
for provider in config.providers.iter() {
match provider {
ProviderConfig::Nitrado(nitrado_config) => {
if name == nitrado_config.name {
return Some(Box::new(NitradoProvider::new(nitrado_config)));
}
}
ProviderConfig::Hetzner(hetzner_config) => {
if name == hetzner_config.name {
return Some(Box::new(HetznerProvider::new(hetzner_config)));
}
}
ProviderConfig::Netcup(netcup_config) => {
if name == netcup_config.name {
return Some(Box::new(NetcupProvider::new(netcup_config)));
}
}
}
}

Expand All @@ -77,6 +92,20 @@ impl<'command> ExecutableCommand<'command> for Command<'command> {
type R = Result<(), Error>;

async fn execute(&self, input: &'command Self::I) -> Self::R {
if self.subdomain_args.all && !self.subdomain_args.subdomains.is_empty() {
error!("Cannot specify both --all and specific subdomains");
return Err(Error::ProviderError(anyhow::anyhow!(
"Cannot specify both --all and specific subdomains"
)));
}

if !self.subdomain_args.all && self.subdomain_args.subdomains.is_empty() {
error!("Must specify either --all or specific subdomains");
return Err(Error::ProviderError(anyhow::anyhow!(
"Must specify either --all or specific subdomains"
)));
}

let config = input.config;
let provider_name = self.provider.as_str();

Expand Down Expand Up @@ -109,13 +138,13 @@ impl<'command> ExecutableCommand<'command> for Command<'command> {

let records = match results {
Err(e) => {
eprintln!("Error: {}", e);
error!("Error: {}", e);
return Err(e.into());
}
Ok(records) => records,
};

println!("Records: {:#?}", records);
info!("Records: {:#?}", records);
Ok(())
}
}
Loading