Repository: bigtop
Updated Branches:
  refs/heads/master cf19b047f -> f4515e8c6


BIGTOP-2575: zk charm test updates (closes #156)

Signed-off-by: Kevin W Monroe <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/bigtop/repo
Commit: http://git-wip-us.apache.org/repos/asf/bigtop/commit/f4515e8c
Tree: http://git-wip-us.apache.org/repos/asf/bigtop/tree/f4515e8c
Diff: http://git-wip-us.apache.org/repos/asf/bigtop/diff/f4515e8c

Branch: refs/heads/master
Commit: f4515e8c6d27a158449141264be066e0c43b2772
Parents: cf19b04
Author: Kevin W Monroe <[email protected]>
Authored: Thu Oct 27 21:55:18 2016 +0000
Committer: Kevin W Monroe <[email protected]>
Committed: Wed Nov 16 14:18:00 2016 -0600

----------------------------------------------------------------------
 .../charm/zookeeper/layer-zookeeper/README.md   |   4 +-
 .../zookeeper/layer-zookeeper/actions/restart   |   7 +-
 .../layer-zookeeper/actions/smoke-test          |   6 +-
 .../lib/charms/layer/bigtop_zookeeper.py        | 188 +++++++++++++++++++
 .../lib/charms/layer/zookeeper.py               | 188 -------------------
 .../layer-zookeeper/reactive/zookeeper.py       |   6 +-
 .../zookeeper/layer-zookeeper/tests/01-deploy   |  74 --------
 .../layer-zookeeper/tests/01-deploy-smoke.py    |  73 +++++++
 .../layer-zookeeper/tests/10-bind-address       | 115 ------------
 .../layer-zookeeper/tests/10-bind-address.py    | 109 +++++++++++
 10 files changed, 384 insertions(+), 386 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/README.md
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/README.md 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/README.md
index 69aa650..af9f449 100644
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/README.md
+++ b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/README.md
@@ -153,9 +153,9 @@ The Zookeeper nodes will automatically perform a rolling 
restart to update the
 Zookeeper quorum without losing any jobs in progress. Once the rolling restart
 has completed, all of the Zookeeper nodes should report the following status:
 
-    ready (n zk nodes)
+    ready (n units)
 
-(Where 'n' is the total number of Zookeeper nodes in your quorum.)
+(Where 'n' is the total number of Zookeeper units in the quorum.)
 
 
 # Integrating

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/restart
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/restart 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/restart
index 4dcf6ae..7bb5136 100755
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/restart
+++ b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/restart
@@ -18,14 +18,15 @@
 import sys
 sys.path.append('lib')  # Add our helpers to our path.
 
-from charmhelpers.core import hookenv
-from charms.layer.zookeeper import Zookeeper
-from charms.reactive import is_state
+from charmhelpers.core import hookenv  # noqa: E402
+from charms.layer.bigtop_zookeeper import Zookeeper  # noqa: E402
+from charms.reactive import is_state  # noqa: E402
 
 LOG = hookenv.log
 
 LOG("starting restart handler.")
 
+
 def main():
     if not is_state('zookeeper.started'):
         hookenv.action_fail('Cannot restart: Zookeeper has not yet started!')

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/smoke-test
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/smoke-test 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/smoke-test
index 37264cf..6481462 100755
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/smoke-test
+++ b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/actions/smoke-test
@@ -18,9 +18,9 @@
 import sys
 sys.path.append('lib')
 
-from charmhelpers.core import hookenv
-from charms.layer.apache_bigtop_base import Bigtop
-from charms.reactive import is_state
+from charmhelpers.core import hookenv  # noqa: E402
+from charms.layer.apache_bigtop_base import Bigtop  # noqa: E402
+from charms.reactive import is_state  # noqa: E402
 
 
 def fail(msg, output=None):

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/bigtop_zookeeper.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/bigtop_zookeeper.py
 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/bigtop_zookeeper.py
new file mode 100644
index 0000000..5f1695c
--- /dev/null
+++ 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/bigtop_zookeeper.py
@@ -0,0 +1,188 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import subprocess
+
+from charmhelpers.core import host
+from charmhelpers.core.hookenv import (open_port, close_port, log,
+                                       unit_private_ip, local_unit, config)
+from charms import layer
+from charms.layer.apache_bigtop_base import Bigtop
+from charms.reactive.relations import RelationBase
+from jujubigdata.utils import DistConfig
+
+
+def format_node(unit, node_ip):
+    '''
+    Given a juju unit name and an ip address, return a tuple
+    containing an id and formatted ip string suitable for passing to
+    puppet, which will write it out to zoo.cfg.
+
+    '''
+    return (unit.split("/")[1], "{ip}:2888:3888".format(ip=node_ip))
+
+
+class Zookeeper(object):
+    '''
+    Utility class for managing Zookeeper tasks like configuration, start,
+    stop, and adding and removing nodes.
+
+    '''
+    def __init__(self, dist_config=None):
+        self._dist_config = dist_config or DistConfig(
+            data=layer.options('apache-bigtop-base'))
+
+        self._roles = ['zookeeper-server', 'zookeeper-client']
+        self._hosts = {}
+
+    def is_zk_leader(self):
+        '''
+        Attempt to determine whether this node is the Zookeeper leader.
+
+        Note that Zookeeper tracks leadership independently of juju,
+        and that this command can fail, depending on the state that
+        the Zookeeper node is in when we attempt to run it.
+
+        '''
+        try:
+            status = subprocess.check_output(
+                ["/usr/lib/zookeeper/bin/zkServer.sh", "status"])
+            return "leader" in status.decode('utf-8')
+        except Exception:
+            log(
+                "Unable to determine whether this node is the Zookeeper 
leader.",
+                level="WARN"
+            )
+            return False
+
+    def read_peers(self):
+        '''
+        Fetch the list of peers available.
+
+        The first item in this list should always be the node that
+        this code is executing on.
+
+        '''
+        # A Zookeeper node likes to be first on the list.
+        nodes = [(local_unit(), unit_private_ip())]
+        # Get the list of peers
+        zkpeer = RelationBase.from_state('zkpeer.joined')
+        if zkpeer:
+            nodes.extend(sorted(zkpeer.get_nodes()))
+        nodes = [format_node(*node) for node in nodes]
+        return nodes
+
+    def sort_peers(self, zkpeer):
+        '''
+        Return peers, sorted in an order suitable for performing a rolling
+        restart.
+
+        '''
+        peers = self.read_peers()
+        leader = zkpeer.find_zk_leader()
+        peers.sort(key=lambda x: x[1] == leader)
+
+        return peers
+
+    @property
+    def dist_config(self):
+        '''
+        Charm level config.
+
+        '''
+        return self._dist_config
+
+    @property
+    def _override(self):
+        '''
+        Return a dict of keys and values that will override puppet's
+        defaults.
+
+        '''
+        override = {
+            "hadoop_zookeeper::server::myid": local_unit().split("/")[1],
+            "hadoop_zookeeper::server::ensemble": self.read_peers()
+        }
+        network_interface = config().get('network_interface')
+        if network_interface:
+            key = "hadoop_zookeeper::server::client_bind_addr"
+            override[key] = Bigtop().get_ip_for_interface(network_interface)
+
+        return override
+
+    def install(self, nodes=None):
+        '''
+        Write out the config, then run puppet.
+
+        After this runs, we should have a configured and running service.
+
+        '''
+        bigtop = Bigtop()
+        log("Rendering site yaml ''with overrides: {}".format(self._override))
+        bigtop.render_site_yaml(self._hosts, self._roles, self._override)
+        bigtop.trigger_puppet()
+        if self.is_zk_leader():
+            zkpeer = RelationBase.from_state('zkpeer.joined')
+            zkpeer.set_zk_leader()
+
+    def start(self):
+        '''
+        Request that our service start. Normally, puppet will handle this
+        for us.
+
+        '''
+        host.service_start('zookeeper-server')
+
+    def stop(self):
+        '''
+        Stop Zookeeper.
+
+        '''
+        host.service_stop('zookeeper-server')
+
+    def open_ports(self):
+        '''
+        Expose the ports in the configuration to the outside world.
+
+        '''
+        for port in self.dist_config.exposed_ports('zookeeper'):
+            open_port(port)
+
+    def close_ports(self):
+        '''
+        Close off communication from the outside world.
+
+        '''
+        for port in self.dist_config.exposed_ports('zookeeper'):
+            close_port(port)
+
+    def quorum_check(self):
+        '''
+        Returns a string reporting the node count. Append a message
+        informing the user if the node count is too low for good quorum,
+        or is even (meaning that one of the nodes is redundant for
+        quorum).
+
+        '''
+        node_count = len(self.read_peers())
+        if node_count == 1:
+            count_str = "{} unit".format(node_count)
+        else:
+            count_str = "{} units".format(node_count)
+        if node_count < 3:
+            return " ({}; less than 3 is suboptimal)".format(count_str)
+        if node_count % 2 == 0:
+            return " ({}; an even number is suboptimal)".format(count_str)
+        return "({})".format(count_str)

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/zookeeper.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/zookeeper.py
 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/zookeeper.py
deleted file mode 100644
index 4b4932b..0000000
--- 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/lib/charms/layer/zookeeper.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import subprocess
-
-from charmhelpers.core import host
-from charmhelpers.core.hookenv import (open_port, close_port, log,
-                                       unit_private_ip, local_unit, config)
-from charms import layer
-from charms.layer.apache_bigtop_base import Bigtop
-from charms.reactive.relations import RelationBase
-from jujubigdata.utils import DistConfig
-
-
-def format_node(unit, node_ip):
-    '''
-    Given a juju unit name and an ip address, return a tuple
-    containing an id and formatted ip string suitable for passing to
-    puppet, which will write it out to zoo.cfg.
-
-    '''
-    return (unit.split("/")[1], "{ip}:2888:3888".format(ip=node_ip))
-
-
-class Zookeeper(object):
-    '''
-    Utility class for managing Zookeeper tasks like configuration, start,
-    stop, and adding and removing nodes.
-
-    '''
-    def __init__(self, dist_config=None):
-        self._dist_config = dist_config or DistConfig(
-            data=layer.options('apache-bigtop-base'))
-
-        self._roles = ['zookeeper-server', 'zookeeper-client']
-        self._hosts = {}
-
-    def is_zk_leader(self):
-        '''
-        Attempt to determine whether this node is the Zookeeper leader.
-
-        Note that Zookeeper tracks leadership independently of juju,
-        and that this command can fail, depending on the state that
-        the Zookeeper node is in when we attempt to run it.
-
-        '''
-        try:
-            status = subprocess.check_output(
-                ["/usr/lib/zookeeper/bin/zkServer.sh", "status"])
-            return "leader" in status.decode('utf-8')
-        except Exception:
-            log(
-                "Unable to determine whether this node is the Zookeeper 
leader.",
-                level="WARN"
-            )
-            return False
-
-    def read_peers(self):
-        '''
-        Fetch the list of peers available.
-
-        The first item in this list should always be the node that
-        this code is executing on.
-
-        '''
-        # A Zookeeper node likes to be first on the list.
-        nodes = [(local_unit(), unit_private_ip())]
-        # Get the list of peers
-        zkpeer = RelationBase.from_state('zkpeer.joined')
-        if zkpeer:
-            nodes.extend(sorted(zkpeer.get_nodes()))
-        nodes = [format_node(*node) for node in nodes]
-        return nodes
-
-    def sort_peers(self, zkpeer):
-        '''
-        Return peers, sorted in an order suitable for performing a rolling
-        restart.
-
-        '''
-        peers = self.read_peers()
-        leader = zkpeer.find_zk_leader()
-        peers.sort(key=lambda x: x[1] == leader)
-
-        return peers
-
-    @property
-    def dist_config(self):
-        '''
-        Charm level config.
-
-        '''
-        return self._dist_config
-
-    @property
-    def _override(self):
-        '''
-        Return a dict of keys and values that will override puppet's
-        defaults.
-
-        '''
-        override = {
-            "hadoop_zookeeper::server::myid": local_unit().split("/")[1],
-            "hadoop_zookeeper::server::ensemble": self.read_peers()
-        }
-        network_interface = config().get('network_interface')
-        if network_interface:
-            key = "hadoop_zookeeper::server::client_bind_addr"
-            override[key] = Bigtop().get_ip_for_interface(network_interface)
-
-        return override
-
-    def install(self, nodes=None):
-        '''
-        Write out the config, then run puppet.
-
-        After this runs, we should have a configured and running service.
-
-        '''
-        bigtop = Bigtop()
-        log("Rendering site yaml ''with overrides: {}".format(self._override))
-        bigtop.render_site_yaml(self._hosts, self._roles, self._override)
-        bigtop.trigger_puppet()
-        if self.is_zk_leader():
-            zkpeer = RelationBase.from_state('zkpeer.joined')
-            zkpeer.set_zk_leader()
-
-    def start(self):
-        '''
-        Request that our service start. Normally, puppet will handle this
-        for us.
-
-        '''
-        host.service_start('zookeeper-server')
-
-    def stop(self):
-        '''
-        Stop Zookeeper.
-
-        '''
-        host.service_stop('zookeeper-server')
-
-    def open_ports(self):
-        '''
-        Expose the ports in the configuration to the outside world.
-
-        '''
-        for port in self.dist_config.exposed_ports('zookeeper'):
-            open_port(port)
-
-    def close_ports(self):
-        '''
-        Close off communication from the outside world.
-
-        '''
-        for port in self.dist_config.exposed_ports('zookeeper'):
-            close_port(port)
-
-    def quorum_check(self):
-        '''
-        Returns a string reporting the node count. Append a message
-        informing the user if the node count is too low for good quorum,
-        or is even (meaning that one of the nodes is redundant for
-        quorum).
-
-        '''
-        node_count = len(self.read_peers())
-        if node_count == 1:
-            count_str = "{} zk node".format(node_count)
-        else:
-            count_str = "{} zk nodes".format(node_count)
-        if node_count < 3:
-            return " ({}; less than 3 nodes is suboptimal)".format(count_str)
-        if node_count % 2 == 0:
-            return " ({}; an even number is suboptimal)".format(count_str)
-        return "({})".format(count_str)

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/reactive/zookeeper.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/reactive/zookeeper.py 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/reactive/zookeeper.py
index 825c219..a4c7773 100644
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/reactive/zookeeper.py
+++ b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/reactive/zookeeper.py
@@ -16,7 +16,8 @@
 import json
 import time
 from charmhelpers.core import hookenv
-from charms.layer.zookeeper import Zookeeper
+from charms.layer.apache_bigtop_base import get_package_version
+from charms.layer.bigtop_zookeeper import Zookeeper
 from charms.leadership import leader_set, leader_get
 from charms.reactive import set_state, when, when_not, is_state
 from charms.reactive.helpers import data_changed
@@ -44,6 +45,9 @@ def install_zookeeper():
     set_state('zookeeper.installed')
     set_state('zookeeper.started')
     hookenv.status_set('active', 'ready {}'.format(zookeeper.quorum_check()))
+    # set app version string for juju status output
+    zoo_version = get_package_version('zookeeper') or 'unknown'
+    hookenv.application_version_set(zoo_version)
 
 
 def _restart_zookeeper(msg):

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy
deleted file mode 100755
index 744a71f..0000000
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/python3
-
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-import amulet
-
-TIMEOUT = 1800
-
-
-class TestDeploy(unittest.TestCase):
-    """
-    Deployment test for Apache Zookkepper quorum
-    """
-
-    @classmethod
-    def setUpClass(cls):
-        cls.d = amulet.Deployment(series='xenial')
-
-        cls.d.add('zookeeper', charm='zookeeper', units=3)
-
-        cls.d.setup(timeout=TIMEOUT)
-        cls.d.sentry.wait(timeout=TIMEOUT)
-        cls.unit = cls.d.sentry['zookeeper'][0]
-
-    def test_deploy(self):
-        output, retcode = self.unit.run("pgrep -a java")
-        assert 'QuorumPeerMain' in output, "zookeeper QuorumPeerMain daemon is 
not started"
-
-    def test_quorum(self):
-        '''
-        Verify that our peers are talking to each other, and taking on
-        appropriate roles.
-
-        '''
-        self.assertEqual(3, len(self.d.sentry['zookeeper']))
-
-        # Verify that everything worked.
-        for unit in self.d.sentry['zookeeper']:
-            output, _ = unit.run(
-                "/usr/lib/zookeeper/bin/zkServer.sh status"
-            )
-            # Unit should be a leader or follower
-            self.assertTrue("leader" in output or "follower" in output)
-
-    def test_smoke(self):
-        """Validates Zookeeper using the Bigtop 'zookeeper' smoke test."""
-        smk_uuids = []
-
-        for unit in self.d.sentry['zookeeper']:
-            smk_uuids.append(unit.action_do("smoke-test"))
-
-        for smk_uuid in smk_uuids:
-            result = self.d.action_fetch(smk_uuid, full_output=True)
-            # zookeeper smoke-test sets outcome=success on success
-            if (result['outcome'] != "success"):
-                error = "Zookeeper smoke-test failed"
-                amulet.raise_status(amulet.FAIL, msg=error)
-
-if __name__ == '__main__':
-    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy-smoke.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy-smoke.py 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy-smoke.py
new file mode 100755
index 0000000..1ef64d8
--- /dev/null
+++ 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/01-deploy-smoke.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python3
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import amulet
+import unittest
+
+TIMEOUT = 1800
+
+
+class TestDeploy(unittest.TestCase):
+    """
+    Deployment test for Apache Zookeeper quorum
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        cls.d = amulet.Deployment(series='xenial')
+
+        cls.d.add('zookeeper', charm='zookeeper', units=3)
+
+        cls.d.setup(timeout=TIMEOUT)
+        cls.d.sentry.wait_for_messages({'zookeeper': 'ready (3 units)'},
+                                       timeout=TIMEOUT)
+        cls.unit = cls.d.sentry['zookeeper'][0]
+
+    def test_deploy(self):
+        """Verify zk quorum is running"""
+        output, retcode = self.unit.run("pgrep -a java")
+        assert 'QuorumPeerMain' in output, "Zookeeper QuorumPeerMain daemon is 
not started"
+
+    def test_quorum(self):
+        """
+        Verify that our peers are talking to each other, and taking on
+        appropriate roles.
+        """
+        for unit in self.d.sentry['zookeeper']:
+            output, _ = unit.run(
+                "/usr/lib/zookeeper/bin/zkServer.sh status"
+            )
+            # Unit should be a leader or follower
+            self.assertTrue("leader" in output or "follower" in output)
+
+    def test_smoke(self):
+        """Validates Zookeeper using the Bigtop 'zookeeper' smoke test."""
+        smk_uuids = []
+
+        for unit in self.d.sentry['zookeeper']:
+            smk_uuids.append(unit.run_action('smoke-test'))
+
+        for smk_uuid in smk_uuids:
+            # 'zookeeper' smoke takes a while (bigtop tests are slow)
+            result = self.d.action_fetch(smk_uuid, timeout=1800, 
full_output=True)
+            # actions set status=completed on success
+            if (result['status'] != "completed"):
+                self.fail('Zookeeper smoke-test failed: %s' % result)
+
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address
deleted file mode 100755
index 66e42eb..0000000
--- a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/python3
-
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-import re
-import amulet
-import subprocess
-
-DEPLOY_TIMEOUT = 1800
-CONFIG_TIMEOUT = 900
-
-
-class TestBindClientPort(unittest.TestCase):
-    """
-    Test to verify that we can bind to listen for client connections
-    on a specific interface.
-    """
-
-    @classmethod
-    def setUpClass(cls):
-        cls.d = amulet.Deployment(series='xenial')
-
-        cls.d.add('zookeeper', charm='zookeeper', units=3)
-
-        cls.d.setup(timeout=CONFIG_TIMEOUT)
-        cls.d.sentry.wait(timeout=DEPLOY_TIMEOUT)
-        cls.unit = cls.d.sentry['zookeeper'][0]
-
-    def test_bind_port(self):
-        """
-        Test to verify that we update client port bindings successfully.
-
-        """
-        network_interface = None
-        # Regular expression should handle interfaces in the format
-        # eth[n], and in the format en[foo] (the "predicatble
-        # interface names" in v197+ of systemd).
-        ethernet_interface = re.compile('^e[thn]+.*')
-        interfaces, _ = self.unit.run(
-            "ifconfig -a | sed 's/[ \t].*//;/^$/d'")
-        interfaces = interfaces.split()  # Splits on newlines
-        for interface in interfaces:
-            if ethernet_interface.match(interface):
-                network_interface = interface
-                break
-
-        if network_interface is None:
-            raise Exception(
-                "Could not find any interface on the unit that matched my "
-                "criteria.")
-        # self.d.configure broken due to change in juju api. TODO:
-        # switch this out when fixed.
-        subprocess.check_call(
-            ['juju', 'config', 'zookeeper', 'network_interface={}'.format(
-                network_interface)])
-        #self.d.configure('zookeeper', {'network_interface': 
network_interface})
-        self.d.sentry.wait_for_messages(
-            {'zookeeper': 'updating network interface'}, 
timeout=CONFIG_TIMEOUT)
-        self.d.sentry.wait_for_messages(
-            {'zookeeper': 'ready (3 zk nodes)'}, timeout=CONFIG_TIMEOUT)
-        ret = self.unit.run(
-            'grep clientPortAddress /etc/zookeeper/conf/zoo.cfg')[0]
-        matcher = re.compile(
-            "^clientPortAddress=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*")
-
-        self.assertTrue(matcher.match(ret))
-
-        # Verify that smoke tests still run
-        smk_uuid = self.unit.action_do("smoke-test")
-        result = self.d.action_fetch(smk_uuid, full_output=True)
-        # zookeeper smoke-test sets outcome=success on success
-        if (result['outcome'] != "success"):
-            error = "Zookeeper smoke-test failed"
-            amulet.raise_status(amulet.FAIL, msg=error)
-
-    @unittest.skip(
-        'Broken handling of 0.0.0.0 bindings upstream, in Zookeeper project.')
-    def test_reset_bindings(self):
-        """
-        Verify that we can reset the client port bindings to 0.0.0.0
-
-        """
-        self.d.configure('zookeeper', {'network_interface': '0.0.0.0'})
-        self.d.sentry.wait_for_messages(
-            {'zookeeper': 'updating network interface'}, 
timeout=CONFIG_TIMEOUT)
-        self.d.sentry.wait_for_messages(
-            {'zookeeper': 'ready (3 zk nodes)'}, timeout=CONFIG_TIMEOUT)
-        ret = self.unit.run(
-            'grep clientPortAddress /etc/zookeeper/conf/zoo.cfg')[0]
-
-        matcher = re.compile("^clientPortAddress=0\.0\.0\.0.*")
-        self.assertTrue(matcher.match(ret))
-
-        # Verify that smoke tests still run
-        smk_uuid = self.unit.action_do("smoke-test")
-        output = self.d.action_fetch(smk_uuid, full_output=True)
-        assert "completed" in output['status']
-
-
-if __name__ == '__main__':
-    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f4515e8c/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address.py 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address.py
new file mode 100755
index 0000000..8fa2bb7
--- /dev/null
+++ 
b/bigtop-packages/src/charm/zookeeper/layer-zookeeper/tests/10-bind-address.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python3
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import amulet
+import re
+import time
+import unittest
+
+TIMEOUT = 1800
+
+
+class TestBindClientPort(unittest.TestCase):
+    """
+    Test to verify that we can bind to listen for client connections
+    on a specific interface.
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        cls.d = amulet.Deployment(series='xenial')
+
+        cls.d.add('zk-test', charm='zookeeper')
+
+        cls.d.setup(timeout=TIMEOUT)
+        cls.d.sentry.wait_for_messages({'zk-test': re.compile('ready')},
+                                       timeout=TIMEOUT)
+        cls.unit = cls.d.sentry['zk-test'][0]
+
+    def test_bind_port(self):
+        """
+        Verify that we update client port bindings successfully.
+        """
+        network_interface = None
+        # Regular expression should handle interfaces in the format
+        # eth[n], and in the format en[foo] (the "predicatble
+        # interface names" in v197+ of systemd).
+        ethernet_interface = re.compile('^e[thn]+.*')
+        interfaces, _ = self.unit.run(
+            "ifconfig -a | sed 's/[ \t].*//;/^$/d'")
+        interfaces = interfaces.split()  # Splits on newlines
+        for interface in interfaces:
+            if ethernet_interface.match(interface):
+                network_interface = interface
+                break
+
+        if network_interface is None:
+            raise Exception(
+                "Could not find any interface on the unit that matched my "
+                "criteria.")
+        self.d.configure('zk-test', {'network_interface': network_interface})
+
+        # NB: we used to watch for a maintenance status message, but every now
+        # and then, we'd miss it. Wait 2m to let the config-changed hook 
settle.
+        time.sleep(120)
+        ret = self.unit.run(
+            'grep clientPortAddress /etc/zookeeper/conf/zoo.cfg')[0]
+
+        matcher = re.compile(
+            "^clientPortAddress=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*")
+        self.assertTrue(matcher.match(ret))
+
+        # Verify that smoke tests still run
+        smk_uuid = self.unit.run_action('smoke-test')
+        # 'zookeeper' smoke takes a while (bigtop tests are slow)
+        result = self.d.action_fetch(smk_uuid, timeout=1800, full_output=True)
+        # actions set status=completed on success
+        if (result['status'] != "completed"):
+            self.fail('Zookeeper smoke-test failed: %s' % result)
+
+    def test_reset_bindings(self):
+        """
+        Verify that we can reset the client port bindings to 0.0.0.0
+        """
+        self.d.configure('zk-test', {'network_interface': '0.0.0.0'})
+
+        # NB: we used to watch for a maintenance status message, but every now
+        # and then, we'd miss it. Wait 2m to let the config-changed hook 
settle.
+        time.sleep(120)
+        ret = self.unit.run(
+            'grep clientPortAddress /etc/zookeeper/conf/zoo.cfg')[0]
+
+        matcher = re.compile("^clientPortAddress=0\.0\.0\.0.*")
+        self.assertTrue(matcher.match(ret))
+
+        # Verify that smoke tests still run
+        smk_uuid = self.unit.run_action('smoke-test')
+        # 'zookeeper' smoke takes a while (bigtop tests are slow)
+        result = self.d.action_fetch(smk_uuid, timeout=1800, full_output=True)
+        # actions set status=completed on success
+        if (result['status'] != "completed"):
+            self.fail('Zookeeper smoke-test failed: %s' % result)
+
+
+if __name__ == '__main__':
+    unittest.main()

Reply via email to