~brendan-donegan/maas/qa-lab-tests_sort_dependencies

« back to all changes in this revision

Viewing changes to maas-integration.py

  • Committer: Brendan Donegan
  • Date: 2016-06-15 10:06:39 UTC
  • mfrom: (433.2.49 juju2_tests)
  • Revision ID: brendan.donegan@canonical.com-20160615100639-x97krag4dk103b7f
MergeĀ lp:~brendan-donegan/maas/qa-lab-tests_juju2_tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
import platform
16
16
import re
17
17
import sys
 
18
import tempfile
18
19
from contextlib import closing
19
20
from distutils.version import StrictVersion
20
21
from itertools import count
55
56
from testtools.matchers import (
56
57
    Contains,
57
58
    ContainsAll,
 
59
    Equals,
 
60
    Not,
58
61
)
59
62
from timeout import timeout
60
63
# Import `pause_until_released` if you need to block execution at a given state
67
70
    get_maas_revision,
68
71
    get_maas_version,
69
72
    get_ubuntu_version,
70
 
    is_juju_core,
71
73
    retries,
72
74
    run_command,
73
75
    pause_until_released  # If this is not used below, linters will complain.
96
98
    ADMIN_USER,
97
99
    ARM_LAB,
98
100
    CLUSTER_CONTROLLER_IP,
 
101
    DO_NOT_USE_ARM_NODES,
99
102
    DO_NOT_TEST_JUJU,
100
 
    DO_NOT_USE_ARM_NODES,
101
103
    HTTP_PROXY,
102
 
    JUJU_CONFIG,
103
104
    LAB_DNS_CONFIG,
104
105
    LENOVO_LAB,
105
106
    MAAS_URL,
114
115
)
115
116
 
116
117
 
117
 
def make_juju_config():
118
 
    config = JUJU_CONFIG
119
 
    if not is_juju_core():
120
 
        config = "%s%s" % (config, "    juju-origin: ppa\n")
121
 
    return config
122
 
 
123
 
 
124
 
def setup_juju_config(server, oauth, series):
125
 
    juju_dir = os.path.expanduser('~/.juju')
126
 
    try:
127
 
        os.mkdir(juju_dir)
128
 
    except OSError:
129
 
        pass
130
 
    config_content = make_juju_config() % (server, oauth, series)
131
 
    juju_configfile = os.path.join(juju_dir, 'environments.yaml')
132
 
    juju_configfile_fd = open(juju_configfile, 'w')
133
 
    juju_configfile_fd.write(config_content.encode('utf-8'))
134
 
 
 
118
def setup_juju_cloud(server, cloud_yaml):
 
119
    cloud_yaml.write("""
 
120
clouds:
 
121
    testmaas:
 
122
        type: maas
 
123
        auth-types: [oauth1]
 
124
        endpoint: {server}""".format(server=server).encode('utf8'))
 
125
    cloud_yaml.file.flush()
 
126
 
 
127
 
 
128
def setup_juju_authentication(credentials_yaml, oauth):
 
129
    credentials_yaml.write("""
 
130
credentials:
 
131
    testmaas:
 
132
        test:
 
133
            auth-type: oauth1
 
134
            maas-oauth: {oauth}""".format(oauth=oauth))
 
135
    credentials_yaml.flush()
135
136
 
136
137
def get_token_str():
137
138
    admin = User.objects.get(username=ADMIN_USER)
157
158
 
158
159
 
159
160
def setup_local_dns():
160
 
    content = open('/etc/resolv.conf').read().decode('ascii')
 
161
    with open('/etc/resolv.conf', encoding='ascii') as fd:
 
162
        content = fd.read()
161
163
    content = 'nameserver 127.0.0.1\n' + content
162
 
    with open('/etc/resolv.conf', 'w') as f:
163
 
        f.write(content.encode('utf-8'))
 
164
    with open('/etc/resolv.conf', mode='w', encoding='ascii') as f:
 
165
        f.write(content)
164
166
 
165
167
 
166
168
DEB_PROXY_CONFIG = """
170
172
       urlparse(SQUID_DEB_PROXY_URL).port)
171
173
 
172
174
 
173
 
# Configure the region proxy to use the proxy.
174
 
def setup_deb_proxy():
175
 
    config = '/usr/share/maas/maas-proxy.conf'
176
 
    content = open(config).read().decode('ascii')
177
 
    content = content + DEB_PROXY_CONFIG
178
 
    with open(config, 'w') as f:
179
 
        f.write(content.encode('utf-8'))
180
 
    run_command(['sudo', 'service', 'maas-proxy', 'restart'])
181
 
 
182
175
tests_order = [
183
176
    "test_create_admin",
184
177
    "test_restart_dbus_avahi",
226
219
    "test_configure_juju",
227
220
    "test_juju_bootstrap",
228
221
    "test_apply_tag_to_all_machines",
229
 
    "test_juju_bootstrapped",
230
222
    "test_check_tag_applied_to_all_machines",
231
 
    "test_juju_deploy_mysql",
 
223
    "test_juju_deploy_postgresql",
232
224
    "test_machines_deployed",
233
 
    "test_static_ip_addresses",
 
225
    "test_ip_addresses_not_in_dynamic_range",
234
226
]
235
227
 
236
228
def sorting_method(ignored, first_test, second_test):
258
250
    "management": 2,
259
251
    "ip_range_low": "10.245.136.10",
260
252
    "ip_range_high": "10.245.136.200",
261
 
    # TODO: static ranges no longer exist
262
 
    "static_ip_range_low": "10.245.136.201",
263
 
    "static_ip_range_high": "10.245.136.250",
264
253
    # add cidr as it is now default in new networking configs.
265
254
    "cidr": "10.245.136.0/21"
266
255
}
400
389
        command.extend(args)
401
390
        retcode, output, err = run_command(command, env=env)
402
391
        command_name = " ".join(map(pipes.quote, command))
403
 
        self.addDetail(command_name, text_content(
404
 
            output.decode("UTF-8", "replace")))
405
 
        self.addDetail(command_name, text_content(
406
 
            err.decode("UTF-8", "replace")))
407
 
        return output
 
392
        self.addDetail(command_name, text_content(output))
 
393
        self.addDetail(command_name, text_content(err))
 
394
        return retcode, output, err
408
395
 
409
396
    def get_juju_status(self):
410
 
        status_output = self._run_juju_command(["status"])
 
397
        # Juju2 status defaults to tabular so we need to force YAML
 
398
        _, status_output, _ = self._run_juju_command(["status", "--format=yaml"])
411
399
        status = yaml.safe_load(status_output)
412
400
        return status
413
401
 
419
407
                machines = status['machines'].values()
420
408
                running_machines = [
421
409
                    machine for machine in machines
422
 
                    if machine.get('agent-state', '') in [
 
410
                    if machine.get('machine-status', {}).get('current', '') in [
423
411
                        'running', 'started']]
424
412
                if len(running_machines) >= nb_machines:
425
413
                    break
426
414
            sleep(20)
427
415
 
428
 
    def _wait_units_started(self, service, nb_units):
429
 
        """Wait until a service has at least `nb_units` units."""
 
416
    def _wait_units_started(self, application, nb_units):
 
417
        """Wait until an application has at least `nb_units` units."""
430
418
        while True:
431
419
            status = self.get_juju_status()
432
420
            try:
433
 
                units = status['services'][service]['units'].values()
 
421
                units = status['services'][application]['units'].values()
434
422
            except KeyError:
435
423
                units = []
436
424
            started_units = [
437
425
                unit for unit in units
438
 
                if unit.get('agent-state', '') == 'started']
 
426
                if unit.get('workload-status', {}).get('current', '') == 'active']
439
427
            if len(started_units) >= nb_units:
440
428
                break
441
429
            sleep(20)
988
976
    def test_configure_juju(self):
989
977
        # Proxy is currently broken: disable using the lab's proxy
990
978
        # as parent for now.
991
 
        setup_deb_proxy()  # Maybe it's not broken anymore
992
979
        token_str = get_token_str()
993
980
        # Workaround bug 972829 (in juju precise).
994
981
        server_url = MAAS_URL.replace('/MAAS', ':80/MAAS')
995
 
        setup_juju_config(server_url, token_str, series=NODE_SERIES)
 
982
        with tempfile.NamedTemporaryFile() as cloud_yaml:
 
983
            # Create cloud configuration
 
984
            setup_juju_cloud(
 
985
                server=server_url, cloud_yaml=cloud_yaml
 
986
            )
 
987
            # Add cloud to Juju
 
988
            retcode, _, _ = self._run_juju_command(
 
989
                ['add-cloud', 'testmaas', cloud_yaml.name]
 
990
            )
 
991
            self.assertThat(retcode, Equals(0))
 
992
        retcode, list_clouds_output, _ = self._run_juju_command(
 
993
            ['list-clouds']
 
994
        )
 
995
        self.assertThat(retcode, Equals(0))
 
996
        self.assertThat(list_clouds_output, Contains("local:testmaas"))
 
997
        # Setup credentials
 
998
        with open(os.path.expanduser(
 
999
            '~/.local/share/juju/credentials.yaml'), mode='w', encoding='utf8') as credentials:
 
1000
            setup_juju_authentication(oauth=token_str, credentials_yaml=credentials)
 
1001
        retcode, list_creds_output, _ = self._run_juju_command(
 
1002
            ['list-credentials']
 
1003
        )
 
1004
        self.assertThat(retcode, Equals(0))
 
1005
        self.assertThat(list_creds_output, Contains("local:testmaas"))
996
1006
        setup_local_dns()
997
1007
 
 
1008
    @timeout(60 * 60)
998
1009
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
999
 
    @timeout(60 * 60)
1000
1010
    def test_juju_bootstrap(self):
1001
1011
        # Wait a bit to let all the nodes go down.
1002
1012
        # XXX: rvb 2013-04-23 bug=1171418
1003
1013
        sleep(30)
1004
 
        if is_juju_core():
1005
 
            command = ['bootstrap', '--upload-tools']
1006
 
        else:
1007
 
            command = ['bootstrap']
1008
 
        self._run_juju_command(command)
1009
 
 
1010
 
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
1011
 
    @timeout(60 * 60)
1012
 
    def test_juju_bootstrapped(self):
1013
 
        """Wait for one machine with the Juju agent up."""
1014
 
        self._wait_machines_running(1)
1015
 
 
1016
 
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
1017
 
    def test_juju_deploy_mysql(self):
1018
 
        # Deploy mysql.
1019
 
        self._run_juju_command(["set-env", "http-proxy=%s" % HTTP_PROXY])
1020
 
        self._run_juju_command(["set-env", "https-proxy=%s" % HTTP_PROXY])
 
1014
        # Proxy has to be set while bootstrapping
 
1015
        with tempfile.NamedTemporaryFile() as bootstrap_config:
 
1016
            bootstrap_config.write("""
 
1017
http-proxy: {proxy}
 
1018
https-proxy: {proxy}""".format(proxy=HTTP_PROXY).encode('utf8'))
 
1019
            bootstrap_config.file.flush()
 
1020
            retcode, _, _ = self._run_juju_command([
 
1021
                'bootstrap', 'autopkgtest', 'testmaas', '--upload-tools',
 
1022
                '--config={config}'.format(config=bootstrap_config.name)
 
1023
            ])
 
1024
            self.assertThat(retcode, Equals(0))
 
1025
 
 
1026
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
 
1027
    def test_juju_deploy_postgresql(self):
 
1028
        # Deploy postgresql.
1021
1029
        env = os.environ.copy()
1022
1030
        env['http_proxy'] = HTTP_PROXY
1023
1031
        env['https_proxy'] = HTTP_PROXY
1024
 
        self._run_juju_command(["deploy", "mysql"], env=env)
1025
 
        self._wait_machines_running(2)
1026
 
        self._wait_units_started('mysql', 1)
 
1032
        retcode, _, _ = self._run_juju_command(["deploy", "postgresql"], env=env)
 
1033
        self.assertThat(retcode, Equals(0))
 
1034
        self._wait_machines_running(1)
 
1035
        self._wait_units_started('postgresql', 1)
1027
1036
 
1028
1037
    nb_of_deployed_machines = 2
1029
1038
 
 
1039
    @timeout(10*60)
1030
1040
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
1031
 
    @timeout(10)
1032
1041
    def test_machines_deployed(self):
1033
 
        allocated_machines = self._wait_machines(
 
1042
        deployed_machines = self._wait_machines(
1034
1043
            NODE_STATUS.DEPLOYED, num_expected=self.nb_of_deployed_machines)
1035
 
        params = [
1036
 
            "nodes=%s" % node['system_id']
1037
 
            for node in allocated_machines
1038
 
            ]
1039
 
        output, err = self._run_maas_cli(
1040
 
            ["nodes", "deployment-status"] + params)
1041
 
        deployment_statuses = loads(output).values()
1042
 
        self.assertEqual(
1043
 
            ["Deployed"] * self.nb_of_deployed_machines, deployment_statuses)
 
1044
        for machine in deployed_machines:
 
1045
            self.assertThat(machine.get('status_name', ''), Equals('Deployed'))
1044
1046
 
 
1047
    @timeout(10*60)
1045
1048
    @skipIf(DO_NOT_TEST_JUJU, "Not testing juju")
1046
 
    @timeout(10)
1047
 
    def test_static_ip_addresses(self):
1048
 
        # Make sure the deployed machines have addresses in the static range.
 
1049
    def test_ip_addresses_not_in_dynamic_range(self):
 
1050
        # Make sure the deployed machines have addresses in the dynamic range.
1049
1051
        deployed_machines = self._wait_machines(
1050
1052
            NODE_STATUS.DEPLOYED, num_expected=self.nb_of_deployed_machines)
1051
1053
        for deployed_machine in deployed_machines:
1052
1054
            ips = [IPAddress(ip) for ip in deployed_machine['ip_addresses']]
1053
1055
            ip_range = IPRange(
1054
 
                REGION_DHCP_CONFIG['static_ip_range_low'],
1055
 
                REGION_DHCP_CONFIG['static_ip_range_high'])
1056
 
            self.assertThat(
1057
 
                ip_range,
1058
 
                ContainsAll(ips),
1059
 
                "The IP addresses of the deployed nodes are not in the "
1060
 
                "cluster interface's static range.")
 
1056
                REGION_DHCP_CONFIG['ip_range_low'],
 
1057
                REGION_DHCP_CONFIG['ip_range_high'])
 
1058
            for ip in ips:
 
1059
                self.assertThat(ip_range, Not(Contains(ip)))
1061
1060
 
1062
1061
    @classmethod
1063
1062
    def dump_database(cls):