~matsubara/maas/dhcpd-workaround-raring

141 by Diogo Matsubara
add test
1
import os
2
from simplejson import loads
3
import sys
4
from subprocess import Popen, PIPE
5
from time import sleep
149 by Diogo Matsubara
use TestCase from testools instead of unittest and improve assertions
6
from testtools import TestCase
154 by Diogo Matsubara
change login api assertion and comment out import pxe files for now
7
from testtools.matchers import Contains, Equals, StartsWith
182.2.1 by Raphael Badin
Retry to fetch the mediawiki homepage once.
8
from testtools.content import text_content
188.3.7 by Raphael Badin
Merge trunk.
9
from unittest import skipIf
174.1.1 by Raphael Badin
Add juju tests.
10
import yaml
195.1.1 by Raphael Badin
Do not use arch constraint if on precise.
11
import platform
181.1.1 by Raphael Badin
Add test for mediawiki service.
12
import urllib2
141 by Diogo Matsubara
add test
13
146 by Diogo Matsubara
add timeout decorator
14
from timeout import timeout
15
141 by Diogo Matsubara
add test
16
sys.path.insert(0, "/usr/share/maas")
17
os.environ['DJANGO_SETTINGS_MODULE'] = 'maas.settings'
18
from django.core.management import call_command
19
from django.contrib.auth.models import User
20
21
from maasserver.models.user import get_creds_tuple
22
from apiclient.creds import convert_tuple_to_string
23
188.3.1 by Raphael Badin
Use env var to configure the test.
24
# Environment variables that can be used to configured
25
# what is tested.
26
27
# Series to install on deployed nodes.
28
NODE_SERIES = os.environ.get('NODE_SERIES', 'precise')
29
30
# Whether or not the ARM nodes should be used
31
# in the test.
188.3.5 by Raphael Badin
Formatting.
32
DO_NOT_USE_ARM_NODES = bool(
33
    os.environ.get('DO_NOT_USE_ARM_NODES', False))
188.3.1 by Raphael Badin
Use env var to configure the test.
34
194.1.3 by Raphael Badin
Avoid double negation.
35
36
USE_ARM_NODES = not DO_NOT_USE_ARM_NODES
37
38
188.3.7 by Raphael Badin
Merge trunk.
39
# Whether or not the juju tests should be performed.
40
DO_NOT_TEST_JUJU = bool(
41
    os.environ.get('DO_NOT_TEST_JUJU', False))
42
188.3.1 by Raphael Badin
Use env var to configure the test.
43
185.1.1 by Raphael Badin
Fix MAAS_URL.
44
MAAS_URL = "http://192.168.21.5/MAAS"
141 by Diogo Matsubara
add test
45
ADMIN_USER = "admin"
46
PASSWORD = "test"
47
POWER_USER = "root"
48
POWER_PASS = "ubuntu"
49
50
LENOVO_LAB = {
195.1.4 by Raphael Badin
Re-enable lenovo nodes.
51
    "00:E0:81:DD:D5:99" : "192.168.22.33",
52
    "00:E0:81:DD:D1:0B" : "192.168.22.34",
53
    "00:E0:81:DD:D4:11" : "192.168.22.35",
54
    "00:E0:81:D1:B1:47" : "192.168.22.36",
188.2.4 by Raphael Badin
Add option to disable ARM nodes.
55
# There are in a different network, enable them
56
# when testing with a CC on a different network
57
# is supported.
58
#    "00:E0:81:DD:D1:1B" : "192.168.22.37",
59
#    "00:E0:81:DD:D1:2B" : "192.168.22.38",
60
#    "00:E0:81:DD:D1:A3" : "192.168.22.39",
61
#    "00:E0:81:DC:38:6D" : "192.168.22.40",
62
#    "00:E0:81:DD:D0:FF" : "192.168.22.41",
63
#    "00:E0:81:DD:D4:F9" : "192.168.22.42"
141 by Diogo Matsubara
add test
64
    }
65
66
ARM_LAB = {
67
    'fc:2f:40:d8:fb:1a': '192.168.21.50',
182.1.1 by Diogo Matsubara
Enable the 4 arm nodes again.
68
    'fc:2f:40:fa:2f:9a': '192.168.21.51',
141 by Diogo Matsubara
add test
69
    'fc:2f:40:ec:73:42': '192.168.21.52',
70
    'fc:2f:40:d5:87:ce': '192.168.21.53'
71
    }
72
73
LAB_DNS_CONFIG = """
74
options {
75
    directory "/var/cache/bind";
76
    forwarders {
77
    10.98.0.1;
78
    };
184.1.1 by Raphael Badin
Fix dns config.
79
    allow-query-cache {any;};
141 by Diogo Matsubara
add test
80
    dnssec-validation auto;
81
    auth-nxdomain no;    # conform to RFC1035
82
};
83
"""
84
174.1.1 by Raphael Badin
Add juju tests.
85
JUJU_CONFIG = """
86
default: maas
87
environments:
88
  maas:
89
    type: maas
90
    maas-server: '%s'
91
    maas-oauth: '%s'
92
    admin-secret: 'nothing'
93
    default-series: %s
174.1.5 by Raphael Badin
Fix tests.
94
    juju-origin: ppa
174.1.1 by Raphael Badin
Add juju tests.
95
"""
96
97
177.3.1 by Raphael Badin
Improve juju-related code.
98
def setup_juju_config(server, oauth, series):
174.1.1 by Raphael Badin
Add juju tests.
99
    juju_dir = os.path.expanduser('~/.juju')
174.1.4 by Raphael Badin
Split script.
100
    try:
101
        os.mkdir(juju_dir)
102
    except OSError:
103
        pass
174.1.1 by Raphael Badin
Add juju tests.
104
    config_content = JUJU_CONFIG % (server, oauth, series)
105
    juju_configfile = os.path.join(juju_dir, 'environments.yaml')
174.1.3 by Raphael Badin
Fix config writing.
106
    juju_configfile_fd = open(juju_configfile, 'w')
107
    juju_configfile_fd.write(config_content)
174.1.1 by Raphael Badin
Add juju tests.
108
109
110
def get_token_str():
111
    admin = User.objects.get(username=ADMIN_USER)
112
    token = admin.tokens.all()[0]
113
    return convert_tuple_to_string(get_creds_tuple(token))
114
141 by Diogo Matsubara
add test
115
174.1.4 by Raphael Badin
Split script.
116
def setup_ssh():
117
    home_dir = os.path.expanduser('~/')
118
    ssh_dir = os.path.join(home_dir, '.ssh')
119
    # Setup ssh keys.
120
    ssh_key = os.path.join(ssh_dir, 'id_rsa')
121
    if not os.path.exists(ssh_key):
122
        try:
123
            os.mkdir(ssh_dir)
124
        except OSError:
125
            pass
126
        Popen(
127
            ['ssh-keygen', '-t', 'rsa', '-N', '', '-f', ssh_key],
128
            stdout=PIPE, stderr=PIPE).communicate()
129
    # Setup ssh config.
130
    ssh_config = os.path.join(ssh_dir, 'config')
131
    with open(ssh_config, 'w') as f:
132
        f.write('StrictHostKeyChecking no')
133
134
135
def setup_local_dns():
136
    content = open('/etc/resolv.conf').read()
137
    content = 'nameserver 127.0.0.1\n' + content
138
    with open('/etc/resolv.conf', 'w') as f:
139
        f.write(content)
140
174.1.8 by Raphael Badin
Fix style.
141
142
DEB_PROXY_CONFIG = """
143
cache_peer 10.98.0.13 parent 8000 0 no-query no-digest
144
never_direct allow all
145
"""
146
147
148
# Configure the region proxy to use the proxy on 10.98.0.13.
174.1.4 by Raphael Badin
Split script.
149
def setup_deb_proxy():
150
    config = '/etc/squid-deb-proxy/squid-deb-proxy.conf'
151
    content = open(config).read()
174.1.8 by Raphael Badin
Fix style.
152
    content = content + DEB_PROXY_CONFIG
174.1.4 by Raphael Badin
Split script.
153
    with open(config, 'w') as f:
154
        f.write(content)
155
    Popen(
156
        ['sudo', 'service', 'squid-deb-proxy', 'restart'],
157
        stdout=PIPE, stderr=PIPE).communicate()
174.1.6 by Raphael Badin
Remove classes.
158
174.1.4 by Raphael Badin
Split script.
159
141 by Diogo Matsubara
add test
160
class TestMAASIntegration(TestCase):
161
188.2.4 by Raphael Badin
Add option to disable ARM nodes.
162
    def get_node_count(self):
163
        """The number of available nodes."""
164
        count = len(LENOVO_LAB)
194.1.3 by Raphael Badin
Avoid double negation.
165
        if USE_ARM_NODES:
188.2.4 by Raphael Badin
Add option to disable ARM nodes.
166
            count += len(ARM_LAB)
167
        return count
168
141 by Diogo Matsubara
add test
169
    def _run_command(self, args):
186.1.1 by Raphael Badin
Connect stdin to PIPE.
170
        process = Popen(args, stdout=PIPE, stderr=PIPE, stdin=PIPE)
141 by Diogo Matsubara
add test
171
        stdout, stderr = process.communicate()
172
        return stdout, stderr
173
174
    def _run_maas_cli(self, args):
188.2.2 by Raphael Badin
Move addDetail into _run_maas_cli.
175
        result = self._run_command(["maas-cli", "maas"] + args)
176
        self.addDetail(
177
            'maas-cli maas %s' % str(args), text_content(str(result)))
178
        return result
141 by Diogo Matsubara
add test
179
199.1.1 by Raphael Badin
Disable raring.
180
    def test_00_disable_raring(self):
199.1.2 by Raphael Badin
Add bug references.
181
        """Disable raring, the images are not available yet.
182
        # XXX: rvb 2013-02-04 bug=1115178
183
        # XXX: rvb 2013-02-04 bug=1115175
184
        """
199.1.1 by Raphael Badin
Disable raring.
185
        maas_fd = open("/etc/maas/import_pxe_files" , "r+")
186
        maas_file = maas_fd.read()
187
        maas_file = maas_file.replace(
188
            'RELEASES="precise quantal raring"',
189
            'RELEASES="precise quantal"')
190
        maas_fd.seek(0)
191
        maas_fd.write(maas_file)
192
        maas_fd.close()
193
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
194
    def test_01_create_admin(self):
141 by Diogo Matsubara
add test
195
        """Run maas createsuperuser."""
196
        cmd_output = call_command(
197
            "createadmin", username=ADMIN_USER, password=PASSWORD,
198
            email="example@canonical.com", noinput=True)
199
        # No output, means admin user was created successfully.
200
        self.assertEqual(cmd_output, None)
201
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
202
    def test_02_update_maas_url(self):
141 by Diogo Matsubara
add test
203
        #XXX: matsubara For some reason using a debconf file to set the
204
        # initial value of DEFAULT_MAAS_URL is not working.
205
        maas_fd = open("/etc/maas/maas_local_settings.py" , "r+")
206
        maas_file = maas_fd.read()
207
        maas_file = maas_file.replace(
208
            'DEFAULT_MAAS_URL = "http://10.98.0.90/MAAS"',
209
            'DEFAULT_MAAS_URL = "http://192.168.21.5/MAAS"')
210
        maas_fd.seek(0)
211
        maas_fd.write(maas_file)
212
        maas_fd.close()
149 by Diogo Matsubara
use TestCase from testools instead of unittest and improve assertions
213
        output, err = self._run_command(["service", "apache2", "restart"])
150 by Diogo Matsubara
fix apacher restart assertion
214
        self.assertThat(
215
            output, StartsWith(' * Restarting web server apache2'))
141 by Diogo Matsubara
add test
216
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
217
    def test_03_restart_dbus_avahi(self):
218
        """XXX: matsubara bug=1065775 """
219
        output, err = self._run_command(["service", "dbus", "restart"])
177.1.3 by Raphael Badin
Relax test test_03_restart_dbus_avahi.
220
        self.assertThat(output, Contains('dbus start/running'))
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
221
        output, err = self._run_command(["service", "avahi-daemon", "restart"])
177.1.3 by Raphael Badin
Relax test test_03_restart_dbus_avahi.
222
        self.assertThat(output, Contains('avahi-daemon start/running'))
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
223
224
    def test_04_update_pxe_config(self):
141 by Diogo Matsubara
add test
225
        ephemerals_fd = open("/etc/maas/import_ephemerals", "r+")
226
        ephemerals = ephemerals_fd.read()
177.1.4 by Raphael Badin
Update ephemerals correctly.
227
        # Update mirrors for both trunk and the quantal SRU.
228
        ephemerals_snippet = (
229
            '\n'
177.1.5 by Raphael Badin
Fix snippet.
230
            'CLOUD_IMAGES_ARCHIVE="http://10.98.0.13/mirrors/maas-ephemeral"\n'
231
            'REMOTE_IMAGES_MIRROR="http://10.98.0.13/mirrors/maas-ephemeral"\n'
197.1.1 by Raphael Badin
Do not use the daily images.
232
        #    XXX: rvb 2013-01-18: Do not use the daily ephemeral images as
233
        #    they seem to be broken (more precisely, the image from 20130107 is
234
        #    and the one from 20121008 isn't);  investigation is underway.
235
        #   'STREAM=daily\n'
177.1.4 by Raphael Badin
Update ephemerals correctly.
236
            )
237
        ephemerals += ephemerals_snippet
141 by Diogo Matsubara
add test
238
        ephemerals_fd.seek(0)
239
        ephemerals_fd.write(ephemerals)
240
        ephemerals_fd.close()
167 by Diogo Matsubara
remove one workaround and add another one
241
        # XXX: matsubara Bug=1074167
171 by Diogo Matsubara
do not download squashfs images and use proxy
242
        # Update import_pxe_files to not download squashfs images
243
        # and use a proxy.
244
        pxe_fd = open('/etc/maas/import_pxe_files', "r+")
167 by Diogo Matsubara
remove one workaround and add another one
245
        pxe_file = pxe_fd.read()
177.2.1 by Raphael Badin
Update test_04_update_pxe_config.
246
        pxe_snippet = 'export http_proxy="http://10.98.0.13:3128"\n'
247
        pxe_file = pxe_snippet + pxe_file
167 by Diogo Matsubara
remove one workaround and add another one
248
        pxe_fd.seek(0)
249
        pxe_fd.write(pxe_file)
250
        pxe_fd.close()
141 by Diogo Matsubara
add test
251
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
252
    def test_05_import_pxe_files(self):
166 by Diogo Matsubara
add assertion for import pxe files, making sure it doesn't output any error
253
        output, err = self._run_command(["maas-import-pxe-files"])
170 by Diogo Matsubara
add proper assert for import-pxe-files output
254
        self.assertThat(output, Contains('Downloading to temporary location'))
172 by Diogo Matsubara
add reference to bug 1076444 and comment out an assertion
255
        # XXX: matsubara Bug=1076444
256
        # maas-import-pxe-files outputs to stderr during normal operation.
257
        #self.assertIs(err, '')
141 by Diogo Matsubara
add test
258
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
259
    def test_06_update_preseed_arm(self):
141 by Diogo Matsubara
add test
260
        #XXX: matsubara add workaround to boot arm nodes.
261
        userdata_fd = open("/usr/share/maas/preseeds/enlist_userdata", "r+")
262
        userdata = userdata_fd.read()
263
        userdata += '\napt_sources:\n - source: "deb http://ports.ubuntu.com/ubuntu-ports precise-proposed main"'
264
        userdata_fd.seek(0)
265
        userdata_fd.write(userdata)
266
        userdata_fd.close()
267
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
268
    def test_07_login_api(self):
174.1.1 by Raphael Badin
Add juju tests.
269
        token_str = get_token_str()
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
270
        api_url = MAAS_URL + "/api/1.0/"
271
        output, err = self._run_command(
272
            ["maas-cli", "login", "maas", api_url, token_str])
273
        self.assertThat(
274
            output, Contains(
185.1.2 by Raphael Badin
Fix test.
275
            "\nYou are now logged in to the MAAS server"))
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
276
198.1.3 by Raphael Badin
Fix cluster waiting code.
277
    def get_master_ng_uuid(self):
278
        output, err = self._run_maas_cli(["node-groups", "list"])
279
        node_groups = loads(output)
280
        master_nodegroup = node_groups[0]
198.1.5 by Raphael Badin
Fix typo.
281
        return master_nodegroup['uuid']
