~andrewjbeach/juju-ci-tools/make-local-patcher

« back to all changes in this revision

Viewing changes to tests/test_remote.py

  • Committer: Aaron Bentley
  • Date: 2014-02-28 16:40:22 UTC
  • mto: This revision was merged to the branch mainline in revision 257.
  • Revision ID: aaron.bentley@canonical.com-20140228164022-kfip2tphn9m9invi
Add juju-backup script.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""Tests for remote access to juju machines."""
2
 
 
3
 
from mock import patch
4
 
import os
5
 
import subprocess
6
 
import sys
7
 
 
8
 
import winrm
9
 
 
10
 
from jujupy import (
11
 
    EnvJujuClient,
12
 
    get_timeout_path,
13
 
    JujuData,
14
 
    Status,
15
 
)
16
 
from remote import (
17
 
    remote_from_address,
18
 
    remote_from_unit,
19
 
    WinRmRemote,
20
 
)
21
 
import tests
22
 
from utility import (
23
 
    temp_dir,
24
 
)
25
 
 
26
 
 
27
 
class TestRemote(tests.FakeHomeTestCase):
28
 
 
29
 
    precise_status_output = """\
30
 
    machines:
31
 
        "1":
32
 
            series: precise
33
 
    services:
34
 
        a-service:
35
 
            units:
36
 
                a-service/0:
37
 
                    machine: "1"
38
 
                    public-address: 10.55.60.1
39
 
    """
40
 
 
41
 
    win2012hvr2_status_output = """\
42
 
    machines:
43
 
        "2":
44
 
            series: win2012hvr2
45
 
    services:
46
 
        a-service:
47
 
            units:
48
 
                a-service/0:
49
 
                    machine: "2"
50
 
                    public-address: 10.55.60.2
