Merge lp:~doanac/utah/rsyslog-v4 into lp:utah

Proposed by Andy Doan
Status: Merged
Merged at revision: 831
Proposed branch: lp:~doanac/utah/rsyslog-v4
Merge into: lp:utah
Diff against target: 959 lines (+593/-45) (has conflicts)
15 files modified
examples/run_install_test.py (+7/-0)
examples/run_test_bamboo_feeder.py (+6/-0)
examples/run_test_cobbler.py (+6/-0)
examples/run_test_vm.py (+7/-0)
examples/run_utah_tests.py (+7/-0)
templates/50-utahdefault.conf.jinja2 (+1/-0)
templates/utah-latecommand.jinja2 (+9/-0)
tests/test_rsyslog.py (+212/-0)
utah/config.py (+49/-1)
utah/provisioning/baremetal/bamboofeeder.py (+6/-11)
utah/provisioning/baremetal/cobbler.py (+17/-18)
utah/provisioning/provisioning.py (+55/-9)
utah/provisioning/rsyslog.py (+195/-0)
utah/provisioning/vm/vm.py (+15/-5)
utah_howto.txt (+1/-1)
Text conflict in examples/run_install_test.py
Text conflict in examples/run_test_bamboo_feeder.py
Text conflict in examples/run_test_cobbler.py
Text conflict in examples/run_test_vm.py
Text conflict in examples/run_utah_tests.py
To merge this branch: bzr merge lp:~doanac/utah/rsyslog-v4
Reviewer Review Type Date Requested Status
UTAH Dev Pending
Review via email: mp+151840@code.launchpad.net

Description of the change

yet another attempt to try and get BZR to not screw up my diffs:

This has finally been tested fairly well and should be ready to review. This patch set allows UTAH to read syslog messages from the target test device to understand what's going on (ie is install working, did the system boot).

Since the messages you'll need to queue on will likely change over time, I've made this configurable via our JSON config. The current configuration that seems to be working looks like:

    "install_steps": [
      {
        "message": "system started",
        "pattern": ".*",
        "booted": true,
        "timeout": 360
      },
      {
        "message": "install started",
        "pattern": [
          ".*ubiquity\\[\\d+\\]: Ubiquity \\d",
          ".*anna-install"
        ],
        "timeout": 120
      },
      {
        "message": "install complete",
        "comment": "the finish-install pattern was needed for server bootspeed job",
        "pattern": [
          ".*ubiquity reboot",
          ".*log-output -t ubiquity umount /target$",
          ".*finish-install.d/94save-logs",
          ".*finish-install: umount"
        ],
        "timeout": 3600
      }
    ],
    "boot_steps": [
      {
        "message": "system booted",
        "pattern": ".*Linux version \\d",
        "timeout": 180
      },
      {
        "message": "disk mounted",
        "pattern": ".*mounted filesystem with ordered data",
        "timeout": 180
      },
      {
        "message": "network active",
        "pattern": ".*NetworkManager",
        "timeout": 180
      }
    ]
}

I'm thinking this might be a good thing to include as a conf.d/10_syslog-messages file and be installed by default. let me know if that makes sense.

To post a comment you must log in.
Revision history for this message
Andy Doan (doanac) wrote :

some original comments from max:

So, it looks like you've added some generic exception logging to run_test_vm.py, but not any of the other test scripts. I forgot that script even exists; it used to be the script to run the vm-tools integration, but that integration has been deprecated for a while. I think if we're changing one run script, we should probably be changing them all or changing run.py. I think we should also consider whether changing them at all makes sense, given the likelihood that we'll be removing most of them soon in a separate merge.

On lines 270 and 401, I'd consider using a generic hostname, like ubuntu. I'd also consider picking a weird specific date, like the beginning of the unix epoch, or the date and time I was born, or when ubuntu was first released, but I'm weird like that.

On 468 and 532 we're still checking for SSH in a retry loop with a long timeout, even though we know the machine is installed and booted. I think this is reasonable behavior, at least for now, but I think a comment in there will help us remember that we may want to revise that at some point. Similarly, notes on lines 938 and 960 might make sense.

Since you've taken out the removal of the serial device on line 945, have you verified that the log correctly appends after a reboot and doesn't just overwrite the old one? I think I've had problems with that before.

I haven't actually reviewed the new rsyslog.py yet, but those are my thoughts on everything else.

lp:~doanac/utah/rsyslog-v4 updated
841. By Andy Doan

review comments from max

Revision history for this message
Andy Doan (doanac) wrote :

and my comments to his comments:

On 03/05/2013 10:41 AM, Max Brustkern wrote:
> So, it looks like you've added some generic exception logging to
> run_test_vm.py, but not any of the other test scripts. I forgot that
> script even exists; it used to be the script to run the vm-tools
> integration, but that integration has been deprecated for a while. I
> think if we're changing one run script, we should probably be
> changing them all or changing run.py. I think we should also
> consider whether changing them at all makes sense, given the
> likelihood that we'll be removing most of them soon in a separate
> merge.

I fixed the one because it happened to be swallowing a syntax error I
discovered while testing my code. I don't mind updating the others - it
might save someone else 20 minutes in the future.

> On lines 270 and 401, I'd consider using a generic hostname, like
> ubuntu. I'd also consider picking a weird specific date, like the
> beginning of the unix epoch, or the date and time I was born, or when
> ubuntu was first released, but I'm weird like that.

sure.

> On 468 and 532 we're still checking for SSH in a retry loop with a
> long timeout, even though we know the machine is installed and
> booted. I think this is reasonable behavior, at least for now, but I
> think a comment in there will help us remember that we may want to
> revise that at some point. Similarly, notes on lines 938 and 960
> might make sense.

I suppose we should just update our default config now, but I wasn't
sure if this would play nice with reboot support changes?

> Since you've taken out the removal of the serial device on line 945,
> have you verified that the log correctly appends after a reboot and
> doesn't just overwrite the old one? I think I've had problems with
> that before.

It does not append to the file. However, the rsyslog.py code creates a
-install.log file that has all of that.

> I haven't actually reviewed the new rsyslog.py yet, but those are my
> thoughts on everything else.

Cool - i'll make some updates ASAP

Revision history for this message
Max Brustkern (nuclearbob) wrote :

I've got two thoughts on the configuration.

