wip: refactor
This commit is contained in:
parent
419b78b55e
commit
c1d09cd391
13 changed files with 165 additions and 231 deletions
|
@ -11,8 +11,9 @@ use domain::tsig::{Algorithm, Key, KeyName};
|
|||
use domain::net::client::request::{self, RequestMessage, RequestMessageMulti, SendRequest, SendRequestMulti};
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use crate::resources::record;
|
||||
use crate::resources::dns::internal;
|
||||
use crate::proto;
|
||||
use crate::errors::Error;
|
||||
use super::{RecordDriver, ZoneDriver, DnsDriverError};
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
@ -127,7 +128,7 @@ impl ZoneDriver for DnsDriver {
|
|||
impl RecordDriver for DnsDriver {
|
||||
/// ------------- AXFR -------------
|
||||
|
||||
async fn get_records(&self, zone: &str) -> Result<Vec<record::Record>, DnsDriverError> {
|
||||
async fn get_records(&self, zone: &str) -> Result<internal::RecordList, DnsDriverError> {
|
||||
let mut msg = MessageBuilder::new_vec();
|
||||
msg.header_mut().set_ad(true);
|
||||
|
||||
|
@ -172,7 +173,7 @@ impl RecordDriver for DnsDriver {
|
|||
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
|
||||
records.pop();
|
||||
|
||||
Ok(records)
|
||||
Ok(internal::RecordList { records })
|
||||
}
|
||||
|
||||
/// ------------- Dynamic Update - RFC 2136 -------------
|
||||
|
@ -221,7 +222,7 @@ impl RecordDriver for DnsDriver {
|
|||
/// zone rrset rr Add to an RRset
|
||||
|
||||
|
||||
async fn add_records(&self, zone: &str, new_records: &[record::DnsRecordImpl]) -> Result<(), DnsDriverError> {
|
||||
async fn add_records(&self, zone: &str, new_records: internal::RecordList) -> Result<(), DnsDriverError> {
|
||||
let mut msg = MessageBuilder::new_vec();
|
||||
msg.header_mut().set_opcode(Opcode::UPDATE);
|
||||
|
||||
|
@ -233,7 +234,8 @@ impl RecordDriver for DnsDriver {
|
|||
|
||||
let mut msg = msg.authority();
|
||||
|
||||
for record in new_records {
|
||||
for record in new_records.records {
|
||||
let record = proto::dns::RecordImpl::try_from(record)?;
|
||||
msg.push(record)?;
|
||||
}
|
||||
|
||||
|
@ -294,6 +296,12 @@ impl From<wire::ParseError> for DnsDriverError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Error> for DnsDriverError {
|
||||
fn from(value: Error) -> Self {
|
||||
DnsDriverError::OperationError { reason: Box::new(value) }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
use trust_dns_proto::DnsHandle;
|
||||
use trust_dns_client::client::ClientHandle;
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::resources::record;
|
||||
use crate::resources::dns::internal;
|
||||
|
||||
pub type BoxedZoneDriver = Arc<dyn ZoneDriver>;
|
||||
pub type BoxedRecordDriver = Arc<dyn RecordDriver>;
|
||||
|
@ -25,8 +25,8 @@ pub trait ZoneDriver: Send + Sync {
|
|||
|
||||
#[async_trait]
|
||||
pub trait RecordDriver: Send + Sync {
|
||||
async fn get_records(&self, zone: &str) -> Result<Vec<record::Record>, DnsDriverError>;
|
||||
async fn add_records(&self, zone: &str, new_records: &[record::DnsRecordImpl]) -> Result<(), DnsDriverError>;
|
||||
async fn get_records(&self, zone: &str) -> Result<internal::RecordList, DnsDriverError>;
|
||||
async fn add_records(&self, zone: &str, new_records: internal::RecordList) -> Result<(), DnsDriverError>;
|
||||
//async fn update_records(&mut self, zone: dns::Name, class: dns::DNSClass, old_records: Vec<dns::Record>, new_records: Vec<dns::Record>) -> ConnectorResult<()>;
|
||||
//async fn delete_records(&mut self, zone: dns::Name, class: dns::DNSClass, records: Vec<dns::Record>) -> ConnectorResult<()>;
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ use serde::{Serialize, Serializer};
|
|||
use serde_json::{Value, json};
|
||||
|
||||
use crate::dns::DnsDriverError;
|
||||
use crate::resources::record::{RecordError, RecordParseError};
|
||||
use crate::resources::dns::external::rdata::RDataValidationError;
|
||||
use crate::resources::dns::external::record::{RecordError, RecordValidationError};
|
||||
use crate::resources::zone::ZoneError;
|
||||
use crate::validation::{DomainValidationError, TxtParseError};
|
||||
use crate::template::TemplateError;
|
||||
|
@ -157,6 +158,9 @@ impl fmt::Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl IntoResponse for Error {
|
||||
fn into_response(self) -> Response {
|
||||
if let Some(status) = self.status {
|
||||
|
@ -319,41 +323,46 @@ impl From<DnsDriverError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<RecordParseError> for Error {
|
||||
fn from(value: RecordParseError) -> Self {
|
||||
impl From<RDataValidationError> for Error {
|
||||
fn from(value: RDataValidationError) -> Self {
|
||||
match value {
|
||||
RecordParseError::Ip4Address { input } => {
|
||||
RDataValidationError::Ip4Address { input } => {
|
||||
Error::new("record:parse:ip4", "The following IPv4 address {input} is invalid. IPv4 addresses should have four numbers, each between 0 and 255, separated by dots.")
|
||||
.with_details(json!({
|
||||
"input": input
|
||||
}))
|
||||
},
|
||||
RecordParseError::Ip6Address { input } => {
|
||||
RDataValidationError::Ip6Address { input } => {
|
||||
Error::new("record:parse:ip6", "The following IPv4 address {input} is invalid. IPv6 addresses should have eight groups of four hexadecimal digit separated by colons. Leftmost zeros in a group can be omitted, sequence of zeros can be shorted by a double colons.")
|
||||
.with_details(json!({
|
||||
"input": input
|
||||
}))
|
||||
},
|
||||
RecordParseError::RDataUnknown { input, field, rtype } => {
|
||||
Error::new("record:parse:rdata_unknown", "Unknown error while parsing record rdata field")
|
||||
.with_details(json!({
|
||||
"input": input,
|
||||
"field": field,
|
||||
"rtype": rtype,
|
||||
}))
|
||||
},
|
||||
RecordParseError::NameUnknown { input } => {
|
||||
Error::new("record:parse:name_unknown", "Unknown error while parsing record name")
|
||||
.with_details(json!({
|
||||
"input": input
|
||||
}))
|
||||
},
|
||||
RecordParseError::NotInZone { name, zone } => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RecordValidationError> for Error {
|
||||
fn from(value: RecordValidationError) -> Self {
|
||||
match value {
|
||||
RecordValidationError::NotInZone { name, zone } => {
|
||||
Error::new("record:parse:not_in_zone", "The domain name {name} is not in the current zone ({zone})")
|
||||
.with_details(json!({
|
||||
"name": name,
|
||||
"zone": zone
|
||||
}))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RecordError > for Error {
|
||||
fn from(value: RecordError) -> Self {
|
||||
match value {
|
||||
RecordError::Validation { suberrors } => {
|
||||
Error::new("record:validation", "Error while validating input records")
|
||||
.with_suberrors(suberrors)
|
||||
.with_status(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -377,18 +386,6 @@ impl From<TemplateError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<RecordError > for Error {
|
||||
fn from(value: RecordError) -> Self {
|
||||
match value {
|
||||
RecordError::Validation { suberrors } => {
|
||||
Error::new("record:validation", "Error while validating input records")
|
||||
.with_suberrors(suberrors)
|
||||
.with_status(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProtoDnsError> for Error {
|
||||
fn from(value: ProtoDnsError) -> Self {
|
||||
match value {
|
||||
|
@ -400,6 +397,12 @@ impl From<ProtoDnsError> for Error {
|
|||
"rtype": rtype,
|
||||
}))
|
||||
},
|
||||
ProtoDnsError::NameParseError { input } => {
|
||||
Error::new("proto:dns:name_unknown", "Unknown error while parsing name")
|
||||
.with_details(json!({
|
||||
"input": input
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,17 @@ use std::fmt::Write;
|
|||
|
||||
use domain::base::rdata::ComposeRecordData;
|
||||
use domain::base::wire::{Composer, ParseError};
|
||||
use domain::base::{Name, ParseRecordData, ParsedName, RecordData, Rtype, ToName, Ttl};
|
||||
use domain::base::{iana::Class, Name, ParseRecordData, ParsedName, RecordData, Record, Rtype, ToName, Ttl};
|
||||
use domain::rdata;
|
||||
use domain::dep::octseq::{Parser, Octets};
|
||||
|
||||
use crate::resources::dns::internal;
|
||||
use crate::errors::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProtoDnsError {
|
||||
RDataUnknown { input: String, field: String, rtype: String },
|
||||
NameParseError { input: String }
|
||||
}
|
||||
|
||||
/* --------- A --------- */
|
||||
|
@ -423,3 +425,58 @@ impl<Name: ToName, Octs: AsRef<[u8]>> ComposeRecordData for ParsedRData<Name, Oc
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- Records --------- */
|
||||
|
||||
pub(crate) type RecordImpl = Record<
|
||||
Name<Vec<u8>>,
|
||||
ParsedRData<Name<Vec<u8>>,Vec<u8>>
|
||||
>;
|
||||
|
||||
|
||||
impl<Name: ToString, Oct: AsRef<[u8]>> From<Record<Name, ParsedRData<Name, Oct>>> for internal::Record {
|
||||
fn from(value: Record<Name, ParsedRData<Name, Oct>>) -> Self {
|
||||
internal::Record {
|
||||
name: internal::Name::new(value.owner().to_string()),
|
||||
ttl: value.ttl().as_secs(),
|
||||
rdata: internal::RData::from(value.into_data()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<internal::Record> for RecordImpl {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: internal::Record) -> Result<Self, Self::Error> {
|
||||
let owner = value.name.to_string();
|
||||
let owner = owner.parse::<Name<_>>().map_err(|e| {
|
||||
Error::from(ProtoDnsError::NameParseError {
|
||||
input: owner
|
||||
}).with_cause(&e.to_string())
|
||||
})?;
|
||||
|
||||
let ttl = Ttl::from_secs(value.ttl);
|
||||
let data = value.rdata.try_into()?;
|
||||
Ok(Record::new(owner, Class::IN, ttl, data))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct RecordList {
|
||||
pub records: Vec<RecordImpl>
|
||||
}
|
||||
|
||||
impl TryFrom<internal::RecordList> for RecordList {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: internal::RecordList) -> Result<Self, Self::Error> {
|
||||
let mut records = Vec::with_capacity(value.records.len());
|
||||
|
||||
for record in value.records.into_iter() {
|
||||
records.push(record.try_into()?)
|
||||
}
|
||||
|
||||
Ok(RecordList { records })
|
||||
}
|
||||
}
|
||||
|
|
3
src/resources/dns/external/mod.rs
vendored
3
src/resources/dns/external/mod.rs
vendored
|
@ -1,2 +1,5 @@
|
|||
pub mod rdata;
|
||||
pub mod record;
|
||||
|
||||
pub use rdata::*;
|
||||
pub use record::*;
|
||||
|
|
26
src/resources/dns/external/rdata.rs
vendored
26
src/resources/dns/external/rdata.rs
vendored
|
@ -1,16 +1,20 @@
|
|||
use std::fmt::Write;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use domain::base::{Rtype, scan::Symbol};
|
||||
use domain::base::scan::Symbol;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::errors::Error;
|
||||
use crate::validation;
|
||||
|
||||
use crate::macros::{append_errors, push_error};
|
||||
use crate::resources::record::RecordParseError;
|
||||
use crate::resources::dns::internal;
|
||||
|
||||
pub enum RDataValidationError {
|
||||
Ip4Address { input: String },
|
||||
Ip6Address { input: String },
|
||||
}
|
||||
|
||||
/// Type used to serialize / deserialize resource records data to response / request
|
||||
///
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
@ -34,20 +38,6 @@ pub enum RData {
|
|||
}
|
||||
|
||||
impl RData {
|
||||
pub fn rtype(&self) -> Rtype {
|
||||
match self {
|
||||
RData::A(_) => Rtype::A,
|
||||
RData::Aaaa(_) => Rtype::AAAA,
|
||||
RData::Cname(_) => Rtype::CNAME,
|
||||
RData::Mx(_) => Rtype::MX,
|
||||
RData::Ns(_) => Rtype::NS,
|
||||
RData::Ptr(_) => Rtype::PTR,
|
||||
RData::Soa(_) => Rtype::SOA,
|
||||
RData::Srv(_) => Rtype::SRV,
|
||||
RData::Txt(_) => Rtype::TXT,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(self) -> Result<internal::RData, Vec<Error>> {
|
||||
let rdata = match self {
|
||||
RData::A(data) => internal::RData::A(data.validate()?),
|
||||
|
@ -101,7 +91,7 @@ impl A {
|
|||
let mut errors = Vec::new();
|
||||
|
||||
let address = push_error!(self.address.parse::<Ipv4Addr>().map_err(|e| {
|
||||
Error::from(RecordParseError::Ip4Address { input: self.address })
|
||||
Error::from(RDataValidationError::Ip4Address { input: self.address })
|
||||
.with_cause(&e.to_string())
|
||||
.with_path("/address")
|
||||
}), errors);
|
||||
|
@ -137,7 +127,7 @@ impl Aaaa {
|
|||
|
||||
// TODO: replace with custom validation
|
||||
let address = push_error!(self.address.parse::<Ipv6Addr>().map_err(|e| {
|
||||
Error::from(RecordParseError::Ip6Address { input: self.address })
|
||||
Error::from(RDataValidationError::Ip6Address { input: self.address })
|
||||
.with_cause(&e.to_string())
|
||||
.with_path("/address")
|
||||
}), errors);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
pub mod rdata;
|
||||
pub mod record;
|
||||
pub mod base;
|
||||
|
||||
pub use rdata::*;
|
||||
pub use record::*;
|
||||
pub use base::*;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::fmt;
|
||||
|
||||
use super::{Name, Rtype};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum RData {
|
||||
A(A),
|
||||
Aaaa(Aaaa),
|
||||
|
@ -13,49 +15,54 @@ pub enum RData {
|
|||
Txt(Txt),
|
||||
}
|
||||
|
||||
pub struct Name {
|
||||
name: String
|
||||
}
|
||||
|
||||
impl Name {
|
||||
pub fn new(name: String) -> Self {
|
||||
Name {
|
||||
name,
|
||||
impl RData {
|
||||
pub fn rtype(&self) -> Rtype {
|
||||
match self {
|
||||
RData::A(_) => Rtype::A,
|
||||
RData::Aaaa(_) => Rtype::Aaaa,
|
||||
RData::Cname(_) => Rtype::Cname,
|
||||
RData::Mx(_) => Rtype::Mx,
|
||||
RData::Ns(_) => Rtype::Ns,
|
||||
RData::Ptr(_) => Rtype::Ptr,
|
||||
RData::Soa(_) => Rtype::Soa,
|
||||
RData::Srv(_) => Rtype::Srv,
|
||||
RData::Txt(_) => Rtype::Txt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct A {
|
||||
pub address: Ipv4Addr,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Aaaa {
|
||||
pub address: Ipv6Addr,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cname {
|
||||
pub target: Name,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Mx {
|
||||
pub preference: u16,
|
||||
pub mail_exchanger: Name,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ns {
|
||||
pub target: Name,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ptr {
|
||||
pub target: Name,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Soa {
|
||||
pub primary_server: Name,
|
||||
pub maintainer: Name,
|
||||
|
@ -66,6 +73,7 @@ pub struct Soa {
|
|||
pub serial: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Srv {
|
||||
pub server: Name,
|
||||
pub port: u16,
|
||||
|
@ -73,6 +81,7 @@ pub struct Srv {
|
|||
pub weight: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Txt {
|
||||
pub text: Vec<u8>,
|
||||
}
|
||||
|
|
|
@ -20,6 +20,4 @@ pub use zone::{Zone, AddZoneMemberRequest, CreateZoneRequest};
|
|||
*/
|
||||
|
||||
pub mod zone;
|
||||
//pub mod rdata;
|
||||
pub mod record;
|
||||
pub mod dns;
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use domain::base::{iana::Class, Name, Record as DnsRecord, Ttl};
|
||||
|
||||
use crate::{errors::Error, validation};
|
||||
use crate::macros::{append_errors, push_error};
|
||||
|
||||
use crate::resources::dns::external;
|
||||
use crate::resources::dns::internal;
|
||||
use crate::proto;
|
||||
|
||||
pub enum RecordParseError {
|
||||
Ip4Address { input: String },
|
||||
Ip6Address { input: String },
|
||||
RDataUnknown { input: String, field: String, rtype: String },
|
||||
NameUnknown { input: String },
|
||||
NotInZone { name: String, zone: String },
|
||||
}
|
||||
|
||||
pub enum RecordError {
|
||||
Validation { suberrors: Vec<Error> },
|
||||
}
|
||||
|
||||
pub(crate) type DnsRecordImpl = DnsRecord<
|
||||
Name<Vec<u8>>,
|
||||
proto::dns::ParsedRData<Name<Vec<u8>>,Vec<u8>>
|
||||
>;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Record {
|
||||
pub name: String,
|
||||
pub ttl: u32,
|
||||
#[serde(flatten)]
|
||||
pub rdata: external::RData
|
||||
}
|
||||
|
||||
// TODO: Proto
|
||||
impl<Name: ToString, Oct: AsRef<[u8]>> From<DnsRecord<Name, proto::dns::ParsedRData<Name, Oct>>> for Record {
|
||||
fn from(value: DnsRecord<Name, proto::dns::ParsedRData<Name, Oct>>) -> Self {
|
||||
Record {
|
||||
name: value.owner().to_string(),
|
||||
ttl: value.ttl().as_secs(),
|
||||
rdata: internal::RData::from(value.into_data()).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Record {
|
||||
fn convert(self, zone_name: &Name<Vec<u8>>) -> Result<DnsRecordImpl, Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let name = push_error!(validation::normalize_domain(&self.name), errors, "/name");
|
||||
|
||||
let name = name.and_then(|name| push_error!(name.parse::<Name<_>>().map_err(|e| {
|
||||
Error::from(RecordParseError::NameUnknown {
|
||||
input: self.name.clone()
|
||||
}).with_cause(&e.to_string())
|
||||
}), errors, "/name"));
|
||||
|
||||
let name = name.and_then(|name| {
|
||||
if !name.ends_with(zone_name) {
|
||||
errors.push(
|
||||
Error::from(RecordParseError::NotInZone { name: self.name, zone: zone_name.to_string() })
|
||||
.with_path("/name")
|
||||
);
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
}
|
||||
});
|
||||
|
||||
let ttl = Ttl::from_secs(self.ttl);
|
||||
let rdata = append_errors!(self.rdata.validate(), errors, "/rdata");
|
||||
|
||||
|
||||
if errors.is_empty() {
|
||||
// TODO: Split this in proto / external
|
||||
let rdata = proto::dns::ParsedRData::try_from(rdata.unwrap()).unwrap();
|
||||
Ok(DnsRecord::new(name.unwrap(), Class::IN, ttl, rdata))
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct RecordList(pub Vec<Record>);
|
||||
|
||||
impl RecordList {
|
||||
fn convert(self, zone_name: &Name<Vec<u8>>) -> Result<Vec<DnsRecordImpl>, Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut records = Vec::new();
|
||||
|
||||
for (index, record) in self.0.into_iter().enumerate() {
|
||||
let record = append_errors!(record.convert(zone_name), errors, &format!("/{index}"));
|
||||
|
||||
if let Some(record) = record {
|
||||
records.push(record)
|
||||
}
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(records)
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize)]
|
||||
pub struct AddRecordsRequest {
|
||||
pub new_records: RecordList
|
||||
}
|
||||
|
||||
pub struct AddRecords {
|
||||
pub new_records: Vec<DnsRecordImpl>
|
||||
}
|
||||
|
||||
impl AddRecordsRequest {
|
||||
pub fn validate(self, zone_name: &str) -> Result<AddRecords, Error> {
|
||||
let zone_name: Name<Vec<u8>> = zone_name.parse().expect("zone name is assumed to be valid");
|
||||
|
||||
let mut errors = Vec::new();
|
||||
let records = append_errors!(self.new_records.convert(&zone_name), errors, "/new_records");
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(AddRecords {
|
||||
new_records: records.unwrap(),
|
||||
})
|
||||
} else {
|
||||
Err(Error::from(RecordError::Validation { suberrors: errors }))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ use crate::database::{BoxedDb, sqlite::SqliteDB};
|
|||
use crate::dns::{BoxedZoneDriver, BoxedRecordDriver, DnsDriverError};
|
||||
use crate::errors::Error;
|
||||
use crate::macros::push_error;
|
||||
use crate::resources::record::RecordList;
|
||||
use crate::resources::dns::internal::RecordList;
|
||||
use crate::validation;
|
||||
|
||||
pub enum ZoneError {
|
||||
|
@ -45,13 +45,9 @@ impl Zone {
|
|||
let zone = db.get_zone_by_name(zone_name).await?;
|
||||
let mut records = record_driver.get_records(&zone.name).await?;
|
||||
|
||||
records.sort_by(|r1, r2| {
|
||||
let key1 = (&r1.name, r1.rdata.rtype());
|
||||
let key2 = (&r2.name, r2.rdata.rtype());
|
||||
key1.cmp(&key2)
|
||||
});
|
||||
records.sort();
|
||||
|
||||
Ok(RecordList(records))
|
||||
Ok(records)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ use axum::Json;
|
|||
use crate::AppState;
|
||||
use crate::errors::Error;
|
||||
use crate::resources::zone::{CreateZoneRequest, Zone};
|
||||
use crate::resources::record::{AddRecordsRequest, Record, RecordList};
|
||||
use crate::resources::dns::external;
|
||||
use crate::resources::dns::internal;
|
||||
|
||||
|
||||
pub async fn create_zone(
|
||||
|
@ -18,26 +19,26 @@ pub async fn create_zone(
|
|||
pub async fn get_zone_records(
|
||||
Path(zone_name): Path<String>,
|
||||
State(app): State<AppState>,
|
||||
) -> Result<Json<RecordList>, Error>
|
||||
) -> Result<Json<external::RecordList>, Error>
|
||||
{
|
||||
Zone::get_records(&zone_name, app.db, app.records).await.map(Json)
|
||||
Zone::get_records(&zone_name, app.db, app.records)
|
||||
.await
|
||||
.map(|records| Json(records.into()))
|
||||
}
|
||||
|
||||
pub async fn create_zone_records(
|
||||
Path(zone_name): Path<String>,
|
||||
State(app): State<AppState>,
|
||||
Json(add_records): Json<AddRecordsRequest>,
|
||||
) -> Result<Json<Vec<Record>>, Error>
|
||||
Json(add_records): Json<external::AddRecords>,
|
||||
) -> Result<Json<external::RecordList>, Error>
|
||||
{
|
||||
|
||||
let zone = app.db.get_zone_by_name(&zone_name).await?;
|
||||
let add_records = add_records.validate(&zone.name)?;
|
||||
app.records.add_records(&zone.name, &add_records.new_records).await?;
|
||||
let records = add_records.new_records.into_iter()
|
||||
.map(|r| r.into())
|
||||
.collect();
|
||||
let name = internal::Name::new(zone.name.clone());
|
||||
let add_records = add_records.validate(&name)?;
|
||||
app.records.add_records(&zone.name, add_records.new_records.clone()).await?;
|
||||
|
||||
Ok(Json(records))
|
||||
Ok(Json(add_records.new_records.into()))
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::AppState;
|
|||
use crate::errors::Error;
|
||||
use crate::resources::zone::Zone;
|
||||
use crate::template::Template;
|
||||
|
||||
use crate::resources::dns::external;
|
||||
|
||||
pub async fn get_zone_records_page(
|
||||
Path(zone_name): Path<String>,
|
||||
|
@ -20,7 +20,7 @@ pub async fn get_zone_records_page(
|
|||
app.template_engine,
|
||||
json!({
|
||||
"current_zone": zone_name,
|
||||
"records": records,
|
||||
"records": external::RecordList::from(records),
|
||||
})
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue