mirror of
https://github.com/oskar456/dzonegit.git
synced 2024-05-11 05:55:41 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef059861b7 | ||
|
|
94461383e8 | ||
|
|
3e09833ec1 | ||
|
|
9ad1e74a88 | ||
|
|
a7d693253d | ||
|
|
3777453d2f | ||
|
|
023906177a | ||
|
|
e79bb901f3 | ||
|
|
f07c84aa32 | ||
|
|
62e35c59d0 | ||
|
|
806976ca6e | ||
|
|
17f771bca6 | ||
|
|
03cf26bbbe | ||
|
|
9923df14b7 | ||
|
|
8d99e86222 |
@@ -5,6 +5,9 @@ python:
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "nightly"
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: "nightly"
|
||||
install:
|
||||
- pip install -e .
|
||||
- pip install pytest
|
||||
|
||||
30
README.rst
30
README.rst
@@ -15,6 +15,7 @@ Main features
|
||||
- check if zone file compiles properly using `named-compilezone(8)`_
|
||||
- autodetect zone name from file name or ``$ORIGIN`` directive
|
||||
- enforce updating serial number when zone content is changed
|
||||
- optional ``smudge`` filter to replace ``$UNIXTIME`` directive with current UNIX time
|
||||
- both ``pre-commit`` and ``pre-receive``/``update`` hooks to enforce similar checks in the remote repository
|
||||
- ``post-receive`` hook to checkout the working copy from a bare repository, generate config snippets for various DNS server software and reload them
|
||||
- only Python 3.5+ standard library is used
|
||||
@@ -53,6 +54,27 @@ Full instalation and usage
|
||||
documentation on how to add custom hooks`_
|
||||
- on the server, set up the configuration options for each repository
|
||||
|
||||
Support for $UNIXTIME directive
|
||||
-------------------------------
|
||||
|
||||
If you want to use ``$UNIXTIME`` in your zone files instead of serial number,
|
||||
you have to install a `smudge` filter on the server, that will replace the
|
||||
directive with current unix time on every checkout. First, set up the filter
|
||||
in the Git configuration:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ git config --global filter.dzonegit.smudge $(which dzonegit-smudge-serial)
|
||||
|
||||
|
||||
Then, apply the filter on all zone files using either ``.git/info/attributes``
|
||||
or directly ``.gitattributes`` file inside the repository:
|
||||
|
||||
.. code-block::
|
||||
|
||||
*.zone filter=dzonegit
|
||||
|
||||
|
||||
Configuration options
|
||||
---------------------
|
||||
|
||||
@@ -63,10 +85,18 @@ named ``dzonegit``. All boolean options default to *False*.
|
||||
*dzonegit.ignorewhitespaceerrors*
|
||||
Ignore white space errors in ``pre-commit`` and ``pre-receive``/``update`` hooks.
|
||||
|
||||
*dzonegit.allowfancynames*
|
||||
In ``pre-commit`` and ``pre-receive``/``update`` hooks, do not enforce zone
|
||||
file name to be similar to the name of the zone.
|
||||
|
||||
*dzonegit.noserialupdate*
|
||||
Do not try to automatically update zone serial number if necessary.
|
||||
Valid only in the ``pre-commit`` hook.
|
||||
|
||||
*dzonegit.nomissingdotcheck*
|
||||
Do not check for forgotten final dot on the right-hand side of PTR records.
|
||||
Valid only in the ``pre-commit`` hook.
|
||||
|
||||
*dzonegit.checkoutpath*
|
||||
Path to a writable directory, to which ``post-receive`` hook checks out
|
||||
current *HEAD* after each update.
|
||||
|
||||
122
dzonegit.py
122
dzonegit.py
@@ -41,17 +41,17 @@ class HookException(ValueError):
|
||||
return "".join(r)
|
||||
|
||||
|
||||
def get_head():
|
||||
r = subprocess.run(
|
||||
["git", "rev-parse", "--verify", "HEAD"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if r.returncode == 0:
|
||||
return r.stdout.decode("utf-8").strip()
|
||||
else:
|
||||
# Initial commit: diff against an empty tree object
|
||||
return "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
def get_head(empty=False):
|
||||
if not empty:
|
||||
r = subprocess.run(
|
||||
["git", "rev-parse", "--verify", "HEAD"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if r.returncode == 0:
|
||||
return r.stdout.decode("ascii").strip()
|
||||
# Initial commit: diff against an empty tree object
|
||||
return "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
|
||||
def check_whitespace_errors(against, revision=None):
|
||||
@@ -83,14 +83,44 @@ def get_file_contents(path, revision=None):
|
||||
return r.stdout
|
||||
|
||||
|
||||
def compile_zone(zonename, zonedata):
|
||||
def unixtime_directive(zonedata, unixtime=None):
|
||||
""" Filter binary zone data. Replace $UNIXTIME with current unix time. """
|
||||
if unixtime is None:
|
||||
unixtime = int(time.time())
|
||||
return re.sub(
|
||||
br'\$UNIXTIME\b',
|
||||
str(unixtime).encode("ascii"),
|
||||
zonedata,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def check_missing_trailing_dot(zonename, compiled_zonedata):
|
||||
badlines = []
|
||||
for line in compiled_zonedata.splitlines():
|
||||
if re.search(
|
||||
r"\sPTR\s+[^\s]*\.{}.$".format(zonename).encode("ascii"),
|
||||
line,
|
||||
re.I,
|
||||
):
|
||||
badlines.append(line.decode("utf-8"))
|
||||
if badlines:
|
||||
raise HookException(
|
||||
"Possibly missing trailing dot after PTR records:\n{}".format(
|
||||
"\n".join(badlines),
|
||||
),
|
||||
fname=zonename,
|
||||
)
|
||||
|
||||
|
||||
def compile_zone(zonename, zonedata, unixtime=None, missing_dot=False):
|
||||
""" Compile the zone. Return tuple with results."""
|
||||
CompileResults = namedtuple(
|
||||
"CompileResults", "success, serial, zonehash, stderr",
|
||||
)
|
||||
r = subprocess.run(
|
||||
["/usr/sbin/named-compilezone", "-o", "-", zonename, "/dev/stdin"],
|
||||
input=zonedata,
|
||||
input=unixtime_directive(zonedata, unixtime),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
@@ -98,6 +128,8 @@ def compile_zone(zonename, zonedata):
|
||||
m = re.search(r"^zone.*loaded serial ([0-9]*)$", stderr, re.MULTILINE)
|
||||
if r.returncode == 0 and m:
|
||||
serial = m.group(1)
|
||||
if missing_dot:
|
||||
check_missing_trailing_dot(zonename, r.stdout)
|
||||
zonehash = sha256(r.stdout).hexdigest()
|
||||
return CompileResults(True, serial, zonehash, stderr)
|
||||
else:
|
||||
@@ -134,7 +166,7 @@ def get_altered_files(against, diff_filter=None, revision=None):
|
||||
If revision is None, list changes between staging area and
|
||||
revision. Otherwise differences between two revisions are computed.
|
||||
"""
|
||||
cmd = ["git", "diff", "--name-only", "-z"]
|
||||
cmd = ["git", "diff", "--name-only", "-z", "--no-renames"]
|
||||
if diff_filter:
|
||||
cmd.append("--diff-filter={}".format(diff_filter))
|
||||
if revision:
|
||||
@@ -173,15 +205,15 @@ def get_zone_origin(zonedata):
|
||||
def get_zone_name(path, zonedata):
|
||||
"""
|
||||
Try to guess zone name from either filename or the first $ORIGIN.
|
||||
Throw a HookException if filename and zone ORIGIN differ more than
|
||||
in slashes.
|
||||
Unless disabled, throw a HookException if filename and zone ORIGIN differ
|
||||
more than in slashes.
|
||||
"""
|
||||
stemname = Path(path).stem.lower()
|
||||
originname = get_zone_origin(zonedata)
|
||||
if originname:
|
||||
tt = str.maketrans("", "", "/_,:-+*%^&#$")
|
||||
sn, on = [s.translate(tt) for s in [stemname, originname]]
|
||||
if sn != on:
|
||||
if sn != on and not get_config("dzonegit.allowfancynames", bool):
|
||||
raise HookException(
|
||||
"Zone origin {o} differs from zone file.".format(o=originname),
|
||||
fname=path,
|
||||
@@ -191,15 +223,21 @@ def get_zone_name(path, zonedata):
|
||||
return stemname
|
||||
|
||||
|
||||
def check_updated_zones(against, revision=None, autoupdate_serial=False):
|
||||
def check_updated_zones(
|
||||
against,
|
||||
revision=None,
|
||||
autoupdate_serial=False,
|
||||
missing_dot=False,
|
||||
):
|
||||
""" Check whether all updated zone files compile. """
|
||||
unixtime = int(time.time())
|
||||
for f in get_altered_files(against, "AMCR", revision):
|
||||
if not f.suffix == ".zone":
|
||||
continue
|
||||
print("Checking file {f}".format(f=f))
|
||||
zonedata = get_file_contents(f, revision)
|
||||
zname = get_zone_name(f, zonedata)
|
||||
rnew = compile_zone(zname, zonedata)
|
||||
rnew = compile_zone(zname, zonedata, unixtime, missing_dot)
|
||||
if not rnew.success:
|
||||
raise HookException(
|
||||
"New zone version does not compile",
|
||||
@@ -208,7 +246,7 @@ def check_updated_zones(against, revision=None, autoupdate_serial=False):
|
||||
try:
|
||||
zonedata = get_file_contents(f, against)
|
||||
zname = get_zone_name(f, zonedata)
|
||||
rold = compile_zone(zname, zonedata)
|
||||
rold = compile_zone(zname, zonedata, unixtime-1)
|
||||
|
||||
if (rold.success and rold.zonehash != rnew.zonehash and not
|
||||
is_serial_increased(rold.serial, rnew.serial)):
|
||||
@@ -219,9 +257,11 @@ def check_updated_zones(against, revision=None, autoupdate_serial=False):
|
||||
|
||||
if autoupdate_serial:
|
||||
newserial = get_increased_serial(rnew.serial)
|
||||
replace_serial(f, rnew.serial, newserial)
|
||||
errmsg += " Serial has been automatically increased."
|
||||
errmsg += " Check and recommit."
|
||||
if replace_serial(f, rnew.serial, newserial):
|
||||
errmsg += " Serial has been automatically increased."
|
||||
errmsg += " Check and recommit."
|
||||
else:
|
||||
errmsg += " Autoupdate of serial number failed."
|
||||
raise HookException(
|
||||
errmsg,
|
||||
fname=f,
|
||||
@@ -264,8 +304,9 @@ def replace_serial(path, oldserial, newserial):
|
||||
flags=re.DOTALL | re.IGNORECASE | re.MULTILINE,
|
||||
)
|
||||
if count != 1:
|
||||
raise HookException("Cannot update zone serial number")
|
||||
return False
|
||||
path.write_text(updated)
|
||||
return True
|
||||
|
||||
|
||||
def get_zone_wildcards(name):
|
||||
@@ -369,13 +410,19 @@ def load_set_file(path):
|
||||
}
|
||||
|
||||
|
||||
def do_commit_checks(against, revision=None, autoupdate_serial=False):
|
||||
def do_commit_checks(
|
||||
against,
|
||||
revision=None,
|
||||
autoupdate_serial=False,
|
||||
missing_dot=False,
|
||||
):
|
||||
try:
|
||||
if not get_config("dzonegit.ignorewhitespaceerrors", bool):
|
||||
check_whitespace_errors(against, revision=revision)
|
||||
check_updated_zones(
|
||||
against, revision=revision,
|
||||
autoupdate_serial=autoupdate_serial,
|
||||
missing_dot=missing_dot,
|
||||
)
|
||||
except HookException as e:
|
||||
print(e)
|
||||
@@ -385,7 +432,12 @@ def do_commit_checks(against, revision=None, autoupdate_serial=False):
|
||||
def pre_commit():
|
||||
against = get_head()
|
||||
autoupdate_serial = not get_config("dzonegit.noserialupdate", bool)
|
||||
do_commit_checks(against, autoupdate_serial=autoupdate_serial)
|
||||
missing_dot = not get_config("dzonegit.nomissingdotcheck", bool)
|
||||
do_commit_checks(
|
||||
against,
|
||||
autoupdate_serial=autoupdate_serial,
|
||||
missing_dot=missing_dot,
|
||||
)
|
||||
|
||||
|
||||
def update(argv=sys.argv):
|
||||
@@ -398,7 +450,7 @@ def update(argv=sys.argv):
|
||||
refname, against, revision = argv[1:4]
|
||||
|
||||
if against == "0000000000000000000000000000000000000000":
|
||||
against = get_head() # Empty commit
|
||||
against = get_head(True) # Empty commit
|
||||
|
||||
if refname != "refs/heads/master":
|
||||
raise SystemExit("Nothing else than master branch is accepted here")
|
||||
@@ -416,7 +468,7 @@ def pre_receive(stdin=sys.stdin):
|
||||
"is accepted here",
|
||||
)
|
||||
if against == "0000000000000000000000000000000000000000":
|
||||
against = get_head() # Empty commit
|
||||
against = get_head(True) # Empty commit
|
||||
do_commit_checks(against, revision)
|
||||
|
||||
|
||||
@@ -434,6 +486,7 @@ def post_receive(stdin=sys.stdin):
|
||||
raise SystemExit("Checkout path not defined. Nothing to do.")
|
||||
|
||||
print("Checking out repository into {}…".format(checkoutpath))
|
||||
Path(checkoutpath).mkdir(parents=True, exist_ok=True)
|
||||
subprocess.run(
|
||||
["git", "checkout", "-f", "master"],
|
||||
check=True,
|
||||
@@ -465,7 +518,7 @@ def post_receive(stdin=sys.stdin):
|
||||
if refname != "refs/heads/master":
|
||||
continue
|
||||
if against == "0000000000000000000000000000000000000000":
|
||||
against = get_head() # Empty commit
|
||||
against = get_head(True) # Empty commit
|
||||
should_reconfig = [
|
||||
f for f in get_altered_files(against, "ACDRU", revision)
|
||||
if f.suffix == ".zone"
|
||||
@@ -495,6 +548,15 @@ def post_receive(stdin=sys.stdin):
|
||||
subprocess.run(cmd)
|
||||
|
||||
|
||||
def smudge_serial(
|
||||
bstdin=sys.stdin.buffer,
|
||||
bstdout=sys.stdout.buffer,
|
||||
unixtime=None,
|
||||
):
|
||||
"""Replace all $UNIXTIME directives with current unix time."""
|
||||
bstdout.write(unixtime_directive(bstdin.read(), unixtime))
|
||||
|
||||
|
||||
def get_action(argv=sys.argv):
|
||||
name = Path(argv[0]).name
|
||||
if "pre-commit" in name:
|
||||
@@ -505,6 +567,8 @@ def get_action(argv=sys.argv):
|
||||
return pre_receive
|
||||
if "post-receive" in name:
|
||||
return post_receive
|
||||
if "smudge" in name:
|
||||
return smudge_serial
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
5
setup.py
5
setup.py
@@ -5,7 +5,7 @@ readme = Path(__file__).with_name("README.rst").read_text()
|
||||
|
||||
setup(
|
||||
name="dzonegit",
|
||||
version="0.4",
|
||||
version="0.10",
|
||||
description="Git hooks to manage a repository of DNS zones",
|
||||
long_description=readme,
|
||||
long_description_content_type="text/x-rst",
|
||||
@@ -23,10 +23,11 @@ setup(
|
||||
"dzonegit-pre-receive = dzonegit:pre_receive",
|
||||
"dzonegit-post-receive = dzonegit:post_receive",
|
||||
"dzonegit-update = dzonegit:update",
|
||||
"dzonegit-smudge-serial = dzonegit:smudge_serial",
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: System Administrators",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
|
||||
@@ -4,7 +4,7 @@ import subprocess
|
||||
import time
|
||||
import datetime
|
||||
import os
|
||||
from io import StringIO
|
||||
from io import StringIO, BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import dzonegit
|
||||
@@ -62,16 +62,47 @@ $ORIGIN example.com.
|
||||
60 IN NS ns
|
||||
ns.example.com. 60 IN A 192.0.2.1
|
||||
"""
|
||||
r = dzonegit.compile_zone("example.org", testzone)
|
||||
r = dzonegit.compile_zone("example.org", testzone, missing_dot=True)
|
||||
assert not r.success
|
||||
assert r.zonehash is None
|
||||
assert r.stderr
|
||||
r = dzonegit.compile_zone("example.com", testzone)
|
||||
r = dzonegit.compile_zone("example.com", testzone, missing_dot=True)
|
||||
assert r.success
|
||||
assert r.serial == "1234567890"
|
||||
assert r.zonehash
|
||||
r2 = dzonegit.compile_zone("example.com", testzone + b"\n\n; some comment")
|
||||
assert r.zonehash == r2.zonehash
|
||||
testzone += b"1 60 IN PTR www\n"
|
||||
dzonegit.compile_zone("example.com", testzone, missing_dot=False)
|
||||
with pytest.raises(ValueError):
|
||||
dzonegit.compile_zone("example.com", testzone, missing_dot=True)
|
||||
|
||||
|
||||
def test_compile_unsmudged_zone():
|
||||
testzone = b"""
|
||||
$ORIGIN example.com.
|
||||
@ 60 IN SOA ns hostmaster (
|
||||
$UNIXTIME ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
900 ; retry (15 minutes)
|
||||
1814400 ; expire (3 weeks)
|
||||
60 ; minimum (1 minute)
|
||||
)
|
||||
60 IN NS ns
|
||||
ns.example.com. 60 IN A 192.0.2.1
|
||||
"""
|
||||
replaced = dzonegit.unixtime_directive(testzone)
|
||||
assert b"$UNIXTIME" not in replaced
|
||||
r = dzonegit.compile_zone("example.com", testzone, 123456)
|
||||
assert r.success
|
||||
assert r.serial == str(123456)
|
||||
|
||||
|
||||
def test_smudge_serial():
|
||||
bstdin = BytesIO(b"something $UNIXTIME something")
|
||||
bstdout = BytesIO()
|
||||
dzonegit.smudge_serial(bstdin, bstdout, 123456)
|
||||
assert b"something 123456 something" == bstdout.getvalue()
|
||||
|
||||
|
||||
def test_is_serial_increased():
|
||||
@@ -131,6 +162,8 @@ ns.example.com. 60 IN A 192.0.2.1
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
dzonegit.get_zone_name("zones/example.org.zone", testzone)
|
||||
subprocess.call(["git", "config", "dzonegit.allowfancynames", "TRUE"])
|
||||
dzonegit.get_zone_name("zones/example.org.zone", testzone)
|
||||
testzone = b"""
|
||||
$ORIGIN 240/28.2.0.192.in-addr.arpa.
|
||||
@ 60 IN SOA ns hostmaster 1 60 60 60 60
|
||||
@@ -148,12 +181,12 @@ def test_replace_serial(git_dir):
|
||||
@ 60 IN SOA ns hm 1 61 60 60 60
|
||||
60 NS ns.example.org.
|
||||
""")
|
||||
dzonegit.replace_serial(Path("dummy.zone"), "1", "60")
|
||||
assert dzonegit.replace_serial(Path("dummy.zone"), "1", "60")
|
||||
assert git_dir.join("dummy.zone").read() == """
|
||||
@ 60 IN SOA ns hm 60 61 60 60 60
|
||||
60 NS ns.example.org.
|
||||
"""
|
||||
dzonegit.replace_serial(Path("dummy.zone"), "60", "61")
|
||||
assert dzonegit.replace_serial(Path("dummy.zone"), "60", "61")
|
||||
assert git_dir.join("dummy.zone").read() == """
|
||||
@ 60 IN SOA ns hm 61 61 60 60 60
|
||||
60 NS ns.example.org.
|
||||
@@ -168,7 +201,7 @@ def test_replace_serial(git_dir):
|
||||
)
|
||||
60 NS ns.example.org.
|
||||
""")
|
||||
dzonegit.replace_serial(Path("dummy.zone"), "60", "6000000")
|
||||
assert dzonegit.replace_serial(Path("dummy.zone"), "60", "6000000")
|
||||
assert git_dir.join("dummy.zone").read() == """
|
||||
@ 60 IN SOA ns hm (
|
||||
6000000 ; serial
|
||||
@@ -179,6 +212,7 @@ def test_replace_serial(git_dir):
|
||||
)
|
||||
60 NS ns.example.org.
|
||||
"""
|
||||
assert not dzonegit.replace_serial(Path("dummy.zone"), "0", "60")
|
||||
|
||||
|
||||
def test_check_updated_zones(git_dir):
|
||||
@@ -226,6 +260,29 @@ $ORIGIN dummy.
|
||||
dzonegit.check_updated_zones("HEAD", autoupdate_serial=True)
|
||||
subprocess.call(["git", "add", "dummy.zone"])
|
||||
dzonegit.check_updated_zones(dzonegit.get_head())
|
||||
git_dir.join("dummy.zone").write("""
|
||||
$ORIGIN dummy.
|
||||
@ 60 IN SOA ns hm $UNIXTIME 61 60 60 60
|
||||
60 NS ns.example.org.
|
||||
""")
|
||||
subprocess.call(["git", "add", "dummy.zone"])
|
||||
dzonegit.check_updated_zones(dzonegit.get_head())
|
||||
subprocess.call(["git", "commit", "-m", "dummy.zone with $UNIXTIME"])
|
||||
git_dir.join("dummy.zone").write("""
|
||||
$ORIGIN dummy.
|
||||
@ 60 IN SOA ns hm 1 60 60 60 60
|
||||
60 NS ns.example.org.
|
||||
""")
|
||||
subprocess.call(["git", "add", "dummy.zone"])
|
||||
with pytest.raises(ValueError):
|
||||
dzonegit.check_updated_zones(dzonegit.get_head())
|
||||
git_dir.join("dummy.zone").write("""
|
||||
$ORIGIN dummy.
|
||||
@ 60 IN SOA ns hm $UNIXTIME 60 60 60 60
|
||||
60 NS ns.example.org.
|
||||
""")
|
||||
subprocess.call(["git", "add", "dummy.zone"])
|
||||
dzonegit.check_updated_zones(dzonegit.get_head())
|
||||
subprocess.call(["git", "commit", "-m", "final dummy.zone"])
|
||||
dzonegit.check_updated_zones("HEAD~", "HEAD")
|
||||
|
||||
@@ -276,11 +333,11 @@ def test_post_receive(git_dir):
|
||||
git_dir.chdir()
|
||||
head = dzonegit.get_head()
|
||||
revisions = "{} {} refs/heads/master\n".format(
|
||||
"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
|
||||
"0000000000000000000000000000000000000000",
|
||||
head,
|
||||
)
|
||||
stdin = StringIO(revisions)
|
||||
codir = git_dir.mkdir("co")
|
||||
codir = git_dir.join("co")
|
||||
subprocess.call(["git", "config", "dzonegit.checkoutpath", str(codir)])
|
||||
subprocess.call([
|
||||
"git", "config", "dzonegit.reconfigcmd",
|
||||
@@ -289,6 +346,17 @@ def test_post_receive(git_dir):
|
||||
dzonegit.post_receive(stdin)
|
||||
assert codir.join("dummy.zone").check()
|
||||
assert codir.join("test").read() == "TEST\n"
|
||||
# Test reconfig after renaming the file
|
||||
codir.join("test").write("")
|
||||
subprocess.call(["git", "mv", "dummy.zone", "dummy.zone.old"])
|
||||
subprocess.call(["git", "commit", "-m", "rename dummy zone"])
|
||||
revisions = "{} {} refs/heads/master\n".format(
|
||||
head,
|
||||
dzonegit.get_head(),
|
||||
)
|
||||
stdin = StringIO(revisions)
|
||||
dzonegit.post_receive(stdin)
|
||||
assert codir.join("test").read() == "TEST\n"
|
||||
|
||||
|
||||
def test_template_config(git_dir):
|
||||
@@ -332,3 +400,10 @@ def test_get_zone_wildcards():
|
||||
"a.long.zone.name", "*.long.zone.name",
|
||||
"*.zone.name", "*.name", "*",
|
||||
]
|
||||
|
||||
|
||||
def test_missing_trailing_dot():
|
||||
zonename = "example.com"
|
||||
zonedata = b"something.example.com. IN PTR s.example.com."
|
||||
with pytest.raises(ValueError):
|
||||
dzonegit.check_missing_trailing_dot(zonename, zonedata)
|
||||
|
||||
Reference in New Issue
Block a user