xref: /3.0.3-GA/couchbase-cli/buckets.py (revision ee0caaa0)
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4from usage import usage
5
6import restclient
7from timeout import timed_out
8import time
9import sys
10import urllib
11
12rest_cmds = {
13    'bucket-list': '/pools/default/buckets',
14    'bucket-flush': '/pools/default/buckets/',
15    'bucket-delete': '/pools/default/buckets/',
16    'bucket-create': '/pools/default/buckets/',
17    'bucket-edit': '/pools/default/buckets/',
18    'bucket-get': '/pools/default/buckets',
19    'bucket-stats': '/pools/default/buckets/%s/stats?zoom=hour',
20    'bucket-node-stats': '/pools/default/buckets/%s/stats/%s?zoom=%s',
21    'bucket-info': '/pools/default/buckets/%s',
22    'bucket-compact': '/pools/default/buckets/',
23    'bucket-ddocs': '/pools/default/buckets/%s/ddocs',
24    }
25methods = {
26    'bucket-list': 'GET',
27    'bucket-delete': 'DELETE',
28    'bucket-create': 'POST',
29    'bucket-edit': 'POST',
30    'bucket-flush': 'POST',
31    'bucket-get': 'GET',
32    'bucket-stats': 'GET',
33    'bucket-node-stats': 'GET',
34    'bucket-compact': 'POST',
35    'bucket-ddocs': 'GET',
36    }
37
38priority = {
39    'low': 3,
40    'high': 8,
41    }
42
43class Buckets:
44    def __init__(self):
45        self.debug = False
46        self.rest_cmd = rest_cmds['bucket-list']
47        self.method = 'GET'
48
49    @timed_out(60)
50    def runCmd(self, cmd, server, port,
51               user, password, opts):
52        self.user = user
53        self.password = password
54
55        bucketname = ''
56        buckettype = ''
57        authtype = 'sasl'
58        bucketport = '11211'
59        bucketpassword = ''
60        bucketramsize = ''
61        bucketreplication = '1'
62        bucketpriority = None
63        eviction_policy = None
64        output = 'default'
65        wait_for_bucket_ready = False
66        enable_flush = None
67        enable_replica_index = None
68        force = False
69        compact_data_only = False
70        compact_view_only = False
71
72        for (o, a) in opts:
73            if o in ('-b', '--bucket'):
74                bucketname = a
75            elif o == '--bucket-type':
76                buckettype = a
77            elif o == '--bucket-port':
78                bucketport = a
79            elif o == '--bucket-password':
80                bucketpassword = a
81            elif o == '--bucket-ramsize':
82                bucketramsize = a
83            elif o == '--bucket-replica':
84                bucketreplication = a
85            elif o == '--bucket-eviction-policy':
86                eviction_policy = a
87            elif o == '--bucket-priority':
88                bucketpriority = a
89            elif o == '-d' or o == '--debug':
90                self.debug = True
91            elif o in ('-o', '--output'):
92                output = a
93            elif o == '--enable-flush':
94                enable_flush = a
95            elif o == '--enable-index-replica':
96                enable_replica_index = a
97            elif o == '--wait':
98                wait_for_bucket_ready = True
99            elif o == '--force':
100                force = True
101            elif o == '--data-only':
102                compact_data_only = True
103            elif o == '--view-only':
104                compact_view_only = True
105
106        self.rest_cmd = rest_cmds[cmd]
107        rest = restclient.RestClient(server, port, {'debug':self.debug})
108
109        # get the parameters straight
110        opts = {}
111        opts['error_msg'] = "unable to %s;" % cmd
112        opts['success_msg'] = "%s" % cmd
113
114        if cmd in ('bucket-create', 'bucket-edit'):
115            if bucketname:
116                rest.setParam('name', bucketname)
117                if bucketname == "default":
118                    if bucketport and bucketport != "11211":
119                        usage("default bucket must be on port 11211.")
120                    if bucketpassword:
121                        usage("default bucket should only have empty password.")
122                    authtype = 'sasl'
123                else:
124                    if bucketport == "11211":
125                        authtype = 'sasl'
126                    else:
127                        authtype = 'none'
128                        if bucketpassword:
129                            usage("a sasl bucket is supported only on port 11211.")
130            if buckettype:
131                rest.setParam('bucketType', buckettype)
132            if authtype:
133                rest.setParam('authType', authtype)
134            if bucketport:
135                rest.setParam('proxyPort', bucketport)
136            if bucketpassword:
137                rest.setParam('saslPassword', bucketpassword)
138            if bucketramsize:
139                rest.setParam('ramQuotaMB', bucketramsize)
140            if bucketreplication:
141                rest.setParam('replicaNumber', bucketreplication)
142            if enable_flush:
143                rest.setParam('flushEnabled', enable_flush)
144            if eviction_policy:
145                if eviction_policy in ['valueOnly', 'fullEviction']:
146                    rest.setParam('evictionPolicy', eviction_policy)
147                else:
148                    usage("eviction policy value should be either 'valueOnly' or 'fullEviction'.")
149            if enable_replica_index and cmd == 'bucket-create':
150                rest.setParam('replicaIndex', enable_replica_index)
151            if bucketpriority:
152                if bucketpriority in priority:
153                    rest.setParam('threadsNumber', priority[bucketpriority])
154                else:
155                    usage("bucket priority must be either low or high.")
156
157        if cmd in ('bucket-delete', 'bucket-flush', 'bucket-edit'):
158            self.rest_cmd = self.rest_cmd + bucketname
159        if cmd == 'bucket-flush':
160            self.rest_cmd = self.rest_cmd + '/controller/doFlush'
161            if not force:
162                question = "Running this command will totally PURGE database data from disk. " + \
163                           "Do you really want to do it? (Yes/No)"
164                confirm = raw_input(question)
165                if confirm in ('Y', 'Yes'):
166                    print "\nDatabase data will be purged from disk ..."
167                else:
168                    print "\nDatabase data will not be purged. Done."
169                    return False
170            else:
171                print "Database data will be purged from disk ..."
172            opts['error_msg'] = "unable to %s; please check if the bucket exists or not;" % cmd
173        elif cmd == 'bucket-compact':
174            if compact_data_only and compact_view_only:
175                print "You cannot compact data only and view only at the same time."
176                return False
177            elif compact_data_only:
178                self.rest_cmd = self.rest_cmd + bucketname + '/controller/compactDatabases'
179            elif compact_view_only:
180                self.compact_view(rest, server, port, bucketname)
181                return True
182            else:
183                self.rest_cmd = self.rest_cmd + bucketname + '/controller/compactBucket'
184        elif cmd == 'bucket-ddocs':
185            self.rest_cmd = self.rest_cmd % bucketname
186
187        data = rest.restCmd(methods[cmd], urllib.quote(self.rest_cmd),
188                            self.user, self.password, opts)
189
190        if cmd in ("bucket-get", "bucket-stats", "bucket-node-stats", "bucket-ddocs"):
191            return rest.getJson(data)
192        elif cmd == "bucket-list":
193            if output == 'json':
194                print data
195            else:
196                json = rest.getJson(data)
197                for bucket in json:
198                    print '%s' % bucket['name']
199                    print ' bucketType: %s' % bucket['bucketType']
200                    print ' authType: %s' % bucket['authType']
201                    if bucket['authType'] == "sasl":
202                        print ' saslPassword: %s' % bucket['saslPassword']
203                    else:
204                        print ' proxyPort: %s' % bucket['proxyPort']
205                    print ' numReplicas: %s' % bucket['replicaNumber']
206                    print ' ramQuota: %s' % bucket['quota']['ram']
207                    print ' ramUsed: %s' % bucket['basicStats']['memUsed']
208        elif cmd == "bucket-create" and wait_for_bucket_ready:
209            rest_query = restclient.RestClient(server, port, {'debug':self.debug})
210            timeout_in_seconds = 120
211            start = time.time()
212            # Make sure the bucket exists before querying its status
213            bucket_exist = False
214            while (time.time() - start) <= timeout_in_seconds and not bucket_exist:
215                buckets = rest_query.restCmd('GET', rest_cmds['bucket-list'],
216                                             self.user, self.password, opts)
217                for bucket in rest_query.getJson(buckets):
218                    if bucket["name"] == bucketname:
219                        bucket_exist = True
220                        break
221                if not bucket_exist:
222                    sys.stderr.write(".")
223                    time.sleep(2)
224
225            if not bucket_exist:
226                print "\nFail to create bucket '%s' within %s seconds" %\
227                      (bucketname, timeout_in_seconds)
228                return False
229
230            #Query status for all bucket nodes
231            while (time.time() - start) <= timeout_in_seconds:
232                bucket_info = rest_query.restCmd('GET', urllib.quote(rest_cmds['bucket-info'] % bucketname),
233                                                 self.user, self.password, opts)
234                json = rest_query.getJson(bucket_info)
235                all_node_ready = True
236                for node in json["nodes"]:
237                    if node["status"] != "healthy":
238                        all_node_ready = False
239                        break
240                if all_node_ready:
241                    if output == 'json':
242                        print rest.jsonMessage(data)
243                    else:
244                        print data
245                    return True
246                else:
247                    sys.stderr.write(".")
248                    time.sleep(2)
249
250            print "\nBucket '%s' is created but not ready to use within %s seconds" %\
251                 (bucketname, timeout_in_seconds)
252            return False
253        else:
254            if output == 'json':
255                print rest.jsonMessage(data)
256            else:
257                print data
258
259    def compact_view(self, rest, server, port, bucket_name):
260        opts = {}
261        opts['error_msg'] = "unable to compact view; please check your username (-u) and password (-p);"
262        opts['success_msg'] = "compact view for bucket"
263
264        rest_query = restclient.RestClient(server, port, {'debug':self.debug})
265        rest_cmd = '/pools/default/buckets/%s/ddocs' % bucket_name
266        ddoc_info = rest_query.restCmd('GET', urllib.quote(rest_cmd),
267                                       self.user, self.password, opts)
268        json = rest_query.getJson(ddoc_info)
269        for row in json["rows"]:
270            cmd = row["controllers"]["compact"]
271            data = rest.restCmd('POST', cmd,
272                                self.user, self.password, opts)
273            print data
274
275class BucketStats:
276    def __init__(self, bucket_name):
277        self.debug = False
278        self.rest_cmd = rest_cmds['bucket-stats'] % bucket_name
279        self.method = 'GET'
280
281    def runCmd(self, cmd, server, port,
282               user, password, opts):
283        opts = {}
284        opts['error_msg'] = "unable to %s" % cmd
285        opts['success_msg'] = "%s" % cmd
286
287        #print server, port, cmd, self.rest_cmd
288        rest = restclient.RestClient(server, port, {'debug':self.debug})
289        data = rest.restCmd(methods[cmd], self.rest_cmd,
290                            user, password, opts)
291        return rest.getJson(data)
292
293class BucketNodeStats:
294    def __init__(self, bucket_name, stat_name, scale):
295        self.debug = False
296        self.rest_cmd = rest_cmds['bucket-node-stats'] % (bucket_name, stat_name, scale)
297        self.method = 'GET'
298        #print self.rest_cmd
299
300    def runCmd(self, cmd, server, port,
301               user, password, opts):
302        opts = {}
303        opts['error_msg'] = "unable to %s" % cmd
304        opts['success_msg'] = "%s" % cmd
305
306        #print server, port, cmd, self.rest_cmd
307        rest = restclient.RestClient(server, port, {'debug':self.debug})
308        data = rest.restCmd(methods[cmd], self.rest_cmd,
309                            user, password, opts)
310        return rest.getJson(data)
311