51
 
    """
52
 
 
53
 
    def test_remote_from_unit(self):
54
 
        env = JujuData("an-env", {"type": "nonlocal"})
55
 
        client = EnvJujuClient(env, None, None)
56
 
        unit = "a-service/0"
57
 
        with patch.object(client, "get_status", autospec=True) as st:
58
 
            st.return_value = Status.from_text(self.precise_status_output)
59
 
            remote = remote_from_unit(client, unit)
60
 
        self.assertEqual(
61
 
            repr(remote),
62
 
            "<SSHRemote env='an-env' unit='a-service/0'>")
63
 
        self.assertIs(False, remote.is_windows())
64
 
 
65
 
    def test_remote_from_unit_with_series(self):
66
 
        env = JujuData("an-env", {"type": "nonlocal"})
67
 
        client = EnvJujuClient(env, None, None)
68
 
        unit = "a-service/0"
69
 
        remote = remote_from_unit(client, unit, series="trusty")
70
 
        self.assertEqual(
71
 
            repr(remote),
72
 
            "<SSHRemote env='an-env' unit='a-service/0'>")
73
 
        self.assertIs(False, remote.is_windows())
74
 
 
75
 
    def test_remote_from_unit_with_status(self):
76
 
        env = JujuData("an-env", {"type": "nonlocal"})
77
 
        client = EnvJujuClient(env, None, None)
78
 
        unit = "a-service/0"
79
 
        status = Status.from_text(self.win2012hvr2_status_output)
80
 
        remote = remote_from_unit(client, unit, status=status)
81
 
        self.assertEqual(
82
 
            repr(remote),
83
 
            "<WinRmRemote env='an-env' unit='a-service/0' addr='10.55.60.2'>")
84
 
        self.assertIs(True, remote.is_windows())
85
 
 
86
 
    def test_remote_from_address(self):
87
 
        remote = remote_from_address("10.55.60.1")
88
 
        self.assertEqual(repr(remote), "<SSHRemote addr='10.55.60.1'>")
89
 
        self.assertIs(None, remote.is_windows())
90
 
 
91
 
    def test_remote_from_address_and_series(self):
92
 
        remote = remote_from_address("10.55.60.2", series="trusty")
93
 
        self.assertEqual(repr(remote), "<SSHRemote addr='10.55.60.2'>")
94
 
        self.assertIs(False, remote.is_windows())
95
 
 
96
 
    def test_remote_from_address_and_win_series(self):
97
 
        remote = remote_from_address("10.55.60.3", series="win2012hvr2")
98
 
        self.assertEqual(repr(remote), "<WinRmRemote addr='10.55.60.3'>")
99
 
        self.assertIs(True, remote.is_windows())
100
 
 
101
 
    def test_run_with_unit(self):
102
 
        env = JujuData("an-env", {"type": "nonlocal"})
103
 
        client = EnvJujuClient(env, None, None)
104
 
        unit = "a-service/0"
105
 
        remote = remote_from_unit(client, unit, series="trusty")
106
 
        with patch.object(client, "get_juju_output") as mock_cmd:
107
 
            mock_cmd.return_value = "contents of /a/file"
108
 
            output = remote.run("cat /a/file")
109
 
            self.assertEqual(output, "contents of /a/file")
110
 
        mock_cmd.assert_called_once_with("ssh", unit, "cat /a/file",
111
 
                                         timeout=120)
112
 
 
113
 
    def test_run_with_unit_fallback(self):
114
 
        env = JujuData("an-env", {"type": "nonlocal"})
115
 
        client = EnvJujuClient(env, None, None)
116
 
        unit = "a-service/0"
117
 
        with patch.object(client, "get_status") as st:
118
 
            st.return_value = Status.from_text(self.precise_status_output)
119
 
            remote = remote_from_unit(client, unit)
120
 
            with patch.object(client, "get_juju_output") as mock_gjo:
121
 
                mock_gjo.side_effect = subprocess.CalledProcessError(1, "ssh",
122
 
                                                                     output="")
123
 
                with patch.object(remote, "_run_subprocess") as mock_run:
124
 
                    mock_run.return_value = "contents of /a/file"
125
 
                    output = remote.run("cat /a/file")
126
 
                    self.assertEqual(output, "contents of /a/file")
127
 
        mock_gjo.assert_called_once_with("ssh", unit, "cat /a/file",
128
 
                                         timeout=120)
129
 
        mock_run.assert_called_once_with([
130
 
            "ssh",
131
 
            "-o", "User ubuntu",
132
 
            "-o", "UserKnownHostsFile /dev/null",
133
 
            "-o", "StrictHostKeyChecking no",
134
 
            "-o", "PasswordAuthentication no",
135
 
            "10.55.60.1",
136
 
            "cat /a/file",
137
 
        ])
138
 
        self.assertRegexpMatches(
139
 
            self.log_stream.getvalue(),
140
 
            "(?m)^WARNING juju ssh to 'a-service/0' failed, .*")
141
 
 
142
 
    def test_run_with_address(self):
143
 
        remote = remote_from_address("10.55.60.1")
144
 
        with patch.object(remote, "_run_subprocess") as mock_run:
145
 
            mock_run.return_value = "contents of /a/file"
146
 
            output = remote.run("cat /a/file")
147
 
            self.assertEqual(output, "contents of /a/file")
148
 
        mock_run.assert_called_once_with([
149
 
            "ssh",
150
 
            "-o", "User ubuntu",
151
 
            "-o", "UserKnownHostsFile /dev/null",
152
 
            "-o", "StrictHostKeyChecking no",
153
 
            "-o", "PasswordAuthentication no",
154
 
            "10.55.60.1",
155
 
            "cat /a/file",
156
 
        ])
157
 
 
158
 
    def test_cat(self):
159
 
        remote = remote_from_address("10.55.60.1")
160
 
        with patch.object(remote, "_run_subprocess") as mock_run:
161
 
            remote.cat("/a/file")
162
 
        mock_run.assert_called_once_with([
163
 
            "ssh",
164
 
            "-o", "User ubuntu",
165
 
            "-o", "UserKnownHostsFile /dev/null",
166
 
            "-o", "StrictHostKeyChecking no",
167
 
            "-o", "PasswordAuthentication no",
168
 
            "10.55.60.1",
169
 
            "cat /a/file",
170
 
        ])
171
 
 
172
 
    def test_cat_on_windows(self):
173
 
        env = JujuData("an-env", {"type": "nonlocal"})
174
 
        client = EnvJujuClient(env, None, None)
175
 
        unit = "a-service/0"
176
 
        with patch.object(client, "get_status", autospec=True) as st:
177
 
            st.return_value = Status.from_text(self.win2012hvr2_status_output)
178
 
            response = winrm.Response(("contents of /a/file", "",  0))
179
 
            remote = remote_from_unit(client, unit)
180
 
            with patch.object(remote.session, "run_cmd", autospec=True,
181
 
                              return_value=response) as mock_run:
182
 
                output = remote.cat("/a/file")
183
 
                self.assertEqual(output, "contents of /a/file")
184
 
        st.assert_called_once_with()
185
 
        mock_run.assert_called_once_with("type", ["/a/file"])
186
 
 
187
 
    def test_copy(self):
188
 
        remote = remote_from_address("10.55.60.1")
189
 
        dest = "/local/path"
190
 
        with patch.object(remote, "_run_subprocess") as mock_run:
191
 
            remote.copy(dest, ["/var/log/*", "~/.config"])
192
 
        mock_run.assert_called_once_with([
193
 
            "scp",
194
 
            "-rC",
195
 
            "-o", "User ubuntu",
196
 
            "-o", "UserKnownHostsFile /dev/null",
197
 
            "-o", "StrictHostKeyChecking no",
198
 
            "-o", "PasswordAuthentication no",
199
 
            "10.55.60.1:/var/log/*",
200
 
            "10.55.60.1:~/.config",
201
 
            "/local/path",
202
 
        ])
203
 
 
204
 
    def test_copy_on_windows(self):
205
 
        env = JujuData("an-env", {"type": "nonlocal"})
206
 
        client = EnvJujuClient(env, None, None)
207
 
        unit = "a-service/0"
208
 
        dest = "/local/path"
209
 
        with patch.object(client, "get_status", autospec=True) as st:
210
 
            st.return_value = Status.from_text(self.win2012hvr2_status_output)
211
 
            response = winrm.Response(("fake output", "",  0))
212
 
            remote = remote_from_unit(client, unit)
213
 
            with patch.object(remote.session, "run_ps", autospec=True,
214
 
                              return_value=response) as mock_run:
215
 
                with patch.object(remote, "_encoded_copy_to_dir",
216
 
                                  autospec=True) as mock_cpdir:
217
 
                    remote.copy(dest, ["C:\\logs\\*", "%APPDATA%\\*.log"])
218
 
        mock_cpdir.assert_called_once_with(dest, "fake output")
219
 
        st.assert_called_once_with()
220
 
        self.assertEquals(mock_run.call_count, 1)
221
 
        self.assertRegexpMatches(
222
 
            mock_run.call_args[0][0],
223
 
            r'.*"C:\\logs\\[*]","%APPDATA%\\[*].log".*')
224
 
 
225
 
    def test_copy_ipv6(self):
226
 
        remote = remote_from_address("2001:db8::34")
227
 
        self.assertEqual(remote.address, "2001:db8::34")
228
 
        dest = "/local/path"
229
 
        with patch.object(remote, "_run_subprocess") as mock_run:
230
 
            remote.copy(dest, ["/var/log/*", "~/.config"])
231
 
        mock_run.assert_called_once_with([
232
 
            "scp",
233
 
            "-rC",
234
 
            "-o", "User ubuntu",
235
 
            "-o", "UserKnownHostsFile /dev/null",
236
 
            "-o", "StrictHostKeyChecking no",
237
 
            "-o", "PasswordAuthentication no",
238
 
            "[2001:db8::34]:/var/log/*",
239
 
            "[2001:db8::34]:~/.config",
240
 
            "/local/path",
241
 
        ])
242
 
 
243
 
    def test_run_cmd(self):
244
 
        env = JujuData("an-env", {"type": "nonlocal"})
245
 
        client = EnvJujuClient(env, None, None)
246
 
        unit = "a-service/0"
247
 
        with patch.object(client, "get_status", autospec=True) as st:
248
 
            st.return_value = Status.from_text(self.win2012hvr2_status_output)
249
 
            response = winrm.Response(("some out", "some err",  0))
250
 
            remote = remote_from_unit(client, unit)
251
 
            with patch.object(remote.session, "run_cmd", autospec=True,
252
 
                              return_value=response) as mock_run:
253
 
                output = remote.run_cmd(
254
 
                    ["C:\\Program Files\\bin.exe", "/IN", "Bob's Stuff"])
255
 
                self.assertEqual(output, response)
256
 
        st.assert_called_once_with()
257
 
        mock_run.assert_called_once_with(
258
 
            '"C:\\Program Files\\bin.exe"', ['/IN "Bob\'s Stuff"'])
259
 
 
260
 
    def test_run_subprocess_timeout(self):
261
 
        remote = remote_from_address("10.55.60.1")
262
 
        remote.timeout = 63
263
 
        with patch("subprocess.check_output", autospec=True) as mock_co:
264
 
            remote.cat("/a/file")
265
 
        mock_co.assert_called_once_with((
266
 
            sys.executable,
267
 
            get_timeout_path(),
268
 
            "63.00",
269
 
            "--",
270
 
            "ssh",
271
 
            "-o", "User ubuntu",
272
 
            "-o", "UserKnownHostsFile /dev/null",
273
 
            "-o", "StrictHostKeyChecking no",
274
 
            "-o", "PasswordAuthentication no",
275
 
            "10.55.60.1",
276
 
            "cat /a/file",
277
 
            ),
278
 
            stdin=subprocess.PIPE,
279
 
        )
280
 
 
281
 
    def test_encoded_copy_to_dir_one(self):
282
 
        output = "testfile|K0ktLuECAA==\r\n"
283
 
        with temp_dir() as dest:
284
 
            WinRmRemote._encoded_copy_to_dir(dest, output)
285
 
            with open(os.path.join(dest, "testfile")) as f:
286
 
                self.assertEqual(f.read(), "test\n")
287
 
 
288
 
    def test_encoded_copy_to_dir_many(self):
289
 
        output = "test one|K0ktLuECAA==\r\ntest two|K0ktLuECAA==\r\n\r\n"
290
 
        with temp_dir() as dest:
291
 
            WinRmRemote._encoded_copy_to_dir(dest, output)
292
 
            for name in ("test one", "test two"):
293
 
                with open(os.path.join(dest, name)) as f:
294
 
                    self.assertEqual(f.read(), "test\n")
295
 
 
296
 
    def test_encoded_copy_traversal_guard(self):
297
 
        output = "../../../etc/passwd|K0ktLuECAA==\r\n"
298
 
        with temp_dir() as dest:
299
 
            with self.assertRaises(ValueError):
300
 
                WinRmRemote._encoded_copy_to_dir(dest, output)