xref: /5.5.2/testrunner/lib/couchbase_cli.py (revision 5b89dc5c)
1from remote.remote_util import RemoteMachineShellConnection
2from testconstants import COUCHBASE_FROM_4DOT6
3
4
5class CouchbaseCLI:
6    def __init__(self, server, username, password, cb_version=None):
7        self.server = server
8        self.hostname = "%s:%s" % (server.ip, server.port)
9        self.username = username
10        self.password = password
11        self.cb_version = cb_version
12
13    def bucket_create(self, name, bucket_type, quota,
14                      eviction_policy, replica_count, enable_replica_indexes,
15                      priority, enable_flush, wait):
16        options = self._get_default_options()
17        if name is not None:
18            options += " --bucket " + name
19        if bucket_type is not None:
20            options += " --bucket-type " + bucket_type
21        if quota is not None:
22            options += " --bucket-ramsize " + str(quota)
23        if eviction_policy is not None:
24            options += " --bucket-eviction-policy " + eviction_policy
25        if replica_count is not None:
26            options += " --bucket-replica " + str(replica_count)
27        if enable_replica_indexes is not None:
28            options += " --enable-index-replica " + str(enable_replica_indexes)
29        if priority is not None:
30            options += " --bucket-priority " + priority
31        if enable_flush is not None:
32            options += " --enable-flush " + str(enable_flush)
33        if wait:
34            options += " --wait"
35
36        remote_client = RemoteMachineShellConnection(self.server)
37        stdout, stderr = remote_client.couchbase_cli("bucket-create",
38                                                     self.hostname.split(":")[0], options)
39        remote_client.disconnect()
40        return stdout, stderr, self._was_success(stdout, "Bucket created")
41
42    def bucket_compact(self, bucket_name, data_only, views_only):
43        options = self._get_default_options()
44        if bucket_name is not None:
45            options += " --bucket " + bucket_name
46        if data_only:
47            options += " --data-only"
48        if views_only:
49            options += " --view-only"
50
51        remote_client = RemoteMachineShellConnection(self.server)
52        stdout, stderr = remote_client.couchbase_cli("bucket-compact",
53                                                     self.hostname, options)
54        remote_client.disconnect()
55        return stdout, stderr, self._was_success(stdout,
56                                                 "Bucket compaction started")
57
58    def bucket_delete(self, bucket_name):
59        options = self._get_default_options()
60        if bucket_name is not None:
61            options += " --bucket " + bucket_name
62
63        remote_client = RemoteMachineShellConnection(self.server)
64        stdout, stderr = remote_client.couchbase_cli("bucket-delete",
65                                                     self.hostname, options)
66        remote_client.disconnect()
67        return stdout, stderr, self._was_success(stdout, "Bucket deleted")
68
69    def bucket_edit(self, name, quota, eviction_policy,
70                    replica_count, priority, enable_flush):
71        options = self._get_default_options()
72        if name is not None:
73            options += " --bucket " + name
74        if quota is not None:
75            options += " --bucket-ramsize " + str(quota)
76        if eviction_policy is not None:
77            options += " --bucket-eviction-policy " + eviction_policy
78        if replica_count is not None:
79            options += " --bucket-replica " + str(replica_count)
80        if priority is not None:
81            options += " --bucket-priority " + priority
82        if enable_flush is not None:
83            options += " --enable-flush " + str(enable_flush)
84
85        remote_client = RemoteMachineShellConnection(self.server)
86        stdout, stderr = remote_client.couchbase_cli("bucket-edit",
87                                                     self.hostname, options)
88        remote_client.disconnect()
89        return stdout, stderr, self._was_success(stdout, "Bucket edited")
90
91    def bucket_flush(self, name, force):
92        options = self._get_default_options()
93        if name is not None:
94            options += " --bucket " + name
95        if force:
96            options += " --force"
97
98        remote_client = RemoteMachineShellConnection(self.server)
99        stdout, stderr = remote_client.couchbase_cli("bucket-flush",
100                                                     self.hostname, options)
101        remote_client.disconnect()
102        return stdout, stderr, self._was_success(stdout, "Bucket flushed")
103
104    def cluster_edit(self, data_ramsize, index_ramsize, fts_ramsize,
105                     cluster_name, cluster_username,
106                     cluster_password, cluster_port):
107        return self._setting_cluster("cluster-edit", data_ramsize,
108                                     index_ramsize, fts_ramsize, cluster_name,
109                                     cluster_username, cluster_password,
110                                     cluster_port)
111
112    def cluster_init(self, data_ramsize, index_ramsize, fts_ramsize, services,
113                     index_storage_mode, cluster_name,
114                     cluster_username, cluster_password, cluster_port):
115        options = ""
116        if cluster_username:
117            options += " --cluster-username " + str(cluster_username)
118        if cluster_password:
119            options += " --cluster-password " + str(cluster_password)
120        if data_ramsize:
121            options += " --cluster-ramsize " + str(data_ramsize)
122        if index_ramsize:
123            options += " --cluster-index-ramsize " + str(index_ramsize)
124        if fts_ramsize:
125            options += " --cluster-fts-ramsize " + str(fts_ramsize)
126        if cluster_name:
127            options += " --cluster-name " + str(cluster_name)
128        if index_storage_mode:
129            options += " --index-storage-setting " + str(index_storage_mode)
130        if cluster_port:
131            options += " --cluster-port " + str(cluster_port)
132        if services:
133            options += " --services " + str(services)
134
135        remote_client = RemoteMachineShellConnection(self.server)
136        stdout, stderr = remote_client.couchbase_cli("cluster-init",
137                                                     self.hostname.split(":")[0], options)
138        remote_client.disconnect()
139        print_msg = "Cluster initialized"
140        if self.cb_version is not None and \
141                        self.cb_version[:3] == "4.6":
142            print_msg = "init/edit %s" % self.server.ip
143        return stdout, stderr, self._was_success(stdout, print_msg)
144
145    def collect_logs_start(self, all_nodes, nodes, upload, upload_host,
146                           upload_customer, upload_ticket):
147        options = self._get_default_options()
148        if all_nodes is True:
149            options += " --all-nodes "
150        if nodes is not None:
151            options += " --nodes " + str(nodes)
152        if upload is True:
153            options += " --upload "
154        if upload_host is not None:
155            options += " --upload-host " + str(upload_host)
156        if upload_customer is not None:
157            options += " --customer " + str(upload_customer)
158        if upload_ticket is not None:
159            options += " --ticket " + str(upload_ticket)
160
161        remote_client = RemoteMachineShellConnection(self.server)
162        stdout, stderr = remote_client.couchbase_cli("collect-logs-start",
163                                                     self.hostname, options)
164        remote_client.disconnect()
165        return stdout, stderr, self._was_success(stdout,
166                                                 "Log collection started")
167
168    def collect_logs_stop(self):
169        options = self._get_default_options()
170        remote_client = RemoteMachineShellConnection(self.server)
171        stdout, stderr = remote_client.couchbase_cli("collect-logs-stop",
172                                                     self.hostname, options)
173        remote_client.disconnect()
174        return stdout, stderr, self._was_success(stdout,
175                                                 "Log collection stopped")
176
177    def failover(self, failover_servers, force):
178        options = self._get_default_options()
179        if failover_servers:
180            options += " --server-failover " + str(failover_servers)
181        if force:
182            options += " --force"
183
184        remote_client = RemoteMachineShellConnection(self.server)
185        stdout, stderr = remote_client.couchbase_cli("failover", self.hostname,
186                                                     options)
187        remote_client.disconnect()
188        return stdout, stderr, self._was_success(stdout, "Server failed over")
189
190    def group_manage(self, create, delete, list, move_servers, rename, name,
191                     to_group, from_group):
192        options = self._get_default_options()
193        if create:
194            options += " --create "
195        if delete:
196            options += " --delete "
197        if list:
198            options += " --list "
199        if rename is not None:
200            options += " --rename " + str(rename)
201        if move_servers is not None:
202            options += " --move-servers " + str(move_servers)
203        if name:
204            options += " --group-name " + str(name)
205        if to_group:
206            options += " --to-group " + str(to_group)
207        if from_group:
208            options += " --from-group " + str(from_group)
209
210        remote_client = RemoteMachineShellConnection(self.server)
211        stdout, stderr = remote_client.couchbase_cli("group-manage",
212                                                     self.hostname, options)
213        remote_client.disconnect()
214
215        success = False
216        if create:
217            success = self._was_success(stdout, "Server group created")
218        elif delete:
219            success = self._was_success(stdout, "Server group deleted")
220        elif list:
221            success = self._no_error_in_output(stdout)
222        elif move_servers:
223            success = self._was_success(stdout, "Servers moved between groups")
224        elif rename:
225            success = self._was_success(stdout, "Server group renamed")
226
227        return stdout, stderr, success
228
229    def node_init(self, data_path, index_path, hostname):
230        options = self._get_default_options()
231        if data_path:
232            options += " --node-init-data-path " + str(data_path)
233        if index_path:
234            options += " --node-init-index-path " + str(index_path)
235        if hostname:
236            options += " --node-init-hostname " + str(hostname)
237
238        remote_client = RemoteMachineShellConnection(self.server)
239        stdout, stderr = remote_client.couchbase_cli("node-init",
240                                                     self.hostname, options)
241        remote_client.disconnect()
242        return stdout, stderr, self._was_success(stdout, "Node initialized")
243
244    def rebalance(self, remove_servers):
245        options = self._get_default_options()
246        if remove_servers:
247            options += " --server-remove " + str(remove_servers)
248
249        remote_client = RemoteMachineShellConnection(self.server)
250        stdout, stderr = remote_client.couchbase_cli("rebalance",
251                                                     self.hostname, options)
252        remote_client.disconnect()
253        return stdout, stderr, self._was_success(stdout, "Rebalance complete")
254
255    def rebalance_stop(self):
256        options = self._get_default_options()
257        remote_client = RemoteMachineShellConnection(self.server)
258        stdout, stderr = remote_client.couchbase_cli("rebalance-stop",
259                                                     self.hostname, options)
260        remote_client.disconnect()
261        return stdout, stderr, self._was_success(stdout, "Rebalance stopped")
262
263    def recovery(self, servers, recovery_type):
264        options = self._get_default_options()
265        if servers:
266            options += " --server-recovery " + str(servers)
267        if recovery_type:
268            options += " --recovery-type " + str(recovery_type)
269
270        remote_client = RemoteMachineShellConnection(self.server)
271        stdout, stderr = remote_client.couchbase_cli("recovery", self.hostname,
272                                                     options)
273        remote_client.disconnect()
274        return stdout, stderr, self._was_success(stdout, "Servers recovered")
275
276    def server_add(self, server, server_username, server_password, group_name,
277                   services, index_storage_mode):
278        options = self._get_default_options()
279        if server:
280            options += " --server-add " + str(server)
281        if server_username:
282            options += " --server-add-username " + str(server_username)
283        if server_password:
284            options += " --server-add-password " + str(server_password)
285        if group_name:
286            options += " --group-name " + str(group_name)
287        if services:
288            options += " --services " + str(services)
289        if index_storage_mode:
290            options += " --index-storage-setting " + str(index_storage_mode)
291
292        remote_client = RemoteMachineShellConnection(self.server)
293        stdout, stderr = remote_client.couchbase_cli("server-add",
294                                                     self.hostname, options)
295        remote_client.disconnect()
296        return stdout, stderr, self._was_success(stdout, "Server added")
297
298    def server_readd(self, servers):
299        options = self._get_default_options()
300        if servers:
301            options += " --server-add " + str(servers)
302
303        remote_client = RemoteMachineShellConnection(self.server)
304        stdout, stderr = remote_client.couchbase_cli("server-readd",
305                                                     self.hostname, options)
306        remote_client.disconnect()
307        return stdout, stderr, self._was_success(stdout, "Servers recovered")
308
309    def setting_audit(self, enabled, log_path, rotate_interval):
310        options = self._get_default_options()
311        if enabled is not None:
312            options += " --audit-enabled " + str(enabled)
313        if log_path is not None:
314            options += " --audit-log-path " + str(log_path)
315        if rotate_interval is not None:
316            options += " --audit-log-rotate-interval " + str(rotate_interval)
317
318        remote_client = RemoteMachineShellConnection(self.server)
319        stdout, stderr = remote_client.couchbase_cli("setting-audit",
320                                                     self.hostname, options)
321        remote_client.disconnect()
322        return stdout, stderr, self._was_success(stdout,
323                                                 "Audit settings modified")
324
325    def setting_alert(self, enabled, email_recipients, email_sender,
326                      email_username, email_password, email_host,
327                      email_port, encrypted, alert_af_node,
328                      alert_af_max_reached, alert_af_node_down, alert_af_small,
329                      alert_af_disable, alert_ip_changed, alert_disk_space,
330                      alert_meta_overhead, alert_meta_oom,
331                      alert_write_failed, alert_audit_dropped):
332        options = self._get_default_options()
333
334        if enabled is not None:
335            options += " --enable-email-alert " + str(enabled)
336        if email_recipients is not None:
337            options += " --email-recipients " + str(email_recipients)
338        if email_sender is not None:
339            options += " --email-sender " + str(email_sender)
340        if email_username is not None:
341            options += " --email-user " + str(email_username)
342        if email_password is not None:
343            options += " --email-password " + str(email_password)
344        if email_host is not None:
345            options += " --email-host " + str(email_host)
346        if email_port is not None:
347            options += " --email-port " + str(email_port)
348        if encrypted is not None:
349            options += "--enable-email-encrypt" + str(encrypted)
350        if alert_af_node:
351            options += " --alert-auto-failover-node "
352        if alert_af_max_reached:
353            options += " --alert-auto-failover-max-reached "
354        if alert_af_node_down:
355            options += " --alert-auto-failover-node-down "
356        if alert_af_small:
357            options += " --alert-auto-failover-cluster-small "
358        if alert_af_disable:
359            options += " --alert-auto-failover-disable "
360        if alert_ip_changed:
361            options += " --alert-ip-changed "
362        if alert_disk_space:
363            options += " --alert-disk-space "
364        if alert_meta_overhead:
365            options += " --alert-meta-overhead "
366        if alert_meta_oom:
367            options += " --alert-meta-oom "
368        if alert_write_failed:
369            options += " --alert-write-failed "
370        if alert_audit_dropped:
371            options += " --alert-audit-msg-dropped "
372
373        remote_client = RemoteMachineShellConnection(self.server)
374        stdout, stderr = remote_client.couchbase_cli("setting-alert",
375                                                     self.hostname, options)
376        remote_client.disconnect()
377        return stdout, stderr, self._was_success(stdout, "Email alert "
378                                                         "settings modified")
379
380    def setting_autofailover(self, enabled, timeout):
381        options = self._get_default_options()
382        if enabled is not None:
383            options += " --enable-auto-failover " + str(enabled)
384        if timeout is not None:
385            options += " --auto-failover-timeout " + str(timeout)
386
387        remote_client = RemoteMachineShellConnection(self.server)
388        stdout, stderr = remote_client.couchbase_cli("setting-autofailover",
389                                                     self.server.ip, options)
390        remote_client.disconnect()
391        return stdout, stderr, self._was_success(stdout, "Auto-failover "
392                                                         "settings modified")
393
394    def setting_autoreprovision(self, enabled, max_nodes):
395        options = self._get_default_options()
396        if enabled is not None:
397            options += " --enabled " + str(enabled)
398        if max_nodes is not None:
399            options += " --max-nodes " + str(max_nodes)
400
401        remote_client = RemoteMachineShellConnection(self.server)
402        stdout, stderr = remote_client.couchbase_cli("setting-autoreprovision",
403                                                     self.server.ip, options)
404        remote_client.disconnect()
405        return stdout, stderr, self._was_success(stdout, "Auto-reprovision "
406                                                         "settings modified")
407
408    def setting_cluster(self, data_ramsize, index_ramsize, fts_ramsize,
409                        cluster_name, cluster_username,
410                        cluster_password, cluster_port):
411        return self._setting_cluster("setting-cluster", data_ramsize,
412                                     index_ramsize, fts_ramsize, cluster_name,
413                                     cluster_username, cluster_password,
414                                     cluster_port)
415
416    def setting_compaction(self, db_frag_perc, db_frag_size, view_frag_perc,
417                           view_frag_size, from_period, to_period,
418                           abort_outside, parallel_compact, purgeint):
419        options = self._get_default_options()
420        if db_frag_perc is not None:
421            options += " --compaction-db-percentage " + str(db_frag_perc)
422        if db_frag_size is not None:
423            options += " --compaction-db-size " + str(db_frag_size)
424        if view_frag_perc is not None:
425            options += " --compaction-view-percentage " + str(view_frag_perc)
426        if view_frag_size is not None:
427            options += " --compaction-view-size " + str(view_frag_size)
428        if from_period is not None:
429            options += " --compaction-period-from " + str(from_period)
430        if to_period is not None:
431            options += " --compaction-period-to " + str(to_period)
432        if abort_outside is not None:
433            options += " --enable-compaction-abort " + str(abort_outside)
434        if parallel_compact is not None:
435            options += " --enable-compaction-parallel " + str(parallel_compact)
436        if purgeint is not None:
437            options += " --metadata-purge-interval " + str(purgeint)
438
439        remote_client = RemoteMachineShellConnection(self.server)
440        stdout, stderr = remote_client.couchbase_cli("setting-compaction",
441                                                     self.hostname, options)
442        remote_client.disconnect()
443        return stdout, stderr, self._was_success(stdout, "Compaction "
444                                                         "settings modified")
445
446    def setting_gsi_compaction(self, compact_mode, compact_percent, compact_interval,
447                                               from_period, to_period, enable_abort):
448        options = self._get_default_options()
449        if compact_mode is not None:
450            options += " --gsi-compaction-mode %s" % compact_mode
451            if compact_mode == "append":
452                if compact_percent is not None:
453                    options += " --compaction-gsi-percentage=" + str(compact_percent)
454            elif compact_mode == "circular":
455                if compact_interval is not None:
456                    options += " --compaction-gsi-interval " + str(compact_interval)
457                if from_period is not None:
458                    options += " --compaction-gsi-period-from=" + str(from_period)
459                if to_period is not None:
460                    options += " --compaction-gsi-period-to=" + str(to_period)
461                if enable_abort:
462                    options += " --enable-gsi-compaction-abort=" + str(enable_abort)
463            else:
464                raise Exception("need compact mode to run!")
465
466        remote_client = RemoteMachineShellConnection(self.server)
467        stdout, stderr = remote_client.couchbase_cli("setting-compaction",
468                                                     self.hostname, options)
469        remote_client.disconnect()
470        return stdout, stderr, self._was_success(stdout, "Compaction settings modified")
471
472    def setting_index(self, max_rollbacks, stable_snap_interval,
473                      mem_snap_interval, storage_mode, threads,
474                      log_level):
475        options = self._get_default_options()
476        if max_rollbacks:
477            options += " --index-max-rollback-points " + str(max_rollbacks)
478        if stable_snap_interval:
479            options += " --index-stable-snapshot-interval " + str(
480                stable_snap_interval)
481        if mem_snap_interval:
482            options += " --index-memory-snapshot-interval " + str(
483                mem_snap_interval)
484        if storage_mode:
485            options += " --index-storage-setting " + str(storage_mode)
486        if threads:
487            options += " --index-threads " + str(threads)
488        if log_level:
489            options += " --index-log-level " + str(log_level)
490
491        remote_client = RemoteMachineShellConnection(self.server)
492        stdout, stderr = remote_client.couchbase_cli("setting-index",
493                                                     self.hostname, options)
494        remote_client.disconnect()
495        return stdout, stderr, self._was_success(stdout,
496                                                 "Indexer settings modified")
497
498    def setting_ldap(self, admins, ro_admins, default, enabled):
499        options = self._get_default_options()
500        if admins:
501            options += " --ldap-admins " + str(admins)
502        if ro_admins:
503            options += " --ldap-roadmins " + str(ro_admins)
504        if default:
505            options += " --ldap-default " + str(default)
506        if enabled is not None:
507            options += " --ldap-enabled " + str(enabled)
508
509        remote_client = RemoteMachineShellConnection(self.server)
510        stdout, stderr = remote_client.couchbase_cli("setting-ldap",
511                                                     self.hostname, options)
512        remote_client.disconnect()
513        return stdout, stderr, self._was_success(stdout,
514                                                 "LDAP settings modified")
515
516    def setting_notification(self, enable):
517        options = self._get_default_options()
518        if enable is not None:
519            options += " --enable-notification " + str(enable)
520
521        remote_client = RemoteMachineShellConnection(self.server)
522        stdout, stderr = remote_client.couchbase_cli("setting-notification",
523                                                     self.hostname, options)
524        remote_client.disconnect()
525        return stdout, stderr, self._was_success(stdout, "Notification "
526                                                         "settings updated")
527
528    def user_manage(self, delete, list, set, rbac_username, rbac_password, roles,
529                    auth_domain):
530        options = self._get_default_options()
531        if delete:
532            options += " --delete "
533        if list:
534            options += " --list "
535        if set:
536            options += " --set "
537        if rbac_username is not None:
538            options += " --rbac-username " + str(rbac_username)
539        if rbac_password:
540            options += " --rbac-password " + str(rbac_password)
541        if roles:
542            options += " --roles " + str(roles)
543        if auth_domain:
544            options += " --auth-domain " + str(auth_domain)
545
546        remote_client = RemoteMachineShellConnection(self.server)
547        stdout, stderr = remote_client.couchbase_cli("user-manage",
548                                                     self.hostname, options)
549        remote_client.disconnect()
550
551        if delete:
552            return stdout, stderr, self._was_success(stdout, "Local read-only"
553                                                             "user deleted")
554        elif set:
555            return stdout, stderr, self._was_success(stdout, "RBAC user set")
556        else:
557            return stdout, stderr, self._no_error_in_output(stdout)
558
559    def _setting_cluster(self, cmd, data_ramsize, index_ramsize, fts_ramsize,
560                         cluster_name, cluster_username,
561                         cluster_password, cluster_port):
562        options = self._get_default_options()
563        if cluster_username is not None:
564            options += " --cluster-username " + str(cluster_username)
565        if cluster_password is not None:
566            options += " --cluster-password " + str(cluster_password)
567        if data_ramsize:
568            options += " --cluster-ramsize " + str(data_ramsize)
569        if index_ramsize:
570            options += " --cluster-index-ramsize " + str(index_ramsize)
571        if fts_ramsize:
572            options += " --cluster-fts-ramsize " + str(fts_ramsize)
573        if cluster_name:
574            if cluster_name == "empty":
575                cluster_name = " "
576            options += " --cluster-name " + str(cluster_name)
577        if cluster_port:
578            options += " --cluster-port " + str(cluster_port)
579
580        remote_client = RemoteMachineShellConnection(self.server)
581        stdout, stderr = remote_client.couchbase_cli(cmd, self.hostname,
582                                                     options)
583        remote_client.disconnect()
584        return stdout, stderr, self._was_success(stdout,
585                                                 "Cluster settings modified")
586
587    def _get_default_options(self):
588        options = ""
589        if self.username is not None:
590            options += " -u " + str(self.username)
591        if self.password is not None:
592            options += " -p " + str(self.password)
593        return options
594
595    def _no_error_in_output(self, stdout):
596        """Inspects each line of the command output and checks to see if
597        the command errored. This check is used for API's that get data and
598        do not simply report a success message.
599
600        Options:
601        stdout - A list of output lines from stdout
602        Returns true if not error was found, false otherwise
603        """
604
605        for line in stdout:
606            if line.startswith("ERROR:"):
607                return False
608        return True
609
610    def _was_success(self, stdout, message):
611        """Inspects each line of the command output and checks to see if
612        the command succeeded
613
614        Options:
615        stdout - A list of output lines from stdout
616        message - The success message
617
618        Returns a boolean indicating whether or not the success message was
619        found in the output
620        """
621
622        for line in stdout:
623            if line == "SUCCESS: " + message:
624                return True
625        return False
626