Merge lp:~allenap/maas/fix-makefile-write-dhcp-stuff into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 624
Proposed branch: lp:~allenap/maas/fix-makefile-write-dhcp-stuff
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 173 lines (+15/-66)
4 files modified
Makefile (+1/-6)
buildout.cfg (+1/-7)
src/provisioningserver/dhcp/tests/test_writer.py (+7/-40)
src/provisioningserver/dhcp/writer.py (+6/-13)
To merge this branch: bzr merge lp:~allenap/maas/fix-makefile-write-dhcp-stuff
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+109324@code.launchpad.net

Commit message

Tweak the way the DHCPConfigWriter is plumbed in.

Description of the change

This changes a few bits about the new DHCPConfigWriter.

- Renames write_dhcp_config.py to writer.py. It's in the
  provisioningserver.dhcp module, and it hardly needs explaining that
  it's about configuration.

- Removes the write_dhcp_config script entirely. It's not necessary -
  use bin/py -m provisioningserver/dhcp/writer instead - and is
  misleading because packages cannot use it anyway as it is generated
  by buildout.

- Remove all references to write_dhcp_config from Makefile.

- Remove the test for the write_dhcp_config script.

- Use stdout.write() to emit the config instead of print(); the latter
  adds an extra newline.

- Encodes the config as ASCII for the paranoid.

- Drive-by: restricts the scripts that the [database] part in
  buildout.cfg creates to just the bin/database script. Previously it
  was also generating a bin/postgresfixture script.

To post a comment you must log in.
Revision history for this message
Raphaël Badin (rvb) wrote :

Looks good. +15/-66 without loosing functionality, that's nice.

Maybe we can wait for Julian to clarify things about [0] but I'll leave it up to you because, in my opinion, this is all good.

[0]

> Removes the write_dhcp_config script entirely. It's not necessary -
> use bin/py -m provisioningserver/dhcp/writer instead - and is
> misleading because packages cannot use it anyway as it is generated
> by buildout.

I agree with you. Since Julian is away I can only speculate here but this script can only be a development convenience and if it's the case then using the command as you suggest is, I think, good enough.

So far, when we had the need to expose a command, the usual way to do that has been to create a Django command. Now, unless I'm mistaken, this is part of the provisioning server because it will be run by the workers. We haven't talked about this but the workers will probably need to install a specific maas package (something like 'maas-worker') rather that the server 'maas' package and this worker package will only contain the worker code (i.e. the module 'provisioningserver'). This implies that if we want to ship scripts in this worker package we will have to come up with a new strategy because the Django MAAS application (and thus CLI) won't be installed there.

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

If these scripts are only needed by packaging then we can just use the
python -m ... forms. For users, it may be worth having a single
front-end script, e.g. maas-provision or maas-worker, that follows the
verb pattern, or subparsers as argparse calls it. In other words,
something like:

  maas-provision verb --verb-specific-option

Or, more specifically:

  maas-provision dhcp-config --subnet ...

Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Friday 08 Jun 2012 12:49:33 you wrote:
> Review: Approve
>
> Looks good. +15/-66 without loosing functionality, that's nice.

'losing'

> Maybe we can wait for Julian to clarify things about [0] but I'll leave it
> up to you because, in my opinion, this is all good.
>
> [0]
>
> > Removes the write_dhcp_config script entirely. It's not necessary -
> >
> > use bin/py -m provisioningserver/dhcp/writer instead - and is
> > misleading because packages cannot use it anyway as it is generated
> > by buildout.
>
> I agree with you. Since Julian is away I can only speculate here but this
> script can only be a development convenience and if it's the case then
> using the command as you suggest is, I think, good enough.

I'm kinda unhappy about this change, I'd have at least expected you to talk to
me before just removing my work. I put the generated script in as a
development convenience, because the bin/py example above is pretty hideous to
remember and type. I intended the package to use the module's script as-is
however, because it will have set up paths already.

Also, the branch has removed a test which checks the stdout output, and the
new name "writer" is inaccurate. If you want to split hairs, it's
"write_config".

I'd appreciate it if you'd put the script back, either buildout-generated or a
shortcut using the bin/py method.

Why did you remove the build dependency from the check target? Regardless of
my changes it seems a good idea.

Revision history for this message
Gavin Panella (allenap) wrote :

I guess I probably ought not to have done this branch... I was just
itching to do something and I didn't have the presence of mind to back
off. Anyway, point by point:

> I'm kinda unhappy about this change, I'd have at least expected you
> to talk to me before just removing my work.

I figured you were away for the weekend now and probably unavailable,
it's easy to undo stuff, and I am hoping to seek forgiveness instead
of getting advance permission.

