3
from twisted.internet.defer import inlineCallbacks, succeed, fail
7
from txzookeeper import ZookeeperClient
8
from txzookeeper.client import ConnectionTimeoutException
9
from txzookeeper.tests.utils import deleteTree
11
from juju.lib.testing import TestCase
13
from juju.errors import EnvironmentPending, NoConnection
14
from juju.state.sshclient import SSHClient
15
from juju.providers.ec2.tests.common import EC2TestMixin
16
from juju.tests.common import get_test_zookeeper_address
19
class EC2ConnectTest(EC2TestMixin, TestCase):
21
def mock_find_zookeepers(self, instance):
22
self.s3.get_object(self.env_name, "provider-state")
23
self.mocker.result(succeed(dump(
24
{"zookeeper-instances": ["i-foobar"]})))
25
self.ec2.describe_instances("i-foobar")
26
self.mocker.result(succeed([instance]))
28
def mock_connect(self, share, instance, result):
29
self.mock_find_zookeepers(instance)
30
client = self.mocker.patch(SSHClient)
31
client.connect("foo.example.com:2181", timeout=30, share=share)
32
self.mocker.result(result)
34
def assert_connect_error(self, error, expect_type, expect_message):
35
instance = self.get_instance("i-foobar", dns_name="foo.example.com")
36
self.mock_connect(False, instance, fail(error))
39
provider = self.get_provider()
40
d = provider.connect()
42
def check_error(error):
43
self.assertEqual(str(error), expect_message)
44
self.assertFailure(d, expect_type)
45
d.addCallback(check_error)
48
def test_no_dns_name(self):
50
`EnvironmentPending` should be raised if no zookeeper nodes have dns
53
instance = self.get_instance("i-foobar")
54
self.mock_find_zookeepers(instance)
57
provider = self.get_provider()
58
d = provider.connect()
60
def check_error(error):
62
str(error), "No machines have addresses assigned yet")
64
self.assertFailure(d, NoConnection)
65
d.addCallback(check_error)
68
def test_provider_connect_forwards_share_option(self):
69
"""The `share` kwarg should be passed through to `SSHClient.connect`"""
70
instance = self.get_instance("i-foobar", dns_name="foo.example.com")
71
connected_client = self.mocker.mock(type=SSHClient)
72
self.mock_connect(True, instance, succeed(connected_client))
73
# We'll test the wait on initialization separately.
74
connected_client.exists_and_watch("/initialized")
75
self.mocker.result((succeed(True), None))
78
provider = self.get_provider()
79
d = provider.connect(share=True)
81
def verify_result(result):
82
self.assertIdentical(connected_client, result)
83
d.addCallback(verify_result)
86
def test_no_connection(self):
87
"""`NoConnection` errors should become `EnvironmentPending`s"""
88
return self.assert_connect_error(
89
NoConnection("KABOOM!"), EnvironmentPending,
90
"Cannot connect to machine i-foobar (perhaps still initializing): "
93
def test_txzookeeper_error(self):
95
`ConnectionTimeoutException` errors should become `EnvironmentPending`s
97
return self.assert_connect_error(
98
ConnectionTimeoutException("SPLAT!"), EnvironmentPending,
99
"Cannot connect to machine i-foobar (perhaps still initializing): "
102
def test_other_error(self):
103
"""Other errors should propagate"""
104
return self.assert_connect_error(
105
TypeError("THUD!"), TypeError, "THUD!")
108
def test_provider_connect_waits_on_initialization(self):
110
A connection to a zookeeper that is running, but whose juju state
111
is not ready, should wait until that state is ready.
113
# Hand back a real connected client to test the wait on initialization.
114
instance = self.get_instance("i-foobar", dns_name="foo.example.com")
115
connected_client = ZookeeperClient()
116
self.client = connected_client # for poke_zk
117
self.mock_connect(False, instance, succeed(connected_client))
121
zookeeper.set_debug_level(0)
122
yield connected_client.connect(get_test_zookeeper_address())
126
provider = self.get_provider()
127
client_deferred = provider.connect()
128
client_deferred.addCallback(client_result.append)
130
# Give it a chance to do it incorrectly.
134
self.assertEquals(client_result, [])
136
yield connected_client.create("/initialized")
138
yield client_deferred
139
self.assertTrue(client_result, client_result)
140
self.assertIdentical(client_result[0], connected_client)
142
deleteTree("/", connected_client.handle)
143
connected_client.close()