1. I'm still seeing ubiquity (such as precise desktop amd64) installs where the last line is like:
Mar 11 14:44:37 utah-1657-precise-amd64 rsyslogd: [origin software="rsyslogd" swVersion="5.8.6" x-pid="1652" x-info="http://www.rsyslog.com"] exiting on signal 15.
I think that should be one of the options.
2. I think the configuration should be in the package. Since all installs will now be assuming it exists, I think it should be in config.py. The reason everything is in config.py is so that if a user has an empty utah config file, we can still theoretically have some defaults and work. I think that design decision is something we want to evaluate, per some email discussions, but for now, I think we should continue doing things in that manner until we actually move away from it.

Finally, I'm seeing some weird things on mini installs like this:
...
Test logs copied to the following files:
 /var/log/utah/utah-1670-quantal-mini-amd64_pass.run_2013-03-11_16-03-59.yaml
Exception in thread Thread-1 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/lib/python2.7/dist-packages/paramiko/transport.py", line 1571, in run
  File "/usr/lib/python2.7/dist-packages/paramiko/transport.py", line 1386, in _log
  File "/usr/lib/python2.7/logging/__init__.py", line 1203, in log
  File "/usr/lib/python2.7/logging/__init__.py", line 1257, in _log
  File "/usr/lib/python2.7/logging/__init__.py", line 1231, in makeRecord
<type 'exceptions.TypeError'>: 'NoneType' object is not callable
Exception in thread Thread-3 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/lib/python2.7/dist-packages/paramiko/transport.py", line 1571, in run
  File "/usr/lib/python2.7/dist-packages/paramiko/transport.py", line 1386, in _log
  File "/usr/lib/python2.7/logging/__init__.py", line 1203, in log
  File "/usr/lib/python2.7/logging/__init__.py", line 1257, in _log
  File "/usr/lib/python2.7/logging/__init__.py", line 1231, in makeRecord
<type 'exceptions.TypeError'>: 'NoneType' object is not callable
0

This was a run of
run_utah_tests.py --lots-of-arguments ; echo $?
It looks like utah ran fine and exited with status 0, but dumped some weird stuff? It's confusing, and intermittent. It may not even be related to this change, but I wanted to mention it somewhere so we didn't lose sight of it completely.

Revision history for this message
Andy Doan (doanac) wrote :

On 03/11/2013 01:26 PM, Max Brustkern wrote:
> 1. I'm still seeing ubiquity (such as precise desktop amd64) installs where the last line is like:
> Mar 11 14:44:37 utah-1657-precise-amd64 rsyslogd: [origin software="rsyslogd" swVersion="5.8.6" x-pid="1652" x-info="http://www.rsyslog.com"] exiting on signal 15.
> I think that should be one of the options.

I left that one out because one we always hit one of the other current
regex's before this ever shows. However, its still a good safe-guard to
keep us from waiting forever.

> 2. I think the configuration should be in the package. Since all installs will now be assuming it exists, I think it should be in config.py. The reason everything is in config.py is so that if a user has an empty utah config file, we can still theoretically have some defaults and work. I think that design decision is something we want to evaluate, per some email discussions, but for now, I think we should continue doing things in that manner until we actually move away from it.

I agree. I wasn't sure if we wanted to start putting new fields like
this in conf.d instead of config.py so that things don't break when we
update the package. However, I guess apt will warn us, right?

> Finally, I'm seeing some weird things on mini installs like this:

That's interesting. I wonder if this happens on trunk?

Revision history for this message
Max Brustkern (nuclearbob) wrote :

> I agree. I wasn't sure if we wanted to start putting new fields like
> this in conf.d instead of config.py so that things don't break when we
> update the package. However, I guess apt will warn us, right?

Currently, most things are config.something, so if we refer to config.something and it's not in config.py and it's not in any config file, we'll have an Exception. This means that if the user blanks out their config file, and the item isn't in config.py, there's the possibility of an exception, so we put everything in config.py to avoid the possibility of the user creating a situation which is likely to generate an exception. I don't think this design is scaling well, but I'd like to have an agreed-upon new design before we move away from it.

>
> > Finally, I'm seeing some weird things on mini installs like this:
>
> That's interesting. I wonder if this happens on trunk?

I'm looking into that now.

Revision history for this message
Andy Doan (doanac) wrote :

On 03/11/2013 01:51 PM, Max Brustkern wrote:
> Currently, most things are config.something, so if we refer to config.something and it's not in config.py and it's not in any config file, we'll have an Exception. This means that if the user blanks out their config file, and the item isn't in config.py, there's the possibility of an exception, so we put everything in config.py to avoid the possibility of the user creating a situation which is likely to generate an exception. I don't think this design is scaling well, but I'd like to have an agreed-upon new design before we move away from it.

I mis-read your initial comment and was thinking you were suggesting
putting it in /etc/utah/config. config.py is a good place for this, not
sure why I didn't do it that way from the start.

Revision history for this message
Max Brustkern (nuclearbob) wrote :

I've got one last thing. Should rsyslog.py be held to the new standard for external exceptions that we've been discussing in code reviews, or should we come back to that file and implement that later?

Revision history for this message
Andy Doan (doanac) wrote :

On 03/11/2013 04:06 PM, Max Brustkern wrote:
> I've got one last thing. Should rsyslog.py be held to the new standard for external exceptions that we've been discussing in code reviews, or should we come back to that file and implement that later?

I wondered about that. I finally decided to keep this targeted at one
thing and we could go back later and clean stuff up.

lp:~doanac/utah/rsyslog-v4 updated
842. By Andy Doan

add default install/booted steps to config

These have been tested by Max and I on all the different permutations
we could come up with and they seem to work.

Revision history for this message
Andy Doan (doanac) wrote :

@max - I've added the config.py change as requested and tested locally.

Revision history for this message
Max Brustkern (nuclearbob) wrote :

I see merge conflicts again. Assuming we can resolve those before the final commit, I think we're good to go.

Revision history for this message
Andy Doan (doanac) wrote :

something must be broke in my copy of bzr. all i did for the last change was:

http://bazaar.launchpad.net/~doanac/utah/rsyslog-v4/revision/842

