Repository: bigtop
Updated Branches:
  refs/heads/master f1f5619a3 -> f5e89f4e1


http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/icon.svg
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/icon.svg 
b/bigtop-packages/src/charm/spark/layer-spark/icon.svg
new file mode 100644
index 0000000..a0da80d
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/icon.svg
@@ -0,0 +1,843 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="96"
+   height="96"
+   id="svg6517"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon.svg">
+  <defs
+     id="defs6519">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#Background"
+       id="linearGradient6461"
+       gradientUnits="userSpaceOnUse"
+       x1="0"
+       y1="970.29498"
+       x2="144"
+       y2="970.29498"
+       
gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" />
+    <linearGradient
+       id="Background">
+      <stop
+         id="stop4178"
+         offset="0"
+         style="stop-color:#b8b8b8;stop-opacity:1" />
+      <stop
+         id="stop4180"
+         offset="1"
+         style="stop-color:#c9c9c9;stop-opacity:1" />
+    </linearGradient>
+    <filter
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Inner Shadow"
+       id="filter1121">
+      <feFlood
+         flood-opacity="0.59999999999999998"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood1123" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="out"
+         result="composite1"
+         id="feComposite1125" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="1"
+         result="blur"
+         id="feGaussianBlur1127" />
+      <feOffset
+         dx="0"
+         dy="2"
+         result="offset"
+         id="feOffset1129" />
+      <feComposite
+         in="offset"
+         in2="SourceGraphic"
+         operator="atop"
+         result="composite2"
+         id="feComposite1131" />
+    </filter>
+    <filter
+       style="color-interpolation-filters:sRGB;"
+       inkscape:label="Drop Shadow"
+       id="filter950">
+      <feFlood
+         flood-opacity="0.25"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood952" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite954" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="1"
+         result="blur"
+         id="feGaussianBlur956" />
+      <feOffset
+         dx="0"
+         dy="1"
+         result="offset"
+         id="feOffset958" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite960" />
+    </filter>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath873">
+      <g
+         transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
+         id="g875"
+         inkscape:label="Layer 1"
+         style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
+        <path
+           style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
+           d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 
144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 
-46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 
L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"
+           id="path877"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="sssssssss" />
+      </g>
+    </clipPath>
+    <filter
+       inkscape:collect="always"
+       id="filter891"
+       inkscape:label="Badge Shadow">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.71999962"
+         id="feGaussianBlur893" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.0745362"
+     inkscape:cx="18.514671"
+     inkscape:cy="-0.067172296"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1056"
+     inkscape:window-x="2160"
+     inkscape:window-y="340"
+     inkscape:window-maximized="1"
+     showborder="true"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:showpageshadow="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid821" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="16,48"
+       id="guide823" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="64,80"
+       id="guide825" />
+    <sodipodi:guide
+       orientation="1,0"
+       position="80,40"
+       id="guide827" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="64,16"
+       id="guide829" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata6522">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="BACKGROUND"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(268,-635.29076)"
+     style="display:inline">
+    <path
+       
style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
+       d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 
31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 
0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C 
-264.11215,731.29077 -268,727.39888 -268,700.15563 Z"
+       id="path6455"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="sssssssss" />
+    <image
+       y="636.29077"
+       x="-260.2941"
+       id="image3115"
+       
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFU
+eJzs3XeYVNX5B/Dve869M7O7sCKg9Coo2JC6uxTFroklajQxGjUmUaMmFmyJGmvsMcWoMTGJmqiJ
+SUz9RaOiRulgb4g0AQUBkbZl5t5z3t8fswuIgLuzs7Pt+3mefYTdmXPfmcU57z3lPQARERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER
+EREREREREREREREREREREREREdG2SXMHQERELcecu84assvymYeaeO3+Lo46wAAJsRvS4c5TN3bd
+c+o+F/9xTnPHSPnBBICIiLDgjmNOSS6ffQa8Hxgg7mVFk04CWDhAFc5rBNiVGVv038rOezw29Mpn
+/tvcMVPjMAEgImrHfq5a+qXLBt+SiD8+WW1RJ1EH6yN4AE4CKAQqAqNAgBhQhYesUVvyjw/O//2V
+o/rvv7y5XwPlhgkAEVE79Qf9uPSAScPuDv3Gk42xNtu5G8QSQKCwiKEQCBSAwMNCAYRw8Op9ZIqf
+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
+npYDbiNE9BSJ2QISUA0rAYQIBjCORXcAKKWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU
+UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJK
+KaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSiml
+lFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRS
+SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkop
+pZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU
+UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJK
+KaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSiml
+lFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRS
+SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkop
+pZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU
+UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJK
+KaWUUkoppZRSSimllFJKKaWUqsn/Bw1WfWPJuUdqAAAAAElFTkSuQmCC
+"
+       height="89.999992"
+       width="87.294098" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="PLACE YOUR PICTOGRAM HERE"
+     style="display:inline" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="BADGE"
+     style="display:none"
+     sodipodi:insensitive="true">
+    <g
+       style="display:inline"
+       transform="translate(-340.00001,-581)"
+       id="g4394"
+       clip-path="none">
+      <g
+         id="g855">
+        <g
+           inkscape:groupmode="maskhelper"
+           id="g870"
+           clip-path="url(#clipPath873)"
+           style="opacity:0.6;filter:url(#filter891)">
+          <path
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 
-12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
+             sodipodi:ry="12"
+             sodipodi:rx="12"
+             sodipodi:cy="552.36218"
+             sodipodi:cx="252"
+             id="path844"
+             
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+             sodipodi:type="arc" />
+        </g>
+        <g
+           id="g862">
+          <path
+             sodipodi:type="arc"
+             
style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+             id="path4398"
+             sodipodi:cx="252"
+             sodipodi:cy="552.36218"
+             sodipodi:rx="12"
+             sodipodi:ry="12"
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 
-12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" 
/>
+          <path
+             transform="matrix(1.25,0,0,1.25,33,-100.45273)"
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 
-12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
+             sodipodi:ry="12"
+             sodipodi:rx="12"
+             sodipodi:cy="552.36218"
+             sodipodi:cx="252"
+             id="path4400"
+             
style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+             sodipodi:type="arc" />
+          <path
+             sodipodi:type="star"
+             
style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+             id="path4459"
+             sodipodi:sides="5"
+             sodipodi:cx="666.19574"
+             sodipodi:cy="589.50385"
+             sodipodi:r1="7.2431178"
+             sodipodi:r2="4.3458705"
+             sodipodi:arg1="1.0471976"
+             sodipodi:arg2="1.6755161"
+             inkscape:flatsided="false"
+             inkscape:rounded="0.1"
+             inkscape:randomized="0"
+             d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 
-4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 
-0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 
-2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 
4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 
0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 
4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 
-0.18379,0.41279 0.0427,4.27917 -0.34859,4.5051 z"
+             
transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)"
 />
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/layer.yaml
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/layer.yaml 
b/bigtop-packages/src/charm/spark/layer-spark/layer.yaml
new file mode 100644
index 0000000..b67a34e
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/layer.yaml
@@ -0,0 +1,28 @@
+repo: [email protected]:juju-solutions/layer-apache-bigtop-spark.git
+includes:
+  - 'layer:apache-bigtop-base'
+  - 'layer:hadoop-client'
+  - 'layer:leadership'
+  - 'interface:benchmark'
+  - 'interface:spark'
+  - 'interface:zookeeper'
+  - 'interface:spark-quorum'
+options:
+  hadoop-client:
+    groups:
+        - 'hadoop'
+    dirs:
+      spark_events:
+        path: '/var/log/spark/apps'
+    ports:
+      # Ports that need to be exposed, overridden, or manually specified.
+      # Only expose ports serving a UI or external API (i.e., namenode and
+      # resourcemanager).  Communication among units within the cluster does
+      # not need ports to be explicitly opened.
+      spark-history:
+        port: 18080
+        exposed_on: 'spark'
+      spark-webui:
+        port: 8080
+        exposed_on: 'spark'
+    silent: True

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/lib/charms/layer/bigtop_spark.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/spark/layer-spark/lib/charms/layer/bigtop_spark.py 
b/bigtop-packages/src/charm/spark/layer-spark/lib/charms/layer/bigtop_spark.py
new file mode 100755
index 0000000..52f5e97
--- /dev/null
+++ 
b/bigtop-packages/src/charm/spark/layer-spark/lib/charms/layer/bigtop_spark.py
@@ -0,0 +1,255 @@
+# 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.
+from jujubigdata import utils
+from path import Path
+
+from charms.layer.apache_bigtop_base import Bigtop
+from charms.reactive import is_state
+from charms import layer
+from charmhelpers.core import hookenv, host, unitdata
+from charmhelpers.fetch.archiveurl import ArchiveUrlFetchHandler
+
+
+class Spark(object):
+    """
+    This class manages Spark.
+    """
+    def __init__(self):
+        self.dist_config = utils.DistConfig(
+            data=layer.options('hadoop-client'))
+
+    # translate our execution_mode into the appropriate --master value
+    def get_master_url(self, spark_master_host):
+        mode = hookenv.config()['spark_execution_mode']
+        zk_units = unitdata.kv().get('zookeeper.units', [])
+        master = None
+        if mode.startswith('local') or mode == 'yarn-cluster':
+            master = mode
+        elif mode == 'standalone' and not zk_units:
+            master = 'spark://{}:7077'.format(spark_master_host)
+        elif mode == 'standalone' and zk_units:
+            master_ips = [p[1] for p in unitdata.kv().get('sparkpeer.units')]
+            nodes = []
+            for ip in master_ips:
+                nodes.append('{}:7077'.format(ip))
+            nodes_str = ','.join(nodes)
+            master = 'spark://{}'.format(nodes_str)
+        elif mode.startswith('yarn'):
+            master = 'yarn-client'
+        return master
+
+    def get_roles(self):
+        roles = ['spark-worker', 'spark-client']
+        zk_units = unitdata.kv().get('zookeeper.units', [])
+        if is_state('leadership.is_leader') or zk_units:
+            roles.append('spark-master')
+            roles.append('spark-history-server')
+        return roles
+
+    def install_benchmark(self):
+        install_sb = hookenv.config()['spark_bench_enabled']
+        sb_dir = '/home/ubuntu/spark-bench'
+        if install_sb:
+            if not unitdata.kv().get('spark_bench.installed', False):
+                if utils.cpu_arch() == 'ppc64le':
+                    sb_url = hookenv.config()['spark_bench_ppc64le']
+                else:
+                    # TODO: may need more arch cases (go with x86 sb for now)
+                    sb_url = hookenv.config()['spark_bench_x86_64']
+
+                Path(sb_dir).rmtree_p()
+                au = ArchiveUrlFetchHandler()
+                au.install(sb_url, '/home/ubuntu')
+
+                # #####
+                # Handle glob if we use a .tgz that doesn't expand to sb_dir
+                # sb_archive_dir = glob('/home/ubuntu/spark-bench-*')[0]
+                # SparkBench expects to live in ~/spark-bench, so put it there
+                # Path(sb_archive_dir).rename(sb_dir)
+                # #####
+
+                unitdata.kv().set('spark_bench.installed', True)
+                unitdata.kv().flush(True)
+        else:
+            Path(sb_dir).rmtree_p()
+            unitdata.kv().set('spark_bench.installed', False)
+            unitdata.kv().flush(True)
+
+    def setup(self):
+        self.dist_config.add_users()
+        self.dist_config.add_dirs()
+        self.install_demo()
+        self.open_ports()
+
+    def setup_hdfs_logs(self):
+        # create hdfs storage space for history server
+        dc = self.dist_config
+        events_dir = dc.path('spark_events')
+        events_dir = 'hdfs://{}'.format(events_dir)
+        utils.run_as('hdfs', 'hdfs', 'dfs', '-mkdir', '-p', events_dir)
+        utils.run_as('hdfs', 'hdfs', 'dfs', '-chown', '-R', 'ubuntu:spark',
+                     events_dir)
+        return events_dir
+
+    def configure(self, available_hosts, zk_units, peers):
+        """
+        This is the core logic of setting up spark.
+
+        Two flags are needed:
+
+          * Namenode exists aka HDFS is there
+          * Resource manager exists aka YARN is ready
+
+        both flags are infered from the available hosts.
+
+        :param dict available_hosts: Hosts that Spark should know about.
+        """
+        unitdata.kv().set('zookeeper.units', zk_units)
+        unitdata.kv().set('sparkpeer.units', peers)
+        unitdata.kv().flush(True)
+
+        if not unitdata.kv().get('spark.bootstrapped', False):
+            self.setup()
+            unitdata.kv().set('spark.bootstrapped', True)
+
+        self.install_benchmark()
+
+        master_ip = 
utils.resolve_private_address(available_hosts['spark-master'])
+        hosts = {
+            'spark': master_ip,
+        }
+
+        dc = self.dist_config
+        events_log_dir = 'file://{}'.format(dc.path('spark_events'))
+        if 'namenode' in available_hosts:
+            hosts['namenode'] = available_hosts['namenode']
+            events_log_dir = self.setup_hdfs_logs()
+
+        if 'resourcemanager' in available_hosts:
+            hosts['resourcemanager'] = available_hosts['resourcemanager']
+
+        roles = self.get_roles()
+
+        override = {
+            'spark::common::master_url': self.get_master_url(master_ip),
+            'spark::common::event_log_dir': events_log_dir,
+            'spark::common::history_log_dir': events_log_dir,
+        }
+
+        if zk_units:
+            zks = []
+            for unit in zk_units:
+                ip = utils.resolve_private_address(unit['host'])
+                zks.append("%s:%s" % (ip, unit['port']))
+
+            zk_connect = ",".join(zks)
+            override['spark::common::zookeeper_connection_string'] = zk_connect
+        else:
+            override['spark::common::zookeeper_connection_string'] = ""
+
+        bigtop = Bigtop()
+        bigtop.render_site_yaml(hosts, roles, override)
+        bigtop.trigger_puppet()
+        # There is a race condition here.
+        # The work role will not start the first time we trigger puppet apply.
+        # The exception in /var/logs/spark:
+        # Exception in thread "main" org.apache.spark.SparkException: Invalid 
master URL: spark://:7077
+        # The master url is not set at the time the worker start the first 
time.
+        # TODO(kjackal): ...do the needed... (investiate,debug,submit patch)
+        bigtop.trigger_puppet()
+        if 'namenode' not in available_hosts:
+            # Local event dir (not in HDFS) needs to be 777 so non-spark
+            # users can write job history there. It needs to be g+s so
+            # spark (in the spark group) can read non-spark user entries.
+            dc.path('spark_events').chmod(0o2777)
+
+        self.patch_worker_master_url(master_ip)
+
+    def patch_worker_master_url(self, master_ip):
+        '''
+        Patch the worker startup script to use the full master url istead of 
contracting it.
+        The master url is placed in the spark-env.sh so that the startup 
script will use it.
+        In HA mode the master_ip is set to be the local_ip instead of the one 
the leader
+        elects. This requires a restart of the master service.
+        '''
+        master_url = self.get_master_url(master_ip)
+        zk_units = unitdata.kv().get('zookeeper.units', [])
+        if master_url.startswith('spark://'):
+            if zk_units:
+                master_ip = hookenv.unit_private_ip()
+            spark_env = '/etc/spark/conf/spark-env.sh'
+            utils.re_edit_in_place(spark_env, {
+                r'.*SPARK_MASTER_URL.*': "export 
SPARK_MASTER_URL={}".format(master_url),
+                r'.*SPARK_MASTER_IP.*': "export 
SPARK_MASTER_IP={}".format(master_ip),
+            }, append_non_matches=True)
+
+            self.inplace_change('/etc/init.d/spark-worker',
+                                'spark://$SPARK_MASTER_IP:$SPARK_MASTER_PORT',
+                                '$SPARK_MASTER_URL')
+            host.service_restart('spark-master')
+            host.service_restart('spark-worker')
+
+    def inplace_change(self, filename, old_string, new_string):
+        # Safely read the input filename using 'with'
+        with open(filename) as f:
+            s = f.read()
+            if old_string not in s:
+                return
+
+        # Safely write the changed content, if found in the file
+        with open(filename, 'w') as f:
+            s = s.replace(old_string, new_string)
+            f.write(s)
+
+    def install_demo(self):
+        '''
+        Install sparkpi.sh to /home/ubuntu (executes SparkPI example app)
+        '''
+        demo_source = 'scripts/sparkpi.sh'
+        demo_target = '/home/ubuntu/sparkpi.sh'
+        Path(demo_source).copy(demo_target)
+        Path(demo_target).chmod(0o755)
+        Path(demo_target).chown('ubuntu', 'hadoop')
+
+    def start(self):
+        if unitdata.kv().get('spark.uprading', False):
+            return
+
+        # stop services (if they're running) to pick up any config change
+        self.stop()
+        # always start the history server, start master/worker if we're 
standalone
+        host.service_start('spark-history-server')
+        if hookenv.config()['spark_execution_mode'] == 'standalone':
+            host.service_start('spark-master')
+            host.service_start('spark-worker')
+
+    def stop(self):
+        if not unitdata.kv().get('spark.installed', False):
+            return
+        # Only stop services if they're running
+        if utils.jps("HistoryServer"):
+            host.service_stop('spark-history-server')
+        if utils.jps("Master"):
+            host.service_stop('spark-master')
+        if utils.jps("Worker"):
+            host.service_stop('spark-worker')
+
+    def open_ports(self):
+        for port in self.dist_config.exposed_ports('spark'):
+            hookenv.open_port(port)
+
+    def close_ports(self):
+        for port in self.dist_config.exposed_ports('spark'):
+            hookenv.close_port(port)

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/metadata.yaml
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/metadata.yaml 
b/bigtop-packages/src/charm/spark/layer-spark/metadata.yaml
new file mode 100644
index 0000000..efec6f0
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/metadata.yaml
@@ -0,0 +1,19 @@
+name: spark
+summary: Apache Spark from Apache Bigtop platform
+maintainer: Juju Big Data <[email protected]>
+description: >
+  Apache Spark is a fast and general engine for large-scale data processing.
+
+  Learn more at http://spark.apache.org.
+tags: ["applications"]
+provides:
+  benchmark:
+    interface: benchmark
+  client:
+    interface: spark
+requires:
+  zookeeper:
+    interface: zookeeper
+peers:
+  sparkpeers:
+    interface: spark-quorum

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/reactive/spark.py
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/reactive/spark.py 
b/bigtop-packages/src/charm/spark/layer-spark/reactive/spark.py
new file mode 100644
index 0000000..bb36401
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/reactive/spark.py
@@ -0,0 +1,171 @@
+# 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.
+from charms.reactive import RelationBase, when, when_not, is_state, set_state, 
remove_state, when_any
+from charms.layer.apache_bigtop_base import get_fqdn
+from charms.layer.bigtop_spark import Spark
+from charmhelpers.core import hookenv
+from charms import leadership
+from charms.reactive.helpers import data_changed
+from jujubigdata import utils
+from charms import layer
+
+
+def set_deployment_mode_state(state):
+    if is_state('spark.yarn.installed'):
+        remove_state('spark.yarn.installed')
+    if is_state('spark.standalone.installed'):
+        remove_state('spark.standalone.installed')
+    remove_state('spark.ready.to.install')
+    set_state('spark.started')
+    set_state(state)
+
+
+def report_status():
+    mode = hookenv.config()['spark_execution_mode']
+    if (not is_state('spark.yarn.installed')) and mode.startswith('yarn'):
+        hookenv.status_set('blocked',
+                           'yarn execution mode not available')
+        return
+
+    if mode == 'standalone' and is_state('zookeeper.ready'):
+        mode = mode + " - HA"
+    elif mode == 'standalone' and is_state('leadership.is_leader'):
+        mode = mode + " - master"
+
+    hookenv.status_set('active', 'ready ({})'.format(mode))
+
+
+def install_spark(hadoop=None, zks=None):
+    spark_master_host = leadership.leader_get('master-fqdn')
+    if not spark_master_host:
+        hookenv.status_set('waiting', 'master not elected yet')
+        return False
+
+    hosts = {
+        'spark-master': spark_master_host,
+    }
+
+    if is_state('hadoop.yarn.ready'):
+        rms = hadoop.resourcemanagers()
+        hosts['resourcemanager'] = rms[0]
+
+    if is_state('hadoop.hdfs.ready'):
+        nns = hadoop.namenodes()
+        hosts['namenode'] = nns[0]
+
+    spark = Spark()
+    spark.configure(hosts, zks, get_spark_peers())
+    return True
+
+
+@when('config.changed', 'spark.started')
+def reconfigure_spark():
+    config = hookenv.config()
+    mode = config['spark_execution_mode']
+    hookenv.status_set('maintenance',
+                       'changing default execution mode to {}'.format(mode))
+
+    hadoop = (RelationBase.from_state('hadoop.yarn.ready') or
+              RelationBase.from_state('hadoop.hdfs.ready'))
+
+    zks = None
+    if is_state('zookeeper.ready'):
+        zk = RelationBase.from_state('zookeeper.ready')
+        zks = zk.zookeepers()
+
+    if install_spark(hadoop, zks):
+        report_status()
+
+
+# This is a triky call. We want to fire when the leader changes, yarn and hdfs 
become ready or
+# depart. In the future this should fire when Cassandra or any other storage
+# becomes ready or departs. Since hdfs and yarn do not have a departed state 
we make sure
+# we fire this method always ('spark.started'). We then build a 
deployment-matrix
+# and if anything has changed we re-install.
+# 'hadoop.yarn.ready', 'hadoop.hdfs.ready' can be ommited but I like them here 
for clarity
+@when_any('hadoop.yarn.ready',
+          'hadoop.hdfs.ready', 'master.elected', 'sparkpeers.joined', 
'zookeeper.ready')
+@when('bigtop.available', 'master.elected')
+def reinstall_spark():
+    spark_master_host = leadership.leader_get('master-fqdn')
+    peers = []
+    zks = []
+    if is_state('zookeeper.ready'):
+        # if ZK is availuable we are in HA. We do not want reconfigurations if 
a leader fails
+        # HA takes care of this
+        spark_master_host = ''
+        zk = RelationBase.from_state('zookeeper.ready')
+        zks = zk.zookeepers()
+        # We need reconfigure Spark when in HA and peers change ignore 
otherwise
+        peers = get_spark_peers()
+
+    deployment_matrix = {
+        'spark_master': spark_master_host,
+        'yarn_ready': is_state('hadoop.yarn.ready'),
+        'hdfs_ready': is_state('hadoop.hdfs.ready'),
+        'zookeepers': zks,
+        'peers': peers,
+    }
+
+    if not data_changed('deployment_matrix', deployment_matrix):
+        return
+
+    hookenv.status_set('maintenance', 'configuring spark')
+    hadoop = (RelationBase.from_state('hadoop.yarn.ready') or
+              RelationBase.from_state('hadoop.hdfs.ready'))
+    if install_spark(hadoop, zks):
+        if is_state('hadoop.yarn.ready'):
+            set_deployment_mode_state('spark.yarn.installed')
+        else:
+            set_deployment_mode_state('spark.standalone.installed')
+
+        report_status()
+
+
+def get_spark_peers():
+    nodes = [(hookenv.local_unit(), hookenv.unit_private_ip())]
+    sparkpeer = RelationBase.from_state('sparkpeers.joined')
+    if sparkpeer:
+        nodes.extend(sorted(sparkpeer.get_nodes()))
+    return nodes
+
+
+@when('leadership.is_leader', 'bigtop.available')
+def send_fqdn():
+    spark_master_host = get_fqdn()
+    leadership.leader_set({'master-fqdn': spark_master_host})
+    hookenv.log("Setting leader to {}".format(spark_master_host))
+
+
+@when('leadership.changed.master-fqdn')
+def leader_elected():
+    set_state("master.elected")
+
+
+@when('spark.started', 'client.joined')
+def client_present(client):
+    if is_state('leadership.is_leader'):
+        client.set_spark_started()
+        spark = Spark()
+        master_ip = utils.resolve_private_address(hookenv.unit_private_ip())
+        master_url = spark.get_master_url(master_ip)
+        client.send_master_info(master_url, master_ip)
+
+
+@when('client.joined')
+@when_not('spark.started')
+def client_should_stop(client):
+    if is_state('leadership.is_leader'):
+        client.clear_spark_started()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/scripts/sparkpi.sh
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/scripts/sparkpi.sh 
b/bigtop-packages/src/charm/spark/layer-spark/scripts/sparkpi.sh
new file mode 100755
index 0000000..3a34549
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/scripts/sparkpi.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+set -eu
+
+echo "Running SparkPi"
+spark-submit --class org.apache.spark.examples.SparkPi 
/usr/lib/spark/lib/spark-examples-*.jar 10
+echo ""

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/tests/01-basic-deployment.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/spark/layer-spark/tests/01-basic-deployment.py 
b/bigtop-packages/src/charm/spark/layer-spark/tests/01-basic-deployment.py
new file mode 100755
index 0000000..f4022e1
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/tests/01-basic-deployment.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env 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
+
+
+class TestDeploy(unittest.TestCase):
+    """
+    Trivial deployment test for Apache Spark.
+    """
+
+    def test_deploy(self):
+        self.d = amulet.Deployment(series='trusty')
+        self.d.add('spark', 'spark')
+        self.d.setup(timeout=900)
+        self.d.sentry.wait(timeout=1800)
+        self.unit = self.d.sentry['spark'][0]
+
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/tests/02-smoke-test.py
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/tests/02-smoke-test.py 
b/bigtop-packages/src/charm/spark/layer-spark/tests/02-smoke-test.py
new file mode 100755
index 0000000..bb179a2
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/tests/02-smoke-test.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env 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
+
+
+class TestDeploy(unittest.TestCase):
+    """
+    Deployment and smoke-test of Apache Spark.
+    """
+    @classmethod
+    def setUpClass(cls):
+        cls.d = amulet.Deployment(series='trusty')
+        cls.d.add('openjdk', 'openjdk')
+        cls.d.add('spark', 'spark')
+        cls.d.relate('spark:java', 'openjdk:java')
+        cls.d.setup(timeout=900)
+        cls.d.sentry.wait(timeout=1800)
+
+    def test_deploy(self):
+        self.d.sentry.wait_for_messages({
+            "spark": "ready (standalone - master)",
+        })
+        spark = self.d.sentry['spark'][0]
+        smk_uuid = spark.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/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/tests/03-scale-standalone.py
----------------------------------------------------------------------
diff --git 
a/bigtop-packages/src/charm/spark/layer-spark/tests/03-scale-standalone.py 
b/bigtop-packages/src/charm/spark/layer-spark/tests/03-scale-standalone.py
new file mode 100755
index 0000000..38f1290
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/tests/03-scale-standalone.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env 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
+import time
+
+
+class TestScaleStandalone(unittest.TestCase):
+    """
+    Test scaling of Apache Spark in standalone mode.
+    """
+    @classmethod
+    def setUpClass(cls):
+        cls.d = amulet.Deployment(series='trusty')
+        cls.d.add('sparkscale', 'spark', units=3)
+        cls.d.add('openjdk', 'openjdk')
+        cls.d.relate('openjdk:java', 'sparkscale:java')
+        cls.d.setup(timeout=1800)
+        cls.d.sentry.wait(timeout=1800)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.d.remove_service('sparkscale')
+
+    def test_scaleup(self):
+        """
+        Wait for all three spark units to agree on a master.
+        Remove the master.
+        Check that all units agree on the same new master.
+        """
+        print("Waiting for units to become ready.")
+        self.d.sentry.wait_for_messages({"sparkscale": ["ready (standalone - 
master)",
+                                                        "ready (standalone)",
+                                                        "ready 
(standalone)"]}, timeout=900)
+
+        print("Waiting for units to agree on master.")
+        time.sleep(60)
+
+        spark0_unit = self.d.sentry['sparkscale'][0]
+        spark1_unit = self.d.sentry['sparkscale'][1]
+        spark2_unit = self.d.sentry['sparkscale'][2]
+        (stdout0, errcode0) = spark0_unit.run('grep spark.master 
/etc/spark/conf/spark-defaults.conf')
+        (stdout1, errcode1) = spark1_unit.run('grep spark.master 
/etc/spark/conf/spark-defaults.conf')
+        (stdout2, errcode2) = spark2_unit.run('grep spark.master 
/etc/spark/conf/spark-defaults.conf')
+        # ensure units agree on the master
+        assert stdout0 == stdout2
+        assert stdout1 == stdout2
+
+        master_name = ''
+        for unit in self.d.sentry['sparkscale']:
+            (stdout, stderr) = unit.run("pgrep -f \"[M]aster\"")
+            lines = len(stdout.split('\n'))
+            if lines > 0:
+                master_name = unit.info['unit_name']
+                print("Killin master {}".format(master_name))
+                self.d.remove_unit(master_name)
+                break
+
+        print("Waiting for the cluster to select a new master.")
+        time.sleep(60)
+        self.d.sentry.wait_for_messages({"sparkscale": ["ready (standalone - 
master)",
+                                                        "ready 
(standalone)"]}, timeout=900)
+
+        spark1_unit = self.d.sentry['sparkscale'][0]
+        spark2_unit = self.d.sentry['sparkscale'][1]
+        (stdout1, errcode1) = spark1_unit.run('grep spark.master 
/etc/spark/conf/spark-defaults.conf')
+        (stdout2, errcode2) = spark2_unit.run('grep spark.master 
/etc/spark/conf/spark-defaults.conf')
+        # ensure units agree on the master
+        assert stdout1 == stdout2
+
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/tests/10-test-ha.py
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/tests/10-test-ha.py 
b/bigtop-packages/src/charm/spark/layer-spark/tests/10-test-ha.py
new file mode 100755
index 0000000..6f5c6ff
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/tests/10-test-ha.py
@@ -0,0 +1,94 @@
+#!/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 time
+import unittest
+import requests
+
+
+class TestDeployment(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.d = amulet.Deployment(series='trusty')
+        cls.d.add('sparkha', 'spark', units=3)
+        cls.d.add('openjdk', 'openjdk')
+        cls.d.add('zk', 'zookeeper')
+        cls.d.expose('sparkha')
+        cls.d.relate('openjdk:java', 'sparkha:java')
+        cls.d.relate('zk:zookeeper', 'sparkha:zookeeper')
+        try:
+            cls.d.relate('zk:java', 'openjdk:java')
+        except ValueError:
+            # No need to related older versions of the zookeeper charm
+            # to java.
+            pass
+        cls.d.setup(timeout=1800)
+        cls.d.sentry.wait(timeout=1800)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.d.remove_service('sparkha')
+
+    def test_master_selected(self):
+        '''
+        Wait for all three spark units to agree on a master leader.
+        Remove the leader unit.
+        Check that a new leader is elected.
+        '''
+        self.d.sentry.wait_for_messages({"sparkha": ["ready (standalone - HA)",
+                                                     "ready (standalone - HA)",
+                                                     "ready (standalone - 
HA)"]}, timeout=900)
+        # Give some slack for the spark units to elect a master
+        time.sleep(60)
+        master = ''
+        masters_count = 0
+        for unit in self.d.sentry['sparkha']:
+            ip = unit.info['public-address']
+            url = 'http://{}:8080'.format(ip)
+            homepage = requests.get(url)
+            if 'ALIVE' in homepage.text:
+                masters_count += 1
+                master = unit.info['unit_name']
+            else:
+                assert 'STANDBY' in homepage.text
+
+        assert masters_count == 1
+
+        print("Removing master: {} ".format(master))
+        self.d.remove_unit(master)
+        time.sleep(120)
+
+        self.d.sentry.wait_for_messages({"sparkha": ["ready (standalone - HA)",
+                                                     "ready (standalone - 
HA)"]}, timeout=900)
+
+        masters_count = 0
+        for unit in self.d.sentry['sparkha']:
+            ip = unit.info['public-address']
+            url = 'http://{}:8080'.format(ip)
+            homepage = requests.get(url)
+            if 'ALIVE' in homepage.text:
+                print("New master is {}".format(unit.info['unit_name']))
+                masters_count += 1
+            else:
+                assert 'STANDBY' in homepage.text
+
+        assert masters_count == 1
+
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/tests/tests.yaml
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/tests/tests.yaml 
b/bigtop-packages/src/charm/spark/layer-spark/tests/tests.yaml
new file mode 100644
index 0000000..3b6ce3e
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/tests/tests.yaml
@@ -0,0 +1,3 @@
+reset: false
+packages:
+  - amulet

http://git-wip-us.apache.org/repos/asf/bigtop/blob/f5e89f4e/bigtop-packages/src/charm/spark/layer-spark/wheelhouse.txt
----------------------------------------------------------------------
diff --git a/bigtop-packages/src/charm/spark/layer-spark/wheelhouse.txt 
b/bigtop-packages/src/charm/spark/layer-spark/wheelhouse.txt
new file mode 100644
index 0000000..183242f
--- /dev/null
+++ b/bigtop-packages/src/charm/spark/layer-spark/wheelhouse.txt
@@ -0,0 +1 @@
+charms.benchmark>=1.0.0,<2.0.0

Reply via email to