Merge lp:~javier.collado/utah/bug1061011 into lp:utah

Proposed by Javier Collado
Status: Merged
Merged at revision: 702
Proposed branch: lp:~javier.collado/utah/bug1061011
Merge into: lp:utah
Diff against target: 188 lines (+92/-38)
3 files modified
tests/test_preseed.py (+46/-0)
utah/preseed.py (+40/-36)
utah/provisioning/provisioning.py (+6/-2)
To merge this branch: bzr merge lp:~javier.collado/utah/bug1061011
Reviewer Review Type Date Requested Status
Max Brustkern (community) Approve
Review via email: mp+128497@code.launchpad.net

Description of the change

As agreed in the bugs comments, this branch adds a new exception to the preseed
module, so that the traceback when a duplicated question name is found in the
preseed file is clearer. In particular, the new traceback would be something
like this:

  File "/home/javi/code/bzr/utah/bug1061011/utah/preseed.py", line 134, in section_updated
    raise DuplicatedQuestionName(new_text)
utah.preseed.DuplicatedQuestionName: partman/confirm

In addition to this a new module with a few simple test cases have been added
to the tests/ directory (they can be executed with nosetests tests/). I'm not
sure if that's the best location for server test cases, but I haven't found any
other test cases and this one looks fine to me since the files under tests/
aren't included in the binary package. Anyway, under tests/ there's already a
script that is used to run the client test cases, but I guess we can have both
things together.

In the future, we could also have a jenkins job to run the test cases for the
server as there is already one to run the test cases for the client.

To post a comment you must log in.
Revision history for this message
Max Brustkern (nuclearbob) wrote :

I like that new exception. If you've already tested this, we should be good to go ahead and merge, otherwise, I'll try to test it.

review: Approve
Revision history for this message
Javier Collado (javier.collado) wrote :

@Max

