xref: /4.6.0/couchbase-cli/couchbase-cli (revision 78921a5e)
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                'wait',
163                'force',
164                'data-only',
165                'view-only',
166                'version',
167                'xdcr-cluster-name=',
168                'xdcr-hostname=',
169                'xdcr-username=',
170                'xdcr-password=',
171                'xdcr-from-bucket=',
172                'xdcr-to-bucket=',
173                'xdcr-replicator=',
174                'xdcr-replication-mode=',
175                'xdcr-demand-encryption=',
176                'xdcr-certificate=',
177                'create',
178                'edit',
179                'delete',
180                'list',
181                'set',
182                'pause',
183                'resume',
184                'settings',
185                'ro-username=',
186                'ro-password=',
187                'checkpoint-interval=',
188                'worker-batch-size='
189                'doc-batch-size=',
190                'failure-restart-interval=',
191                'optimistic-replication-threshold=',
192                'source-nozzle-per-node=',
193                'target-nozzle-per-node=',
194                'log-level=',
195                'stats-interval=',
196                'email-recipients=',
197                'email-sender=',
198                'email-user=',
199                'email-password=',
200                'email-host=',
201                'email-port=',
202                'enable-email-encrypt=',
203                'alert-auto-failover-node',
204                'alert-auto-failover-max-reached',
205                'alert-auto-failover-node-down',
206                'alert-auto-failover-cluster-small',
207                'alert-auto-failover-disabled',
208                'alert-ip-changed',
209                'alert-disk-space',
210                'alert-meta-overhead',
211                'alert-meta-oom',
212                'alert-write-failed',
213                'alert-audit-msg-dropped',
214                'group-name=',
215                'rename=',
216                'add-servers=',
217                'move-servers=',
218                'from-group=',
219                'to-group=',
220                'retrieve-cert=',
221                'regenerate-cert=',
222                'cluster-cert-info',
223                'node-cert-info',
224                'upload-cluster-ca=',
225                'set-node-certificate',
226                'extended',
227                'recovery-type=',
228                'recovery-buckets=',
229                'nodes=',
230                'all-nodes',
231                'upload',
232                'upload-host=',
233                'customer=',
234                'ticket=',
235                'services=',
236                'help',
237                'ssl',
238                'filter-expression=',
239                'audit-enabled=',
240                'audit-log-path=',
241                'audit-log-rotate-interval=',
242                'ldap-enabled=',
243                'ldap-admins=',
244                'ldap-roadmins=',
245                'ldap-default=',
246                'index-max-rollback-points=',
247                'index-stable-snapshot-interval=',
248                'index-memory-snapshot-interval=',
249                'index-threads=',
250                'index-log-level=',
251                'vm=',
252                'get-roles',
253                'roles=',
254                'my-roles',
255                'set-users=',
256                'set-names=',
257                'delete-users=',
258                ])
259    except getopt.GetoptError, err:
260        usage.command_error(err)
261    if len(_args) > 0:
262        err_message = ("Possible missing '--' in front of one of parameters '%s'," +
263                       " please see -h for more help.") % _args
264        usage.command_error(err_message)
265    commands = {
266        'host-list'         : listservers.ListServers,
267        'server-list'       : listservers.ListServers,
268        'server-info'       : info.Info,
269        'server-eshell'     : info.Info,
270        'server-add'        : node.Node,
271        'server-readd'      : node.Node,
272        'group-manage'      : node.Node,
273        'rebalance'         : node.Node,
274        'rebalance-stop'    : node.Node,
275        'rebalance-status'  : node.Node,
276        'eject-server'      : node.Node,
277        'failover'          : node.Node,
278        'recovery'          : node.Node,
279        'cluster-init'      : node.Node,
280        'cluster-edit'      : node.Node,
281        'ssl-manage'        : node.Node,
282        'node-init'         : node.Node,
283        'user-manage'       : node.Node,
284        'collect-logs-start'  : node.Node,
285        'collect-logs-stop'   : node.Node,
286        'collect-logs-status' : node.Node,
287        'bucket-list'       : buckets.Buckets,
288        'bucket-create'     : buckets.Buckets,
289        'bucket-edit'       : buckets.Buckets,
290        'bucket-delete'     : buckets.Buckets,
291        'bucket-flush'      : buckets.Buckets,
292        'bucket-compact'    : buckets.Buckets,
293        'master-password'   : node.Node,
294        'setting-cluster'   : node.Node,
295        'setting-compaction'    : node.Node,
296        'setting-notification'  : node.Node,
297        'setting-autofailover'  : node.Node,
298        'setting-alert'         : node.Node,
299        'setting-audit'         : node.Node,
300        'setting-ldap'          : node.Node,
301        'admin-role-manage'     : node.Node,
302        'setting-xdcr'          : xdcr.XDCR,
303        'setting-index'         : node.Node,
304        'xdcr-setup'            : xdcr.XDCR,
305        'xdcr-replicate'        : xdcr.XDCR,
306        'help'                  : usage.Usage
307        }
308
309    if len(sys.argv) <= 1:
310        usage.short_usage(commands)
311
312    cmd = sys.argv[1]
313
314    if cmd not in commands:
315        # cmd not a command, maybe help is needed.
316        for x in sys.argv:
317            if x in ('-h', '-H', '--help'):
318                usage.all_help(commands) # exits program.
319
320        err_message = ("'%s' is not a couchbase-cli command;" +
321                       " please see -h for more help.") % cmd
322        usage.command_error(err_message) # exits program.
323
324    if cmd == "help":
325        usage.all_help(commands)
326
327    # If a command and -h,-H,--help give context sensitive help by passing cmd
328    for x in sys.argv:
329        if x in ('-h', '-H', '--help'):
330            usage.one_command_usage(cmd, commands)
331
332    for (opt, arg) in opts:
333        if opt in ('-c', '--cluster'):
334            cluster = arg
335        if opt in ('-u', '--user'):
336            user = arg
337        if opt in ('-p', '--password'):
338            password = arg
339        if opt in ('-d', '--debug'):
340            debug = True
341        if opt in ('-s', '--ssl'):
342            ssl = True
343
344    if cmd == "cluster-init" and not cluster:
345        cluster = "127.0.0.1:8091"
346
347    if not cluster:
348        usage.command_error("please provide a CLUSTER, or use -h for more help.")
349
350    if cmd != "cluster-init" and cmd != "master-password":
351        if not user:
352            if CB_USERNAME in os.environ:
353                user = os.environ[CB_USERNAME]
354            else:
355                usage.command_error("Username cannot be empty. \
356Please use -u or set environment variable %s."  % CB_USERNAME)
357        if not password:
358            if CB_PASSWORD in os.environ:
359                password = os.environ[CB_PASSWORD]
360            else:
361                usage.command_error("Password cannot be empty. \
362Please use -p or set environment variable %s." % CB_PASSWORD)
363
364    server, port = util.hostport(cluster)
365
366    if debug:
367        print "INFO: running command: %s" % cmd
368
369    c = commands[cmd]()
370    try:
371        c.runCmd(cmd, server, port, user, password, ssl, opts)
372    except TimeoutException, err:
373        print "TIMED OUT: command: %s: %s:%d, %s" % (cmd, server, port, err)
374        sys.exit(1)
375    except KeyboardInterrupt:
376        print "INTERRUPTED: command: %s: %s:%d" % (cmd, server, port)
377        sys.exit(1)
378    except Exception, err:
379        print "ERROR: command: %s: %s:%d, %s" % (cmd, server, port, err)
380        sys.exit(1)
381
382if __name__ == '__main__':
383    main()
384