> I put the generated script in as a development convenience, because
> the bin/py example above is pretty hideous to remember and type. I
> intended the package to use the module's script as-is however,
> because it will have set up paths already.

The extra section in buildout.cfg wasn't needed for example, though
that's not much of an issue. Really I felt that this was the wrong way
to go about exposing commands. The conveniences we create for
ourselves as developers will inevitably flow downstream, and I would
like to avoid that in this case. The `python -m module` pattern
prevents PATH pollution and also keeps us aware that exposing
provisioning commands to users is not a well solved problem.

The Django side of MAAS has management commands. I think the
provisioning side should have something similar, a "command verb"
pattern, like django-admin or bzr for example.

Also, if we want to expose non-developer scripts, we ought to put them
in setup.py instead of buildout.cfg. I think this'll make them easier
for packagers to use.

> Also, the branch has removed a test which checks the stdout output,

I didn't realise that was what it was trying to test. I'll add a test
for this, but I'll use self.patch(sys, "stdout", ...) instead, if
that's okay?

> and the new name "writer" is inaccurate. If you want to split hairs,
> it's "write_config".

Every other package and module name, afaict, is a noun. Another
natural place for DHCPConfigWriter could be
provisioninserver.dhcp.scripts?

> I'd appreciate it if you'd put the script back, either
> buildout-generated or a shortcut using the bin/py method.

Okay.

> Why did you remove the build dependency from the check target?
> Regardless of my changes it seems a good idea.

Yeah, it is a good idea. This was actually the thing that got me
started on this branch: the massive rubber hammer to squash a single
missing dependency.

