Commit bc77bb16 authored by Gaël Berthaud-Müller's avatar Gaël Berthaud-Müller
Browse files

add delete route

parent 5f18e326
......@@ -423,3 +423,15 @@ paths:
'200':
description: ''
delete:
security:
- ApiToken: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RecordList'
responses:
'200':
description: ''
......@@ -117,7 +117,7 @@ class TestZones(unittest.TestCase):
type='TXT'
)
self.api.zones_zone_records_post(zone='example.com.', record_list=RecordList(value=[old_record]))
self.api.zones_zone_records_post(zone='example.com.', record_list=RecordList([old_record]))
update_records_request = UpdateRecordsRequest(
old_records=RecordList([old_record]),
......@@ -133,4 +133,25 @@ class TestZones(unittest.TestCase):
self.assertEqual(record.text, new_record.text, msg='New record does not have the expected value')
found = True
self.assertTrue(found, msg='New record not found in zone records')
self.assertTrue(found, msg='Updated record not found in zone records')
def test_delete_records(self):
name = random_name('example.com.')
record = RecordTypeTXT(
_class='IN',
ttl=300,
name=name,
text=random_string(32),
type='TXT'
)
self.api.zones_zone_records_post(zone='example.com.', record_list=RecordList([record]))
self.api.zones_zone_records_delete(zone='example.com.', record_list=RecordList([record]))
records = self.api.zones_zone_records_get(zone='example.com.')
found = False
for record in records.value:
if type(record) is RecordTypeTXT and record.name == name:
found = True
self.assertFalse(found, msg='Delete record found in zone records')
\ No newline at end of file
......@@ -11,6 +11,7 @@ pub trait RecordApi {
async fn get_records(&mut self, zone: dns::Name, class: dns::DNSClass) -> Result<Vec<dns::Record>, Self::Error>;
async fn add_records(&mut self, zone: dns::Name, class: dns::DNSClass, new_records: Vec<dns::Record>) -> Result<(), Self::Error>;
async fn update_records(&mut self, zone: dns::Name, class: dns::DNSClass, old_records: Vec<dns::Record>, new_records: Vec<dns::Record>) -> Result<(), Self::Error>;
async fn delete_records(&mut self, zone: dns::Name, class: dns::DNSClass, records: Vec<dns::Record>) -> Result<(), Self::Error>;
// delete_records
}
......
......@@ -9,6 +9,9 @@ use super::client::{ClientResponse, DnsClient};
use super::api::{RecordApi, ZoneApi};
const MAX_PAYLOAD_LEN: u16 = 1232;
#[derive(Debug)]
pub enum DnsApiError {
ClientError(ClientError),
......@@ -82,7 +85,7 @@ impl RecordApi for DnsApiClient {
{
let edns = message.edns_mut();
edns.set_max_payload(1232);
edns.set_max_payload(MAX_PAYLOAD_LEN);
edns.set_version(0);
}
......@@ -100,12 +103,11 @@ impl RecordApi for DnsApiClient {
async fn update_records(&mut self, zone: Name, class: DNSClass, old_records: Vec<Record>, new_records: Vec<Record>) -> Result<(), Self::Error>
{
// Taken from trust_dns_client::op::update_message::compare_and_swap
// The original function can not be used as is because it takes a RecordSet and not a Record list
// for updates, the query section is used for the zone
let mut zone_query: Query = Query::new();
let mut zone_query = Query::new();
zone_query.set_name(zone.clone())
.set_query_class(class)
.set_query_type(RecordType::SOA);
......@@ -130,8 +132,8 @@ impl RecordApi for DnsApiClient {
// add the delete for the old record
let mut delete = old_records;
// the class must be none for delete
for record in delete.iter_mut() {
// the class must be none for delete
record.set_dns_class(DNSClass::NONE);
// the TTL should be 0
record.set_ttl(0);
......@@ -144,7 +146,7 @@ impl RecordApi for DnsApiClient {
// Extended dns
{
let edns = message.edns_mut();
edns.set_max_payload(1232);
edns.set_max_payload(MAX_PAYLOAD_LEN);
edns.set_version(0);
}
......@@ -159,6 +161,55 @@ impl RecordApi for DnsApiClient {
Ok(())
}
async fn delete_records(&mut self, zone: Name, class: DNSClass, records: Vec<Record>) -> Result<(), Self::Error>
{
// for updates, the query section is used for the zone
let mut zone_query = Query::new();
zone_query.set_name(zone.clone())
.set_query_class(class)
.set_query_type(RecordType::SOA);
let mut message: Message = Message::new();
// build the message
// TODO: set random / time based id
message
.set_id(0)
.set_message_type(MessageType::Query)
.set_op_code(OpCode::Update)
.set_recursion_desired(false);
message.add_zone(zone_query);
let mut delete = records;
for record in delete.iter_mut() {
// the class must be none for delete
record.set_dns_class(DNSClass::NONE);
// the TTL should be 0
record.set_ttl(0);
}
message.add_updates(delete);
// Extended dns
{
let edns = message.edns_mut();
edns.set_max_payload(MAX_PAYLOAD_LEN);
edns.set_version(0);
}
let response = ClientResponse(self.client.send(message)).await.map_err(|e| DnsApiError::ClientError(e))?;
if response.response_code() != ResponseCode::NoError {
return Err(DnsApiError::ResponceNotOk {
code: response.response_code(),
zone: zone,
});
}
Ok(())
}
}
......
......@@ -29,10 +29,11 @@ async fn rocket() -> rocket::Rocket {
get_zone_records,
create_zone_records,
update_zone_records,
delete_zone_records,
get_zones,
create_zone,
add_member_to_zone,
create_auth_token,
create_user
create_user,
])
}
......@@ -56,7 +56,6 @@ pub async fn create_zone_records(
}
}).await?;
let mut dns_api = DnsApiClient::new(client);
dns_api.add_records(
......@@ -90,7 +89,6 @@ pub async fn update_zone_records(
}
}).await?;
let mut dns_api = DnsApiClient::new(client);
dns_api.update_records(
......@@ -103,6 +101,36 @@ pub async fn update_zone_records(
return Ok(Json(()));
}
#[delete("/zones/<zone>/records", data = "<records>")]
pub async fn delete_zone_records(
client: DnsClient,
conn: DbConn,
user_info: Result<models::UserInfo, models::ErrorResponse>,
zone: models::AbsoluteName,
records: Json<models::RecordList>
) -> Result<Json<()>, models::ErrorResponse> {
let user_info = user_info?;
let zone_name = zone.to_utf8();
conn.run(move |c| {
if user_info.is_admin() {
models::Zone::get_by_name(c, &zone_name)
} else {
user_info.get_zone(c, &zone_name)
}
}).await?;
let mut dns_api = DnsApiClient::new(client);
dns_api.delete_records(
zone.clone(),
models::DNSClass::IN.into(),
records.into_inner().try_into_dns_type(zone.into_inner(), models::DNSClass::IN.into())?
).await?;
return Ok(Json(()));
}
#[get("/zones")]
pub async fn get_zones(
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment