~hazmat/pyjuju/security-policy-rules-redux

« back to all changes in this revision

Viewing changes to juju/lib/lxc/tests/test_lxc.py

merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os
 
2
import tempfile
 
3
 
 
4
from twisted.internet.defer import inlineCallbacks
 
5
from twisted.internet.threads import deferToThread
 
6
 
 
7
from juju.lib.lxc import (_lxc_start, _lxc_stop, _lxc_create,
 
8
                              _lxc_wait, _lxc_ls, _lxc_destroy,
 
9
                              LXCContainer, get_containers, LXCError)
 
10
from juju.lib.testing import TestCase
 
11
 
 
12
 
 
13
def run_lxc_tests():
 
14
    if os.environ.get("TEST_LXC"):
 
15
        return None
 
16
    return "TEST_LXC=1 to include lxc tests"
 
17
 
 
18
 
 
19
DATA_PATH = os.path.abspath(
 
20
    os.path.join(os.path.dirname(__file__), "..", "data"))
 
21
 
 
22
 
 
23
DEFAULT_CONTAINER = "lxc_test"
 
24
 
 
25
 
 
26
class LXCTest(TestCase):
 
27
    timeout = 240
 
28
    skip = run_lxc_tests()
 
29
 
 
30
    def setUp(self):
 
31
        self.config = self.make_config()
 
32
 
 
33
        @self.addCleanup
 
34
        def remove_config():
 
35
            if os.path.exists(self.config):
 
36
                os.unlink(self.config)
 
37
 
 
38
    def make_config(self, network_name="virbr0"):
 
39
        lxc_config = os.path.join(DATA_PATH, "lxc.conf")
 
40
        template = open(lxc_config, "r").read()
 
41
 
 
42
        fd, output_fn = tempfile.mkstemp(suffix=".conf")
 
43
        output_config = open(output_fn, "w")
 
44
        output_config.write(template % {"network_name": network_name})
 
45
        output_config.close()
 
46
 
 
47
        return output_fn
 
48
 
 
49
    def clean_container(self, container_name):
 
50
        if os.path.exists("/var/lib/lxc/%s" % container_name):
 
51
            _lxc_stop(container_name)
 
52
            _lxc_destroy(container_name)
 
53
 
 
54
    def test_lxc_create(self):
 
55
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
56
 
 
57
        _lxc_create(DEFAULT_CONTAINER, config_file=self.config)
 
58
 
 
59
        # verify we can find the container
 
60
        output = _lxc_ls()
 
61
        self.assertIn(DEFAULT_CONTAINER, output)
 
62
 
 
63
        # remove and verify the container was removed
 
64
        _lxc_destroy(DEFAULT_CONTAINER)
 
65
        output = _lxc_ls()
 
66
        self.assertNotIn(DEFAULT_CONTAINER, output)
 
67
 
 
68
    def test_lxc_start(self):
 
69
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
70
 
 
71
        _lxc_create(DEFAULT_CONTAINER, config_file=self.config)
 
72
 
 
73
        _lxc_start(DEFAULT_CONTAINER)
 
74
        _lxc_stop(DEFAULT_CONTAINER)
 
75
 
 
76
    @inlineCallbacks
 
77
    def test_lxc_deferred(self):
 
78
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
79
        yield deferToThread(
 
80
            _lxc_create, DEFAULT_CONTAINER, config_file=self.config)
 
81
        yield deferToThread(_lxc_start, DEFAULT_CONTAINER)
 
82
 
 
83
    @inlineCallbacks
 
84
    def test_lxc_container(self):
 
85
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
86
        customize_log = self.makeFile()
 
87
        c = LXCContainer(
 
88
            DEFAULT_CONTAINER, "dsa...", "ppa", customize_log=customize_log)
 
89
 
 
90
        running = yield c.is_running()
 
91
        self.assertFalse(running)
 
