← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~julian-edwards/maas/dhcp-standalone-writer into lp:maas

 

Julian Edwards has proposed merging lp:~julian-edwards/maas/dhcp-standalone-writer into lp:maas.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~julian-edwards/maas/dhcp-standalone-writer/+merge/109074

This executable generates a DHCP config by utilising the existing module that does the work.  This script just passes in the command line arguments as appropriate.  It's intended to be used from the Ubuntu package's installation scripts as a one-off.
-- 
https://code.launchpad.net/~julian-edwards/maas/dhcp-standalone-writer/+merge/109074
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/dhcp-standalone-writer into lp:maas.
=== modified file 'Makefile'
--- Makefile	2012-05-23 16:45:00 +0000
+++ Makefile	2012-06-07 06:04:23 +0000
@@ -21,6 +21,7 @@
     bin/twistd.pserv bin/test.pserv \
     bin/twistd.txlongpoll \
     bin/py bin/ipy \
+    bin/write_dhcp_config \
     $(js_enums)
 
 all: build doc
@@ -69,6 +70,10 @@
 	bin/buildout install repl
 	@touch --no-create bin/py bin/ipy
 
+bin/write_dhcp_config: bin/buildout buildout.cfg versions.cfg setup.py
+	bin/buildout install write-dhcp-config
+	@touch --no-create bin/write_dhcp_config
+
 test: bin/test.maas bin/test.maastesting bin/test.pserv $(js_enums)
 	bin/test.maas
 	bin/test.maastesting

=== modified file 'buildout.cfg'
--- buildout.cfg	2012-05-28 20:10:50 +0000
+++ buildout.cfg	2012-06-07 06:04:23 +0000
@@ -9,6 +9,7 @@
   repl
   sphinx
   txlongpoll
+  write-dhcp-config
 extensions = buildout-versions
 buildout_versions_file = versions.cfg
 versions = versions
@@ -213,3 +214,9 @@
   txamqp
 entry-points = twistd.txlongpoll=twisted.scripts.twistd:run
 scripts = twistd.txlongpoll
+
+[write-dhcp-config]
+recipe = z3c.recipe.scripts
+extra-paths = ${common:extra-paths}
+entry-points = write_dhcp_config=provisioningserver.dhcp.write_dhcp_config:run
+scripts = write_dhcp_config

=== modified file 'src/provisioningserver/dhcp/config.py'
--- src/provisioningserver/dhcp/config.py	2012-06-06 04:39:20 +0000
+++ src/provisioningserver/dhcp/config.py	2012-06-07 06:04:23 +0000
@@ -31,7 +31,7 @@
       match if substring (option vendor-class-identifier, 0, 21) = "U-boot.armv7.highbank";
     }
 
