xref: /4.6.0/couchbase-cli/couchbase-cli (revision d08d5a08)
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5couchbase-cli - command-line cluster administration tool
6"""
7
8import getopt
9import sys
10import os
11
12import listservers
13import buckets
14import node
15import xdcr
16import info
17import util_cli as util
18import usage
19from timeout import TimeoutException
20
21CB_USERNAME = 'CB_REST_USERNAME'
22CB_PASSWORD = 'CB_REST_PASSWORD'
23
24HAS_NO_ARG = 1
25MAYBE_HAS_ARG = 2
26HAS_ARG = 3
27
28#Return:
29#   has_arg?
30#   full option name
31def _long_has_args(opt, longopts):
32    possibilities = [o for o in longopts if o.startswith(opt)]
33    if not possibilities:
34        raise GetoptError(_('option --%s not recognized') % opt, opt)
35    # Is there an exact match?
36    if opt in possibilities:
37        return HAS_NO_ARG, opt
38    elif opt + '=' in possibilities:
39        return HAS_ARG, opt
40    elif opt + '?' in possibilities:
41        return MAYBE_HAS_ARG, opt
42    # No exact match, so better be unique.
43    if len(possibilities) > 1:
44        # XXX since possibilities contains all valid continuations, might be
45        # nice to work them into the error msg
46        raise GetoptError(_('option --%s not a unique prefix') % opt, opt)
47    assert len(possibilities) == 1
48    unique_match = possibilities[0]
49    has_arg = HAS_NO_ARG
50    if unique_match.endswith('='):
51        has_arg = HAS_ARG
52    if unique_match.endswith('?'):
53        has_arg = MAYBE_HAS_ARG
54    if has_arg == HAS_ARG or has_arg == MAYBE_HAS_ARG:
55        unique_match = unique_match[:-1]
56    return has_arg, unique_match
57
58def _do_longs (opts, opt, longopts, args):
59    try:
60        i = opt.index('=')
61    except ValueError:
62        optarg = None
63    else:
64        opt, optarg = opt[:i], opt[i+1:]
65
66    has_arg, opt = _long_has_args(opt, longopts)
67    if has_arg == HAS_ARG or has_arg == MAYBE_HAS_ARG:
68        if optarg is None:
69            if has_arg == HAS_ARG:
70                if not args:
71                    raise getopt.GetoptError('option --%s requires argument' % opt, opt)
72                else:
73                    optarg, args = args[0], args[1:]
74            elif has_arg == MAYBE_HAS_ARG:
75                if args and not (args[0].startswith("--") or args[0].startswith("-")):
76                    optarg, args = args[0], args[1:]
77    elif optarg is not None:
78        raise getopt.GetoptError('option --%s must not have an argument' % opt, opt)
79    opts.append(('--' + opt, optarg or ''))
80    return opts, args
81
82getopt.do_longs = _do_longs
83
84def main():
85
86    debug = False
87
88    (cluster, user, password, ssl) = ('', '', '', False)
89
90    try:
91        (opts, _args) = getopt.getopt(sys.argv[2:],
92                                     'a:b:c:dse:gdlmo:OPp:r:Ssu:vVhH', [
93                'cluster=',
94                'debug',
95                'storage',
96                'password=',
97                'user=',
98                'mem',
99                'output=',
100                'os',
101                'ports',
102                'stats',
103                'license',
104                'server-add=',
105                'server-add-username=',
106                'server-add-password=',
107                'server-remove=',
108                'server-failover=',
109                'server-recovery=',
110                'cluster-init=',
111                'cluster-init-username=',
112                'cluster-username=',
113                'cluster-init-password=',
114                'cluster-password=',
115                'cluster-init-port=',
116                'cluster-port=',
117                'cluster-init-ramsize=',
118                'cluster-ramsize=',
119                'cluster-name=',
120                'cluster-index-ramsize=',
121                'cluster-fts-ramsize=',
122                'index-storage-setting=',
123                'enable-auto-failover=',
124                'auto-failover-timeout=',
125                'enable-notification=',
126                'enable-email-alert=',
127                'compaction-db-percentage=',
128                'compaction-db-size=',
129                'compaction-view-percentage=',
130                'compaction-view-size=',
131                'compaction-period-from=',
132                'compaction-period-to=',
133                'enable-compaction-abort=',
134                'enable-compaction-parallel=',
135                'gsi-compaction-mode=',
136                'compaction-gsi-percentage=',
137                'compaction-gsi-size=',
138                'compaction-gsi-interval=',
139                'compaction-gsi-period-from=',
140                'compaction-gsi-period-to=',
141                'enable-gsi-compaction-abort=',
142                'metadata-purge-interval=',
143                'node-init=',
144                'node-init-data-path=',
145                'node-init-index-path=',
146                'node-init-hostname=',
147                'bucket=',
148                'bucket-type=',
149                'bucket-port=',
150                'bucket-password=',
151                'bucket-ramsize=',
152                'bucket-replica=',
153                'bucket-priority=',
154                'bucket-eviction-policy=',
155                'enable-flush=',
156                'enable-index-replica=',
157                'conflict-resolution=',
158                'new-password?',
159                'rotate-data-key',
160                'send-password?',
161                'config-path=',
162                'regenerate',
163                'wait',
164                'force',
165                'data-only',
166                'view-only',
167                'version',
168                'xdcr-cluster-name=',
169                'xdcr-hostname=',
170                'xdcr-username=',
171                'xdcr-password=',
172                'xdcr-from-bucket=',
173                'xdcr-to-bucket=',
174                'xdcr-replicator=',
175                'xdcr-replication-mode=',
176                'xdcr-demand-encryption=',
177                'xdcr-certificate=',
178                'create',
179                'edit',
180                'delete',
181                'list',
182                'set',
183                'pause',
184                'resume',
185                'settings',
186                'ro-username=',
187                'ro-password=',
188                'checkpoint-interval=',
189                'worker-batch-size='
190                'doc-batch-size=',
191                'failure-restart-interval=',
192                'optimistic-replication-threshold=',
193                'source-nozzle-per-node=',
194                'target-nozzle-per-node=',
195                'log-level=',
196                'stats-interval=',
197                'email-recipients=',
198                'email-sender=',
199                'email-user=',
200                'email-password=',
201                'email-host=',
202                'email-port=',
203                'enable-email-encrypt=',
204                'alert-auto-failover-node',
205                'alert-auto-failover-max-reached',
206                'alert-auto-failover-node-down',
207                'alert-auto-failover-cluster-small',
208                'alert-auto-failover-disabled',
209                'alert-ip-changed',
210                'alert-disk-space',
211                'alert-meta-overhead',
212                'alert-meta-oom',
213                'alert-write-failed',
214                'alert-audit-msg-dropped',
215                'group-name=',
216                'rename=',
217                'add-servers=',
218                'move-servers=',
219                'from-group=',
220                'to-group=',
221                'retrieve-cert=',
222                'regenerate-cert=',
223                'cluster-cert-info',
224                'node-cert-info',
225                'upload-cluster-ca=',
226                'set-node-certificate',
227                'extended',
228                'recovery-type=',
229                'recovery-buckets=',
230                'nodes=',
231                'all-nodes',
232                'upload',
233                'upload-host=',
234                'customer=',
235                'ticket=',
236                'services=',
237                'help',
238                'ssl',
239                'filter-expression=',
240                'audit-enabled=',
241                'audit-log-path=',
242                'audit-log-rotate-interval=',
243                'ldap-enabled=',
244                'ldap-admins=',
245                'ldap-roadmins=',
246                'ldap-default=',
247                'index-max-rollback-points=',
248                'index-stable-snapshot-interval=',
249                'index-memory-snapshot-interval=',
250                'index-threads=',
251                'index-log-level=',
252                'vm=',
253                'get-roles',
254                'roles=',
255                'my-roles',
256                'set-users=',
257                'set-names=',
258                'delete-users=',
259                ])
260    except getopt.GetoptError, err:
261        usage.command_error(err)
262    if len(_args) > 0:
263        err_message = ("Possible missing '--' in front of one of parameters '%s'," +
264                       " please see -h for more help.") % _args
265        usage.command_error(err_message)
266    commands = {
267        'host-list'         : listservers.ListServers,
268        'server-list'       : listservers.ListServers,
269        'server-info'       : info.Info,
270        'server-eshell'     : info.Info,
271        'server-add'        : node.Node,
272        'server-readd'      : node.Node,
273        'group-manage'      : node.Node,
274        'rebalance'         : node.Node,
275        'rebalance-stop'    : node.Node,
276        'rebalance-status'  : node.Node,
277        'eject-server'      : node.Node,
278        'failover'          : node.Node,
279        'recovery'          : node.Node,
280        'cluster-init'      : node.Node,
281        'cluster-edit'      : node.Node,
282        'ssl-manage'        : node.Node,
283        'node-init'         : node.Node,
284        'user-manage'       : node.Node,
285        'collect-logs-start'  : node.Node,
286        'collect-logs-stop'   : node.Node,
287        'collect-logs-status' : node.Node,
288        'bucket-list'       : buckets.Buckets,
289        'bucket-create'     : buckets.Buckets,
290        'bucket-edit'       : buckets.Buckets,
291        'bucket-delete'     : buckets.Buckets,
292        'bucket-flush'      : buckets.Buckets,
293        'bucket-compact'    : buckets.Buckets,
294        'master-password'   : node.Node,
295        'setting-cluster'   : node.Node,
296        'reset-admin-password'  : node.Node,
297        'setting-compaction'    : node.Node,
298        'setting-notification'  : node.Node,
299        'setting-autofailover'  : node.Node,
300        'setting-alert'         : node.Node,
301        'setting-audit'         : node.Node,
302        'setting-ldap'          : node.Node,
303        'admin-role-manage'     : node.Node,
304        'setting-xdcr'          : xdcr.XDCR,
305        'setting-index'         : node.Node,
306        'xdcr-setup'            : xdcr.XDCR,
307        'xdcr-replicate'        : xdcr.XDCR,
308        'help'                  : usage.Usage
309        }
310
311    if len(sys.argv) <= 1:
312        usage.short_usage(commands)
313
314    cmd = sys.argv[1]
315
316    if cmd not in commands:
317        # cmd not a command, maybe help is needed.
318        for x in sys.argv:
319            if x in ('-h', '-H', '--help'):
320                usage.all_help(commands) # exits program.
321
322        err_message = ("'%s' is not a couchbase-cli command;" +
323                       " please see -h for more help.") % cmd
324        usage.command_error(err_message) # exits program.
325
326    if cmd == "help":
327        usage.all_help(commands)
328
329    # If a command and -h,-H,--help give context sensitive help by passing cmd
330    for x in sys.argv:
331        if x in ('-h', '-H', '--help'):
332            usage.one_command_usage(cmd, commands)
333
334    for (opt, arg) in opts:
335        if opt in ('-c', '--cluster'):
336            cluster = arg
337        if opt in ('-u', '--user'):
338            user = arg
339        if opt in ('-p', '--password'):
340            password = arg
341        if opt in ('-d', '--debug'):
342            debug = True
343        if opt in ('-s', '--ssl'):
344            ssl = True
345
346    if cmd == "cluster-init" and not cluster:
347        cluster = "127.0.0.1:8091"
348
349    if not cluster:
350        usage.command_error("please provide a CLUSTER, or use -h for more help.")
351
352    if cmd != "cluster-init" and cmd != "master-password":
353        if not user:
354            if CB_USERNAME in os.environ:
355                user = os.environ[CB_USERNAME]
356            else:
357                usage.command_error("Username cannot be empty. \
358Please use -u or set environment variable %s."  % CB_USERNAME)
359        if not password:
360            if CB_PASSWORD in os.environ:
361                password = os.environ[CB_PASSWORD]
362            else:
363                usage.command_error("Password cannot be empty. \
364Please use -p or set environment variable %s." % CB_PASSWORD)
365
366    server, port = util.hostport(cluster)
367
368    if debug:
369        print "INFO: running command: %s" % cmd
370
371    c = commands[cmd]()
372    try:
373        c.runCmd(cmd, server, port, user, password, ssl, opts)
374    except TimeoutException, err:
375        print "TIMED OUT: command: %s: %s:%d, %s" % (cmd, server, port, err)
376        sys.exit(1)
377    except KeyboardInterrupt:
378        print "INTERRUPTED: command: %s: %s:%d" % (cmd, server, port)
379        sys.exit(1)
380    except Exception, err:
381        print "ERROR: command: %s: %s:%d, %s" % (cmd, server, port, err)
382        sys.exit(1)
383
384if __name__ == '__main__':
385    main()
386