198.1.3 by Raphael Badin
Fix cluster waiting code.
282
198.1.4 by Raphael Badin
Improve timeout.
283
    @timeout(5*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
284
    def test_08_cluster_connected(self):
285
        # The master cluster is connected and changed the uuid field of the
286
        # nodegroup object from 'master' to its UUID.
198.1.3 by Raphael Badin
Fix cluster waiting code.
287
        name = self.get_master_ng_uuid()
288
        while name == 'master':
198.1.1 by Raphael Badin
Wait for cluster to connect.
289
            sleep(10)
198.1.3 by Raphael Badin
Fix cluster waiting code.
290
            name = self.get_master_ng_uuid()
198.1.1 by Raphael Badin
Wait for cluster to connect.
291
203 by Diogo Matsubara
separate workaround from test code
292
    def _update_dhcpd_apparmor_profile(self):
293
        """Workaround for raring due to bug 1107686."""
294
        dhcpd_fd = open("/etc/apparmor.d/usr.sbin.dhcpd", "r+")
295
        dhcpd_file = dhcpd_fd.read()
296
        dhcpd_file = dhcpd_file.replace(
297
            'network packet packet,',
298
            'network packet packet,\n  network packet raw,')
299
        dhcpd_fd.seek(0)
300
        dhcpd_fd.write(dhcpd_file)
301
        dhcpd_fd.close()
302
        output, err = self._run_command(["service", "apparmor", "reload"])
303
        self.assertThat(output, Contains('* Reloading AppArmor profiles'))
304
198.1.1 by Raphael Badin
Wait for cluster to connect.
305
    @timeout(60)
306
    def test_09_set_up_dhcp(self):
202 by Diogo Matsubara
workaround for raring only
307
        if "raring" in platform.linux_distribution():
203 by Diogo Matsubara
separate workaround from test code
308
            self._update_dhcpd_apparmor_profile()
201 by Diogo Matsubara
workaround for bug 1107686
309
145 by Diogo Matsubara
update how dhcp is configured and min number of nodes to wait for
310
        output, err = self._run_maas_cli(["node-groups", "list"])
311
        node_groups = loads(output)
153 by Diogo Matsubara
fix assertion for dhcp setup
312
        output, err = self._run_maas_cli([
158 by Diogo Matsubara
proper call to maas-cli
313
            "node-group-interface", "update", node_groups[0]['uuid'],
314
            "eth1", "ip=192.168.21.5", "interface=eth1", "management=2",
141 by Diogo Matsubara
add test
315
            "subnet_mask=255.255.255.0",
316
            "broadcast_ip=192.168.21.255",
317
            "router_ip=192.168.21.1",
318
            "ip_range_low=192.168.21.10",
319
            "ip_range_high=192.168.21.30"])
156 by Diogo Matsubara
change dhcp assertions
320
        node_group = loads(output)
321
        self.assertThat(node_group['ip'], Equals('192.168.21.5'))
322
        self.assertThat(node_group['interface'], Equals('eth1'))
323
        self.assertThat(node_group['subnet_mask'], Equals('255.255.255.0'))
324
        self.assertThat(node_group['broadcast_ip'], Equals('192.168.21.255'))
325
        self.assertThat(node_group['ip_range_low'], Equals('192.168.21.10'))
326
        self.assertThat(node_group['ip_range_high'], Equals('192.168.21.30'))
153 by Diogo Matsubara
fix assertion for dhcp setup
327
        # Wait for the task to complete and create the dhcpd.conf file.
141 by Diogo Matsubara
add test
328
        while os.path.exists("/etc/maas/dhcpd.conf") is False:
329
            sleep(2)
330
198.1.1 by Raphael Badin
Wait for cluster to connect.
331
    def test_10_update_dns_config(self):
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
332
        #XXX: matsubara Could be asked by maas-dns package and configurable
333
        # through debconf seed file.
334
        dns_config = open("/etc/bind/named.conf.options", 'w')
335
        dns_config.write(LAB_DNS_CONFIG)
336
        dns_config.close()
337
        output, err = self._run_command(["service", "bind9", "restart"])
162 by Diogo Matsubara
more assertion fixes
338
        self.assertThat(output, Contains(
339
            '* Starting domain name service... bind9'))
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
340
141 by Diogo Matsubara
add test
341
    def power_on(self, ip, user, password):
184.2.1 by Diogo Matsubara
add --stop to nosetests, so test will stop on first failure. Add assertion for ipmi power on and off commands
342
        output, err = self._run_command(
141 by Diogo Matsubara
add test
343
            ["ipmipower", "-h", ip, "-u", user, "-p", password, "--on"])
184.2.8 by Diogo Matsubara
use self.addDetail() to add more debug info when power on and off fail
344
        self.addDetail('IPMI power on %s' % ip, text_content(str(output)))
184.2.4 by Diogo Matsubara
use contains for power on/off assertions
345
        self.assertThat(output, Contains("%s: ok" % ip))
141 by Diogo Matsubara
add test
346
347
    def power_off(self, ip, user, password):
184.2.2 by Diogo Matsubara
fix power on
348
        output, err = self._run_command(
141 by Diogo Matsubara
add test
349
            ["ipmipower", "-h", ip, "-u", user, "-p", password, "--off"])
184.2.8 by Diogo Matsubara
use self.addDetail() to add more debug info when power on and off fail
350
        self.addDetail('IPMI power off %s' % ip, text_content(str(output)))
184.2.7 by Diogo Matsubara
remove debug code
351
        self.assertThat(output, Contains("%s: ok" % ip))
141 by Diogo Matsubara
add test
352
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
353
    def _boot_nodes(self):
141 by Diogo Matsubara
add test
354
        # Run ipmipower to boot up nodes.
355
        for ipmi_address in LENOVO_LAB.values():
356
            self.power_off(ipmi_address, POWER_USER, POWER_PASS)
357
            self.power_on(ipmi_address, POWER_USER, POWER_PASS)
194.1.3 by Raphael Badin
Avoid double negation.
358
        if USE_ARM_NODES:
188.2.4 by Raphael Badin
Add option to disable ARM nodes.
359
            for ipmi_address in ARM_LAB.values():
360
                self.power_off(ipmi_address, 'admin', 'admin')
361
                self.power_on(ipmi_address, 'admin', 'admin')
141 by Diogo Matsubara
add test
362
198.1.1 by Raphael Badin
Wait for cluster to connect.
363
    def test_11_boot_nodes_enlist(self):
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
364
        self._boot_nodes()
365
188.2.4 by Raphael Badin
Add option to disable ARM nodes.
366
    def _wait_nodes(self, status, min_node=None):
367
        """Wait for `min_node` nodes with status `status`."""
368
        if min_node is None:
369
            min_node = self.get_node_count()
141 by Diogo Matsubara
add test
370
        # XXX: matsubara Can't filter by status.
371
        output, err = self._run_maas_cli(["nodes", "list"])
372
        node_list = loads(output)
373
        filtered_list = [
374
            node for node in node_list if node['status'] == status]
375
        while not len(filtered_list) == min_node:
376
            sleep(5)
377
            output, err = self._run_maas_cli(["nodes", "list"])
378
            node_list = loads(output)
379
            filtered_list = [
380
                node for node in node_list if node['status'] == status]
381
182.1.1 by Diogo Matsubara
Enable the 4 arm nodes again.
382
    @timeout(5*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
383
    def test_12_check_nodes_declared(self):
141 by Diogo Matsubara
add test
384
        self._wait_nodes(0)
385
198.1.1 by Raphael Badin
Wait for cluster to connect.
386
    def test_13_set_nodes_ipmi_config(self):
141 by Diogo Matsubara
add test
387
        """Set IPMI configuration for each node."""
388
        all_nodes = {}
389
        all_nodes.update(LENOVO_LAB)
390
        all_nodes.update(ARM_LAB)
391
        for mac in all_nodes.keys():
392
            # run maas-cli command to search node by mac and return system_id
393
            out, err = self._run_maas_cli(
394
                ["nodes", "list", "mac_address=%s" % mac])
395
            node_list = loads(out)
396
            for node in node_list:
397
                if ARM_LAB.has_key(mac):
398
                    power_user = power_pass = 'admin'
399
                else:
400
                    power_user = POWER_USER
401
                    power_pass = POWER_PASS
174.1.1 by Raphael Badin
Add juju tests.
402
                self._run_maas_cli(
141 by Diogo Matsubara
add test
403
                    ["node", "update", node['system_id'], "power_type=ipmi",
404
                    "power_parameters_power_address=%s " % all_nodes[mac],
405
                    "power_parameters_power_user=%s" % power_user,
406
                    "power_parameters_power_pass=%s" % power_pass])
407
198.1.1 by Raphael Badin
Wait for cluster to connect.
408
    def test_14_commission_nodes(self):
141 by Diogo Matsubara
add test
409
        # Use maas-cli to accept all nodes.
148 by Diogo Matsubara
add asserts
410
        output, err = self._run_maas_cli(["nodes","accept-all"])
411
        for node in loads(output):
163 by Diogo Matsubara
fix assertion after commission
412
            self.assertEqual(node['status'], 1)
141 by Diogo Matsubara
add test
413
174.1.10 by Raphael Badin
Increase timeout.
414
    @timeout(10*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
415
    def test_15_check_nodes_ready(self):
159 by Diogo Matsubara
change test name scheme so we can get better reporting when they're running
416
        self._wait_nodes(4)
174.1.1 by Raphael Badin
Add juju tests.
417
174.1.4 by Raphael Badin
Split script.
418
    def setup_juju(self):
174.1.5 by Raphael Badin
Fix tests.
419
        setup_deb_proxy()
174.1.4 by Raphael Badin
Split script.
420
        setup_ssh()
174.1.1 by Raphael Badin
Add juju tests.
421
        token_str = get_token_str()
188.1.3 by Raphael Badin
Fix comment.
422
        # Workaround bug 972829 (in juju precise).
188.1.2 by Raphael Badin
Fix url hack.
423
        server_url = MAAS_URL.replace('/MAAS', ':80/MAAS')
188.3.1 by Raphael Badin
Use env var to configure the test.
424
        setup_juju_config(server_url, token_str, series=NODE_SERIES)
174.1.4 by Raphael Badin
Split script.
425
        setup_local_dns()
426
177.3.1 by Raphael Badin
Improve juju-related code.
427
    def _run_juju_command(self, args):
428
        output, err = self._run_command(["juju"] + args)
177.3.3 by Raphael Badin
Fix juju output check.
429
        # For some reason, in the log, juju replaces '-' by '_'.
430
        command_name = args[0].replace('-', '_')
177.3.1 by Raphael Badin
Improve juju-related code.
431
        self.assertIn(
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
432
            "INFO '%s' command finished successfully" % command_name, err)
177.3.1 by Raphael Badin
Improve juju-related code.
433
        return output
434
188.3.10 by Raphael Badin
Fix message.
435
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
195.1.2 by Raphael Badin
Increase timeout.
436
    @timeout(50*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
437
    def test_16_juju_bootstrap(self):
174.1.4 by Raphael Badin
Split script.
438
        self.setup_juju()
177.3.1 by Raphael Badin
Improve juju-related code.
439
        self._run_juju_command(['bootstrap'])
440
        self._run_juju_command(['status'])
441
442
    def get_juju_status(self):
443
        status_output = self._run_juju_command(["status"])
188.2.1 by Raphael Badin
Add details.
444
        self.addDetail('juju status', text_content(str(status_output)))
177.3.1 by Raphael Badin
Improve juju-related code.
445
        status = yaml.load(status_output)
446
        return status
447
448
    def _wait_machines_running(self, nb_machines):
449
        """Wait until at least `nb_machines` have their agent running."""
450
        while True:
451
            status = self.get_juju_status()
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
452
            machines = status['machines'].values()
177.3.1 by Raphael Badin
Improve juju-related code.
453
            running_machines = [
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
454
                machine for machine in machines
182.2.3 by Raphael Badin
Fix juju status parsing.
455
                if machine.get('agent-state', '') == 'running']
177.3.1 by Raphael Badin
Improve juju-related code.
456
            if len(running_machines) >= nb_machines:
457
                break
458
            sleep(20)
459
460
    def _wait_units_started(self, service, nb_units):
461
        """Wait until a service has at least `nb_units` units."""
462
        while True:
463
            status = self.get_juju_status()
182.2.3 by Raphael Badin
Fix juju status parsing.
464
            try:
465
                units = status['services'][service]['units'].values()
466
            except KeyError:
467
                units = []
177.3.1 by Raphael Badin
Improve juju-related code.
468
            started_units = [
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
469
                unit for unit in units
182.2.3 by Raphael Badin
Fix juju status parsing.
470
                if unit.get('agent-state', '') == 'started']
177.3.1 by Raphael Badin
Improve juju-related code.
471
            if len(started_units) >= nb_units:
472
                break
473
            sleep(20)
174.1.1 by Raphael Badin
Add juju tests.
474
188.3.10 by Raphael Badin
Fix message.
475
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
198.1.1 by Raphael Badin
Wait for cluster to connect.
476
    def test_17_juju_setup(self):
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
477
        # Deploy mediawiki with its mysql db.
177.3.1 by Raphael Badin
Improve juju-related code.
478
        self._run_juju_command(["deploy", "mysql"])
195.1.1 by Raphael Badin
Do not use arch constraint if on precise.
479
        is_precise = platform.linux_distribution()[2] == 'precise'
480
        if USE_ARM_NODES and not is_precise:
194.1.1 by Raphael Badin
Test.
481
            self._run_juju_command(
194.1.2 by Raphael Badin
Test.
482
                ["deploy", "mediawiki", "--constraints", "arch=arm"])
194.1.3 by Raphael Badin
Avoid double negation.
483
        else:
484
            self._run_juju_command(["deploy", "mediawiki"])
177.3.1 by Raphael Badin
Improve juju-related code.
485
        self._run_juju_command(["add-relation", "mediawiki:db", "mysql"])
486
        self._run_juju_command(["expose", "mediawiki"])
177.3.7 by Raphael Badin
Fix comment.
487
        # Add new unit for test 18: we run that here to
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
488
        # parallelize the installation of the new machine.
489
        self._run_juju_command(["add-unit", "mediawiki"])
490
188.3.10 by Raphael Badin
Fix message.
491
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
191.1.1 by Raphael Badin
Improve timeout to cope with slow ARM nodes.
492
    @timeout(30*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
493
    def test_18_juju_deploy_mediawiki(self):
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
494
       self._wait_machines_running(3)
495
       self._wait_units_started('mediawiki', 1)
496
188.3.10 by Raphael Badin
Fix message.
497
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
188.3.7 by Raphael Badin
Merge trunk.
498
    @timeout(5*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
499
    def test_19_mediawiki_homepage(self):
182.2.5 by Raphael Badin
Wait a bit for mediawiki to come up.
500
        while True:
501
            status = self.get_juju_status()
502
            mediawiki_address = (
503
                status['services']['mediawiki']['units'].values(
504
                    )[0]['public-address'])
505
            self.addDetail('juju status', text_content(str(status)))
182.2.8 by Raphael Badin
Fix typo.
506
            mediawiki_url = 'http://%s/mediawiki/' % mediawiki_address
182.2.5 by Raphael Badin
Wait a bit for mediawiki to come up.
507
            opener = urllib2.build_opener()
508
            try:
509
                homepage = opener.open(mediawiki_url).read()
510
            except urllib2.URLError:
511
                pass
182.2.6 by Raphael Badin
Fix exception handling..
512
            else:
196.1.1 by Raphael Badin
Improve temporary failures detection code.
513
                temporary_failures = (
514
                    'database error' in homepage or
515
                    "LocalSettings.php not found" in homepage
516
                    )
517
                if not temporary_failures:
182.2.6 by Raphael Badin
Fix exception handling..
518
                    break
182.2.5 by Raphael Badin
Wait a bit for mediawiki to come up.
519
            sleep(15)
182.2.2 by Raphael Badin
Improve error detection.
520
181.1.1 by Raphael Badin
Add test for mediawiki service.
521
        self.assertIn("<title>Please set name of wiki</title>", homepage)
522
188.3.10 by Raphael Badin
Fix message.
523
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
191.1.1 by Raphael Badin
Improve timeout to cope with slow ARM nodes.
524
    @timeout(30*60)
198.1.1 by Raphael Badin
Wait for cluster to connect.
525
    def test_20_juju_add_unit_mediawiki(self):
177.3.2 by Raphael Badin
Fix juju wrappers. Add test.
526
        self._wait_machines_running(4)
527
        self._wait_units_started('mediawiki', 2)