92
        self.assertFalse(c.is_constructed())
 
93
        # verify we can't run a non-constructed container
 
94
        failure = c.run()
 
95
        yield self.assertFailure(failure, LXCError)
 
96
 
 
97
        yield c.create()
 
98
 
 
99
        self.assertFalse(running)
 
100
        self.assertTrue(c.is_constructed())
 
101
        yield c.run()
 
102
 
 
103
        running = yield c.is_running()
 
104
        self.assertTrue(running)
 
105
        self.assertTrue(c.is_constructed())
 
106
 
 
107
        output = _lxc_ls()
 
108
        self.assertIn(DEFAULT_CONTAINER, output)
 
109
 
 
110
        # verify we have a path into the container
 
111
        self.assertTrue(os.path.exists(c.rootfs))
 
112
        self.assertTrue(c.is_constructed())
 
113
 
 
114
        self.verify_container(c, "dsa...", "ppa")
 
115
 
 
116
        # verify that we are in containers
 
117
        containers = yield get_containers(None)
 
118
        self.assertEqual(containers[DEFAULT_CONTAINER], True)
 
119
 
 
120
        # tear it down
 
121
        yield c.destroy()
 
122
        running = yield c.is_running()
 
123
        self.assertFalse(running)
 
124
 
 
125
        containers = yield get_containers(None)
 
126
        self.assertNotIn(DEFAULT_CONTAINER, containers)
 
127
 
 
128
        # Verify the customize log file.
 
129
        self.assertTrue(os.path.exists(customize_log))
 
130
 
 
131
        # and its gone
 
132
        output = _lxc_ls()
 
133
        self.assertNotIn(DEFAULT_CONTAINER, output)
 
134
 
 
135
    @inlineCallbacks
 
136
    def test_lxc_wait(self):
 
137
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
138
 
 
139
        _lxc_create(DEFAULT_CONTAINER, config_file=self.config)
 
140
 
 
141
        _lxc_start(DEFAULT_CONTAINER)
 
142
 
 
143
        def waitForState(result):
 
144
            self.assertEqual(result, True)
 
145
 
 
146
        d = _lxc_wait(DEFAULT_CONTAINER, "RUNNING")
 
147
        d.addCallback(waitForState)
 
148
        yield d
 
149
 
 
150
        _lxc_stop(DEFAULT_CONTAINER)
 
151
        yield _lxc_wait(DEFAULT_CONTAINER, "STOPPED")
 
152
        _lxc_destroy(DEFAULT_CONTAINER)
 
153
 
 
154
    @inlineCallbacks
 
155
    def test_container_clone(self):
 
156
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER)
 
157
        self.addCleanup(self.clean_container, DEFAULT_CONTAINER + "_child")
 
158
 
 
159
        master_container = LXCContainer(DEFAULT_CONTAINER,
 
160
                                        origin="ppa",
 
161
                                        public_key="dsa...")
 
162
 
 
163
        # verify that we cannot clone an unconstructed container
 
164
        failure = master_container.clone("test_lxc_fail")
 
165
        yield self.assertFailure(failure, LXCError)
 
166
 
 
167
        yield master_container.create()
 
168
 
 
169
        # Clone a child container from the template
 
170
        child_name = DEFAULT_CONTAINER + "_child"
 
171
        c = yield master_container.clone(child_name)
 
172
 
 
173
        self.assertEqual(c.container_name, child_name)
 
174
 
 
175
        running = yield c.is_running()
 
176
        self.assertFalse(running)
 
177
        yield c.run()
 
178
 
 
179
        running = yield c.is_running()
 
180
        self.assertTrue(running)
 
181
 
 
182
        output = _lxc_ls()
 
183
        self.assertIn(DEFAULT_CONTAINER, output)
 
184
 
 
185
        self.verify_container(c, "dsa...", "ppa")
 
186
 
 
187
        # verify that we are in containers
 
188
        containers = yield get_containers(None)
 
189
        self.assertEqual(containers[child_name], True)
 
190
 
 
191
        # tear it down
 
192
        yield c.destroy()
 
193
        running = yield c.is_running()
 
194
        self.assertFalse(running)
 
195
 
 
196
        containers = yield get_containers(None)
 
197
        self.assertNotIn(child_name, containers)
 
198
 
 
199
        # and its gone
 
200
        output = _lxc_ls()
 
201
        self.assertNotIn(child_name, output)
 
202
 
 
203
        yield master_container.destroy()
 
204
 
 
205
    def verify_container(self, c, public_key, origin):
 
206
        """Verify properties of an LXCContainer"""
 
207
 
 
208
        def p(path):
 
209
            return os.path.join(c.rootfs, path)
 
210
 
 
211
        def sudo_get(path):
 
212
            # super get path (superuser priv)
 
213
            rc, output = c.execute(["cat", path])
 
214
            return output
 
215
 
 
216
        def run(cmd):
 
217
            try:
 
218
                rc, output = c.execute(cmd)
 
219
            except LXCError:
 
220
                rc = 1
 
221
            return rc
 
222
 
 
223
        # basic path checks
 
224
        for path in ("etc/juju", "var/lib/juju"):
 
225
            self.assertTrue(os.path.exists(p(path)))
 
226
 
 
227
        # verify packages we depend on are installed
 
228
        for pkg in ("resolvconf", "sudo"):
 
229
            self.assertEqual(run(["dpkg-query", "-s", pkg]), 0)
 
230
 
 
231
        # ubuntu user
 
232
        self.assertEqual(run(["id", "ubuntu"]), 0)
 
233
 
 
234
        # public key checks
 
235
        pub = sudo_get("home/ubuntu/.ssh/authorized_keys")
 
236
        self.assertEqual(pub.strip(), public_key)
 
237
 
 
238
        # sudoers access
 
239
        sudoers = sudo_get("etc/sudoers.d/lxc")
 
240
        self.assertIn("ubuntu ALL=(ALL:ALL) NOPASSWD: ALL", sudoers)
 
241
 
 
242
        # hostname
 
243
        self.assertEqual(c.container_name, sudo_get("etc/hostname").strip())
 
244
        # the lxc-clone command provides a different ordering here
 
245
        # we'd have to run customize_constainer again which removes
 
246
        # some of the point of the clone support to repair this.
 
247
        # droppping assertion for now and replacing with a lax one
 
248
        #XXX::: self.assertIn("127.0.0.1 %s localhost" % c.container_name,
 
249
        #XXX    sudo_get("etc/hosts"))
 
250
 
 
251
        self.assertIn(c.container_name, sudo_get("etc/hosts"))
 
252
 
 
253
        # nameserver
 
254
        resolv_conf = sudo_get("etc/resolvconf/resolv.conf.d/base")
 
255
        self.assertIn("nameserver 192.168.122.1", resolv_conf)
 
256
 
 
257
        # verify apt-cacher
 
258
        apt_proxy = sudo_get("/etc/apt/apt.conf.d/02juju-apt-proxy")
 
259
        self.assertIn('Acquire::http { Proxy "http://192.168.122.1:3142"; };',
 
260
                      apt_proxy)
 
261
 
 
262
        # check basic juju installation
 
263
        # these could be more through
 
264
        if origin == "ppa":
 
265
            self.assertEqual(0, run(["dpkg-query", "-s", "juju"]))
 
266
        elif origin == "distro":
 
267
            self.assertEqual(0, run(["dpkg-query", "-s", "juju"]))
 
268
        elif origin == "branch":
 
269
            # package isn't installed
 
270
            self.assertEqual(1, run(["dpkg-query", "-s", "juju"]))
 
271
            # but the branch is checked out
 
272
            self.asssertTrue(os.path.exists(p("usr/lib/juju/juju")))