-    subnet %(subnet)s netmask %(subnet_mask) {
+    subnet %(subnet)s netmask %(subnet_mask)s {
            next-server %(next_server)s;
            option subnet-mask %(subnet_mask)s;
            option broadcast-address %(broadcast_address)s;

=== added file 'src/provisioningserver/dhcp/tests/test_write_dhcp_config.py'
--- src/provisioningserver/dhcp/tests/test_write_dhcp_config.py	1970-01-01 00:00:00 +0000
+++ src/provisioningserver/dhcp/tests/test_write_dhcp_config.py	2012-06-07 06:04:23 +0000
@@ -0,0 +1,128 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for write-dhcp-config.py"""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = []
+
+import os
+import subprocess
+
+from maastesting.testcase import TestCase
+from testtools.matchers import (
+    Contains,
+    MatchesAll,
+    MatchesStructure,
+    )
+
+from provisioningserver.dhcp.write_dhcp_config import DHCPConfigWriter
+
+
+class TestModule(TestCase):
+    """Test the write-dhcp-config module."""
+
+    def test_arg_setup(self):
+        writer = DHCPConfigWriter()
+        test_args = [
+            '--subnet', 'subnet',
+            '--subnet-mask', 'subnet-mask',
+            '--next-server', 'next-server',
+            '--broadcast-address', 'broadcast-address',
+            '--dns-servers', 'dns-servers',
+            '--gateway', 'gateway',
+            '--low-range', 'low-range',
+            '--high-range', 'high-range',
+            '--out-file', 'out-file',
+            ]
+        writer.parse_args(test_args)
+
+        self.assertThat(
+            writer.args, MatchesStructure.byEquality(
+                subnet='subnet',
+                subnet_mask='subnet-mask',
+                next_server='next-server',
+                broadcast_address='broadcast-address',
+                dns_servers='dns-servers',
+                gateway='gateway',
+                low_range='low-range',
+                high_range='high-range',
+                out_file='out-file'))
+
+    def test_generate(self):
+        writer = DHCPConfigWriter()
+        test_args = [
+            '--subnet', 'subnet',
+            '--subnet-mask', 'subnet-mask',
+            '--next-server', 'next-server',
+            '--broadcast-address', 'broadcast-address',
+            '--dns-servers', 'dns-servers',
+            '--gateway', 'gateway',
+            '--low-range', 'low-range',
+            '--high-range', 'high-range',
+            ]
+        writer.parse_args(test_args)
+        output = writer.generate()
+
+        contains_all_params = MatchesAll(
+            Contains('subnet'), Contains('subnet-mask'),
+            Contains('next-server'), Contains('broadcast-address'),
+            Contains('dns-servers'), Contains('gateway'),
+            Contains('low-range'), Contains('high-range'))
+        self.assertThat(output, contains_all_params)
+
+    def test_run_with_file_output(self):
+        temp_dir = self.make_dir()
+        outfile = os.path.join(temp_dir, "outfile")
+        writer = DHCPConfigWriter()
+        test_args = [
+            '--subnet', 'subnet',
+            '--subnet-mask', 'subnet-mask',
+            '--next-server', 'next-server',
+            '--broadcast-address', 'broadcast-address',
+            '--dns-servers', 'dns-servers',
+            '--gateway', 'gateway',
+            '--low-range', 'low-range',
+            '--high-range', 'high-range',
+            '--out-file', outfile,
+            ]
+        writer.run(test_args)
+
+        self.assertTrue(os.path.exists(outfile))
+
+
+class TestScriptExecutable(TestCase):
+    """Test that the actual script is executable."""
+
+    def test_script(self):
+        test_args = [
+            '--subnet', 'subnet',
+            '--subnet-mask', 'subnet-mask',
+            '--next-server', 'next-server',
+            '--broadcast-address', 'broadcast-address',
+            '--dns-servers', 'dns-servers',
+            '--gateway', 'gateway',
+            '--low-range', 'low-range',
+            '--high-range', 'high-range',
+            ]
+
+        exe = [os.path.join(
+            os.path.dirname(__file__),
+            os.pardir, os.pardir, os.pardir, os.pardir,
+            "bin", "write_dhcp_config")]
+
+        exe.extend(test_args)
+        output = subprocess.check_output(exe)
+
+        contains_all_params = MatchesAll(
+            Contains('subnet'), Contains('subnet-mask'),
+            Contains('next-server'), Contains('broadcast-address'),
+            Contains('dns-servers'), Contains('gateway'),
+            Contains('low-range'), Contains('high-range'))
+        self.assertThat(output, contains_all_params)

=== added file 'src/provisioningserver/dhcp/write_dhcp_config.py'
--- src/provisioningserver/dhcp/write_dhcp_config.py	1970-01-01 00:00:00 +0000
+++ src/provisioningserver/dhcp/write_dhcp_config.py	2012-06-07 06:04:23 +0000
@@ -0,0 +1,91 @@
+# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Utility script to write out a dhcp server config from cmd line params."""
+
+from __future__ import (
+    absolute_import,
+    print_function,
+    unicode_literals,
+    )
+
+__metaclass__ = type
+__all__ = []
+
+
+import argparse
+
+from provisioningserver.dhcp import config
+
+
+class DHCPConfigWriter:
+
+    def __init__(self):
+        self.set_up_args()
+
+    def set_up_args(self):
+        """Initialise an ArgumentParser's options."""
+        self.argument_parser = argparse.ArgumentParser(description=__doc__)
+        self.argument_parser.add_argument(
+            "--subnet", action="store", type=str, required=True, help=(
+                "Base subnet declaration, e.g. 192.168.1.0"))
+        self.argument_parser.add_argument(
+            "--subnet-mask", action="store", type=str, required=True, help=(
+                "The mask for the subnet, e.g. 255.255.255.0"))
+        self.argument_parser.add_argument(
+            "--next-server", action="store", type=str, required=True, help=(
+                "The address of the TFTP server"))
+        self.argument_parser.add_argument(
+            "--broadcast-address", action="store", type=str, required=True,
+            help=(
+                "The broadcast IP address for the subnet,"
+                "e.g. 192.168.1.255"))
+        self.argument_parser.add_argument(
+            "--dns-servers", action="store", type=str, required=True, help=(
+                "One or more IP addresses of the DNS server for the subnet"))
+        self.argument_parser.add_argument(
+            "--gateway", action="store", type=str, required=True, help=(
+                "The router/gateway IP address for the subnet"))
+        self.argument_parser.add_argument(
+            "--low-range", action="store", type=str, required=True, help=(
+                "The first IP address in the range of IP addresses to"
+                "allocate"))
+        self.argument_parser.add_argument(
+            "--high-range", action="store", type=str, required=True, help=(
+                "The last IP address in the range of IP addresses to"
+                "allocate"))
+        self.argument_parser.add_argument(
+            "--out-file", action="store", type=str, required=False, help=(
+                "The file to write the config.  If not set will write "
+                "to stdout"))
+
+    def parse_args(self, argv=None):
+        """Parse provided argv or default to sys.argv."""
+        self.args = self.argument_parser.parse_args(argv)
+
+    def generate(self):
+        """Generate the config."""
+        params = self.args.__dict__
+        output = config.get_config(**params)
+        return output
+
+    def run(self, argv=None):
+        """Generate the config and write to stdout or a file as required."""
+        self.parse_args(argv)
+        output = self.generate()
+        outfile = self.args.out_file
+        if outfile is not None:
+            with open(outfile, "w") as f:
+                f.write(output)
+        else:
+            print(output)
+
+
+def run():
+    """Entry point for scripts."""
+    writer = DHCPConfigWriter()
+    writer.run()
+
+
+if __name__ == "__main__":
+    run()