Yes, I already tested it, so I'm merging it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'tests/test_preseed.py'
--- tests/test_preseed.py 1970-01-01 00:00:00 +0000
+++ tests/test_preseed.py 2012-10-08 13:46:36 +0000
@@ -0,0 +1,46 @@
1from utah.preseed import (
2 Preseed,
3 Section,
4 BlankSection,
5 CommentSection,
6 ConfigurationSection,
7 DuplicatedQuestionName,
8 )
9
10import unittest
11
12
13class TestPreseedLoadDump(unittest.TestCase):
14 """
15 Minimal load/dump test cases
16 """
17 BASIC_PRESEED = """# Comment
18
19d-i passwd/username string utah
20"""
21
22 DUPLICATED_QUESTION_NAME_PRESEED = """d-i passwd/username string utah
23d-i passwd/username string utah
24"""
25
26 def test_load(self):
27 """Load basic preseed"""
28 preseed = Preseed(self.BASIC_PRESEED.splitlines())
29
30 self.assertEqual(len(preseed.sections), 3)
31 section_types = (CommentSection, BlankSection, ConfigurationSection)
32 for index, section_type in enumerate(section_types):
33 self.assertIsInstance(preseed.sections[index], section_type)
34
35 def test_dump(self):
36 """Dump basic preseed"""
37 preseed = Preseed()
38 preseed.append(Section.new(preseed, '# Comment'))
39 preseed.append(Section.new(preseed, ''))
40 preseed.append(Section.new(preseed, 'd-i passwd/username string utah'))
41 self.assertEqual(preseed.dump(), self.BASIC_PRESEED)
42
43 def test_duplicated_question_name(self):
44 """Exception raised on duplicated question name"""
45 with self.assertRaises(DuplicatedQuestionName):
46 Preseed(self.DUPLICATED_QUESTION_NAME_PRESEED.splitlines())
047
=== modified file 'utah/preseed.py'
--- utah/preseed.py 2012-09-06 12:34:28 +0000
+++ utah/preseed.py 2012-10-08 13:46:36 +0000
@@ -8,12 +8,13 @@
8 """8 """
9 Read/Write preseed files easily9 Read/Write preseed files easily
10 """10 """
11 def __init__(self, filename):11 def __init__(self, lines=None):
12 # Used to access quickly to configuration sections by question name12 # Used to access quickly to configuration sections by question name
13 self._qnames = {}13 self._qnames = {}
1414 if lines is not None:
15 self.filename = filename15 self.load(lines)
16 self.read(filename)16 else:
17 self.sections = []
1718
18 def __getitem__(self, key):19 def __getitem__(self, key):
19 """20 """
@@ -37,42 +38,38 @@
3738
38 return key in self._qnames39 return key in self._qnames
3940
40 def read(self, filename=None):41 def load(self, lines):
41 """42 """
42 Read a whole preseed file and parse its configuration lines43 Parse preseed configuration lines
43 """
44 if filename is not None:
45 self.filename = filename
46 else:
47 filename = self.filename
4844
45 :param lines: Any iterable that yields preseed file configuration lines
46 :type lines: iterable
47 """
49 self.sections = []48 self.sections = []
50 with open(filename) as f:49 # One line might be made of multiple lines
51 # One line might be made of multiple lines50 # that are continued with '\\'
52 # that are continued with '\\'51 output_lines = []
53 output_lines = []52 for input_line in lines:
54 for input_line in f:53 input_line = input_line.rstrip('\n')
55 input_line = input_line.rstrip('\n')54 output_lines.append(input_line)
56 output_lines.append(input_line)55
5756 # Line is finished only when no continuation character is found
58 # Line is finished only when no continuation character is found57 if not input_line.endswith('\\'):
59 if not input_line.endswith('\\'):58 new_section = Section.new(self, output_lines)
60 new_section = Section.new(self, output_lines)59 self.append(new_section)
61 self.append(new_section)60 output_lines = []
62 output_lines = []61
6362 return self
64 def write(self, filename=None):63
64 def dump(self):
65 """65 """
66 Dump preseed configuration statements
66 Write the modified file to the same or a new location67 Write the modified file to the same or a new location
68
69 :returns: Formatted preseed configuration lines
70 :rtype: string
67 """71 """
68 if filename is not None:72 return ''.join(str(section) for section in self.sections)
69 self.filename = filename
70 else:
71 filename = self.filename
72
73 with open(filename, 'w') as f:
74 for section in self.sections:
75 f.write('{}'.format(section))
7673
77 def append(self, new_section, ref_section=None):74 def append(self, new_section, ref_section=None):
78 """75 """
@@ -133,7 +130,8 @@
133 """130 """
134 if property_name == 'qname':131 if property_name == 'qname':
135 new_text = new_value.text132 new_text = new_value.text
136 assert new_text not in self._qnames133 if new_text in self._qnames:
134 raise DuplicatedQuestionName(new_text)
137135
138 if old_value is not None:136 if old_value is not None:
139 old_text = old_value.text137 old_text = old_value.text
@@ -350,3 +348,9 @@
350348
351 def property_updated(self, property_name, old_value, new_value):349 def property_updated(self, property_name, old_value, new_value):
352 self.parent.section_updated(self, property_name, old_value, new_value)350 self.parent.section_updated(self, property_name, old_value, new_value)
351
352
353class DuplicatedQuestionName(Exception):
354 """
355 Exception raised when a question name is found more than once in a preseed
356 """
353357
=== modified file 'utah/provisioning/provisioning.py'
--- utah/provisioning/provisioning.py 2012-10-04 11:49:14 +0000
+++ utah/provisioning/provisioning.py 2012-10-08 13:46:36 +0000
@@ -787,7 +787,8 @@
787 self.logger.info('Setting up preseed')787 self.logger.info('Setting up preseed')
788 if tmpdir is None:788 if tmpdir is None:
789 tmpdir = self.tmpdir789 tmpdir = self.tmpdir
790 preseed = Preseed(self.preseed)790 with open(self.preseed) as f:
791 preseed = Preseed(f)
791 if 'preseed/late_command' in preseed:792 if 'preseed/late_command' in preseed:
792 question = preseed['preseed/late_command']793 question = preseed['preseed/late_command']
793 if self.installtype == 'desktop':794 if self.installtype == 'desktop':
@@ -833,7 +834,10 @@
833 question = preseed['passwd/username']834 question = preseed['passwd/username']
834 question.value = config.user835 question.value = config.user
835836
836 preseed.write(os.path.join(tmpdir, 'initrd.d', 'preseed.cfg'))837 output_preseed_filename = os.path.join(tmpdir,
838 'initrd.d', 'preseed.cfg')
839 with open(output_preseed_filename, 'w') as f:
840 f.write(preseed.dump())
837841
838 if self.installtype == 'desktop':842 if self.installtype == 'desktop':
839 self.logger.info('Inserting preseed into casper')843 self.logger.info('Inserting preseed into casper')

Subscribers

People subscribed via source and target branches