So, given that testing a full build is good, but that it's worthwhile
exercising the dependencies in Makefile too, I'll change it to do a
full build *after* running tests.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2012-06-08 00:23:22 +0000
+++ Makefile 2012-06-08 10:31:19 +0000
@@ -21,7 +21,6 @@
21 bin/twistd.pserv bin/test.pserv \21 bin/twistd.pserv bin/test.pserv \
22 bin/twistd.txlongpoll \22 bin/twistd.txlongpoll \
23 bin/py bin/ipy \23 bin/py bin/ipy \
24 bin/write_dhcp_config \
25 $(js_enums)24 $(js_enums)
2625
27all: build doc26all: build doc
@@ -70,10 +69,6 @@
70 bin/buildout install repl69 bin/buildout install repl
71 @touch --no-create bin/py bin/ipy70 @touch --no-create bin/py bin/ipy
7271
73bin/write_dhcp_config: bin/buildout buildout.cfg versions.cfg setup.py
74 bin/buildout install write-dhcp-config
75 @touch --no-create $@
76
77test: bin/test.maas bin/test.maastesting bin/test.pserv $(js_enums)72test: bin/test.maas bin/test.maastesting bin/test.pserv $(js_enums)
78 bin/test.maas73 bin/test.maas
79 bin/test.maastesting74 bin/test.maastesting
@@ -95,7 +90,7 @@
95lint-js:90lint-js:
96 @find $(sources) -type f -print0 | xargs -r0 $(pocketlint)91 @find $(sources) -type f -print0 | xargs -r0 $(pocketlint)
9792
98check: clean build test93check: clean test
9994
100docs/api.rst: bin/maas src/maasserver/api.py syncdb95docs/api.rst: bin/maas src/maasserver/api.py syncdb
101 bin/maas generate_api_doc > $@96 bin/maas generate_api_doc > $@
10297
=== modified file 'buildout.cfg'
--- buildout.cfg 2012-06-07 05:54:29 +0000
+++ buildout.cfg 2012-06-08 10:31:19 +0000
@@ -9,7 +9,6 @@
9 repl9 repl
10 sphinx10 sphinx
11 txlongpoll11 txlongpoll
12 write-dhcp-config
13extensions = buildout-versions12extensions = buildout-versions
14buildout_versions_file = versions.cfg13buildout_versions_file = versions.cfg
15versions = versions14versions = versions
@@ -80,6 +79,7 @@
80extra-paths = ${common:extra-paths}79extra-paths = ${common:extra-paths}
81interpreter =80interpreter =
82entry-points = database=postgresfixture.main:main81entry-points = database=postgresfixture.main:main
82scripts = database
8383
84[maas]84[maas]
85recipe = zc.recipe.egg85recipe = zc.recipe.egg
@@ -214,9 +214,3 @@
214 txamqp214 txamqp
215entry-points = twistd.txlongpoll=twisted.scripts.twistd:run215entry-points = twistd.txlongpoll=twisted.scripts.twistd:run
216scripts = twistd.txlongpoll216scripts = twistd.txlongpoll
217
218[write-dhcp-config]
219recipe = z3c.recipe.scripts
220extra-paths = ${common:extra-paths}
221entry-points = write_dhcp_config=provisioningserver.dhcp.write_dhcp_config:run
222scripts = write_dhcp_config
223217
=== renamed file 'src/provisioningserver/dhcp/tests/test_write_dhcp_config.py' => 'src/provisioningserver/dhcp/tests/test_writer.py'
--- src/provisioningserver/dhcp/tests/test_write_dhcp_config.py 2012-06-07 07:53:25 +0000
+++ src/provisioningserver/dhcp/tests/test_writer.py 2012-06-08 10:31:19 +0000
@@ -1,7 +1,7 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for write-dhcp-config.py"""4"""Tests for `provisioningserver.dhcp.writer`."""
55
6from __future__ import (6from __future__ import (
7 absolute_import,7 absolute_import,
@@ -13,19 +13,15 @@
13__all__ = []13__all__ = []
1414
15import os15import os
16import subprocess
1716
18from maastesting.matchers import ContainsAll17from maastesting.matchers import ContainsAll
19from maastesting.testcase import TestCase18from maastesting.testcase import TestCase
20from testtools.matchers import (19from provisioningserver.dhcp.writer import DHCPConfigWriter
21 MatchesStructure,20from testtools.matchers import MatchesStructure
22 )21
2322
24from provisioningserver.dhcp.write_dhcp_config import DHCPConfigWriter23class TestDHCPConfigWriter(TestCase):
2524 """Test `DHCPConfigWriter`."""
26
27class TestModule(TestCase):
28 """Test the write-dhcp-config module."""
2925
30 def test_arg_setup(self):26 def test_arg_setup(self):
31 writer = DHCPConfigWriter()27 writer = DHCPConfigWriter()
@@ -92,32 +88,3 @@
92 writer.run(test_args)88 writer.run(test_args)
9389
94 self.assertTrue(os.path.exists(outfile))90 self.assertTrue(os.path.exists(outfile))
95
96
97class TestScriptExecutable(TestCase):
98 """Test that the actual script is executable."""
99
100 def test_script(self):
101 test_args = [
102 '--subnet', 'subnet',
103 '--subnet-mask', 'subnet-mask',
104 '--next-server', 'next-server',
105 '--broadcast-address', 'broadcast-address',
106 '--dns-servers', 'dns-servers',
107 '--gateway', 'gateway',
108 '--low-range', 'low-range',
109 '--high-range', 'high-range',
110 ]
111
112 exe = [os.path.join(
113 os.path.dirname(__file__),
114 os.pardir, os.pardir, os.pardir, os.pardir,
115 "bin", "write_dhcp_config")]
116
117 exe.extend(test_args)
118 output = subprocess.check_output(exe)
119
120 contains_all_params = ContainsAll(
121 ['subnet', 'subnet-mask', 'next-server', 'broadcast-address',
122 'dns-servers', 'gateway', 'low-range', 'high-range'])
123 self.assertThat(output, contains_all_params)
12491
=== renamed file 'src/provisioningserver/dhcp/write_dhcp_config.py' => 'src/provisioningserver/dhcp/writer.py'
--- src/provisioningserver/dhcp/write_dhcp_config.py 2012-06-07 07:53:25 +0000
+++ src/provisioningserver/dhcp/writer.py 2012-06-08 10:31:19 +0000
@@ -12,8 +12,8 @@
12__metaclass__ = type12__metaclass__ = type
13__all__ = []13__all__ = []
1414
15
16import argparse15import argparse
16from sys import stdout
1717
18from provisioningserver.dhcp import config18from provisioningserver.dhcp import config
1919
@@ -73,20 +73,13 @@
73 def run(self, argv=None):73 def run(self, argv=None):
74 """Generate the config and write to stdout or a file as required."""74 """Generate the config and write to stdout or a file as required."""
75 args = self.parse_args(argv)75 args = self.parse_args(argv)
76 output = self.generate(args)76 output = self.generate(args).encode("ascii")
77 outfile = args.out_file77 if args.out_file is not None:
78 if outfile is not None:78 with open(args.out_file, "wb") as f:
79 with open(outfile, "w") as f:
80 f.write(output)79 f.write(output)
81 else:80 else:
82 print(output)81 stdout.write(output)
83
84
85def run():
86 """Entry point for scripts."""
87 writer = DHCPConfigWriter()
88 writer.run()
8982
9083
91if __name__ == "__main__":84if __name__ == "__main__":
92 run()85 DHCPConfigWriter().run()