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