1
0
mirror of https://github.com/oskar456/dzonegit.git synced 2024-05-11 05:55:41 +00:00

29 Commits

Author SHA1 Message Date
Ondřej Caletka
17cbd099de Version 0.15 2021-12-21 22:28:45 +01:00
Ondřej Caletka
d809e24172 Fixup tests for whitespace error handling 2021-12-21 22:24:17 +01:00
Dominik Pantůček
35d01a796e Apply whitespace check only on *.zone files. 2021-12-21 22:23:09 +01:00
sturmianseq
2f7776c0d1 Reverting the latest commit to avoid state pollution 2021-08-16 23:08:58 +02:00
sturmianseq
498d4a8b82 setup the correct pre-state for test_get_zone_name 2021-08-02 14:32:18 +02:00
Ondřej Caletka
a96597decb Migrate to GitHub Actions (#18)
* Migrate to GitHub Actions

* Drop Python 3.5 test

* Delete .travis.yml
2021-08-02 14:28:07 +02:00
Ondřej Caletka
8f952086aa Version 0.14 2020-05-26 11:12:38 +02:00
Ondřej Caletka
83a4049821 Fix tests when user.name and user.email are not defined
Fixes #15
2020-05-26 11:11:23 +02:00
Ondřej Caletka
15cdae67ee Merge pull request #14 from oskar456/zonerelfile 2020-05-17 11:27:54 +02:00
Ondřej Caletka
12fb932711 Version 0.13
Signed-off-by: Ondřej Caletka <ondrej@caletka.cz>
2020-05-17 11:24:29 +02:00
Ondřej Caletka
cb543514ac Document $zonerelfile template macro
Signed-off-by: Ondřej Caletka <ondrej@caletka.cz>
2020-05-17 11:23:51 +02:00
Przemyslaw Sztoch
f9c6a52357 New macro $zonerelfile in template file. 2020-05-17 11:18:06 +02:00
Ondřej Caletka
24d992d999 Version 0.12 2020-04-13 22:28:24 +02:00
Rob Seastrom
7cb7c42d76 change named-compilezone to use /usr/bin/env rather than absolute path 2020-04-13 22:20:54 +02:00
Ondřej Caletka
3dd346294a Merge pull request #9 from oskar456/travis
Use travis-ci.org as .com was not enabled yet
2019-08-19 15:34:31 +02:00
Ondřej Caletka
03fde74ede Use travis-ci.org as .com was not enabled yet 2019-08-19 15:30:34 +02:00
Michal Halenka
3769dd22fb Include Travis CI status in README 2019-08-19 15:00:49 +02:00
Michal Halenka
8d15bb531c Update .travis.yml
Add new python 3.7 release
Fix indentation
2019-08-19 15:00:26 +02:00
Ondřej Caletka
e2e4a3daf7 Version 0.11 2018-09-17 13:50:47 +02:00
Ondřej Caletka
4efef8be9e Do not template line breaks when header and footer are missing 2018-09-17 13:48:52 +02:00
Ondřej Caletka
ef059861b7 Version 0.10 - switch to Beta status 2018-08-28 12:45:08 +02:00
Ondřej Caletka
94461383e8 Add pre-commit check for missing trailing dot in PTR records. 2018-08-28 12:43:51 +02:00
Ondřej Caletka
3e09833ec1 Better handling of empty commit objects 2018-08-28 10:58:47 +02:00
Ondřej Caletka
9ad1e74a88 Fix no reconfig command issued on zone file rename. 2018-08-27 23:13:29 +02:00
Ondřej Caletka
a7d693253d version 0.9 (skipping version 0.8 as it was mistakenly published before) 2018-08-23 10:46:43 +02:00
Ondřej Caletka
3777453d2f Better handling of replace serial failure. 2018-08-23 10:38:56 +02:00
Ondřej Caletka
023906177a version 0.7 2018-08-20 16:37:49 +02:00
Ondřej Caletka
e79bb901f3 $UNIXTIME doc update 2018-08-20 16:37:08 +02:00
Ondřej Caletka
f07c84aa32 Fix no reload on very first push to the repository 2018-08-20 16:33:00 +02:00
6 changed files with 169 additions and 63 deletions

42
.github/workflows/python-test.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Python package
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Instal BIND 9 utils
run: sudo apt-get install -y bind9utils
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
python -m pip install -e .
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest

View File

@@ -1,16 +0,0 @@
before_install:
- sudo apt-get install -y bind9utils
language: python
python:
- "3.5"
- "3.6"
- "nightly"
matrix:
allow_failures:
- python: "nightly"
install:
- pip install -e .
- pip install pytest
script:
- pytest
sudo: false

View File

@@ -1,3 +1,6 @@
.. image:: https://travis-ci.org/oskar456/dzonegit.svg?branch=master
:target: https://travis-ci.org/oskar456/dzonegit
Git hooks to manage a repository of DNS zones Git hooks to manage a repository of DNS zones
============================================= =============================================
@@ -59,24 +62,22 @@ Support for $UNIXTIME directive
If you want to use ``$UNIXTIME`` in your zone files instead of serial number, 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 you have to install a `smudge` filter on the server, that will replace the
directive with current unix time on checkout. First, set up the filter in directive with current unix time on every checkout. First, set up the filter
the Git configuration: in the Git configuration:
.. code-block:: shell .. code-block:: shell
$ git config --global filter.dzonegit.smudge $(which dzonegit-smudge-serial) $ git config --global filter.dzonegit.smudge $(which dzonegit-smudge-serial)
$ git config --global filter.dzonegit.clean cat
Then, apply the filter on all zone files using ``.gitattributes`` file inside Then, apply the filter on all zone files using either ``.git/info/attributes``
the repository: or directly ``.gitattributes`` file inside the repository:
.. code-block:: .. code-block::
*.zone filter=dzonegit *.zone filter=dzonegit
Configuration options Configuration options
--------------------- ---------------------
@@ -95,6 +96,10 @@ named ``dzonegit``. All boolean options default to *False*.
Do not try to automatically update zone serial number if necessary. Do not try to automatically update zone serial number if necessary.
Valid only in the ``pre-commit`` hook. 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* *dzonegit.checkoutpath*
Path to a writable directory, to which ``post-receive`` hook checks out Path to a writable directory, to which ``post-receive`` hook checks out
current *HEAD* after each update. current *HEAD* after each update.
@@ -178,6 +183,9 @@ In the template strings, these placeholders are supported:
``$zonefile`` ``$zonefile``
Full path to the zone file Full path to the zone file
``$zonerelfile``
Path to the zone file, relative to checkout path (useful for chroot environments)
``$zonevar`` ``$zonevar``
Per-zone specific variable, see above Per-zone specific variable, see above

View File

@@ -41,24 +41,24 @@ class HookException(ValueError):
return "".join(r) return "".join(r)
def get_head(): def get_head(empty=False):
r = subprocess.run( if not empty:
["git", "rev-parse", "--verify", "HEAD"], r = subprocess.run(
stdout=subprocess.PIPE, ["git", "rev-parse", "--verify", "HEAD"],
stderr=subprocess.DEVNULL, stdout=subprocess.PIPE,
) stderr=subprocess.DEVNULL,
if r.returncode == 0: )
return r.stdout.decode("utf-8").strip() if r.returncode == 0:
else: return r.stdout.decode("ascii").strip()
# Initial commit: diff against an empty tree object # Initial commit: diff against an empty tree object
return "4b825dc642cb6eb9a060e54bf8d69288fbee4904" return "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
def check_whitespace_errors(against, revision=None): def check_whitespace_errors(against, revision=None):
if revision: if revision:
cmd = ["git", "diff-tree", "--check", against, revision] cmd = ["git", "diff-tree", "--check", against, revision, "*.zone"]
else: else:
cmd = ["git", "diff-index", "--check", "--cached", against] cmd = ["git", "diff-index", "--check", "--cached", against, "*.zone"]
r = subprocess.run( r = subprocess.run(
cmd, cmd,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
@@ -95,13 +95,31 @@ def unixtime_directive(zonedata, unixtime=None):
) )
def compile_zone(zonename, zonedata, unixtime=None): 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.""" """ Compile the zone. Return tuple with results."""
CompileResults = namedtuple( CompileResults = namedtuple(
"CompileResults", "success, serial, zonehash, stderr", "CompileResults", "success, serial, zonehash, stderr",
) )
r = subprocess.run( r = subprocess.run(
["/usr/sbin/named-compilezone", "-o", "-", zonename, "/dev/stdin"], ["/usr/bin/env", "named-compilezone", "-o", "-", zonename, "/dev/stdin"],
input=unixtime_directive(zonedata, unixtime), input=unixtime_directive(zonedata, unixtime),
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
@@ -110,6 +128,8 @@ def compile_zone(zonename, zonedata, unixtime=None):
m = re.search(r"^zone.*loaded serial ([0-9]*)$", stderr, re.MULTILINE) m = re.search(r"^zone.*loaded serial ([0-9]*)$", stderr, re.MULTILINE)
if r.returncode == 0 and m: if r.returncode == 0 and m:
serial = m.group(1) serial = m.group(1)
if missing_dot:
check_missing_trailing_dot(zonename, r.stdout)
zonehash = sha256(r.stdout).hexdigest() zonehash = sha256(r.stdout).hexdigest()
return CompileResults(True, serial, zonehash, stderr) return CompileResults(True, serial, zonehash, stderr)
else: else:
@@ -146,7 +166,7 @@ def get_altered_files(against, diff_filter=None, revision=None):
If revision is None, list changes between staging area and If revision is None, list changes between staging area and
revision. Otherwise differences between two revisions are computed. 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: if diff_filter:
cmd.append("--diff-filter={}".format(diff_filter)) cmd.append("--diff-filter={}".format(diff_filter))
if revision: if revision:
@@ -203,7 +223,12 @@ def get_zone_name(path, zonedata):
return stemname 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. """ """ Check whether all updated zone files compile. """
unixtime = int(time.time()) unixtime = int(time.time())
for f in get_altered_files(against, "AMCR", revision): for f in get_altered_files(against, "AMCR", revision):
@@ -212,7 +237,7 @@ def check_updated_zones(against, revision=None, autoupdate_serial=False):
print("Checking file {f}".format(f=f)) print("Checking file {f}".format(f=f))
zonedata = get_file_contents(f, revision) zonedata = get_file_contents(f, revision)
zname = get_zone_name(f, zonedata) zname = get_zone_name(f, zonedata)
rnew = compile_zone(zname, zonedata, unixtime) rnew = compile_zone(zname, zonedata, unixtime, missing_dot)
if not rnew.success: if not rnew.success:
raise HookException( raise HookException(
"New zone version does not compile", "New zone version does not compile",
@@ -232,9 +257,11 @@ def check_updated_zones(against, revision=None, autoupdate_serial=False):
if autoupdate_serial: if autoupdate_serial:
newserial = get_increased_serial(rnew.serial) newserial = get_increased_serial(rnew.serial)
replace_serial(f, rnew.serial, newserial) if replace_serial(f, rnew.serial, newserial):
errmsg += " Serial has been automatically increased." errmsg += " Serial has been automatically increased."
errmsg += " Check and recommit." errmsg += " Check and recommit."
else:
errmsg += " Autoupdate of serial number failed."
raise HookException( raise HookException(
errmsg, errmsg,
fname=f, fname=f,
@@ -277,8 +304,9 @@ def replace_serial(path, oldserial, newserial):
flags=re.DOTALL | re.IGNORECASE | re.MULTILINE, flags=re.DOTALL | re.IGNORECASE | re.MULTILINE,
) )
if count != 1: if count != 1:
raise HookException("Cannot update zone serial number") return False
path.write_text(updated) path.write_text(updated)
return True
def get_zone_wildcards(name): def get_zone_wildcards(name):
@@ -330,7 +358,8 @@ def template_config(checkoutpath, template, blacklist=set(), whitelist=set()):
out = list() out = list()
zones = dict() zones = dict()
mapping = {"datetime": datetime.datetime.now().strftime("%c")} mapping = {"datetime": datetime.datetime.now().strftime("%c")}
out.append(headertpl.substitute(mapping)) if headertpl.template:
out.append(headertpl.substitute(mapping))
for f in sorted(Path(checkoutpath).glob("**/*.zone")): for f in sorted(Path(checkoutpath).glob("**/*.zone")):
zonename = get_zone_name(f, f.read_bytes()) zonename = get_zone_name(f, f.read_bytes())
if whitelist and not any( if whitelist and not any(
@@ -366,9 +395,10 @@ def template_config(checkoutpath, template, blacklist=set(), whitelist=set()):
zonevar = defaultvar zonevar = defaultvar
out.append(itemtpl.substitute( out.append(itemtpl.substitute(
mapping, zonename=zonename, mapping, zonename=zonename,
zonefile=str(f), zonevar=zonevar, zonefile=str(f), zonerelfile=str(f.relative_to(checkoutpath)), zonevar=zonevar,
)) ))
out.append(footertpl.substitute(mapping)) if footertpl.template:
out.append(footertpl.substitute(mapping))
return "\n".join(out) return "\n".join(out)
@@ -382,13 +412,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: try:
if not get_config("dzonegit.ignorewhitespaceerrors", bool): if not get_config("dzonegit.ignorewhitespaceerrors", bool):
check_whitespace_errors(against, revision=revision) check_whitespace_errors(against, revision=revision)
check_updated_zones( check_updated_zones(
against, revision=revision, against, revision=revision,
autoupdate_serial=autoupdate_serial, autoupdate_serial=autoupdate_serial,
missing_dot=missing_dot,
) )
except HookException as e: except HookException as e:
print(e) print(e)
@@ -398,7 +434,12 @@ def do_commit_checks(against, revision=None, autoupdate_serial=False):
def pre_commit(): def pre_commit():
against = get_head() against = get_head()
autoupdate_serial = not get_config("dzonegit.noserialupdate", bool) 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): def update(argv=sys.argv):
@@ -411,7 +452,7 @@ def update(argv=sys.argv):
refname, against, revision = argv[1:4] refname, against, revision = argv[1:4]
if against == "0000000000000000000000000000000000000000": if against == "0000000000000000000000000000000000000000":
against = get_head() # Empty commit against = get_head(True) # Empty commit
if refname != "refs/heads/master": if refname != "refs/heads/master":
raise SystemExit("Nothing else than master branch is accepted here") raise SystemExit("Nothing else than master branch is accepted here")
@@ -429,7 +470,7 @@ def pre_receive(stdin=sys.stdin):
"is accepted here", "is accepted here",
) )
if against == "0000000000000000000000000000000000000000": if against == "0000000000000000000000000000000000000000":
against = get_head() # Empty commit against = get_head(True) # Empty commit
do_commit_checks(against, revision) do_commit_checks(against, revision)
@@ -479,7 +520,7 @@ def post_receive(stdin=sys.stdin):
if refname != "refs/heads/master": if refname != "refs/heads/master":
continue continue
if against == "0000000000000000000000000000000000000000": if against == "0000000000000000000000000000000000000000":
against = get_head() # Empty commit against = get_head(True) # Empty commit
should_reconfig = [ should_reconfig = [
f for f in get_altered_files(against, "ACDRU", revision) f for f in get_altered_files(against, "ACDRU", revision)
if f.suffix == ".zone" if f.suffix == ".zone"

View File

@@ -5,7 +5,7 @@ readme = Path(__file__).with_name("README.rst").read_text()
setup( setup(
name="dzonegit", name="dzonegit",
version="0.6", version="0.15",
description="Git hooks to manage a repository of DNS zones", description="Git hooks to manage a repository of DNS zones",
long_description=readme, long_description=readme,
long_description_content_type="text/x-rst", long_description_content_type="text/x-rst",
@@ -27,7 +27,7 @@ setup(
], ],
}, },
classifiers=[ classifiers=[
"Development Status :: 3 - Alpha", "Development Status :: 4 - Beta",
"Environment :: Console", "Environment :: Console",
"Intended Audience :: System Administrators", "Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: MIT License",

View File

@@ -15,6 +15,8 @@ def git_dir(tmpdir_factory):
d = tmpdir_factory.getbasetemp() d = tmpdir_factory.getbasetemp()
d.chdir() d.chdir()
subprocess.call(["git", "init"]) subprocess.call(["git", "init"])
subprocess.call(["git", "config", "user.name", "dzonegit pytest"])
subprocess.call(["git", "config", "user.email", "nonexistent@example.com"])
return d return d
@@ -25,18 +27,22 @@ def test_get_head(git_dir):
subprocess.call(["git", "add", "dummy"]) subprocess.call(["git", "add", "dummy"])
subprocess.call(["git", "commit", "-m", "dummy"]) subprocess.call(["git", "commit", "-m", "dummy"])
assert dzonegit.get_head() != "4b825dc642cb6eb9a060e54bf8d69288fbee4904" assert dzonegit.get_head() != "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
subprocess.call(["git", "update-ref", "-d", "HEAD"])
def test_check_whitespace_errors(git_dir): def test_check_whitespace_errors(git_dir):
git_dir.chdir() git_dir.chdir()
git_dir.join("whitespace").write(" ") git_dir.join("whitespace").write(" ")
subprocess.call(["git", "add", "whitespace"]) subprocess.call(["git", "add", "whitespace"])
dzonegit.check_whitespace_errors(dzonegit.get_head())
git_dir.join("whitespace.zone").write(" ")
subprocess.call(["git", "add", "whitespace.zone"])
with pytest.raises(ValueError): with pytest.raises(ValueError):
dzonegit.check_whitespace_errors(dzonegit.get_head()) dzonegit.check_whitespace_errors(dzonegit.get_head())
subprocess.call(["git", "commit", "-m", "whitespace"]) subprocess.call(["git", "commit", "-m", "whitespace"])
with pytest.raises(ValueError): with pytest.raises(ValueError):
dzonegit.check_whitespace_errors("HEAD~", dzonegit.get_head()) dzonegit.check_whitespace_errors("HEAD~", dzonegit.get_head())
subprocess.call(["git", "rm", "-f", "whitespace"]) subprocess.call(["git", "rm", "-f", "whitespace*"])
subprocess.call(["git", "commit", "-m", "rm whitespace"]) subprocess.call(["git", "commit", "-m", "rm whitespace"])
dzonegit.check_whitespace_errors(dzonegit.get_head()) dzonegit.check_whitespace_errors(dzonegit.get_head())
dzonegit.check_whitespace_errors("HEAD~", dzonegit.get_head()) dzonegit.check_whitespace_errors("HEAD~", dzonegit.get_head())
@@ -62,16 +68,20 @@ $ORIGIN example.com.
60 IN NS ns 60 IN NS ns
ns.example.com. 60 IN A 192.0.2.1 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 not r.success
assert r.zonehash is None assert r.zonehash is None
assert r.stderr 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.success
assert r.serial == "1234567890" assert r.serial == "1234567890"
assert r.zonehash assert r.zonehash
r2 = dzonegit.compile_zone("example.com", testzone + b"\n\n; some comment") r2 = dzonegit.compile_zone("example.com", testzone + b"\n\n; some comment")
assert r.zonehash == r2.zonehash 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(): def test_compile_unsmudged_zone():
@@ -118,7 +128,7 @@ def test_get_altered_files(git_dir):
assert files == {Path("dummy"), Path("new")} assert files == {Path("dummy"), Path("new")}
# Refers to test_check_whitespace_errors # Refers to test_check_whitespace_errors
files = set(dzonegit.get_altered_files("HEAD~", "D", "HEAD")) files = set(dzonegit.get_altered_files("HEAD~", "D", "HEAD"))
assert files == {Path("whitespace")} assert files == {Path("whitespace"), Path("whitespace.zone")}
subprocess.call(["git", "checkout", "-f", "HEAD"]) subprocess.call(["git", "checkout", "-f", "HEAD"])
assert set(dzonegit.get_altered_files("HEAD", "AM")) == set() assert set(dzonegit.get_altered_files("HEAD", "AM")) == set()
@@ -150,6 +160,7 @@ $ORIGIN eXample.com. ;coment
60 IN NS ns 60 IN NS ns
ns.example.com. 60 IN A 192.0.2.1 ns.example.com. 60 IN A 192.0.2.1
""" """
subprocess.call(["git", "config", "dzonegit.allowfancynames", "FALSE"])
assert "example.com" == dzonegit.get_zone_name( assert "example.com" == dzonegit.get_zone_name(
"zones/example.com.zone", "", "zones/example.com.zone", "",
) )
@@ -177,12 +188,12 @@ def test_replace_serial(git_dir):
@ 60 IN SOA ns hm 1 61 60 60 60 @ 60 IN SOA ns hm 1 61 60 60 60
60 NS ns.example.org. 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() == """ assert git_dir.join("dummy.zone").read() == """
@ 60 IN SOA ns hm 60 61 60 60 60 @ 60 IN SOA ns hm 60 61 60 60 60
60 NS ns.example.org. 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() == """ assert git_dir.join("dummy.zone").read() == """
@ 60 IN SOA ns hm 61 61 60 60 60 @ 60 IN SOA ns hm 61 61 60 60 60
60 NS ns.example.org. 60 NS ns.example.org.
@@ -197,7 +208,7 @@ def test_replace_serial(git_dir):
) )
60 NS ns.example.org. 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() == """ assert git_dir.join("dummy.zone").read() == """
@ 60 IN SOA ns hm ( @ 60 IN SOA ns hm (
6000000 ; serial 6000000 ; serial
@@ -208,6 +219,7 @@ def test_replace_serial(git_dir):
) )
60 NS ns.example.org. 60 NS ns.example.org.
""" """
assert not dzonegit.replace_serial(Path("dummy.zone"), "0", "60")
def test_check_updated_zones(git_dir): def test_check_updated_zones(git_dir):
@@ -328,7 +340,7 @@ def test_post_receive(git_dir):
git_dir.chdir() git_dir.chdir()
head = dzonegit.get_head() head = dzonegit.get_head()
revisions = "{} {} refs/heads/master\n".format( revisions = "{} {} refs/heads/master\n".format(
"4b825dc642cb6eb9a060e54bf8d69288fbee4904", "0000000000000000000000000000000000000000",
head, head,
) )
stdin = StringIO(revisions) stdin = StringIO(revisions)
@@ -339,9 +351,19 @@ def test_post_receive(git_dir):
"echo TEST >{}/test".format(codir), "echo TEST >{}/test".format(codir),
]) ])
dzonegit.post_receive(stdin) dzonegit.post_receive(stdin)
dzonegit.post_receive(stdin) # Check coping with existing codir
assert codir.join("dummy.zone").check() assert codir.join("dummy.zone").check()
assert codir.join("test").read() == "TEST\n" 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): def test_template_config(git_dir):
@@ -372,6 +394,8 @@ def test_template_config(git_dir):
blacklist=set("*"), blacklist=set("*"),
) )
assert " - zone: \"dummy\"\n file: \"" not in output assert " - zone: \"dummy\"\n file: \"" not in output
output = dzonegit.template_config(str(git_dir), "{}")
assert len(output) == 0
def test_load_set_file(git_dir): def test_load_set_file(git_dir):
@@ -385,3 +409,10 @@ def test_get_zone_wildcards():
"a.long.zone.name", "*.long.zone.name", "a.long.zone.name", "*.long.zone.name",
"*.zone.name", "*.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)