@@ -33,70 +33,92 @@ const supported_label = supported_types
3333 . map ( x => x . toUpperCase ( ) )
3434 . join ( ', ' ) ;
3535
36+ const equalRrset = ( a , b ) => a . record . length == b . record . length &&
37+ a . record . every ( x => b . record . some ( y => y . content == x . content ) ) &&
38+ b . record . every ( x => a . record . some ( y => y . content == x . content ) ) ;
39+
40+ const zonefile2rrset = ( fname , dnsName ) => {
41+ const local_zone = zonefile . parse ( fs . readFileSync ( fname , 'utf-8' ) ) ;
42+ const rrset = [ ] ;
43+ for ( const rrtype of supported_types ) {
44+ const rrset_type = local_zone [ rrtype . toLowerCase ( ) ] || [ ] ;
45+ rrset . push ( ...[ ...new Set ( rrset_type . map ( x => x . name ) ) ] . map ( name => {
46+ const records = rrset_type . filter ( x => formatRecordName ( x . name , dnsName ) === formatRecordName ( name , dnsName ) ) ;
47+ const ttl = records . length >= 0 ? records [ 0 ] . ttl || local_zone . $ttl : local_zone . $ttl ;
48+
49+ return {
50+ name : formatRecordName ( name , dnsName ) ,
51+ type : rrtype . toUpperCase ( ) ,
52+ ttl,
53+ record : rrset_type . filter ( x => x . name === name ) . map ( x => ( {
54+ content : recordTypes [ rrtype ] . to_content ( x , dnsName ) ,
55+ enable : true ,
56+ } ) ) ,
57+ } ;
58+ } ) ) ;
59+ }
60+ return rrset ;
61+ } ;
62+
3663module . exports = ( resource ) => Cli . createCommand ( 'import' , {
3764 description : `Import ${ supported_label } records of ${ resource . title } from BIND-compatible format` ,
3865 plugins : resource . plugins ,
3966 options : Object . assign ( { } , options , resource . options ) ,
4067 dirname : __dirname ,
41- handler : ( args ) => args . helpers . api
42- . get ( `${ args . $node . parent . config . url ( args ) } /${ args . zone } ` )
43- . then ( async remote_zone => {
44- const local_zone = zonefile . parse ( fs . readFileSync ( args [ 'zone-file' ] , 'utf-8' ) ) ;
45-
46- for ( const type of supported_types ) {
47- const remote_rrset_names = new Set ( remote_zone . recordset
48- . filter ( rrset => rrset . type === type . toUpperCase ( ) )
49- . map ( record => record . name ) ) ;
68+ handler : async ( args ) => {
69+ Cli . mutually_exclusive_validate ( args , 'zone-file' , 'nameserver' ) ;
5070
51- const local_rrset_type = local_zone [ type . toLowerCase ( ) ] || [ ] ;
52- const local_rrset_names = new Set ( local_rrset_type . map ( x => formatRecordName ( x . name , remote_zone . dnsName ) ) ) ;
53- const need_to_remove = set_difference ( remote_rrset_names , local_rrset_names ) ;
54- // Delete
55- if ( args . delete ) {
56- for ( const rrset_name of need_to_remove ) {
57- const rrset = remote_zone . recordset . find ( x => x . type === type . toUpperCase ( ) && formatRecordName ( x . name , remote_zone . dnsName ) === rrset_name ) ;
58- const url = `${ resource . url ( args ) } /${ args . zone } /recordset/${ rrset . id } ` ;
59- await args . helpers . api . delete ( url ) ;
60- console . error ( `Delete ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
61- }
62- }
71+ const remote_zone = await args . helpers . api . get ( `${ resource . url ( args ) } /${ args . zone } ` ) ;
72+ const local_zone = zonefile2rrset ( args [ 'zone-file' ] , remote_zone . dnsName ) ;
6373
64- // Upsert
65- const need_to_upsert = set_difference ( local_rrset_names , need_to_remove ) ;
66- for ( const rrset_name of need_to_upsert ) {
67- const records = local_rrset_type
68- . filter ( rrset => formatRecordName ( rrset . name , remote_zone . dnsName ) === rrset_name )
69- . map ( record => recordTypes [ type ] . to_content ( record , remote_zone ) )
70- . map ( content => ( {
71- content : content ,
72- disabled : false ,
73- } ) ) ;
74+ for ( const type of supported_types ) {
75+ const remote_rrset_names = new Set ( remote_zone . recordset
76+ . filter ( rrset => rrset . type === type . toUpperCase ( ) )
77+ . map ( rrset => rrset . name )
78+ ) ;
79+ const local_rrset_names = new Set ( local_zone
80+ . filter ( rrset => rrset . type === type . toUpperCase ( ) )
81+ . map ( rrset => rrset . name )
82+ ) ;
83+ const need_to_remove = set_difference ( remote_rrset_names , local_rrset_names ) ;
7484
75- const ttl = local_rrset_type . find ( rrset => formatRecordName ( rrset . name , remote_zone . dnsName ) === rrset_name ) . ttl | local_zone . $ttl ;
85+ // Delete
86+ if ( args . delete ) {
87+ for ( const rrset_name of need_to_remove ) {
88+ const rrset = remote_zone . recordset . find ( x => x . type === type . toUpperCase ( ) && x . name === rrset_name ) ;
89+ const url = `${ resource . url ( args ) } /${ args . zone } /recordset/${ rrset . id } ` ;
90+ await args . helpers . api . delete ( url ) ;
91+ console . error ( `Delete ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
92+ }
93+ }
7694
77- const data = {
78- name : rrset_name ,
79- ttl : ttl ,
80- type : type . toUpperCase ( ) ,
81- record : records ,
82- } ;
95+ // Upsert
96+ const need_to_upsert = set_difference ( local_rrset_names , need_to_remove ) ;
97+ for ( const rrset_name of need_to_upsert ) {
98+ const rrset = local_zone
99+ . find ( rrset =>
100+ rrset . type === type . toUpperCase ( ) && rrset . name == rrset_name
101+ ) ;
83102
84- const remote_rrset = remote_zone . recordset . find ( rrset => rrset . type === type . toUpperCase ( ) && rrset . name === rrset_name ) ;
85- if ( remote_rrset ) {
86- // Update
87- const url = `${ resource . url ( args ) } /${ args . zone } /recordset/${ remote_rrset . id } ` ;
88- await args . helpers . api . patch ( url , data ) ;
89- console . error ( `Update ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
90- } else {
91- // Add
92- const url = `${ resource . url ( args ) } /${ args . zone } /recordset` ;
93- await args . helpers . api . post ( url , data ) ;
94- console . error ( `Add ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
95- }
103+ const remote_rrset = remote_zone . recordset . find ( rrset => rrset . type === type . toUpperCase ( ) && rrset . name === rrset_name ) ;
104+ if ( remote_rrset && ! equalRrset ( rrset , remote_rrset ) ) {
105+ // Update
106+ const url = `${ resource . url ( args ) } /${ args . zone } /recordset/${ remote_rrset . id } ` ;
107+ await args . helpers . api . patch ( url , rrset ) ;
108+ console . error ( `Update ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
109+ } else if ( ! remote_rrset ) {
110+ // Add
111+ const url = `${ resource . url ( args ) } /${ args . zone } /recordset` ;
112+ await args . helpers . api . post ( url , rrset ) ;
113+ console . error ( `Add ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
114+ } else {
115+ console . error ( `Skip update ${ type . toUpperCase ( ) } ${ rrset_name } ` ) ;
96116 }
97117 }
98- return args . helpers . api
99- . get ( `${ resource . url ( args ) } /${ args . zone } ` )
100- . then ( result => args . helpers . sendOutput ( args , result ) ) ;
101- } ) ,
118+ }
119+
120+ return args . helpers . api
121+ . get ( `${ resource . url ( args ) } /${ args . zone } ` )
122+ . then ( result => args . helpers . sendOutput ( args , result ) ) ;
123+ } ,
102124} ) ;
0 commit comments