delete bulk and export/import
Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
@@ -166,6 +166,232 @@ export class OVHService {
|
||||
return results;
|
||||
}
|
||||
|
||||
async bulkDeleteRecords(zoneName, recordIds) {
|
||||
const results = [];
|
||||
|
||||
for (const recordId of recordIds) {
|
||||
try {
|
||||
await this.deleteDNSRecord(zoneName, recordId);
|
||||
results.push({ recordId, success: true });
|
||||
} catch (error) {
|
||||
results.push({ recordId, success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
exportToBind9(zoneName, records) {
|
||||
const lines = [];
|
||||
lines.push(`; Zone file for ${zoneName}`);
|
||||
lines.push(`; Generated on ${new Date().toISOString()}`);
|
||||
lines.push('');
|
||||
lines.push(`$ORIGIN ${zoneName}.`);
|
||||
lines.push('');
|
||||
|
||||
// Sort records by type for better readability
|
||||
const sortedRecords = [...records].sort((a, b) => {
|
||||
const typeOrder = { SOA: 0, NS: 1, A: 2, AAAA: 3, CNAME: 4, MX: 5, TXT: 6, SRV: 7 };
|
||||
return (typeOrder[a.fieldType] || 99) - (typeOrder[b.fieldType] || 99);
|
||||
});
|
||||
|
||||
for (const record of sortedRecords) {
|
||||
const subdomain = record.subDomain || '@';
|
||||
const ttl = record.ttl || 3600;
|
||||
|
||||
let line = '';
|
||||
|
||||
switch (record.fieldType) {
|
||||
case 'A':
|
||||
case 'AAAA':
|
||||
line = `${subdomain}\t${ttl}\tIN\t${record.fieldType}\t${record.target}`;
|
||||
break;
|
||||
case 'CNAME':
|
||||
line = `${subdomain}\t${ttl}\tIN\tCNAME\t${record.target}${record.target.endsWith('.') ? '' : '.'}`;
|
||||
break;
|
||||
case 'MX':
|
||||
const priority = record.priority || 10;
|
||||
line = `${subdomain}\t${ttl}\tIN\tMX\t${priority} ${record.target}${record.target.endsWith('.') ? '' : '.'}`;
|
||||
break;
|
||||
case 'TXT':
|
||||
const txtValue = record.target.includes(' ') && !record.target.startsWith('"')
|
||||
? `"${record.target}"`
|
||||
: record.target;
|
||||
line = `${subdomain}\t${ttl}\tIN\tTXT\t${txtValue}`;
|
||||
break;
|
||||
case 'SRV':
|
||||
const priority_srv = record.priority || 0;
|
||||
const weight = record.weight || 0;
|
||||
const port = record.port || 0;
|
||||
line = `${subdomain}\t${ttl}\tIN\tSRV\t${priority_srv} ${weight} ${port} ${record.target}${record.target.endsWith('.') ? '' : '.'}`;
|
||||
break;
|
||||
case 'NS':
|
||||
line = `${subdomain}\t${ttl}\tIN\tNS\t${record.target}${record.target.endsWith('.') ? '' : '.'}`;
|
||||
break;
|
||||
case 'CAA':
|
||||
const flags = record.flags || 0;
|
||||
const tag = record.tag || 'issue';
|
||||
line = `${subdomain}\t${ttl}\tIN\tCAA\t${flags} ${tag} "${record.target}"`;
|
||||
break;
|
||||
default:
|
||||
line = `${subdomain}\t${ttl}\tIN\t${record.fieldType}\t${record.target}`;
|
||||
}
|
||||
|
||||
lines.push(line);
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
parseFromBind9(zoneName, zoneContent) {
|
||||
const records = [];
|
||||
const lines = zoneContent.split('\n');
|
||||
|
||||
let currentOrigin = zoneName;
|
||||
|
||||
for (let line of lines) {
|
||||
// Remove comments
|
||||
const commentIndex = line.indexOf(';');
|
||||
if (commentIndex !== -1) {
|
||||
line = line.substring(0, commentIndex);
|
||||
}
|
||||
|
||||
line = line.trim();
|
||||
|
||||
// Skip empty lines
|
||||
if (!line) continue;
|
||||
|
||||
// Handle $ORIGIN directive
|
||||
if (line.startsWith('$ORIGIN')) {
|
||||
const parts = line.split(/\s+/);
|
||||
if (parts[1]) {
|
||||
currentOrigin = parts[1].replace(/\.$/, '');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip $TTL and other directives for now
|
||||
if (line.startsWith('$')) continue;
|
||||
|
||||
// Parse record line
|
||||
const parts = line.split(/\s+/);
|
||||
if (parts.length < 4) continue;
|
||||
|
||||
let idx = 0;
|
||||
let subdomain = parts[idx++];
|
||||
|
||||
// Handle @ symbol
|
||||
if (subdomain === '@') {
|
||||
subdomain = '';
|
||||
}
|
||||
|
||||
// Remove trailing dot from subdomain
|
||||
if (subdomain.endsWith('.')) {
|
||||
subdomain = subdomain.slice(0, -1);
|
||||
}
|
||||
|
||||
let ttl = 3600;
|
||||
let recordClass = 'IN';
|
||||
let recordType = '';
|
||||
|
||||
// Parse TTL (if it's a number)
|
||||
if (!isNaN(parts[idx])) {
|
||||
ttl = parseInt(parts[idx++]);
|
||||
}
|
||||
|
||||
// Parse class (usually IN)
|
||||
if (parts[idx] === 'IN' || parts[idx] === 'CH' || parts[idx] === 'HS') {
|
||||
recordClass = parts[idx++];
|
||||
}
|
||||
|
||||
// Parse record type
|
||||
recordType = parts[idx++];
|
||||
|
||||
// Parse record data based on type
|
||||
const recordData = {
|
||||
fieldType: recordType,
|
||||
subDomain: subdomain,
|
||||
ttl: ttl
|
||||
};
|
||||
|
||||
switch (recordType) {
|
||||
case 'A':
|
||||
case 'AAAA':
|
||||
recordData.target = parts[idx];
|
||||
break;
|
||||
case 'CNAME':
|
||||
case 'NS':
|
||||
recordData.target = parts[idx].replace(/\.$/, '');
|
||||
break;
|
||||
case 'MX':
|
||||
recordData.priority = parseInt(parts[idx++]);
|
||||
recordData.target = parts[idx].replace(/\.$/, '');
|
||||
break;
|
||||
case 'TXT':
|
||||
// Join remaining parts and remove quotes
|
||||
const txtValue = parts.slice(idx).join(' ');
|
||||
recordData.target = txtValue.replace(/^"|"$/g, '');
|
||||
break;
|
||||
case 'SRV':
|
||||
recordData.priority = parseInt(parts[idx++]);
|
||||
recordData.weight = parseInt(parts[idx++]);
|
||||
recordData.port = parseInt(parts[idx++]);
|
||||
recordData.target = parts[idx].replace(/\.$/, '');
|
||||
break;
|
||||
case 'CAA':
|
||||
recordData.flags = parseInt(parts[idx++]);
|
||||
recordData.tag = parts[idx++];
|
||||
const caaValue = parts.slice(idx).join(' ');
|
||||
recordData.target = caaValue.replace(/^"|"$/g, '');
|
||||
break;
|
||||
default:
|
||||
recordData.target = parts.slice(idx).join(' ');
|
||||
}
|
||||
|
||||
// Skip SOA records as they are managed by OVH
|
||||
if (recordType !== 'SOA') {
|
||||
records.push(recordData);
|
||||
}
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
async importFromBind9(zoneName, zoneContent, replaceAll = false) {
|
||||
const records = this.parseFromBind9(zoneName, zoneContent);
|
||||
|
||||
if (replaceAll) {
|
||||
// Delete all existing records (except SOA and NS for zone apex)
|
||||
const existingRecords = await this.getDNSRecords(zoneName);
|
||||
const recordsToDelete = existingRecords.filter(r =>
|
||||
r.fieldType !== 'SOA' &&
|
||||
!(r.fieldType === 'NS' && (!r.subDomain || r.subDomain === ''))
|
||||
);
|
||||
|
||||
for (const record of recordsToDelete) {
|
||||
try {
|
||||
await this.deleteDNSRecord(zoneName, record.id);
|
||||
} catch (error) {
|
||||
console.error(`Failed to delete record ${record.id}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create all imported records
|
||||
const results = [];
|
||||
for (const recordData of records) {
|
||||
try {
|
||||
const result = await this.createDNSRecord(zoneName, recordData);
|
||||
results.push({ success: true, record: result });
|
||||
} catch (error) {
|
||||
results.push({ success: false, error: error.message, record: recordData });
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
Referencia en una nueva incidencia
Block a user