1

I was assigned a task by my boss that I have no idea how to accomplish. He needs me to build a script so that he can do various DNS admin tasks with a command line script. Although I'm not a programmer, I have at least played with python a little.

I'm not sure which would be the best way to accomplish the job. The file follows a very (at least to humans) easy 5 line pattern. The only part of each entry that changes is the domain name itself.

zone "bostire.com" {
        type master;
        allow-transfer {none;};
        file "/etc/bind/zones/bostire.com";
};
zone "caylorscustommolds.com" {
        type master;
        allow-transfer {none;};
        file "/etc/bind/zones/caylorscustommolds.com";
};
zone "contractorsservicesofsek.com" {
        type master;
        allow-transfer {none;};
        file "/etc/bind/zones/contractorsservicesofsek.com";
};

I'll need to be able to have functions that can add, delete, and sort this file. For the sake of future inprovements to the script, I would like to work towards being able to do it like so:

add_entry(newdomain.tld)
del_entry(olddomain.tld)
sort_entries()

In my thinking, which I admit is not the best in the world, if I knew how to read the file into an array of some kind so that it can be sorted, I should be able to use that same array concept to delete. Adding would be straight forward, with a call to sort_entries() afterword.

I don't expect you folks to write the whole dang program for me, but if you could point me in the right direction, or throw out a few ideas for me to read about, that would be great!


I noticed that it didn't seem to be saving the sorted list. So, I set out to investigate why. Here is modified code based on Barnacle_Ed's instructions:

import re

recordslist = open('/home/bradboy/named.conf.local', 'r+')
myregex = re.compile('^zone.*^\};\n', re.DOTALL | re.MULTILINE)
mylist = myregex.findall(recordslist.read())
mylist.sort()
print len(mylist)
numitems = 0
recordslist.seek(0)
for entry in sorted(mylist):
    recordslist.write(entry)
    numitems += 1
    print numitems
recordslist.truncate()
recordslist.close()

Which produces an output of:

bradboy@ns1:~$ python dns.py 
1
1

What am I doing wrong?

bradboy
  • 63
  • 7
  • I guess there are already tools that do that, see here: http://stackoverflow.com/q/236859/989121 – georg Mar 21 '13 at 17:32

1 Answers1

1

Here's a few basic building blocks to get you started off:

1) Open the file for both read and write

myfile = open('your_filename_here', r+)


2) Use re.findall() to partition the entries into a list, where each entry starts with 'zone' and ends with '};'

myregex = re.compile('zone.*?\};', re.DOTALL | re.MULTILINE)
mylist = myregex.findall(myfile.read())


3) To add, delete, and sort, use the append(), remove(), and sort() functions. Note that you'll need the exact contents of one of the array entries in order to delete it...you can do this cleverly with something like

for entry in mylist:
    if 'string_to_remove' in entry:
        mylist.remove(entry)


4) Finally, when you're ready to overwrite your old file with the modified contents of the list, start at the beginning of the file, write out all entries from your list, then discard everything after the resulting position. From a different stackoverflow question,

myfile.seek(0)
for entry in mylist:
    myfile.write(entry)
myfile.truncate()
myfile.close()



Hope this helps!

Community
  • 1
  • 1
Barnacle_Ed
  • 80
  • 11
  • Your point (2) is exactly the boost I needed! The regex pattern has a slight flaw. " }; " appears twice in each entry. I tried making re.compile('^zone.*?\^};', re.DOTALL | re.MULTILINE) so regex would correctly find only the word zone that is the first word of a new line, and the same with the }; However now it matches nothing. Notice the caret, which is supposed to be the new line anchor. Any ideas? – bradboy Mar 21 '13 at 18:32
  • Ah good point, I overlooked the first instance of "};". My mistake! The problem with your current one is you're escaping the second ^, so the regex is looking for a literal '^' character. I think what you want instead is `re.compile('^zone.*^};')` – Barnacle_Ed Mar 21 '13 at 18:52
  • That should be a `re.compile('^zone.*?^};')` (silly me forgot a question mark). Regexes are unforgiving, but powerful when they work. – Barnacle_Ed Mar 21 '13 at 18:58
  • disregard previous comment... I put the carat in the wrong spot. It should look like this: myregex = re.compile('zone.*?^\};', re.DOTALL | re.MULTILINE) – bradboy Mar 21 '13 at 19:02
  • It was stripping the new line, so I had to fix it with a newline in the regex. Corrected version: myregex = re.compile('^zone.*?^\};\n', re.DOTALL | re.MULTILINE) – bradboy Mar 21 '13 at 19:15
  • Cool :) if this helped you out, be sure to "accept" the answer please – Barnacle_Ed Mar 21 '13 at 19:20
  • On the line `myregex = re.compile('^zone.*^\};\n', re.DOTALL | re.MULTILINE)` try changing the regex to `^zone.*?^\};`. You could also try printing mylist to see what the contents look like, then debug from there. – Barnacle_Ed Mar 22 '13 at 16:19