1""" Record namespace commands. """ 2 3import os 4import click 5import json 6 7from gandi.cli.core.cli import cli 8from gandi.cli.core.utils import ( 9 output_generic, 10) 11from gandi.cli.core.params import pass_gandi, StringConstraint 12 13 14@cli.group(name='record') 15@pass_gandi 16def record(gandi): 17 """Commands related to DNS zone records (xmlrpc).""" 18 19 20@record.command() 21@click.option('--zone-id', '-z', default=None, type=click.INT, 22 help='Zone ID to use, if not set default zone will be used.') 23@click.option('--output', '-o', is_flag=True, 24 help='Write the records into a file.') 25@click.option('--format', '-f', type=click.Choice(['text', 'json']), 26 help='Choose the output format', required=False) 27@click.option('--limit', help='Limit number of results.', default=100, 28 show_default=True) 29@click.argument('domain', required=True) 30@pass_gandi 31def list(gandi, domain, zone_id, output, format, limit): 32 """List DNS zone records for a domain.""" 33 options = { 34 'items_per_page': limit, 35 } 36 output_keys = ['name', 'type', 'value', 'ttl'] 37 38 if not zone_id: 39 result = gandi.domain.info(domain) 40 zone_id = result['zone_id'] 41 42 if not zone_id: 43 gandi.echo('No zone records found, domain %s doesn\'t seems to be ' 44 'managed at Gandi.' % domain) 45 return 46 47 records = gandi.record.list(zone_id, options) 48 49 if not output and not format: 50 for num, rec in enumerate(records): 51 if num: 52 gandi.separator_line() 53 output_generic(gandi, rec, output_keys, justify=12) 54 elif output: 55 zone_filename = domain + "_" + str(zone_id) 56 if os.path.isfile(zone_filename): 57 open(zone_filename, 'w').close() 58 for record in records: 59 format_record = ('%s %s IN %s %s' % 60 (record['name'], record['ttl'], 61 record['type'], record['value'])) 62 with open(zone_filename, 'ab') as zone_file: 63 zone_file.write(format_record + '\n') 64 gandi.echo('Your zone file have been writen in %s' % zone_filename) 65 elif format: 66 if format == 'text': 67 for record in records: 68 format_record = ('%s %s IN %s %s' % 69 (record['name'], record['ttl'], 70 record['type'], record['value'])) 71 gandi.echo(format_record) 72 if format == 'json': 73 format_record = json.dumps(records, sort_keys=True, 74 indent=4, separators=(',', ': ')) 75 gandi.echo(format_record) 76 77 return records 78 79 80@record.command() 81@click.option('--zone-id', '-z', default=None, type=click.INT, 82 help='Zone ID to use, if not set, default zone will be used.') 83@click.option('--name', default=None, required=True, 84 help='Relative name, may contain leading wildcard. ' 85 '`@` for empty name') 86@click.option('--type', default=None, required=True, 87 type=click.Choice(['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 88 'WKS', 'SRV', 'LOC', 'SPF']), 89 help='DNS record type') 90@click.option('--value', default=None, required=True, 91 type=StringConstraint(minlen=1, maxlen=1024), 92 help='Value for record. Semantics depends on the record type.' 93 'Currently limited to 1024 ASCII characters.' 94 'In case of TXT, each part between quotes is limited to 255' 95 ' characters') 96@click.option('--ttl', default=None, required=False, 97 type=click.IntRange(min=300, max=2592000), 98 help='Time to live, in seconds, between 5 minutes and 30 days') 99@click.argument('domain', required=True) 100@pass_gandi 101def create(gandi, domain, zone_id, name, type, value, ttl): 102 """Create new DNS zone record entry for a domain.""" 103 104 if not zone_id: 105 result = gandi.domain.info(domain) 106 zone_id = result['zone_id'] 107 108 if not zone_id: 109 gandi.echo('No zone records found, domain %s doesn\'t seems to be ' 110 'managed at Gandi.' % domain) 111 return 112 113 record = {'type': type, 'name': name, 'value': value} 114 if ttl: 115 record['ttl'] = ttl 116 117 result = gandi.record.create(zone_id, record) 118 return result 119 120 121@record.command() 122@click.option('--zone-id', '-z', default=None, type=click.INT, 123 help='Zone ID to use, if not set, default zone will be used.') 124@click.option('--name', default=None, 125 help='Relative name of the record to delete.') 126@click.option('--type', default=None, 127 type=click.Choice(['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 128 'WKS', 'SRV', 'LOC', 'SPF']), 129 help='DNS record type') 130@click.option('--value', default=None, 131 type=StringConstraint(minlen=1, maxlen=1024), 132 help='Value for record. Semantics depends on the record type.' 133 'Currently limited to 1024 ASCII characters.' 134 'In case of TXT, each part between quotes is limited to 255' 135 ' characters') 136@click.argument('domain', required=True) 137@pass_gandi 138def delete(gandi, domain, zone_id, name, type, value): 139 """Delete a record entry for a domain""" 140 if not zone_id: 141 result = gandi.domain.info(domain) 142 zone_id = result['zone_id'] 143 144 if not zone_id: 145 gandi.echo('No zone records found, domain %s doesn\'t seems to be ' 146 'managed at Gandi.' % domain) 147 return 148 if not name and not type and not value: 149 proceed = click.confirm('This command without parameters --type, ' 150 '--name or --value will remove all records' 151 ' in this zone file. Are you sur to ' 152 'perform this action ?') 153 if not proceed: 154 return 155 record = {'name': name, 'type': type, 'value': value} 156 result = gandi.record.delete(zone_id, record) 157 return result 158 159 160@record.command() 161@click.option('--zone-id', '-z', default=None, type=click.INT, 162 help='Zone ID to use, if not set, default zone will be used.') 163@click.option('--file', '-f', type=click.File('r'), 164 required=False, help='Filename of the zone file.') 165@click.option('--record', '-r', default=None, required=False, 166 help="'name TTL IN TYPE [A, AAAA, MX, TXT, SPF] value' \n" 167 "Note that you can specify only a name, but in case of " 168 "multiple entries with the same name, only the first one will " 169 "be updated") 170@click.option('--new-record', default=None, required=False, 171 help="'name TTL IN TYPE [A, AAAA, MX, TXT, SPF] value'") 172@click.argument('domain', required=True) 173@pass_gandi 174def update(gandi, domain, zone_id, file, record, new_record): 175 """Update records entries for a domain. 176 177 You can update an individual record using --record and --new-record 178 parameters 179 180 Or you can use a plaintext file to update all records of a DNS zone at 181 once with --file parameter. 182 """ 183 if not zone_id: 184 result = gandi.domain.info(domain) 185 zone_id = result['zone_id'] 186 187 if not zone_id: 188 gandi.echo('No zone records found, domain %s doesn\'t seems to be' 189 ' managed at Gandi.' % domain) 190 return 191 if file: 192 records = file.read() 193 result = gandi.record.zone_update(zone_id, records) 194 return result 195 elif record and new_record: 196 result = gandi.record.update(zone_id, record, new_record) 197 return result 198 else: 199 gandi.echo('You must indicate a zone file or a record.' 200 ' Use `gandi record update --help` for more information') 201