1#!/usr/bin/env python
2
3# TODO: add installer support for membasez
4
5import getopt
6import copy, re
7import logging
8import os
9import sys
10from threading import Thread
11from datetime import datetime
12import socket
13import Queue
14
15sys.path = [".", "lib"] + sys.path
16import testconstants
17import time
18from builds.build_query import BuildQuery
19import logging.config
20from membase.api.exception import ServerUnavailableException
21from membase.api.rest_client import RestConnection, RestHelper
22from remote.remote_util import RemoteMachineShellConnection, RemoteUtilHelper
23from membase.helper.cluster_helper import ClusterOperationHelper
24from testconstants import MV_LATESTBUILD_REPO
25from testconstants import SHERLOCK_BUILD_REPO
26from testconstants import COUCHBASE_REPO
27from testconstants import CB_REPO, CB_DOWNLOAD_SERVER, CB_DOWNLOAD_SERVER_FQDN
28from testconstants import COUCHBASE_VERSION_2
29from testconstants import COUCHBASE_VERSION_3, COUCHBASE_FROM_WATSON,\
30                          COUCHBASE_FROM_SPOCK
31from testconstants import CB_VERSION_NAME, COUCHBASE_FROM_VERSION_4,\
32                          CB_RELEASE_BUILDS, COUCHBASE_VERSIONS
33from testconstants import MIN_KV_QUOTA, INDEX_QUOTA, FTS_QUOTA, CBAS_QUOTA
34from testconstants import LINUX_COUCHBASE_PORT_CONFIG_PATH, LINUX_COUCHBASE_OLD_CONFIG_PATH
35from testconstants import WIN_COUCHBASE_PORT_CONFIG_PATH, WIN_COUCHBASE_OLD_CONFIG_PATH
36import TestInput
37
38
39logging.config.fileConfig("scripts.logging.conf")
40log = logging.getLogger()
41
42def usage(err=None):
43    print """\
44Syntax: install.py [options]
45
46Options:
47 -p <key=val,...> Comma-separated key=value info.
48 -i <file>        Path to .ini file containing cluster information.
49
50Available keys:
51 product=cb|mb              Used to specify couchbase or membase.
52 version=SHORT_VERSION      Example: "2.0.0r-71".
53 parallel=false             Useful when you're installing a cluster.
54 toy=                       Install a toy build
55 init_nodes=False           Initialize nodes
56 vbuckets=                  The number of vbuckets in the server installation.
57 sync_threads=True          Sync or acync threads(+S or +A)
58 erlang_threads=            Number of erlang threads (default=16:16 for +S type)
59 upr=True                   Enable UPR replication
60 xdcr_upr=                  Enable UPR for XDCR (temporary param until XDCR with UPR is stable), values: None | True | False
61 fts_query_limit=1000000    Set a limit for the max results to be returned by fts for any query
62 change_indexer_ports=false Sets indexer ports values to non-default ports
63 storage_mode=plasma        Sets indexer storage mode
64 enable_ipv6=False          Enable ipv6 mode in ns_server
65
66
67Examples:
68 install.py -i /tmp/ubuntu.ini -p product=cb,version=2.2.0-792
69 install.py -i /tmp/ubuntu.ini -p product=cb,version=2.2.0-792,url=http://builds.hq.northscale.net/latestbuilds....
70 install.py -i /tmp/ubuntu.ini -p product=mb,version=1.7.1r-38,parallel=true,toy=keith
71 install.py -i /tmp/ubuntu.ini -p product=mongo,version=2.0.2
72 install.py -i /tmp/ubuntu.ini -p product=cb,version=0.0.0-704,toy=couchstore,parallel=true,vbuckets=1024
73
74 # to run with build with require openssl version 1.0.0
75 install.py -i /tmp/ubuntu.ini -p product=cb,version=2.2.0-792,openssl=1
76
77 # to install latest release of couchbase server via repo (apt-get and yum)
78  install.py -i /tmp/ubuntu.ini -p product=cb,linux_repo=true
79
80 # to install non-root non default path, add nr_install_dir params
81   install.py -i /tmp/ubuntu.ini -p product=cb,version=5.0.0-1900,nr_install_dir=testnow1
82
83"""
84    sys.exit(err)
85
86
87product = "membase-server(ms),couchbase-single-server(css),couchbase-server(cs),zynga(z)"
88
89errors = {"UNREACHABLE": "",
90          "UNINSTALL-FAILED": "unable to uninstall the product",
91          "INSTALL-FAILED": "unable to install",
92          "BUILD-NOT-FOUND": "unable to find build",
93          "INVALID-PARAMS": "invalid params given"}
94
95
96def installer_factory(params):
97    if params.get("product", None) is None:
98        sys.exit("ERROR: don't know what product you want installed")
99
100    mb_alias = ["membase", "membase-server", "mbs", "mb"]
101    cb_alias = ["couchbase", "couchbase-server", "cb", "cbas"]
102    sdk_alias = ["python-sdk", "pysdk"]
103    es_alias = ["elasticsearch"]
104    css_alias = ["couchbase-single", "couchbase-single-server", "css"]
105    mongo_alias = ["mongo"]
106    moxi_alias = ["moxi", "moxi-server"]
107
108    if params["product"] in mb_alias:
109        return MembaseServerInstaller()
110    elif params["product"] in cb_alias:
111        return CouchbaseServerInstaller()
112    elif params["product"] in mongo_alias:
113        return MongoInstaller()
114    elif params["product"] in moxi_alias:
115        return MoxiInstaller()
116    elif params["product"] in sdk_alias:
117        return SDKInstaller()
118    elif params["product"] in es_alias:
119        return ESInstaller()
120
121    sys.exit("ERROR: don't know about product " + params["product"])
122
123
124class Installer(object):
125
126    def install(self, params):
127        pass
128
129    def initialize(self, params):
130        pass
131
132    def uninstall(self, params):
133        remote_client = RemoteMachineShellConnection(params["server"])
134        #remote_client.membase_uninstall()
135
136        self.msi = 'msi' in params and params['msi'].lower() == 'true'
137        remote_client.couchbase_uninstall(windows_msi=self.msi,product=params['product'])
138        remote_client.disconnect()
139
140
141    def build_url(self, params):
142        _errors = []
143        version = ''
144        server = ''
145        openssl = ''
146        names = []
147        url = ''
148        direct_build_url = None
149
150        # replace "v" with version
151        # replace p with product
152        tmp = {}
153        for k in params:
154            value = params[k]
155            if k == "v":
156                tmp["version"] = value
157            elif k == "p":
158                tmp["version"] = value
159            else:
160                tmp[k] = value
161        params = tmp
162
163        ok = True
164        if not "version" in params and len(params["version"]) < 5:
165            _errors.append(errors["INVALID-PARAMS"])
166            ok = False
167        else:
168            version = params["version"]
169
170        if ok:
171            if not "product" in params:
172                _errors.append(errors["INVALID-PARAMS"])
173                ok = False
174        if ok:
175            if not "server" in params:
176                _errors.append(errors["INVALID-PARAMS"])
177                ok = False
178            else:
179                server = params["server"]
180
181        if ok:
182            if "toy" in params:
183                toy = params["toy"]
184            else:
185                toy = ""
186
187        if ok:
188            if "openssl" in params:
189                openssl = params["openssl"]
190
191        if ok:
192            if "url" in params and params["url"] != ""\
193               and isinstance(params["url"], str):
194                direct_build_url = params["url"]
195        if ok:
196            if "linux_repo" in params and params["linux_repo"].lower() == "true":
197                linux_repo = True
198            else:
199                linux_repo = False
200        if ok:
201            if "msi" in params and params["msi"].lower() == "true":
202                msi = True
203            else:
204                msi = False
205        if ok:
206            mb_alias = ["membase", "membase-server", "mbs", "mb"]
207            cb_alias = ["couchbase", "couchbase-server", "cb"]
208            css_alias = ["couchbase-single", "couchbase-single-server", "css"]
209            moxi_alias = ["moxi", "moxi-server"]
210            cbas_alias = ["cbas", "server-analytics"]
211
212            if params["product"] in cbas_alias:
213                names = ['couchbase-server-analytics', 'server-analytics']
214            elif params["product"] in mb_alias:
215                names = ['membase-server-enterprise', 'membase-server-community']
216            elif params["product"] in cb_alias:
217                if "type" in params and params["type"].lower() in "couchbase-server-community":
218                    names = ['couchbase-server-community']
219                elif "type" in params and params["type"].lower() in "couchbase-server-enterprise":
220                    names = ['couchbase-server-enterprise']
221                else:
222                    names = ['couchbase-server-enterprise', 'couchbase-server-community']
223            elif params["product"] in css_alias:
224                names = ['couchbase-single-server-enterprise', 'couchbase-single-server-community']
225            elif params["product"] in moxi_alias:
226                names = ['moxi-server']
227            else:
228                ok = False
229                _errors.append(errors["INVALID-PARAMS"])
230            if "1" in openssl:
231                names = ['couchbase-server-enterprise_centos6', 'couchbase-server-community_centos6', \
232                         'couchbase-server-enterprise_ubuntu_1204', 'couchbase-server-community_ubuntu_1204']
233            if "toy" in params:
234                names = ['couchbase-server-enterprise']
235
236        remote_client = RemoteMachineShellConnection(server)
237        info = remote_client.extract_remote_info()
238        print "\n*** OS version of this server %s is %s ***" % (remote_client.ip,
239                                                       info.distribution_version)
240        if info.distribution_version.lower() == "suse 12":
241            if version[:5] not in COUCHBASE_FROM_SPOCK:
242                mesg = "%s does not support cb version %s \n" % \
243                         (info.distribution_version, version[:5])
244                remote_client.stop_current_python_running(mesg)
245        if info.type.lower() == "windows":
246            if "-" in version:
247                msi_build = version.split("-")
248                """
249                    In spock from build 2924 and later release, we only support
250                    msi installation method on windows
251                """
252                if "2k8" in info.windows_name:
253                    info.windows_name = 2008
254
255                if msi_build[0] in COUCHBASE_FROM_SPOCK:
256                    info.deliverable_type = "msi"
257                elif "5" > msi_build[0] and info.windows_name == 2016:
258                    log.info("\n========\n"
259                        "         Build version %s does not support on\n"
260                        "         Windows Server 2016\n"
261                        "========"  % msi_build[0])
262                    os.system("ps aux | grep python | grep %d " % os.getpid())
263                    time.sleep(5)
264                    os.system('kill %d' % os.getpid())
265            else:
266                print "Incorrect version format"
267                sys.exit()
268        remote_client.disconnect()
269        if ok and not linux_repo:
270            timeout = 300
271            if "timeout" in params:
272                timeout = int(params["timeout"])
273            releases_version = ["1.6.5.4", "1.7.0", "1.7.1", "1.7.1.1", "1.8.0"]
274            cb_releases_version = ["1.8.1", "2.0.0", "2.0.1", "2.1.0", "2.1.1", "2.2.0",
275                                    "2.5.0", "2.5.1", "2.5.2", "3.0.0", "3.0.1", "3.0.2",
276                                    "3.0.3", "3.1.0", "3.1.1", "3.1.2", "3.1.3", "3.1.5","3.1.6",
277                                    "4.0.0", "4.0.1", "4.1.0", "4.1.1", "4.1.2", "4.5.0"]
278            build_repo = MV_LATESTBUILD_REPO
279            if toy is not "":
280                build_repo = CB_REPO
281            elif "server-analytics" in names:
282                build_repo = CB_REPO.replace("couchbase-server", "server-analytics") + CB_VERSION_NAME[version[:3]] + "/"
283            elif "moxi-server" in names and version[:5] != "2.5.2":
284                print "version   ", version
285                """
286                moxi repo:
287                   http://172.23.120.24/builds/latestbuilds/moxi/4.6.0/101/moxi-server..
288                """
289                build_repo = CB_REPO.replace("couchbase-server", "moxi") + version[:5] + "/"
290            elif version[:5] not in COUCHBASE_VERSION_2 and \
291                 version[:5] not in COUCHBASE_VERSION_3:
292                if version[:3] in CB_VERSION_NAME:
293                    build_repo = CB_REPO + CB_VERSION_NAME[version[:3]] + "/"
294                else:
295                    sys.exit("version is not support yet")
296            if 'enable_ipv6' in params and params['enable_ipv6']:
297                build_repo = build_repo.replace(CB_DOWNLOAD_SERVER,
298                                                CB_DOWNLOAD_SERVER_FQDN)
299            for name in names:
300                if version[:5] in releases_version:
301                    build = BuildQuery().find_membase_release_build(
302                                             deliverable_type=info.deliverable_type,
303                                             os_architecture=info.architecture_type,
304                                             build_version=version,
305                                             product='membase-server-enterprise')
306                elif len(version) > 6 and version[6:].replace("-rel", "") == \
307                                                    CB_RELEASE_BUILDS[version[:5]]:
308                    build = BuildQuery().find_couchbase_release_build(
309                                            deliverable_type=info.deliverable_type,
310                                            os_architecture=info.architecture_type,
311                                            build_version=version,
312                                            product=name,
313                                            os_version = info.distribution_version,
314                                            direct_build_url=direct_build_url)
315                else:
316                    builds, changes = BuildQuery().get_all_builds(version=version,
317                                      timeout=timeout,
318                                      direct_build_url=direct_build_url,
319                                      deliverable_type=info.deliverable_type,
320                                      architecture_type=info.architecture_type,
321                                      edition_type=name,
322                                      repo=build_repo, toy=toy,
323                                      distribution_version=info.distribution_version.lower(),
324                                      distribution_type=info.distribution_type.lower())
325                    build = BuildQuery().find_build(builds, name, info.deliverable_type,
326                                               info.architecture_type, version, toy=toy,
327                                     openssl=openssl, direct_build_url=direct_build_url,
328                                 distribution_version=info.distribution_version.lower(),
329                                       distribution_type=info.distribution_type.lower())
330
331                if build:
332                    if 'amazon' in params:
333                        type = info.type.lower()
334                        if type == 'windows' and version in releases_version:
335                            build.url = build.url.replace("http://builds.hq.northscale.net",
336                                                          "https://s3.amazonaws.com/packages.couchbase")
337                            build.url = build.url.replace("enterprise", "community")
338                            build.name = build.name.replace("enterprise", "community")
339                        else:
340                            """ since url in S3 insert version into it, we need to put version
341                                in like ..latestbuilds/3.0.0/... """
342                            cb_version = version[:5]
343                            build.url = build.url.replace("http://builds.hq.northscale.net/latestbuilds",
344                                        "http://packages.northscale.com/latestbuilds/{0}".format(cb_version))
345                            """ test enterprise version """
346                            #build.url = build.url.replace("enterprise", "community")
347                            #build.name = build.name.replace("enterprise", "community")
348                    """ check if URL is live """
349                    remote_client = RemoteMachineShellConnection(server)
350                    if remote_client.is_url_live(build.url):
351                        return build
352                    else:
353                        sys.exit("ERROR: URL is not good. Check URL again")
354            _errors.append(errors["BUILD-NOT-FOUND"])
355        if not linux_repo:
356            msg = "unable to find a build for product {0} version {1} for package_type {2}"
357            raise Exception(msg.format(names, version, info.deliverable_type))
358
359    def is_socket_active(self, host, port, timeout=300):
360        """ Check if remote socket is open and active
361
362        Keyword arguments:
363        host -- remote address
364        port -- remote port
365        timeout -- check timeout (in seconds)
366
367        Returns:
368        True -- socket is active
369        False -- otherwise
370
371        """
372        start_time = time.time()
373
374        sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
375
376        while time.time() - start_time < timeout:
377            try:
378                sckt.connect((host, port))
379                sckt.shutdown(2)
380                sckt.close()
381                return True
382            except:
383                time.sleep(10)
384
385        return False
386
387class MembaseServerInstaller(Installer):
388    def __init__(self):
389        Installer.__init__(self)
390
391    def initialize(self, params):
392        start_time = time.time()
393        cluster_initialized = False
394        server = params["server"]
395        while time.time() < (start_time + (5 * 60)):
396            rest = RestConnection(server)
397            try:
398                if server.data_path:
399                    remote_client = RemoteMachineShellConnection(server)
400                    remote_client.execute_command('rm -rf {0}/*'.format(server.data_path))
401                    # Make sure that data_path is writable by membase user
402                    remote_client.execute_command("chown -R membase.membase {0}".format(server.data_path))
403                    remote_client.disconnect()
404                    rest.set_data_path(data_path=server.data_path)
405                rest.init_cluster(username=server.rest_username, password=server.rest_password)
406                rest.init_cluster_memoryQuota(memoryQuota=rest.get_nodes_self().mcdMemoryReserved)
407                cluster_initialized = True
408                break
409            except ServerUnavailableException:
410                log.error("error happened while initializing the cluster @ {0}".format(server.ip))
411            log.info('sleep for 5 seconds before trying again ...')
412            time.sleep(5)
413        if not cluster_initialized:
414            raise Exception("unable to initialize membase node")
415
416    def install(self, params, queue=None):
417        try:
418            build = self.build_url(params)
419        except Exception, e:
420            if queue:
421                queue.put(False)
422            raise e
423        remote_client = RemoteMachineShellConnection(params["server"])
424        info = remote_client.extract_remote_info()
425        type = info.type.lower()
426        server = params["server"]
427        if "vbuckets" in params:
428            vbuckets = int(params["vbuckets"][0])
429        else:
430            vbuckets = None
431        if "swappiness" in params:
432            swappiness = int(params["swappiness"])
433        else:
434            swappiness = 0
435
436        if "openssl" in params:
437            openssl = params["openssl"]
438        else:
439            openssl = ""
440
441        if type == "windows":
442            build = self.build_url(params)
443            remote_client.download_binary_in_win(build.url, params["version"])
444            success = remote_client.install_server_win(build, params["version"], \
445                                                       vbuckets=vbuckets)
446        else:
447            downloaded = remote_client.download_build(build)
448            if not downloaded:
449                log.error('server {1} unable to download binaries : {0}' \
450                          .format(build.url, params["server"].ip))
451                return False
452            path = server.data_path or '/tmp'
453            success &= remote_client.install_server(build, path=path, vbuckets=vbuckets, \
454                                                    swappiness=swappiness, openssl=openssl)
455            ready = RestHelper(RestConnection(params["server"])).is_ns_server_running(60)
456            if not ready:
457                log.error("membase-server did not start...")
458            log.info('wait 5 seconds for Membase server to start')
459            time.sleep(5)
460        remote_client.disconnect()
461        if queue:
462            queue.put(success)
463        return success
464
465
466class CouchbaseServerInstaller(Installer):
467    def __init__(self):
468        Installer.__init__(self)
469
470    def initialize(self, params):
471        #log.info('*****CouchbaseServerInstaller initialize the application ****')
472        start_time = time.time()
473        cluster_initialized = False
474        server = params["server"]
475        remote_client = RemoteMachineShellConnection(params["server"])
476        success = True
477        success &= remote_client.is_couchbase_installed()
478        if not success:
479            mesg = "\n\nServer {0} failed to install".format(params["server"].ip)
480            sys.exit(mesg)
481        while time.time() < start_time + 5 * 60:
482            try:
483                rest = RestConnection(server)
484
485                # Optionally change node name and restart server
486                if params.get('use_domain_names', 0):
487                    RemoteUtilHelper.use_hostname_for_server_settings(server)
488
489                if params.get('enable_ipv6', 0):
490                    status, content = RestConnection(server).rename_node(
491                        hostname=server.ip.replace('[', '').replace(']', ''))
492                    if status:
493                        log.info("Node {0} renamed to {1}".format(server.ip,
494                                                                  server.ip.replace('[', '').
495                                                                  replace(']', '')))
496                    else:
497                        log.error("Error renaming node {0} to {1}: {2}".
498                                  format(server.ip,
499                                         server.ip.replace('[', '').replace(']', ''),
500                                         content))
501
502                # Make sure that data_path and index_path are writable by couchbase user
503                for path in set(filter(None, [server.data_path, server.index_path])):
504                    time.sleep(3)
505
506                    for cmd in ("rm -rf {0}/*".format(path),
507                                "chown -R couchbase:couchbase {0}".format(path)):
508                        remote_client.execute_command(cmd)
509                rest.set_data_path(data_path=server.data_path,
510                                       index_path=server.index_path)
511                time.sleep(3)
512
513                # Initialize cluster
514                if "init_nodes" in params:
515                    init_nodes = params["init_nodes"]
516                else:
517                    init_nodes = "True"
518                if (isinstance(init_nodes, bool) and init_nodes) or \
519                        (isinstance(init_nodes, str) and init_nodes.lower() == "true"):
520                    if not server.services:
521                        set_services = ["kv"]
522                    elif server.services:
523                        set_services = server.services.split(',')
524
525                    kv_quota = 0
526                    while kv_quota == 0:
527                        time.sleep(1)
528                        kv_quota = int(rest.get_nodes_self().mcdMemoryReserved)
529                    info = rest.get_nodes_self()
530                    cb_version = info.version[:5]
531                    kv_quota = int(info.mcdMemoryReserved * 2/3)
532                    """ for fts, we need to grep quota from ns_server
533                                but need to make it works even RAM of vm is
534                                smaller than 2 GB """
535
536                    if cb_version in COUCHBASE_FROM_VERSION_4:
537                        if "index" in set_services:
538                            log.info("quota for index service will be %s MB" % (INDEX_QUOTA))
539                            kv_quota -= INDEX_QUOTA
540                            log.info("set index quota to node %s " % server.ip)
541                            rest.set_service_memoryQuota(service='indexMemoryQuota', memoryQuota=INDEX_QUOTA)
542                        if "fts" in set_services:
543                            log.info("quota for fts service will be %s MB" % (FTS_QUOTA))
544                            kv_quota -= FTS_QUOTA
545                            log.info("set both index and fts quota at node %s "% server.ip)
546                            rest.set_service_memoryQuota(service='ftsMemoryQuota', memoryQuota=FTS_QUOTA)
547                        if "cbas" in set_services:
548                            log.info("quota for cbas service will be %s MB" % (CBAS_QUOTA))
549                            kv_quota -= CBAS_QUOTA
550                            rest.set_service_memoryQuota(service = "cbasMemoryQuota", memoryQuota=CBAS_QUOTA)
551                        if kv_quota < MIN_KV_QUOTA:
552                                raise Exception("KV RAM needs to be more than %s MB"
553                                        " at node  %s"  % (MIN_KV_QUOTA, server.ip))
554                    """ set kv quota smaller than 1 MB so that it will satify
555                        the condition smaller than allow quota """
556                    kv_quota -= 1
557                    log.info("quota for kv: %s MB" % kv_quota)
558                    rest.init_cluster_memoryQuota(server.rest_username, \
559                                                       server.rest_password, \
560                                                                     kv_quota)
561                    if params["version"][:5] in COUCHBASE_FROM_VERSION_4:
562                        rest.init_node_services(username=server.rest_username,
563                                                password=server.rest_password,
564                                                        services=set_services)
565                    if "index" in set_services:
566                        if "storage_mode" in params:
567                            storageMode = params["storage_mode"]
568                        else:
569                            storageMode = "plasma"
570                        rest.set_indexer_storage_mode(storageMode=storageMode)
571                    rest.init_cluster(username=server.rest_username,
572                                         password=server.rest_password)
573
574                # Optionally disable consistency check
575                if params.get('disable_consistency', 0):
576                    rest.set_couchdb_option(section='couchdb',
577                                            option='consistency_check_ratio',
578                                            value='0.0')
579
580                # memcached env variable
581                mem_req_tap_env = params.get('MEMCACHED_REQS_TAP_EVENT', 0)
582                if mem_req_tap_env:
583                    remote_client.set_environment_variable('MEMCACHED_REQS_TAP_EVENT',
584                                                           mem_req_tap_env)
585                """ set cbauth environment variables from Watson version
586                    it is checked version inside method """
587                remote_client.set_cbauth_env(server)
588                remote_client.check_man_page()
589                """ add unzip command on server if it is not available """
590                remote_client.check_cmd("unzip")
591                remote_client.is_ntp_installed()
592                remote_client.disconnect()
593                # TODO: Make it work with windows
594                if "erlang_threads" in params:
595                    num_threads = params.get('erlang_threads', testconstants.NUM_ERLANG_THREADS)
596                    # Stop couchbase-server
597                    ClusterOperationHelper.stop_cluster([server])
598                    if "sync_threads" in params or ':' in num_threads:
599                        sync_threads = params.get('sync_threads', True)
600                    else:
601                        sync_threads = False
602                    # Change type of threads(sync/async) and num erlang threads
603                    ClusterOperationHelper.change_erlang_threads_values([server], sync_threads, num_threads)
604                    # Start couchbase-server
605                    ClusterOperationHelper.start_cluster([server])
606                if "erlang_gc_level" in params:
607                    erlang_gc_level = params.get('erlang_gc_level', None)
608                    if erlang_gc_level is None:
609                        # Don't change the value
610                        break
611                    # Stop couchbase-server
612                    ClusterOperationHelper.stop_cluster([server])
613                    # Change num erlang threads
614                    ClusterOperationHelper.change_erlang_gc([server], erlang_gc_level)
615                    # Start couchbase-server
616                    ClusterOperationHelper.start_cluster([server])
617                cluster_initialized = True
618                break
619            except ServerUnavailableException:
620                log.error("error happened while initializing the cluster @ {0}".format(server.ip))
621            log.info('sleep for 5 seconds before trying again ...')
622            time.sleep(5)
623        if not cluster_initialized:
624            sys.exit("unable to initialize couchbase node")
625
626    def install(self, params, queue=None):
627
628        log.info('********CouchbaseServerInstaller:install')
629
630        self.msi = 'msi' in params and params['msi'].lower() == 'true'
631        start_server = True
632        try:
633            if "linux_repo" not in params:
634                build = self.build_url(params)
635        except Exception, e:
636            if queue:
637                queue.put(False)
638            raise e
639        remote_client = RemoteMachineShellConnection(params["server"])
640        info = remote_client.extract_remote_info()
641        type = info.type.lower()
642        server = params["server"]
643        self.nonroot = False
644        if info.deliverable_type in ["rpm", "deb"]:
645            if server.ssh_username != "root":
646                self.nonroot = True
647        if "swappiness" in params:
648            swappiness = int(params["swappiness"])
649        else:
650            swappiness = 0
651        if "openssl" in params:
652            openssl = params["openssl"]
653        else:
654            openssl = ""
655
656        if "vbuckets" in params:
657            vbuckets = int(params["vbuckets"][0])
658        else:
659            vbuckets = None
660
661        if "upr" in params and params["upr"].lower() != "none":
662            upr = params["upr"].lower() == 'true'
663        else:
664            upr = None
665
666        if "xdcr_upr" not in params:
667            xdcr_upr = None
668        else:
669            xdcr_upr = eval(params["xdcr_upr"].capitalize())
670
671        if "fts_query_limit" in params:
672            fts_query_limit = params["fts_query_limit"]
673            start_server = False
674        else:
675            fts_query_limit = None
676
677        if "enable_ipv6" in params:
678            enable_ipv6 = params["enable_ipv6"]
679            start_server = False
680        else:
681            enable_ipv6 = None
682
683        if "linux_repo" in params and params["linux_repo"].lower() == "true":
684            linux_repo = True
685        else:
686            linux_repo = False
687
688        if not linux_repo:
689            if type == "windows":
690                log.info('***** Download Windows binary*****')
691                """
692                    In spock from build 2924 and later release, we only support
693                    msi installation method on windows
694                """
695                if "-" in params["version"] and \
696                    params["version"].split("-")[0] in COUCHBASE_FROM_SPOCK:
697                    self.msi = True
698                    os_type = "msi"
699                remote_client.download_binary_in_win(build.url, params["version"],
700                                                             msi_install=self.msi)
701                success = remote_client.install_server_win(build,
702                                       params["version"].replace("-rel", ""),
703                                       vbuckets=vbuckets,
704                                       fts_query_limit=fts_query_limit,
705                                       enable_ipv6=enable_ipv6,
706                                       windows_msi=self.msi )
707            else:
708                downloaded = remote_client.download_build(build)
709
710                if not downloaded:
711                    sys.exit('server {1} unable to download binaries : {0}' \
712                                     .format(build.url, params["server"].ip))
713                # TODO: need separate methods in remote_util for couchbase and membase install
714                path = server.data_path or '/tmp'
715                try:
716                    success = remote_client.install_server(build, path=path,
717                                         startserver=start_server,\
718                                         vbuckets=vbuckets, swappiness=swappiness,\
719                                        openssl=openssl, upr=upr, xdcr_upr=xdcr_upr,
720                                        fts_query_limit=fts_query_limit,
721                                        enable_ipv6=enable_ipv6)
722                    log.info('wait 5 seconds for Couchbase server to start')
723                    time.sleep(5)
724                    if "rest_vbuckets" in params:
725                        rest_vbuckets = int(params["rest_vbuckets"])
726                        ClusterOperationHelper.set_vbuckets(server, rest_vbuckets)
727                except BaseException, e:
728                    success = False
729                    log.error("installation failed: {0}".format(e))
730            remote_client.disconnect()
731            if queue:
732                queue.put(success)
733            return success
734        elif linux_repo:
735            cb_edition = ""
736            if "type" in params and params["type"] == "community":
737                cb_edition = "community"
738            try:
739                success = remote_client.install_server_via_repo(info.deliverable_type,\
740                                                             cb_edition, remote_client)
741                log.info('wait 5 seconds for Couchbase server to start')
742                time.sleep(5)
743            except BaseException, e:
744                success = False
745                log.error("installation failed: {0}".format(e))
746            remote_client.disconnect()
747            if queue:
748                queue.put(success)
749            return success
750
751class MongoInstaller(Installer):
752    def get_server(self, params):
753        version = params["version"]
754        server = params["server"]
755        server.product_name = "mongodb-linux-x86_64-" + version
756        server.product_tgz = server.product_name + ".tgz"
757        server.product_url = "http://fastdl.mongodb.org/linux/" + server.product_tgz
758        return server
759
760    def mk_remote_client(self, server):
761        remote_client = RemoteMachineShellConnection(server)
762
763        info = remote_client.extract_remote_info()
764        type = info.type.lower()
765        if type == "windows":
766            sys.exit("ERROR: please teach me about windows one day.")
767
768        return remote_client
769
770    def uninstall(self, params):
771        server = self.get_server(params)
772        remote_client = self.mk_remote_client(server)
773        remote_client.execute_command("killall mongod mongos")
774        remote_client.execute_command("killall -9 mongod mongos")
775        remote_client.execute_command("rm -rf ./{0}".format(server.product_name))
776
777    def install(self, params):
778        server = self.get_server(params)
779        remote_client = self.mk_remote_client(server)
780
781        downloaded = remote_client.download_binary(server.product_url, "tgz", server.product_tgz)
782        if not downloaded:
783            log.error(downloaded, 'server {1} unable to download binaries : {0}' \
784                      .format(server.product_url, server.ip))
785
786        remote_client.execute_command("tar -xzvf /tmp/{0}".format(server.product_tgz))
787
788    def initialize(self, params):
789        server = self.get_server(params)
790        remote_client = self.mk_remote_client(server)
791        remote_client.execute_command("mkdir -p {0}/data/data-27019 {0}/data/data-27018 {0}/log". \
792                                          format(server.product_name))
793        remote_client.execute_command("./{0}/bin/mongod --port 27019 --fork --rest --configsvr" \
794                                          " --logpath ./{0}/log/mongod-27019.out" \
795                                          " --dbpath ./{0}/data/data-27019". \
796                                          format(server.product_name))
797        remote_client.execute_command("./{0}/bin/mongod --port 27018 --fork --rest --shardsvr" \
798                                          " --logpath ./{0}/log/mongod-27018.out" \
799                                          " --dbpath ./{0}/data/data-27018". \
800                                          format(server.product_name))
801
802        log.info("check that config server started before launching mongos")
803        if self.is_socket_active(host=server.ip, port=27019):
804            remote_client.execute_command(("./{0}/bin/mongos --port 27017 --fork" \
805                                           " --logpath ./{0}/log/mongos-27017.out" \
806                                           " --configdb " + server.ip + ":27019"). \
807                                          format(server.product_name))
808        else:
809            log.error("Connection with MongoDB config server was not established.")
810            sys.exit()
811
812class MoxiInstaller(Installer):
813    def __init__(self):
814        Installer.__init__(self)
815
816    def initialize(self, params):
817        log.info('There is no initialize phase for moxi')
818
819    def uninstall(self, params):
820        remote_client = RemoteMachineShellConnection(params["server"])
821        remote_client.membase_uninstall()
822        remote_client.couchbase_uninstall()
823        remote_client.moxi_uninstall()
824        remote_client.disconnect()
825
826    def install(self, params, queue=None):
827        try:
828            build = self.build_url(params)
829        except Exception, e:
830            if queue:
831                queue.put(False)
832            raise e
833        remote_client = RemoteMachineShellConnection(params["server"])
834        info = remote_client.extract_remote_info()
835        type = info.type.lower()
836        if type == "windows":
837            raise Exception("Not implemented for windows")
838        else:
839            downloaded = remote_client.download_build(build)
840            if not downloaded:
841                log.error('server {1} unable to download binaries : {0}' \
842                          .format(build.url, params["server"].ip))
843                return False
844            try:
845                success = remote_client.install_moxi(build)
846            except BaseException, e:
847                success = False
848                log.error("installation failed: {0}".format(e))
849        remote_client.disconnect()
850        if queue:
851            queue.put(success)
852        return success
853
854class SDKInstaller(Installer):
855    def __init__(self):
856        pass
857
858    def initialize(self, params):
859        log.info('There is no initialize phase for sdk installation')
860
861    def uninstall(self):
862        pass
863
864    def install(self, params):
865        remote_client = RemoteMachineShellConnection(params["server"])
866        info = remote_client.extract_remote_info()
867        os = info.type.lower()
868        type = info.deliverable_type.lower()
869        version = info.distribution_version.lower()
870        if params['subdoc'] == 'True':
871            sdk_url = 'git+git://github.com/mnunberg/couchbase-python-client.git@subdoc'
872        else:
873            sdk_url = 'git+git://github.com/couchbase/couchbase-python-client.git'
874        if os == 'linux':
875            if (type == 'rpm' and params['subdoc'] == 'False'):
876                repo_file = '/etc/yum.repos.d/couchbase.repo'
877                baseurl = ''
878                if (version.find('centos') != -1 and version.find('6.2') != -1):
879                    baseurl = 'http://packages.couchbase.com/rpm/6.2/x86-64'
880                elif (version.find('centos') != -1 and version.find('6.4') != -1):
881                    baseurl = 'http://packages.couchbase.com/rpm/6.4/x86-64'
882                elif (version.find('centos') != -1 and version.find('7') != -1):
883                    baseurl = 'http://packages.couchbase.com/rpm/7/x86_64'
884                else:
885                    log.info("os version {0} not supported".format(version))
886                    exit(1)
887                remote_client.execute_command("rm -rf {0}".format(repo_file))
888                remote_client.execute_command("touch {0}".format(repo_file))
889                remote_client.execute_command("echo [couchbase] >> {0}".format(repo_file))
890                remote_client.execute_command("echo enabled=1 >> {0}".format(repo_file))
891                remote_client.execute_command("echo name = Couchbase package repository \
892                        >> {0}".format(repo_file))
893                remote_client.execute_command("echo baseurl = {0} >> \
894                        {1}".format(baseurl, repo_file))
895                remote_client.execute_command("yum -n update")
896                remote_client.execute_command("yum -y install \
897                        libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin")
898                remote_client.execute_command("yum -y install python-pip")
899                remote_client.execute_command("pip -y uninstall couchbase")
900                remote_client.execute_command("pip -y install {0}".format(sdk_url))
901
902            elif (type == 'rpm' and params['subdoc'] == 'True'):
903                package_url = ''
904                lcb_core = ''
905                lcb_libevent  = ''
906                lcb_devel = ''
907                lcb_bin = ''
908
909                if (version.find('centos') != -1 and version.find('6') != -1):
910                    package_url = 'http://172.23.105.153/228/DIST/el6/'
911                    lcb_core =  'libcouchbase2-core-2.5.4-11.r10ga37efd8.SP.el6.x86_64.rpm'
912                    lcb_libevent = 'libcouchbase2-libevent-2.5.4-11.r10ga37efd8.SP.el6.x86_64.rpm'
913                    lcb_devel = 'libcouchbase-devel-2.5.4-11.r10ga37efd8.SP.el6.x86_64.rpm'
914                    lcb_bin = 'libcouchbase2-bin-2.5.4-11.r10ga37efd8.SP.el6.x86_64.rpm'
915                    remote_client.execute_command('rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm')
916
917                elif (version.find('centos') != -1 and version.find('7') != -1):
918                    package_url = 'http://172.23.105.153/228/DIST/el7/'
919                    lcb_core = 'libcouchbase2-core-2.5.4-11.r10ga37efd8.SP.el7.centos.x86_64.rpm'
920                    lcb_libevent = 'libcouchbase2-libevent-2.5.4-11.r10ga37efd8.SP.el7.centos.x86_64.rpm'
921                    lcb_devel = 'libcouchbase-devel-2.5.4-11.r10ga37efd8.SP.el7.centos.x86_64.rpm'
922                    lcb_bin = 'libcouchbase2-bin-2.5.4-11.r10ga37efd8.SP.el7.centos.x86_64.rpm'
923
924                    remote_client.execute_command('yum -y  install epel-release')
925
926                remote_client.execute_command('yum -y remove "libcouchbase*"')
927                remote_client.execute_command('rm -rf {0} {1} {2} {3}'.format(lcb_core,
928                    lcb_libevent, lcb_devel, lcb_bin))
929                remote_client.execute_command('wget {0}{1}'.format(package_url, lcb_core))
930                remote_client.execute_command('wget {0}{1}'.format(package_url,
931                    lcb_libevent))
932                remote_client.execute_command('wget {0}{1}'.format(package_url,lcb_devel))
933                remote_client.execute_command('wget {0}{1}'.format(package_url,lcb_bin))
934                remote_client.execute_command('rpm -ivh {0} {1} {2}'.format(lcb_core,
935                    lcb_libevent,lcb_devel,lcb_bin))
936                remote_client.execute_command('yum -y install python-pip')
937                remote_client.execute_command('pip -y uninstall couchbase')
938                remote_client.execute_command('pip -y install {0}'.format(sdk_url))
939
940            elif (type == "deb" and params['subdoc'] == 'False'):
941                repo_file = "/etc/sources.list.d/couchbase.list"
942                entry = ""
943                if (version.find("ubuntu") != -1 and version.find("12.04") != -1):
944                    entry = "http://packages.couchbase.com/ubuntu precise precise/main"
945                elif (version.find("ubuntu") != -1 and version.find("14.04") != -1):
946                    entry = "http://packages.couchbase.com/ubuntu trusty trusty/main"
947                elif (version.find("debian") != -1 and version.find("7") != -1):
948                    entry = "http://packages.couchbase.com/ubuntu wheezy wheezy/main"
949                else:
950                    log.info("os version {0} not supported".format(version))
951                    exit(1)
952                remote_client.execute_command("rm -rf {0}".format(repo_file))
953                remote_client.execute_command("touch {0}".format(repo_file))
954                remote_client.execute_command("deb {0} >> {1}".format(entry, repo_file))
955                remote_client.execute_command("apt-get update")
956                remote_client.execute_command("apt-get -y install libcouchbase2-libevent \
957                        libcouchbase-devel libcouchbase2-bin")
958                remote_client.execute_command("apt-get -y install pip")
959                remote_client.execute_command("pip -y uninstall couchbase")
960                remote_client.execute_command("pip -y install {0}".format(sdk_url))
961        if os == "mac":
962            remote_client.execute_command("brew install libcouchbase;\
963                    brew link libcouchbase")
964            remote_client.execute_command("brew install pip; brew link pip")
965            remote_client.execute_command("pip install {0}".format(sdk_url))
966        if os == "windows":
967            log.info('Currently not supported')
968        remote_client.disconnect()
969        return True
970
971
972class ESInstaller(object):
973    def __init__(self):
974       self.remote_client = None
975       pass
976
977    def initialize(self, params):
978        self.remote_client.execute_command("~/elasticsearch/bin/elasticsearch > es.log 2>&1 &")
979
980    def install(self, params):
981        self.remote_client = RemoteMachineShellConnection(params["server"])
982        self.remote_client.execute_command("pkill -f elasticsearch")
983        self.remote_client.execute_command("rm -rf ~/elasticsearch")
984        self.remote_client.execute_command("rm -rf ~/elasticsearch-*.tar.gz*")
985        download_url = "https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-{0}.tar.gz".format(params["version"])
986        self.remote_client.execute_command("wget {0}".format(download_url))
987        self.remote_client.execute_command("tar xvzf elasticsearch-{0}.tar.gz; mv elasticsearch-{0} elasticsearch".format(params["version"]))
988        self.remote_client.execute_command("echo couchbase.password: password >> ~/elasticsearch/config/elasticsearch.yml")
989        self.remote_client.execute_command("echo network.bind_host: _eth0:ipv4_ >> ~/elasticsearch/config/elasticsearch.yml")
990        self.remote_client.execute_command("echo couchbase.port: 9091 >> ~/elasticsearch/config/elasticsearch.yml")
991        self.remote_client.execute_command("~/elasticsearch/bin/plugin -u {0} -i transport-couchbase".format(params["plugin-url"]))
992        self.remote_client.execute_command("~/elasticsearch/bin/plugin -u https://github.com/mobz/elasticsearch-head/archive/master.zip -i mobz/elasticsearch-head")
993        return True
994
995    def __exit__(self):
996        self.remote_client.disconnect()
997
998
999class InstallerJob(object):
1000    def sequential_install(self, servers, params):
1001        installers = []
1002
1003
1004
1005        for server in servers:
1006            _params = copy.deepcopy(params)
1007            _params["server"] = server
1008            installers.append((installer_factory(_params), _params))
1009
1010        for installer, _params in installers:
1011            try:
1012                installer.uninstall(_params)
1013                if "product" in params and params["product"] in ["couchbase", "couchbase-server", "cb"]:
1014                    success = True
1015                    for server in servers:
1016                        success &= not RemoteMachineShellConnection(server).is_couchbase_installed()
1017                    if not success:
1018                        print "Server:{0}.Couchbase is still" + \
1019                              " installed after uninstall".format(server)
1020                        return success
1021                print "uninstall succeeded"
1022            except Exception as ex:
1023                print "unable to complete the uninstallation: ", ex
1024        success = True
1025        for installer, _params in installers:
1026            try:
1027                success &= installer.install(_params)
1028                try:
1029                    installer.initialize(_params)
1030                except Exception as ex:
1031                    print "unable to initialize the server after successful installation", ex
1032            except Exception as ex:
1033                print "unable to complete the installation: ", ex
1034        return success
1035
1036    def parallel_install(self, servers, params):
1037        uninstall_threads = []
1038        install_threads = []
1039        initializer_threads = []
1040        queue = Queue.Queue()
1041        success = True
1042        for server in servers:
1043            if params.get('enable_ipv6',0):
1044                if re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', server.ip):
1045                    sys.exit("****************************** ERROR: You are "
1046                             "trying to enable IPv6 on an IPv4 machine, "
1047                             "run without enable_ipv6=True ******************")
1048            _params = copy.deepcopy(params)
1049            _params["server"] = server
1050            u_t = Thread(target=installer_factory(params).uninstall,
1051                       name="uninstaller-thread-{0}".format(server.ip),
1052                       args=(_params,))
1053            i_t = Thread(target=installer_factory(params).install,
1054                       name="installer-thread-{0}".format(server.ip),
1055                       args=(_params, queue))
1056            init_t = Thread(target=installer_factory(params).initialize,
1057                       name="initializer-thread-{0}".format(server.ip),
1058                       args=(_params,))
1059            uninstall_threads.append(u_t)
1060            install_threads.append(i_t)
1061            initializer_threads.append(init_t)
1062        for t in uninstall_threads:
1063            t.start()
1064        for t in uninstall_threads:
1065            t.join()
1066            print "thread {0} finished".format(t.name)
1067        if "product" in params and params["product"] in ["couchbase", "couchbase-server", "cb"]:
1068            success = True
1069            for server in servers:
1070                success &= not RemoteMachineShellConnection(server).is_couchbase_installed()
1071            if not success:
1072                print "Server:{0}.Couchbase is still installed after uninstall".format(server)
1073                return success
1074        for t in install_threads:
1075            t.start()
1076        for t in install_threads:
1077            t.join()
1078            print "thread {0} finished".format(t.name)
1079        while not queue.empty():
1080            success &= queue.get()
1081        if not success:
1082            print "installation failed. initializer threads were skipped"
1083            return success
1084        for t in initializer_threads:
1085            t.start()
1086        for t in initializer_threads:
1087            t.join()
1088            print "thread {0} finished".format(t.name)
1089        """ remove any capture files left after install windows """
1090        remote_client = RemoteMachineShellConnection(servers[0])
1091        type = remote_client.extract_remote_info().distribution_type
1092        remote_client.disconnect()
1093        if type.lower() == 'windows':
1094            for server in servers:
1095                shell = RemoteMachineShellConnection(server)
1096                shell.execute_command("rm -f /cygdrive/c/automation/*_172.23*")
1097                shell.execute_command("rm -f /cygdrive/c/automation/*_10.17*")
1098                os.system("rm -f resources/windows/automation/*_172.23*")
1099                os.system("rm -f resources/windows/automation/*_10.17*")
1100        return success
1101
1102
1103def check_build(input):
1104        _params = copy.deepcopy(input.test_params)
1105        _params["server"] = input.servers[0]
1106        installer = installer_factory(_params)
1107        try:
1108            build = installer.build_url(_params)
1109            log.info("Found build: {0}".format(build))
1110        except Exception:
1111            log.error("Cannot find build {0}".format(_params))
1112            exit(1)
1113
1114params = {"ini": "resources/jenkins/fusion.ini",
1115          "product": "ms", "version": "1.7.1r-31", "amazon": "false"}
1116
1117def change_couchbase_indexer_ports(input):
1118    params = {"indexer_admin_port": 9110,
1119            "indexer_scan_port": 9111,
1120            "indexer_http_port": 9112,
1121            "indexer_stream_init_port": 9113,
1122            "indexer_stream_catchup_port": 9114,
1123            "indexer_stream_maint_port": 9115}
1124    remote_client = RemoteMachineShellConnection(input.servers[0])
1125    info = remote_client.extract_remote_info()
1126    remote_client.disconnect()
1127    type = info.type.lower()
1128    if type == "windows":
1129        port_config_path = WIN_COUCHBASE_PORT_CONFIG_PATH
1130        old_config_path = WIN_COUCHBASE_OLD_CONFIG_PATH
1131    else:
1132        port_config_path = LINUX_COUCHBASE_PORT_CONFIG_PATH
1133        old_config_path = LINUX_COUCHBASE_OLD_CONFIG_PATH
1134    filename = "static_config"
1135    for node in input.servers:
1136        output_lines = ''
1137        remote = RemoteMachineShellConnection(node)
1138        remote.stop_server()
1139        lines = remote.read_remote_file(port_config_path, filename)
1140        for line in lines:
1141            for key in params.keys():
1142                if key in line:
1143                    line = ""
1144                    break
1145            output_lines += "{0}".format(line)
1146        for key in params.keys():
1147            line = "{" + str(key) + ", " + str(params[key]) + "}."
1148            output_lines += "{0}\n".format(line)
1149        output_lines = output_lines.replace(r'"', r'\"')
1150        remote.write_remote_file(port_config_path, filename, output_lines)
1151        remote.delete_file(old_config_path, "/config.dat")
1152    for node in input.servers:
1153        remote = RemoteMachineShellConnection(node)
1154        remote.start_server()
1155
1156def main():
1157    log.info('*****Starting the complete install process ****')
1158    log_install_failed = "some nodes were not install successfully!"
1159    try:
1160        (opts, args) = getopt.getopt(sys.argv[1:], 'hi:p:', [])
1161        for o, a in opts:
1162            if o == "-h":
1163                usage()
1164
1165        if len(sys.argv) <= 1:
1166            usage()
1167
1168        input = TestInput.TestInputParser.get_test_input(sys.argv)
1169        """
1170           Terminate the installation process instantly if user put in
1171           incorrect build pattern.  Correct pattern should be
1172           x.x.x-xxx
1173           x.x.x-xxxx
1174           xx.x.x-xxx
1175           xx.x.x-xxxx
1176           where x is a number from 0 to 9
1177        """
1178        correct_build_format = False
1179        if "version" in input.test_params:
1180            build_version = input.test_params["version"]
1181            build_pattern = re.compile("\d\d?\.\d\.\d-\d{3,4}$")
1182            if input.test_params["version"][:5] in COUCHBASE_VERSIONS and \
1183                bool(build_pattern.match(build_version)):
1184                correct_build_format = True
1185        use_direct_url = False
1186        if "url" in input.test_params and input.test_params["url"].startswith("http"):
1187            use_direct_url = True
1188        if not correct_build_format and not use_direct_url:
1189            log.info("\n========\n"
1190                     "         Incorrect build pattern.\n"
1191                     "         It should be 0.0.0-111 or 0.0.0-1111 format\n"
1192                     "         Or \n"
1193                     "         Build version %s does not support yet\n"
1194                     "         Or \n"
1195                     "         There is No build %s in build repo\n"
1196                     "========"
1197                     % (build_version[:5],
1198                        build_version.split("-")[1] if "-" in build_version else "Need build number"))
1199            os.system("ps aux | grep python | grep %d " % os.getpid())
1200            os.system('kill %d' % os.getpid())
1201
1202        if not input.servers:
1203            usage("ERROR: no servers specified. Please use the -i parameter.")
1204    except IndexError:
1205        usage()
1206    except getopt.GetoptError, err:
1207        usage("ERROR: " + str(err))
1208    # TODO: This is not broken, but could be something better
1209    #      like a validator, to check SSH, input params etc
1210    # check_build(input)
1211
1212    if "parallel" in input.test_params and input.test_params['parallel'].lower() != 'false':
1213        # workaround for a python2.6 bug of using strptime with threads
1214        datetime.strptime("30 Nov 00", "%d %b %y")
1215        log.info('Doing  parallel install****')
1216        success = InstallerJob().parallel_install(input.servers, input.test_params)
1217    else:
1218        log.info('Doing  serial install****')
1219        success = InstallerJob().sequential_install(input.servers, input.test_params)
1220    if "product" in input.test_params and input.test_params["product"] in ["couchbase", "couchbase-server", "cb"]:
1221        print "verify installation..."
1222        success = True
1223        for server in input.servers:
1224            success &= RemoteMachineShellConnection(server).is_couchbase_installed()
1225        if not success:
1226            sys.exit(log_install_failed)
1227    if "product" in input.test_params and input.test_params["product"] in ["moxi", "moxi-server"]:
1228        print "verify installation..."
1229        success = True
1230        for server in input.servers:
1231            success &= RemoteMachineShellConnection(server).is_moxi_installed()
1232        if not success:
1233            sys.exit(log_install_failed)
1234    if "change_indexer_ports" in input.test_params and input.test_params["change_indexer_ports"].lower() == 'true'\
1235            and input.test_params["product"] in ["couchbase", "couchbase-server", "cb"]:
1236        change_couchbase_indexer_ports(input)
1237
1238if __name__ == "__main__":
1239    main()
1240