i'll do the merge from a pristine machine.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'examples/run_install_test.py'
--- examples/run_install_test.py 2013-03-11 09:15:18 +0000
+++ examples/run_install_test.py 2013-03-12 16:15:29 +0000
@@ -16,6 +16,7 @@
16# with this program. If not, see <http://www.gnu.org/licenses/>.16# with this program. If not, see <http://www.gnu.org/licenses/>.
1717
18import argparse18import argparse
19import logging
19import sys20import sys
2021
21from utah.exceptions import UTAHException22from utah.exceptions import UTAHException
@@ -79,8 +80,14 @@
7980
80 except UTAHException as error:81 except UTAHException as error:
81 sys.stderr.write('Exception: ' + str(error))82 sys.stderr.write('Exception: ' + str(error))
83<<<<<<< TREE
82 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR84 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
8385
86=======
87 exitstatus = 2
88 except:
89 logging.exception('Unhandled error in UTAH')
90>>>>>>> MERGE-SOURCE
84 finally:91 finally:
85 if not args.no_destroy and machine is not None:92 if not args.no_destroy and machine is not None:
86 try:93 try:
8794
=== modified file 'examples/run_test_bamboo_feeder.py'
--- examples/run_test_bamboo_feeder.py 2013-03-11 09:15:18 +0000
+++ examples/run_test_bamboo_feeder.py 2013-03-12 16:15:29 +0000
@@ -87,8 +87,14 @@
87 logging.error(mesg)87 logging.error(mesg)
88 except (AttributeError, NameError):88 except (AttributeError, NameError):
89 sys.stderr.write(mesg)89 sys.stderr.write(mesg)
90<<<<<<< TREE
90 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR91 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
9192
93=======
94 exitstatus = 2
95 except:
96 logging.exception('Unhandled error in UTAH')
97>>>>>>> MERGE-SOURCE
92 finally:98 finally:
93 if machine is not None:99 if machine is not None:
94 try:100 try:
95101
=== modified file 'examples/run_test_cobbler.py'
--- examples/run_test_cobbler.py 2013-03-11 09:15:18 +0000
+++ examples/run_test_cobbler.py 2013-03-12 16:15:29 +0000
@@ -92,8 +92,14 @@
92 logging.error(mesg)92 logging.error(mesg)
93 except (AttributeError, NameError):93 except (AttributeError, NameError):
94 sys.stderr.write(mesg)94 sys.stderr.write(mesg)
95<<<<<<< TREE
95 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR96 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
9697
98=======
99 exitstatus = 2
100 except:
101 logging.exception('Unhandled error in UTAH')
102>>>>>>> MERGE-SOURCE
97 finally:103 finally:
98 if machine is not None:104 if machine is not None:
99 try:105 try:
100106
=== modified file 'examples/run_test_vm.py'
--- examples/run_test_vm.py 2013-03-11 09:15:18 +0000
+++ examples/run_test_vm.py 2013-03-12 16:15:29 +0000
@@ -16,6 +16,7 @@
16# with this program. If not, see <http://www.gnu.org/licenses/>.16# with this program. If not, see <http://www.gnu.org/licenses/>.
1717
18import argparse18import argparse
19import logging
19import sys20import sys
2021
21from utah.exceptions import UTAHException22from utah.exceptions import UTAHException
@@ -73,8 +74,14 @@
7374
74 except UTAHException as error:75 except UTAHException as error:
75 sys.stderr.write('Exception: ' + str(error))76 sys.stderr.write('Exception: ' + str(error))
77<<<<<<< TREE
76 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR78 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
7779
80=======
81 exitstatus = 2
82 except:
83 logging.exception('Unhandled error in UTAH')
84>>>>>>> MERGE-SOURCE
78 finally:85 finally:
79 if not args.no_destroy and machine is not None:86 if not args.no_destroy and machine is not None:
80 try:87 try:
8188
=== modified file 'examples/run_utah_tests.py'
--- examples/run_utah_tests.py 2013-03-11 09:15:18 +0000
+++ examples/run_utah_tests.py 2013-03-12 16:15:29 +0000
@@ -16,6 +16,7 @@
16# with this program. If not, see <http://www.gnu.org/licenses/>.16# with this program. If not, see <http://www.gnu.org/licenses/>.
1717
18import argparse18import argparse
19import logging
19import sys20import sys
2021
21from utah import config22from utah import config
@@ -95,7 +96,13 @@
95 exitstatus, locallogs = run_tests(args, machine)96 exitstatus, locallogs = run_tests(args, machine)
96 except UTAHException as error:97 except UTAHException as error:
97 sys.stderr.write('Exception: ' + str(error))98 sys.stderr.write('Exception: ' + str(error))
99<<<<<<< TREE
98 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR100 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
101=======
102 exitstatus = 2
103 except:
104 logging.exception('Unhandled error in UTAH')
105>>>>>>> MERGE-SOURCE
99 finally:106 finally:
100 if len(locallogs) != 0:107 if len(locallogs) != 0:
101 print('Test logs copied to the following files:')108 print('Test logs copied to the following files:')
102109
=== modified file 'templates/50-utahdefault.conf.jinja2'
--- templates/50-utahdefault.conf.jinja2 2013-02-21 08:45:09 +0000
+++ templates/50-utahdefault.conf.jinja2 2013-03-12 16:15:29 +0000
@@ -11,3 +11,4 @@
11news.err /var/log/news/news.err11news.err /var/log/news/news.err
12news.notice -/var/log/news/news.notice12news.notice -/var/log/news/news.notice
13*.emerg *13*.emerg *
14*.* {{dest}}
1415
=== modified file 'templates/utah-latecommand.jinja2'
--- templates/utah-latecommand.jinja2 2013-02-25 23:53:25 +0000
+++ templates/utah-latecommand.jinja2 2013-03-12 16:15:29 +0000
@@ -26,8 +26,17 @@
26 echo "{{user}}" >> /target/etc/utah/users26 echo "{{user}}" >> /target/etc/utah/users
27}27}
2828
29copy_rsyslog_cfg() {
30 # ubiquity installs have this under /etc/rsyslog.d
31 # d-i installs have it under /
32 syslogcfg=/etc/rsyslog.d/50-utahdefault.conf
33 [ -f $syslogcfg ] || syslogcfg=/$(basename $syslogcfg)
34 cp $syslogcfg /target/etc/rsyslog.d/
35}
36
29copy_ssh_keys37copy_ssh_keys
30write_utah_data38write_utah_data
39copy_rsyslog_cfg
3140
32log "Copying UTAH latecommmand in-target script..."41log "Copying UTAH latecommmand in-target script..."
33cp utah-latecommand-in-target /target/tmp42cp utah-latecommand-in-target /target/tmp
3443
=== added file 'tests/test_rsyslog.py'
--- tests/test_rsyslog.py 1970-01-01 00:00:00 +0000
+++ tests/test_rsyslog.py 2013-03-12 16:15:29 +0000
@@ -0,0 +1,212 @@
1# Ubuntu Testing Automation Harness
2# Copyright 2013 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import logging
17import socket
18import time
19import tempfile
20import threading
21import unittest
22
23from utah.provisioning.rsyslog import RSyslog
24
25
26class TestRsyslog(unittest.TestCase):
27 logger = logging.getLogger()
28 logger.setLevel(logging.DEBUG)
29 logging.getLogger('rsyslog').addHandler(logging.StreamHandler())
30
31 @staticmethod
32 def producer(port, messages):
33 print 'sending fake messages to port: %d' % port
34 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
35 s.connect(('localhost', port))
36 for m in messages:
37 time.sleep(.5)
38 s.send(m)
39
40 @staticmethod
41 def file_producer(f, messages, truncate=False):
42 for m in messages:
43 f.write(m)
44 f.write('\n')
45 f.flush()
46 time.sleep(1)
47 if truncate:
48 f.truncate(0)
49 f.flush()
50 time.sleep(1)
51 truncate = False
52
53 def test_easy(self):
54 """
55 minimal test to make sure we can match a typical first message
56 """
57 steps = [
58 {
59 "message": "test_easy",
60 "pattern": ".*log source = /proc/kmsg started",
61 "timeout": 120,
62 "booted": False,
63 },
64 ]
65
66 messages = [
67 'test 1',
68 '<13>Feb 20 13:38:55 host user: log source = /proc/kmsg started',
69 ]
70 r = RSyslog("utah-test", '/tmp')
71 threading.Thread(target=self.producer, args=(r.port, messages)).start()
72 r.wait_for_install(steps)
73
74 def test_future(self):
75 """
76 test to make sure we can handle missing a message and understanding
77 where things are in the future
78 """
79 steps = [
80 {
81 "message": "test_future",
82 "pattern": ".*log source = /proc/kmsg started",
83 "timeout": 120,
84 "booted": True,
85 },
86 {
87 "message": "hit skipped",
88 "pattern": "hit skipped",
89 "timeout": 120,
90 },
91 {
92 "message": "message 3",
93 "pattern": "message 3",
94 "timeout": 120,
95 },
96 ]
97
98 messages = [
99 'test 1',
100 'hit skipped',
101 'message 3',
102 ]
103
104 r = RSyslog("utah-test", '/tmp')
105 threading.Thread(target=self.producer, args=(r.port, messages)).start()
106
107 def booted_cb():
108 self.test_future_booted = True
109
110 self.test_future_booted = False
111 r.wait_for_install(steps, booted_cb)
112 self.assertTrue(self.test_future_booted, 'booted callback not made')
113
114 def test_callbacks(self):
115 """
116 minimal test to make sure wait_for_steps works
117 """
118 steps = [
119 {
120 "message": "test callbacks",
121 "pattern": ".*log source = /proc/kmsg started",
122 "timeout": 120,
123 "booted": True,
124 },
125 {
126 "message": "hit skipped",
127 "pattern": "hit skipped",
128 "timeout": 120,
129 },
130 {
131 "message": "message 3",
132 "pattern": "message 3",
133 "timeout": 120,
134 "blah": True,
135 },
136 ]
137
138 messages = [
139 'test 1',
140 'hit skipped',
141 'message 3',
142 ]
143
144 r = RSyslog("utah-test", '/tmp')
145 threading.Thread(target=self.producer, args=(r.port, messages)).start()
146
147 def booted_cb():
148 self.test_callbacks_booted = True
149
150 def blah_cb():
151 self.test_callbacks_blah = True
152
153 self.test_callbacks_booted = self.test_callbacks_blah = False
154 callbacks = {
155 'booted': booted_cb,
156 'blah': blah_cb,
157 }
158 r._wait_for_steps(steps, "/dev/null", callbacks)
159 self.assertTrue(self.test_callbacks_booted, 'booted callback not made')
160 self.assertTrue(self.test_callbacks_blah, 'blah callback not made')
161
162 def test_booted(self):
163 """
164 minimal test to make sure wait_for_booted works
165 """
166 steps = [
167 {
168 "message": "test booted",
169 "pattern": ".*log source = /proc/kmsg started",
170 "timeout": 120,
171 },
172 ]
173
174 messages = [
175 'test 1',
176 '<13>Feb 20 13:38:55 host user: log source = /proc/kmsg started',
177 ]
178
179 r = RSyslog("utah-test", '/tmp')
180 threading.Thread(target=self.producer, args=(r.port, messages)).start()
181 r.wait_for_booted(steps)
182
183 def usefile(self, truncate):
184 """
185 minimal test to make sure wait_for_booted works when tailing a file
186 """
187 steps = [
188 {
189 "message": "truncate test",
190 "pattern": ".*log source = /proc/kmsg started",
191 "timeout": 60,
192 },
193 ]
194
195 messages = [
196 'test 1',
197 'lllllllllllllllllllllllllllllllllllllll',
198 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
199 '<13>Feb 20 13:38:55 host user: log source = /proc/kmsg started',
200 ]
201
202 with tempfile.NamedTemporaryFile() as f:
203 r = RSyslog("utah-test", '/tmp', f.name)
204 threading.Thread(
205 target=self.file_producer, args=(f, messages, truncate)).start()
206 r.wait_for_booted(steps)
207
208 def test_usefile(self):
209 self.usefile(False)
210
211 def test_usefile_truncation(self):
212 self.usefile(True)
0213
=== modified file 'utah/config.py'
--- utah/config.py 2013-02-20 18:22:37 +0000
+++ utah/config.py 2013-03-12 16:15:29 +0000
@@ -141,7 +141,52 @@
141 # a value higher than the default is used to avoid db locking problems141 # a value higher than the default is used to avoid db locking problems
142 sqlite3_db_connection_timeout=30,142 sqlite3_db_connection_timeout=30,
143 # location of the jinja2 templates used by the provisionig module143 # location of the jinja2 templates used by the provisionig module
144 template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates')144 template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates'),
145
146 install_steps=[
147 {
148 'message': 'system started',
149 'pattern': '.*',
150 'booted': True,
151 'timeout': 360,
152 },
153 {
154 'message': 'install started',
155 'pattern': [
156 '.*ubiquity\\[\\d+\\]: Ubiquity \\d',
157 '.*anna-install', # needed for non-ubiquity installs
158 ],
159 'timeout': 120,
160 },
161 {
162 'message': 'install complete',
163 'pattern': [
164 '.*ubiquity reboot',
165 '.*log-output -t ubiquity umount /target$',
166 '.*finish-install.d/94save-logs', # needed for server bootspeed
167 '.*finish-install: umount',
168 '.*rsyslogd:.*exiting on signal 15.',
169 ],
170 "timeout": 3600
171 },
172 ],
173 boot_steps=[
174 {
175 'message': 'system booted',
176 'pattern': '.*Linux version \\d',
177 'timeout': 180,
178 },
179 {
180 'message': 'disk mounted',
181 'pattern': '.*mounted filesystem with ordered data',
182 'timeout': 180,
183 },
184 {
185 'message': 'network active',
186 'pattern': '.*NetworkManager',
187 'timeout': 180,
188 }
189 ]
145)190)
146191
147# These depend on the local user/path, and need to be filtered out192# These depend on the local user/path, and need to be filtered out
@@ -163,6 +208,9 @@
163 vmpath=os.path.join('~', 'vm'),208 vmpath=os.path.join('~', 'vm'),
164)209)
165210
211LOCALDEFAULTS['nfsiface'] = LOCALDEFAULTS['bridge']
212LOCALDEFAULTS['wwwiface'] = LOCALDEFAULTS['bridge']
213
166# These depend on other config options, so they're added last.214# These depend on other config options, so they're added last.
167# Default logfile is /var/log/utah/{hostname}.log215# Default logfile is /var/log/utah/{hostname}.log
168LOCALDEFAULTS['logfile'] = os.path.join(DEFAULTS['logpath'],216LOCALDEFAULTS['logfile'] = os.path.join(DEFAULTS['logpath'],
169217
=== modified file 'utah/provisioning/baremetal/bamboofeeder.py'
--- utah/provisioning/baremetal/bamboofeeder.py 2013-01-24 16:31:58 +0000
+++ utah/provisioning/baremetal/bamboofeeder.py 2013-03-12 16:15:29 +0000
@@ -17,7 +17,6 @@
17Support bare-metal provisioning of bamboo-feeder-based systems.17Support bare-metal provisioning of bamboo-feeder-based systems.
18"""18"""
1919
20import netifaces
21import os20import os
22import pipes21import pipes
23import shutil22import shutil
@@ -60,12 +59,9 @@
60 if self.image is None:59 if self.image is None:
61 raise UTAHBMProvisioningException(60 raise UTAHBMProvisioningException(
62 'Image file required for bamboo-feeder installation')61 'Image file required for bamboo-feeder installation')
63 try:62 self.ip = self._ipaddr(config.wwwiface)
64 iface = config.wwwiface63 self.logger.debug('Configuring for %s with IP %s',
65 except AttributeError:64 config.wwwiface, self.ip)
66 iface = config.bridge
67 self.ip = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
68 self.logger.debug('Configuring for ' + iface + ' with IP ' + self.ip)
69 self._cmdlinesetup()65 self._cmdlinesetup()
70 imageurl = 'http://' + self.ip + '/utah/' + self.name + '.img'66 imageurl = 'http://' + self.ip + '/utah/' + self.name + '.img'
71 preenvurl = 'http://' + self.ip + '/utah/' + self.name + '.preEnv'67 preenvurl = 'http://' + self.ip + '/utah/' + self.name + '.preEnv'
@@ -276,10 +272,9 @@
276 self._umountimage()272 self._umountimage()
277 self.restart()273 self.restart()
278 self.logger.info('System installing')274 self.logger.info('System installing')
279 self.logger.info('Checking every ' + str(config.checktimeout) +275
280 ' seconds until system is installed')276 self.rsyslog.wait_for_install(config.install_steps)
281 self.logger.info('Will time out after ' + str(config.installtimeout)277 self.rsyslog.wait_for_booted(config.boot_steps)
282 + ' seconds')
283 retry(self.sshcheck, config.checktimeout, logmethod=self.logger.info)278 retry(self.sshcheck, config.checktimeout, logmethod=self.logger.info)
284279
285 self.provisioned = True280 self.provisioned = True
286281
=== modified file 'utah/provisioning/baremetal/cobbler.py'
--- utah/provisioning/baremetal/cobbler.py 2013-02-14 10:31:33 +0000
+++ utah/provisioning/baremetal/cobbler.py 2013-03-12 16:15:29 +0000
@@ -17,7 +17,6 @@
17Support bare metal provisioning through cobbler.17Support bare metal provisioning through cobbler.
18"""18"""
1919
20import netifaces
21import os20import os
22import pipes21import pipes
23import subprocess22import subprocess
@@ -133,6 +132,13 @@
133""")132""")
134 myfile.close()133 myfile.close()
135 self._setuppreseed()134 self._setuppreseed()
135
136 if self.rewrite == 'all':
137 self._setuplogging(tmpdir=self.tmpdir)
138 else:
139 self.logger.debug('Skipping logging setup because rewrite is' +
140 self.rewrite)
141
136 initrd = self._repackinitrd()142 initrd = self._repackinitrd()
137143
138 self.logger.info('Setting up system with cobbler')144 self.logger.info('Setting up system with cobbler')
@@ -165,11 +171,7 @@
165 self.logger.debug('Reloading NFS config')171 self.logger.debug('Reloading NFS config')
166 self._runargs(config.nfscommand + ['reload'])172 self._runargs(config.nfscommand + ['reload'])
167 self.logger.debug('Adding NFS boot options')173 self.logger.debug('Adding NFS boot options')
168 try:174 ip = self._ipaddr(config.nfsiface)
169 iface = config.nfsiface
170 except AttributeError:
171 iface = config.bridge
172 ip = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
173 self.cmdline += (' root=/dev/nfs netboot=nfs nfsroot=' +175 self.cmdline += (' root=/dev/nfs netboot=nfs nfsroot=' +
174 ip + ':' + self.isodir)176 ip + ':' + self.isodir)
175 self.cmdline = self.cmdline.strip()177 self.cmdline = self.cmdline.strip()
@@ -190,28 +192,25 @@
190 for arg in self.machineinfo])192 for arg in self.machineinfo])
191193
192 self.restart()194 self.restart()
193195 self.rsyslog.wait_for_install(config.install_steps, self._disable_netboot)
194 self.logger.info('Waiting for installation to begin')196 self.rsyslog.wait_for_booted(config.boot_steps)
195 time.sleep(self.boottimeout)
196 self._cobble(['system', 'edit', '--name=' + self.name,
197 '--netboot-enabled=N'])
198
199 self.logger.info('System installing')
200 self.logger.info('Checking every ' + str(checktimeout) +
201 ' seconds until system is installed')
202 self.logger.info('Will time out after ' + str(installtimeout)
203 + ' seconds')
204 retry(self.sshcheck, checktimeout, logmethod=self.logger.info)
205197
206 if self.installtype == 'desktop':198 if self.installtype == 'desktop':
207 self._removenfs()199 self._removenfs()
208200
201 retry(self.sshcheck, config.checktimeout, logmethod=self.logger.info)
202
209 self.provisioned = True203 self.provisioned = True
210 self.active = True204 self.active = True
211 self._uuid_check()205 self._uuid_check()
212 self.logger.info('System installed')206 self.logger.info('System installed')
213 return True207 return True
214208
209 def _disable_netboot(self):
210 self.logger.info('install seems to have booted, disabling netboot')
211 self._cobble(['system', 'edit', '--name=' + self.name,
212 '--netboot-enabled=N'])
213
215 def _cobble(self, cmd, failok=False):214 def _cobble(self, cmd, failok=False):
216 """215 """
217 Pull out all cobbler commands so that we can later support changing216 Pull out all cobbler commands so that we can later support changing
218217
=== modified file 'utah/provisioning/provisioning.py'
--- utah/provisioning/provisioning.py 2013-02-28 16:44:17 +0000
+++ utah/provisioning/provisioning.py 2013-03-12 16:15:29 +0000
@@ -21,6 +21,7 @@
21import apt.cache21import apt.cache
22import logging22import logging
23import logging.handlers23import logging.handlers
24import netifaces
24import os25import os
25import pipes26import pipes
26import re27import re
@@ -45,6 +46,7 @@
45 OrderedSet,46 OrderedSet,
46)47)
47from utah.preseed import Preseed48from utah.preseed import Preseed
49from utah.provisioning.rsyslog import RSyslog
48from utah.provisioning.exceptions import UTAHProvisioningException50from utah.provisioning.exceptions import UTAHProvisioningException
49from utah.retry import retry51from utah.retry import retry
5052
@@ -217,6 +219,12 @@
217219
218 self.logger.debug('Machine init finished')220 self.logger.debug('Machine init finished')
219221
222 @property
223 def rsyslog(self):
224 if not getattr(self, '_rsyslog', None):
225 self._rsyslog = RSyslog(self.name, config.logpath)
226 return self._rsyslog
227
220 def _namesetup(self, name=None):228 def _namesetup(self, name=None):
221 """229 """
222 Name the machine, automatically or using a specified name.230 Name the machine, automatically or using a specified name.
@@ -955,11 +963,24 @@
955 '[ -e /conf/param.conf ] && . /conf/param.conf',963 '[ -e /conf/param.conf ] && . /conf/param.conf',
956 orderfilename])964 orderfilename])
957965
966 casper_file = os.path.join(tmpdir, 'initrd.d', 'etc', 'casper.conf')
967 tmpfilename = casper_file + '.tmp'
968 with open(casper_file, 'r') as i:
969 with open(tmpfilename, 'w') as o:
970 for line in i:
971 if 'export HOST' in line:
972 o.write('export HOST="{}"\n'.format(self.name))
973 elif 'export FLAVOUR' in line:
974 o.write('export FLAVOUR="Ubuntu"\n')
975 else:
976 o.write(line)
977 o.flush()
978 os.rename(tmpfilename, casper_file)
979
958 def _setuplogging(self, tmpdir=None):980 def _setuplogging(self, tmpdir=None):
959 """981 """
960 Send the installer syslog to a console.982 Send the installer syslog to a console.
961 """983 """
962 # TODO: move this into CustomVM
963 if tmpdir is None:984 if tmpdir is None:
964 tmpdir = self.tmpdir985 tmpdir = self.tmpdir
965 inittab = os.path.join(tmpdir, 'initrd.d', 'etc', 'inittab')986 inittab = os.path.join(tmpdir, 'initrd.d', 'etc', 'inittab')
@@ -970,14 +991,18 @@
970 "# logging to serial\n"991 "# logging to serial\n"
971 "ttyS0::respawn:/usr/bin/tail -n 1200 "992 "ttyS0::respawn:/usr/bin/tail -n 1200 "
972 "-f /var/log/syslog \n")993 "-f /var/log/syslog \n")
973 else:994
974 self.logger.info('No inittab found, creating rsyslog config file')995 self.logger.info('Creating rsyslog config file')
975 template = self.template_env.get_template(996 template = self.template_env.get_template('50-utahdefault.conf.jinja2')
976 '50-utahdefault.conf.jinja2')997 conffilename = os.path.join(tmpdir, 'initrd.d', '50-utahdefault.conf')
977 conffilename = os.path.join(tmpdir, 'initrd.d',998 with open(conffilename, 'w') as f:
978 '50-utahdefault.conf')999 if self.rsyslog.port:
979 with open(conffilename, 'w') as f:1000 ip = self._ipaddr(config.bridge)
980 f.write(template.render())1001 dest = '@{}:{}'.format(ip, self.rsyslog.port)
1002 else:
1003 self.logger.debug('setting up logging to go to serial console')
1004 dest = '|/dev/ttyS0'
1005 f.write(template.render(dest=dest))
9811006
982 def _repackinitrd(self, tmpdir=None):1007 def _repackinitrd(self, tmpdir=None):
983 """1008 """
@@ -1044,6 +1069,19 @@
1044 self.logger.info('Adding debconf/priority=critical option '1069 self.logger.info('Adding debconf/priority=critical option '
1045 'since installtype is not desktop')1070 'since installtype is not desktop')
1046 self.cmdline += ' debconf/priority=critical'1071 self.cmdline += ' debconf/priority=critical'
1072 if 'netcfg/get_hostname=' not in self.cmdline:
1073 self.logger.info('Adding netcfg/get_hostname option')
1074 self.cmdline += (' netcfg/get_hostname={}'.format(self.name))
1075 if 'log_host' not in self.cmdline:
1076 option = 'log_host={}'.format(self._ipaddr(config.bridge))
1077 self.logger.info('Adding {} option for rsyslog'
1078 .format(option))
1079 self.cmdline += ' ' + option
1080 if 'log_port' not in self.cmdline:
1081 option = 'log_port={}'.format(self.rsyslog.port)
1082 self.logger.info('Adding {} option for rsyslog'
1083 .format(option))
1084 self.cmdline += ' ' + option
1047 else:1085 else:
1048 self.logger.info('Not altering command line since rewrite is ' +1086 self.logger.info('Not altering command line since rewrite is ' +
1049 self.rewrite)1087 self.rewrite)
@@ -1065,3 +1103,11 @@
1065 if series is None:1103 if series is None:
1066 self.series = self.image.series1104 self.series = self.image.series
1067 self._cmdlinesetup(boot=boot)1105 self._cmdlinesetup(boot=boot)
1106
1107 @staticmethod
1108 def _ipaddr(ifname):
1109 """
1110 Returns the first IP address found for the given interface name
1111 """
1112 iface = netifaces.ifaddresses(ifname)
1113 return iface[netifaces.AF_INET][0]['addr']
10681114
=== added file 'utah/provisioning/rsyslog.py'
--- utah/provisioning/rsyslog.py 1970-01-01 00:00:00 +0000
+++ utah/provisioning/rsyslog.py 2013-03-12 16:15:29 +0000
@@ -0,0 +1,195 @@
1# Ubuntu Testing Automation Harness
2# Copyright 2013 Canonical Ltd.
3
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import logging
17import os
18import re
19import select
20import socket
21import sys
22import time
23
24from utah.exceptions import UTAHException
25
26
27class RSyslog(object):
28 def __init__(self, hostname, logpath, usefile=None):
29 """
30 :param usefile: allows class to "tail" a file rather than act as an
31 rsyslogd server
32 """
33 self._host = hostname
34 self._logpath = logpath
35
36 self.logger = logging.getLogger('rsyslog')
37
38 if usefile:
39 if not os.path.exists(usefile):
40 self.logger.debug('creating syslog file')
41 with open(usefile, 'w') as f:
42 os.fchmod(f.fileno(), 0660)
43 self._file = open(usefile, 'r')
44 self._where = 0
45 self._read_line = self._read_file
46 self._port = 0
47 else:
48 # start listening on an ephemeral UDP port
49 self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
50 self._sock.bind(('', 0))
51 self._port = self._sock.getsockname()[1]
52 self._read_line = self._read_udp
53 self.logger.info('rsylogd port(%d) opened', self._port)
54
55 @property
56 def port(self):
57 return self._port
58
59 def wait_for_install(self, steps, booted_callback=None):
60 """
61 Works through each step in the steps array to find messages in the
62 syslog indicating what part of the install we are in. Steps is an
63 array of:
64 {
65 "message": "system started",
66 "pattern": ".*log source = /proc/kmsg started",
67 "timeout": 1000,
68 "booted": false
69 },
70 {
71 "message": "system started",
72 "pattern": [
73 ".*log source = /proc/kmsg started"
74 ],
75 "timeout": 1000,
76 "booted": false
77 }
78 "pattern" can an array or string
79 "booted" is optional, but can be used to indicate that the system is
80 fully operational. This can be used in conjunction with the
81 "booted_callback" function.
82 """
83 logfile = '{}/{}-install.log'.format(self._logpath, self._host)
84 callbacks = {'booted': booted_callback}
85 self._wait_for_steps(steps, logfile, callbacks)
86
87 def wait_for_booted(self, steps):
88 """
89 Works the same as the wait_for_install function but takes in steps
90 that determine a system has booted after the install has completed.
91 """
92 logfile = '{}/{}-boot.log'.format(self._logpath, self._host)
93 callbacks = {}
94 self._wait_for_steps(steps, logfile, callbacks)
95
96 def _wait_for_steps(self, steps, logfile, callbacks):
97 with open(logfile, 'w') as f:
98 x = 0
99 while x < len(steps):
100 message = steps[x]['message']
101 pattern = steps[x]['pattern']
102 timeout = steps[x]['timeout']
103
104 if not isinstance(pattern, list):
105 pattern = [pattern]
106 future_pats = self._future_patterns(steps, x)
107 pattern.extend(future_pats)
108 self.logger.info('Waiting %ds for: %s', timeout, message)
109 match = self._wait_for(f, pattern, message, timeout)
110 if match in future_pats:
111 msg = 'Expected pattern missed, matched future pattern: %s'
112 self.logger.warn(msg, match)
113 x = self._fast_forward(steps, match, callbacks)
114
115 self._do_callback(steps[x], callbacks)
116 x += 1
117
118 @staticmethod
119 def _do_callback(step, callbacks):
120 for name, func in callbacks.iteritems():
121 if func and step.get(name, False):
122 func()
123
124 @staticmethod
125 def _future_patterns(steps, index):
126 patterns = []
127 index += 1
128 for step in steps[index:]:
129 pattern = step['pattern']
130 if not isinstance(pattern, list):
131 patterns.append(pattern)
132 else:
133 patterns.extend(pattern)
134 return patterns
135
136 @staticmethod
137 def _fast_forward(steps, pattern, callbacks):
138 """
139 Looks through each item in the steps array to find the index of the
140 given pattern. It will return that index so that the wait_for code
141 knows where to continue from. It will also alert the booted_callback
142 function if that was one of the steps that was missed.
143 """
144 x = 0
145 while x < len(steps):
146 # make sure we don't skip a callback
147 RSyslog._do_callback(steps[x], callbacks)
148
149 patterns = steps[x]['pattern']
150 if not isinstance(patterns, list):
151 patterns = [patterns]
152 if pattern in patterns:
153 return x
154
155 x += 1
156
157 def _wait_for(self, writer, patterns, message, timeout):
158 pats = [re.compile(x) for x in patterns]
159
160 endtime = time.time() + timeout
161 while(time.time() < endtime):
162 data = self._read_line()
163 if data:
164 if self.logger.level <= logging.DEBUG:
165 sys.stderr.write(data)
166 writer.write(data)
167 for pat in pats:
168 if pat.match(data):
169 return pat.pattern
170 raise UTAHException('Timeout occurred for {}'.format(message))
171
172 def _read_udp(self):
173 data = None
174 (rd, _, _) = select.select([self._sock], [], [], 5)
175 if self._sock in rd:
176 data = self._sock.recv(1024)
177 if data[-1] != '\n':
178 data += '\n'
179 return data
180
181 def _read_file(self):
182 # try for up to 5 seconds
183 for _ in xrange(5):
184 line = self._file.readline()
185 if line:
186 self._where = self._file.tell()
187 return line
188
189 if os.fstat(self._file.fileno()).st_size < self._where:
190 self.logger.warn('file truncation detected')
191 self._file.seek(0)
192 self._where = 0
193 elif not line:
194 time.sleep(1)
195 return None
0196
=== modified file 'utah/provisioning/vm/vm.py'
--- utah/provisioning/vm/vm.py 2013-01-24 16:31:58 +0000
+++ utah/provisioning/vm/vm.py 2013-03-12 16:15:29 +0000
@@ -31,6 +31,7 @@
31from utah.process import ProcessChecker31from utah.process import ProcessChecker
32from utah.provisioning.inventory.sqlite import SQLiteInventory32from utah.provisioning.inventory.sqlite import SQLiteInventory
33from utah.provisioning.provisioning import CustomInstallMixin, Machine33from utah.provisioning.provisioning import CustomInstallMixin, Machine
34from utah.provisioning.rsyslog import RSyslog
34from utah.provisioning.ssh import SSHMixin35from utah.provisioning.ssh import SSHMixin
35from utah.provisioning.vm.exceptions import UTAHVMProvisioningException36from utah.provisioning.vm.exceptions import UTAHVMProvisioningException
36from utah.timeout import UTAHTimeout37from utah.timeout import UTAHTimeout
@@ -59,8 +60,15 @@
59 self.lv = libvirt.open(config.qemupath)60 self.lv = libvirt.open(config.qemupath)
60 if self.lv is None:61 if self.lv is None:
61 raise UTAHVMProvisioningException('Cannot connect to libvirt')62 raise UTAHVMProvisioningException('Cannot connect to libvirt')
63 self.syslog = os.path.join(config.logpath, self.name + '.syslog.log')
62 self.logger.debug('LibvirtVM init finished')64 self.logger.debug('LibvirtVM init finished')
6365
66 @property
67 def rsyslog(self):
68 if not getattr(self, '_rsyslog', None):
69 self._rsyslog = RSyslog(self.name, config.logpath, self.syslog)
70 return self._rsyslog
71
64 def _load(self):72 def _load(self):
65 """73 """
66 Load an existing VM.74 Load an existing VM.
@@ -215,6 +223,7 @@
215 self._loggerunsetup()223 self._loggerunsetup()
216 self._loggersetup()224 self._loggersetup()
217 self._dirsetup()225 self._dirsetup()
226 self._cmdlinesetup()
218 if emulator is None:227 if emulator is None:
219 emulator = config.emulator228 emulator = config.emulator
220 if emulator is None:229 if emulator is None:
@@ -401,8 +410,7 @@
401 serial = ElementTree.Element('serial')410 serial = ElementTree.Element('serial')
402 serial.set('type', 'file')411 serial.set('type', 'file')
403 source = ElementTree.Element('source')412 source = ElementTree.Element('source')
404 log_filename = os.path.join(config.logpath, self.name + '.syslog.log')413 source.set('path', self.syslog)
405 source.set('path', log_filename)
406 serial.append(source)414 serial.append(source)
407 target = ElementTree.Element('target')415 target = ElementTree.Element('target')
408 target.set('port', '0')416 target.set('port', '0')
@@ -429,6 +437,7 @@
429 log_filename = os.path.join(config.logpath, self.name + '.syslog.log')437 log_filename = os.path.join(config.logpath, self.name + '.syslog.log')
430 self.logger.info('Logs will be written to ' + log_filename)438 self.logger.info('Logs will be written to ' + log_filename)
431439
440 self.rsyslog.wait_for_install(config.install_steps)
432 while vm.isActive() is not 0:441 while vm.isActive() is not 0:
433 pass442 pass
434443
@@ -458,7 +467,6 @@
458 for cmdline in ose.iterfind('cmdline'):467 for cmdline in ose.iterfind('cmdline'):
459 ose.remove(cmdline)468 ose.remove(cmdline)
460 devices = xml.find('devices')469 devices = xml.find('devices')
461 devices.remove(devices.find('serial'))
462 for disk in list(devices.iterfind('disk')):470 for disk in list(devices.iterfind('disk')):
463 if disk.get('device') == 'cdrom':471 if disk.get('device') == 'cdrom':
464 disk.remove(disk.find('source'))472 disk.remove(disk.find('source'))
@@ -541,9 +549,11 @@
541 self.vm.create()549 self.vm.create()
542 else:550 else:
543 raise UTAHVMProvisioningException('Failed to provision VM')551 raise UTAHVMProvisioningException('Failed to provision VM')
544 self.logger.info('Waiting ' + str(self.boottimeout) +552
545 ' seconds to allow machine to boot')553 self.rsyslog.wait_for_booted(config.boot_steps)
546 try:554 try:
555 self.logger.info(
556 'Waiting %d seconds for ping response', self.boottimeout)
547 self.pingpoll(timeout=self.boottimeout)557 self.pingpoll(timeout=self.boottimeout)
548 except UTAHTimeout:558 except UTAHTimeout:
549 # Ignore timeout for ping, since depending on the network559 # Ignore timeout for ping, since depending on the network
550560
=== modified file 'utah_howto.txt'
--- utah_howto.txt 2012-08-22 16:42:35 +0000
+++ utah_howto.txt 2013-03-12 16:15:29 +0000
@@ -48,7 +48,7 @@
48######################################################################48######################################################################
4949
50# needed to run the self tests50# needed to run the self tests
51sudo apt-get install python-nose51sudo apt-get install python-nose python-mock
5252
53# run the self tests53# run the self tests
54cd utah/client54cd utah/client

Subscribers

People subscribed via source and target branches

to all changes: