1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #ifndef __CCM_BRIDGE_HPP__
18 #define __CCM_BRIDGE_HPP__
19 
20 #include "authentication_type.hpp"
21 #include "bridge_exception.hpp"
22 #include "cass_version.hpp"
23 #include "deployment_type.hpp"
24 #include "dse_credentials_type.hpp"
25 #include "process.hpp"
26 #include "server_type.hpp"
27 #include "tsocket.hpp"
28 
29 #include <map>
30 #include <string>
31 #include <vector>
32 
33 #ifdef CASS_USE_LIBSSH2
34 // Forward declarations for libssh2
35 typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
36 typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
37 #endif
38 
39 // Default values
40 #define DEFAULT_CASSANDRA_VERSION CassVersion("3.11.6")
41 #define DEFAULT_DSE_VERSION DseVersion("6.7.7")
42 #define DEFAULT_USE_GIT false
43 #define DEFAULT_USE_INSTALL_DIR false
44 #define DEFAULT_SERVER_TYPE ServerType(ServerType::CASSANDRA)
45 #define DEFAULT_USE_DSE false
46 #define DEFAULT_USE_DDAC false
47 #define DEFAULT_CLUSTER_PREFIX "cpp-driver"
48 #define DEFAULT_DSE_CREDENTIALS DseCredentialsType::USERNAME_PASSWORD
49 #define DEFAULT_DEPLOYMENT DeploymentType::LOCAL
50 #define DEFAULT_AUTHENTICATION AuthenticationType::USERNAME_PASSWORD
51 #define DEFAULT_HOST "127.0.0.1"
52 #define DEFAULT_REMOTE_DEPLOYMENT_PORT 22
53 #define DEFAULT_REMOTE_DEPLOYMENT_USERNAME "vagrant"
54 #define DEFAULT_REMOTE_DEPLOYMENT_PASSWORD "vagrant"
55 #define DEFAULT_IS_VERBOSE false
56 #define DEFAULT_JVM_ARGUMENTS std::vector<std::string>()
57 
58 // Define the node limit for a cluster
59 #define CLUSTER_NODE_LIMIT 6
60 
61 /**
62  * Node status information for a cluster
63  */
64 struct ClusterStatus {
65   /**
66    * List of IPv4 addresses for `DECOMMISSIONED` nodes
67    */
68   std::vector<std::string> nodes_decommissioned;
69   /**
70    * List of IPv4 addresses for `DOWN` or unavailable nodes
71    */
72   std::vector<std::string> nodes_down;
73   /**
74    * List of IPv4 addresses for `uninitialized` nodes
75    */
76   std::vector<std::string> nodes_uninitialized;
77   /**
78    * List of IPv4 addresses for `UP` or ready nodes
79    */
80   std::vector<std::string> nodes_up;
81   /**
82    * Total number of nodes in the cluster
83    */
84   unsigned int node_count;
85 
86   /**
87    * Constructor
88    */
ClusterStatusClusterStatus89   ClusterStatus()
90       : node_count(0) {}
91 };
92 
93 namespace CCM {
94 /**
95  * Enumeration for a DSE workload
96  */
97 enum DseWorkload {
98   /**
99    * Cassandra
100    */
101   DSE_WORKLOAD_CASSANDRA = 0,
102   /**
103    * CFS - Cassandra file system (Hadoop Distributed File System (HDFS)
104    * replacement
105    */
106   DSE_WORKLOAD_CFS,
107   /**
108    * DSEFS - DataStax Enterprise file system (Spark streaming and Write Ahead
109    * Logging (WAL))
110    */
111   DSE_WORKLOAD_DSEFS,
112   /**
113    * Graph
114    */
115   DSE_WORKLOAD_GRAPH,
116   /**
117    * Hadoop
118    */
119   DSE_WORKLOAD_HADOOP,
120   /**
121    * Solr
122    */
123   DSE_WORKLOAD_SOLR,
124   /**
125    * Spark
126    */
127   DSE_WORKLOAD_SPARK
128 };
129 
130 class Bridge {
131 public:
132   /**
133    * Default DSE workload to apply (Cassandra)
134    */
135   static const std::vector<DseWorkload> DEFAULT_DSE_WORKLOAD;
136 
137   /**
138    * Constructor
139    *
140    * @param cassandra_version Cassandra version to use
141    *                          (default: DEFAULT_CASSANDRA_VERSION)
142    * @param use_git True if version should be obtained from ASF/GitHub; false
143    *                otherwise (default: DEFAULT_USE_GIT). Prepends
144    *                `cassandra-` to version when creating cluster through CCM
145    *                if using Cassandra; otherwise passes version information
146    *                to CCM for git download of DSE. Set branch_tag to
147    *                override default action.
148    * @param branch_tag Branch/Tag to use when use_git is enabled
149    *                   (default: Empty). This value is independent of the
150    *                   version specified.
151    * @param use_install_dir True if CCM should use a particular installation
152    *                        directory; false otherwise
153    *                        (default: DEAFAULT_USE_INSTALL_DIR)
154    * @param install_dir Installation directory to use when use_install_dir is
155    *                    enabled (default: Empty)
156    * @param server_type Server type CCM should create (default: CASSANDRA)
157    * @param dse_workload DSE workload to utilize
158    *                     (default: DEFAULT_DSE_WORKLOAD)
159    * @param cluster_prefix Prefix to use when creating a cluster name
160    *                       (default: DEFAULT_CLUSTER_PREFIX)
161    * @param dse_credentials_type Username|Password/INI file credentials
162    *                             (default: DEFAULT_DSE_CREDENTIALS)
163    * @param dse_username Username for DSE download authentication; empty if
164    *                     using INI file credentials (default: Empty)
165    * @param dse_password Password for DSE download authentication; empty if
166    *                     using INI file credentials (default: Empty)
167    * @param deployment_type Local|Remote deployment (execute command locally
168    *                        or remote (default: DEFAULT_DEPLOYMENT)
169    * @param authentication_type Username|Password/Public key authentication
170    *                            (default: DEFAULT_AUTHENTICATION)
171    * @param host Host/IP address for CCM cluster and/or SSH connection
172    *             (default: DEFAULT_HOST)
173    * @param port TCP/IP port for SSH connection
174    *             (default: DEFAULT_REMOTE_DEPLOYMENT_PORT)
175    * @param username Username for SSH authentication
176    *                 (default: DEFAULT_REMOTE_DEPLOYMENT_USERNAME)
177    * @param password Password for SSH authentication; Empty if using public
178    *                 key (default: DEFAULT_REMOTE_DEPLOYMENT_PASSWORD)
179    * @param public_key Public key for authentication; Empty if using username
180    *                   and password authentication (default: Empty)
181    * @param private_key Private key for authentication; Empty if using
182    *                   username and password authentication (default: Empty)
183    * @param is_verbose True if verbose output should be enabled; false
184    *                   otherwise (default: false)
185    * @throws BridgeException
186    */
187   Bridge(CassVersion cassandra_version = DEFAULT_CASSANDRA_VERSION, bool use_git = DEFAULT_USE_GIT,
188          const std::string& branch_tag = "", bool use_install_dir = DEFAULT_USE_INSTALL_DIR,
189          const std::string& install_dir = "", ServerType server_type = DEFAULT_SERVER_TYPE,
190          std::vector<DseWorkload> dse_workload = DEFAULT_DSE_WORKLOAD,
191          const std::string& cluster_prefix = DEFAULT_CLUSTER_PREFIX,
192          DseCredentialsType dse_credentials_type = DEFAULT_DSE_CREDENTIALS,
193          const std::string& dse_username = "", const std::string& dse_password = "",
194          DeploymentType deployment_type = DEFAULT_DEPLOYMENT,
195          AuthenticationType authentication_type = DEFAULT_AUTHENTICATION,
196          const std::string& host = DEFAULT_HOST, short port = DEFAULT_REMOTE_DEPLOYMENT_PORT,
197          const std::string& username = DEFAULT_REMOTE_DEPLOYMENT_USERNAME,
198          const std::string& password = DEFAULT_REMOTE_DEPLOYMENT_PASSWORD,
199          const std::string& public_key = "", const std::string& private_key = "",
200          bool is_verbose = DEFAULT_IS_VERBOSE);
201 
202   /**
203    * Destructor
204    */
205   ~Bridge();
206 
207   /**
208    * Clear the data on the active cluster; as a side effect the cluster is
209    * also stopped
210    */
211   void clear_cluster_data();
212 
213   /**
214    * Get a comma separated list of IPv4 addresses for nodes in the active
215    * Cassandra cluster
216    *
217    * @param is_all True if all node IPv4 addresses should be returned; false
218    *               if only the `UP` nodes (default: true)
219    * @return Comma separated list of IPv4 addresses
220    */
221   std::string cluster_contact_points(bool is_all = true);
222 
223   /**
224    * Get the list of IPv4 addresses for node in the active Cassandra cluster
225    *
226    * @param is_all True if all node IPv4 addresses should be returned; false
227    *               if only the `UP` nodes (default: true)
228    * @return Array/Vector of IPv4 addresses
229    */
230   std::vector<std::string> cluster_ip_addresses(bool is_all = true);
231 
232   /**
233    * Get the status for the active cluster
234    *
235    * @return Status of the nodes in the active cluster
236    */
237   ClusterStatus cluster_status();
238 
239   /**
240    * Create a Cassandra cluster with nodes in multiple data centers
241    *
242    * @param data_center_nodes Vector of data center nodes
243    * @param with_vnodes True if vnodes tokens should be used; false otherwise
244    *                   (default: false)
245    * @param is_password_authenticator True if password authenticator is
246    *                                  enabled; false otherwise
247    *                                  (default: false)
248    * @param is_ssl True if SSL should be enabled; false otherwise
249    *               (default: false)
250    * @param is_client_authentication True if client authentication should be
251    *                                enabled; false otherwise (default: false)
252    * @return True if cluster was created or switched; false otherwise
253    * @throws BridgeException
254    */
255   bool create_cluster(std::vector<unsigned short> data_center_nodes, bool with_vnodes = false,
256                       bool is_password_authenticator = false, bool is_ssl = false,
257                       bool is_client_authentication = false);
258 
259   /**
260    * Check to see if the active cluster is no longer accepting connections
261    *
262    * NOTE: This method may check the status of the nodes in the cluster
263    *       multiple times
264    *
265    * @return True if cluster is no longer accepting connections; false
266    *    otherwise
267    */
268   bool is_cluster_down();
269 
270   /**
271    * Check to see if the active cluster is ready to accept connections
272    *
273    * NOTE: This method may check the status of the nodes in the cluster
274    *       multiple times
275    *
276    * @return True if cluster is ready to accept connections; false otherwise
277    */
278   bool is_cluster_up();
279 
280   /**
281    * "Hang up" the active Cassandra cluster (SIGHUP)
282    *
283    * @return True if cluster is down; false otherwise
284    */
285   bool hang_up_cluster();
286 
287   /**
288    * Kill the active Cassandra cluster (SIGKILL)
289    *
290    * @return True if cluster is down; false otherwise
291    */
292   bool kill_cluster();
293 
294   /**
295    * Remove active cluster
296    */
297   void remove_cluster();
298 
299   /**
300    * Remove a cluster
301    *
302    * @param cluster_name Cluster name to remove
303    */
304   void remove_cluster(const std::string& cluster_name);
305 
306   /**
307    * Remove all the available clusters
308    * (default deletes generated bridge clusters)
309    *
310    * @param is_all If true all CCM clusters are removed; otherwise false to
311    *               delete bridge generated clusters (default: false)
312    */
313   void remove_all_clusters(bool is_all = false);
314 
315   /**
316    * Start the active Cassandra cluster
317    *
318    * @param jvm_arguments Array/Vector of JVM arguments to apply during
319    *                     cluster start
320    * @return True if cluster is up; false otherwise
321    */
322   bool start_cluster(std::vector<std::string> jvm_arguments);
323 
324   /**
325    * Start the active Cassandra cluster
326    *
327    * @param jvm_argument JVM argument to apply during cluster start (optional)
328    * @return True if cluster is down; false otherwise
329    */
330   bool start_cluster(std::string jvm_argument = "");
331 
332   /**
333    * Stop the active Cassandra cluster
334    *
335    * @param is_kill True if forced termination requested; false otherwise
336    *                (default: false)
337    * @return True if cluster is down; false otherwise
338    */
339   bool stop_cluster(bool is_kill = false);
340 
341   /**
342    * Switch to another available cluster
343    *
344    * @param cluster_name Cluster name to switch to
345    * @return True if switched or is currently active cluster; false otherwise
346    */
347   bool switch_cluster(const std::string& cluster_name);
348 
349   /**
350    * Update the cluster configuration
351    *
352    * @param key_value_pairs Key:Value to update
353    * @param is_dse True if key/value pair should update the dse.yaml file;
354    *               otherwise false (default: false; update cassandra.yaml)
355    * @param is_yaml True if key_value_pairs is a YAML string; otherwise false
356    *                (default: false)
357    *                NOTE: key_value_pairs in this instance must be a vector
358    *                      of strings for use with CCM literal YAML updates.
359    *                      These strings are single or multi-line YAML
360    *                      configurations; multi-line YAML must contain EOL
361    *                      marker at the end of each line (e.g. \n)
362    */
363   void update_cluster_configuration(std::vector<std::string> key_value_pairs, bool is_dse = false,
364                                     bool is_yaml = false);
365 
366   /**
367    * Update the cluster configuration
368    *
369    * @param key Key to update
370    * @param value Value to apply to key configuration
371    * @param is_dse True if key/value pair should update the dse.yaml file;
372    *               otherwise false (default: false; update cassandra.yaml)
373    */
374   void update_cluster_configuration(const std::string& key, const std::string& value,
375                                     bool is_dse = false);
376 
377   /**
378    * Update the cluster configuration using a YAML configuration
379    *
380    * @param yaml YAML configuration to apply to the cluster
381    *             NOTE: These strings are single or multi-line YAML
382    *                   configurations; multi-line YAML must contain EOL
383    *                   marker at the end of each line (e.g. \n)
384    * @param is_dse True if yaml configuration should update the dse.yaml file;
385    *               otherwise false (default: false; update cassandra.yaml)
386    */
387   void update_cluster_configuration_yaml(const std::string& yaml, bool is_dse = false);
388 
389   /**
390    * Update the node configuration
391    *
392    * @param node Node to update configuration on
393    * @param key_value_pairs Key:Value to update
394    */
395   void update_node_configuration(unsigned int node, std::vector<std::string> key_value_pairs);
396 
397   /**
398    * Update the node configuration
399    *
400    * @param node Node to update configuration on
401    * @param key Key to update
402    * @param value Value to apply to key configuration
403    */
404   void update_node_configuration(unsigned int node, const std::string& key,
405                                  const std::string& value);
406 
407   /**
408    * Add a node on the active Cassandra cluster
409    *
410    * @param data_center If provided add the node to the data center; otherwise
411    *                    add node normally (default: no data center)
412    * @return Node added to cluster
413    * @throws BridgeException
414    */
415   unsigned int add_node(const std::string& data_center = "");
416 
417   /**
418    * Bootstrap (add and start) a node on the active cluster
419    *
420    * @param jvm_arguments JVM arguments to apply during node start
421    * @param data_center If provided add the node to the data center; otherwise
422    *                    add node normally (default: no data center)
423    * @return Node added to cluster
424    * @throws BridgeException
425    */
426   unsigned int bootstrap_node(const std::vector<std::string>& jvm_arguments,
427                               const std::string& data_center = "");
428 
429   /**
430    * Bootstrap (add and start) a node on the active cluster
431    *
432    * @param jvm_argument JVM argument to apply during node start
433    *                     (default: no JVM argument)
434    * @param data_center If provided add the node to the data center; otherwise
435    *                    add node normally (default: no data center)
436    * @return Node added to cluster
437    * @throws BridgeException
438    */
439   unsigned int bootstrap_node(const std::string& jvm_argument = "",
440                               const std::string& data_center = "");
441 
442   /**
443    * Decommission a node on the active Cassandra cluster
444    *
445    * @param node Node to decommission
446    * @oaram is_force True if decommission should be forced; false otherwise
447    *                 (default: false)
448    * @return True if node was decommissioned; false otherwise
449    */
450   bool decommission_node(unsigned int node, bool is_force = false);
451 
452   /**
453    * Disable binary protocol for a node on the active Cassandra cluster
454    *
455    * @param node Node to disable binary protocol
456    */
457   void disable_node_binary_protocol(unsigned int node);
458 
459   /**
460    * Disable gossip for a node on the active Cassandra cluster
461    *
462    * @param node Node to disable gossip
463    */
464   void disable_node_gossip(unsigned int node);
465 
466   /**
467    * Disable trace for a node on the active Cassandra cluster
468    *
469    * @param node Node to disable tracing
470    */
471   void disable_node_trace(unsigned int node);
472 
473   /**
474    * Enable binary protocol for a node on the active Cassandra cluster
475    *
476    * @param node Node to enable binary protocol
477    */
478   void enable_node_binary_protocol(unsigned int node);
479 
480   /**
481    * Enable gossip for a node on the active Cassandra cluster
482    *
483    * @param node Node to enable gossip
484    */
485   void enable_node_gossip(unsigned int node);
486 
487   /**
488    * Enable trace for a node on the active Cassandra cluster
489    *
490    * @param node Node to enable tracing
491    */
492   void enable_node_trace(unsigned int node);
493 
494   /**
495    * Execute a CQL statement on a particular node
496    *
497    * @param node Node to execute CQL statement on
498    * @param cql CQL statement to execute
499    */
500   void execute_cql_on_node(unsigned int node, const std::string& cql);
501 
502   /**
503    * Determine if server type is Apache Cassandra
504    *
505    * @return True if Cassandra; false otherwise
506    */
is_cassandra()507   bool is_cassandra() { return server_type_ == ServerType::CASSANDRA; }
508 
509   /**
510    * Determine if server type is DataStax Enterprise
511    *
512    * @return True if DSE; false otherwise
513    */
is_dse()514   bool is_dse() { return server_type_ == ServerType::DSE; }
515 
516   /**
517    * Determine if server type is DataStax Distribution of Apache Cassandra
518    *
519    * @return True if DDAC; false otherwise
520    */
is_ddac()521   bool is_ddac() { return server_type_ == ServerType::DDAC; }
522 
523   /**
524    * Force decommission of a node on the active Cassandra cluster
525    *
526    * NOTE: Alias for decommission_node(node, true)
527    *
528    * @param node Node to decommission
529    * @return True if node was decommissioned; false otherwise
530    */
531   bool force_decommission_node(unsigned int node);
532 
533   /**
534    * "Hang up" a node on the active Cassandra cluster (SIGHUP)
535    *
536    * @param node Node send SIGHUP signal to
537    * @return True if node is down; false otherwise
538    */
539   bool hang_up_node(unsigned int node);
540 
541   /**
542    * Kill a node on the active Cassandra cluster (SIGKILL)
543    *
544    * @param node Node to kill
545    * @return True if node is down; false otherwise
546    */
547   bool kill_node(unsigned int node);
548 
549   /**
550    * Pause a node on the active Cassandra cluster
551    *
552    * @param node Node to pause
553    */
554   void pause_node(unsigned int node);
555 
556   /**
557    * Resume a node on the active Cassandra cluster
558    *
559    * @param node Node to resume
560    */
561   void resume_node(unsigned int node);
562 
563   /**
564    * Start a node on the active Cassandra cluster
565    *
566    * @param node Node to start
567    * @param jvm_arguments Array/Vector of JVM arguments to apply during node
568    *                      start (default: DEFAULT_JVM_ARGUMENTS)
569    * @return True if node is up; false otherwise
570    */
571   bool start_node(unsigned int node,
572                   const std::vector<std::string>& jvm_arguments = DEFAULT_JVM_ARGUMENTS);
573 
574   /**
575    * Start a node on the active Cassandra cluster with an additional JVM
576    * argument
577    *
578    * @param node Node to start
579    * @param jvm_argument JVM argument to apply during node start
580    * @return True if node is up; false otherwise
581    */
582   bool start_node(unsigned int node, const std::string& jvm_argument);
583 
584   /**
585    * Stop a node on the active Cassandra cluster
586    *
587    * @param node Node to stop
588    * @param is_kill True if forced termination requested; false otherwise
589    *                (default: false)
590    * @return True if node is down; false otherwise
591    */
592   bool stop_node(unsigned int node, bool is_kill = false);
593 
594   /**
595    * Get the IP address prefix from the host IP address
596    *
597    * @return IP address prefix
598    */
599   std::string get_ip_prefix();
600 
601   /**
602    * Get the Cassandra version from the active cluster
603    *
604    * @return Cassandra version
605    * @throws BridgeException
606    */
607   CassVersion get_cassandra_version();
608 
609   /**
610    * Get the DSE version from the active cluster
611    *
612    * @return DSE version
613    * @throws BridgeException
614    */
615   DseVersion get_dse_version();
616 
617   /**
618    * Set the DSE workload on a node
619    *
620    * NOTE: This operation should be performed before starting the node;
621    *       otherwise the node will be stopped and restarted
622    *
623    * @param node Node to set DSE workload on
624    * @param workload Workload to be set
625    * @param is_kill True if forced termination requested; false otherwise
626    *                (default: false)
627    * @return True if node was restarted; false otherwise
628    */
629   bool set_dse_workload(unsigned int node, DseWorkload workload, bool is_kill = false);
630 
631   /**
632    * Set the DSE workloads on a node
633    *
634    * NOTE: This operation should be performed before starting the node;
635    *       otherwise the node will be stopped and restarted
636    *
637    * @param node Node to set DSE workload on
638    * @param workloads Workloads to be set
639    * @param is_kill True if forced termination requested; false otherwise
640    *                (default: false)
641    * @return True if node was restarted; false otherwise
642    */
643   bool set_dse_workloads(unsigned int node, std::vector<DseWorkload> workloads,
644                          bool is_kill = false);
645 
646   /**
647    * Set the DSE workload on the cluster
648    *
649    * NOTE: This operation should be performed before starting the cluster;
650    *       otherwise the cluster will be stopped and restarted
651    *
652    * @param workload Workload to be set
653    * @param is_kill True if forced termination requested; false otherwise
654    *                (default: false)
655    * @return True if cluster was restarted; false otherwise
656    */
657   bool set_dse_workload(DseWorkload workload, bool is_kill = false);
658 
659   /**
660    * Set the DSE workloads on the cluster
661    *
662    * NOTE: This operation should be performed before starting the cluster;
663    *       otherwise the cluster will be stopped and restarted
664    *
665    * @param workloads Workloads to be set
666    * @param is_kill True if forced termination requested; false otherwise
667    *                (default: false)
668    * @return True if cluster was restarted; false otherwise
669    */
670   bool set_dse_workloads(std::vector<DseWorkload> workloads, bool is_kill = false);
671 
672   /**
673    * Check to see if a node has been decommissioned
674    *
675    * @param node Node to check `DECOMMISSION` status
676    * @return True if node is decommissioned; false otherwise
677    */
678   bool is_node_decommissioned(unsigned int node);
679 
680   /**
681    * Check to see if a node will no longer accept connections
682    *
683    * NOTE: This method may check the status of the node multiple times
684    *
685    * @param node Node to check `DOWN` status
686    * @param is_quick_check True if `DOWN` status is checked once; false
687    *        otherwise (default: false)
688    * @return True if node is no longer accepting connections; false otherwise
689    */
690   bool is_node_down(unsigned int node, bool is_quick_check = false);
691 
692   /**
693    * Check to see if a node is ready to accept connections
694    *
695    * NOTE: This method may check the status of the node multiple times
696    *
697    * @param node Node to check `UP` status
698    * @param is_quick_check True if `UP` status is checked once; false
699    *        otherwise (default: false)
700    * @return True if node is ready to accept connections; false otherwise
701    */
702   bool is_node_up(unsigned int node, bool is_quick_check = false);
703 
704 private:
705   /**
706    * Cassandra version to use
707    */
708   CassVersion cassandra_version_;
709   /**
710    * DSE version to use
711    */
712   DseVersion dse_version_;
713   /**
714    * Flag to determine if Cassandra/DSE should be built from ASF/GitHub
715    */
716   bool use_git_;
717   /**
718    * Branch/Tag to retrieve from ASF/GitHub
719    */
720   std::string branch_tag_;
721   /**
722    * Flag to determine if installation directory should be used (passed to
723    * CCM)
724    */
725   bool use_install_dir_;
726   /**
727    * Installation directory to pass to CCM
728    */
729   std::string install_dir_;
730   /**
731    * Server type to use with CCM
732    */
733   ServerType server_type_;
734   /**
735    * Workload to apply to the DSE cluster
736    *
737    * NOTE: Multiple workloads will be applied simultaneously via CCM
738    */
739   std::vector<DseWorkload> dse_workload_;
740   /**
741    * Cluster prefix to apply to cluster name during create command
742    */
743   std::string cluster_prefix_;
744   /**
745    * Authentication type (username|password/public key)
746    *
747    * Flag to indicate how SSH authentication should be established
748    */
749   AuthenticationType authentication_type_;
750   /**
751    * DSE credentials type (username|password/INI file)
752    *
753    * Flag to indicate how DSE credentials should be obtained
754    */
755   DseCredentialsType dse_credentials_type_;
756   /**
757    * Username to use when authenticating download access for DSE
758    */
759   std::string dse_username_;
760   /**
761    * Password to use when authenticating download access for DSE
762    */
763   std::string dse_password_;
764   /**
765    * Deployment type (local|ssh)
766    *
767    * Flag to indicate how CCM commands should be executed
768    */
769   DeploymentType deployment_type_;
770   /**
771    * IP address to use when establishing SSH connection for remote CCM
772    * command execution and/or IP address to use for server connection IP
773    * generation
774    */
775   std::string host_;
776 #ifdef CASS_USE_LIBSSH2
777   /**
778    * SSH session handle for establishing connection
779    */
780   LIBSSH2_SESSION* session_;
781   /**
782    * SSH channel handle for interacting with the session
783    */
784   LIBSSH2_CHANNEL* channel_;
785   /**
786    * Socket instance
787    */
788   Socket* socket_;
789 #endif
790   /**
791    * Workload values to use when setting the workload via CCM
792    */
793   static const std::vector<std::string> dse_workloads_;
794   /**
795    * Flag to determine if verbose output is enabled
796    */
797   bool is_verbose_;
798 
799 #ifdef CASS_USE_LIBSSH2
800   /**
801    * Initialize the socket
802    *
803    * @param host Host/IP address for SSH connection
804    * @param port TCP/IP port for SSH connection
805    * @throws SocketException
806    */
807   void initialize_socket(const std::string& host, short port);
808 
809   /**
810    * Synchronize the socket based on the direction of the libssh2 session
811    *
812    * @throws BridgeException
813    * @throws SocketException
814    */
815   void synchronize_socket();
816 
817   /**
818    * Initialize the libssh2 connection
819    *
820    * @throws BridgeException
821    */
822   void initialize_libssh2();
823 
824   /**
825    * Establish connection via libssh2
826    *
827    * @param authentication_type Username|Password/Public key authentication
828    * @param username Username for SSH authentication
829    * @param password Password for SSH authentication; NULL if using public
830    *                 key
831    * @param public_key Public key for authentication; Empty if using username
832    *                   and password authentication
833    * @param private_key Private key for authentication; Empty if using
834    *                   username and password authentication
835    * @throws BridgeException
836    */
837   void establish_libssh2_connection(AuthenticationType authentication_type,
838                                     const std::string& username, const std::string& password,
839                                     const std::string& public_key, const std::string& private_key);
840 
841   /**
842    * Create/Open the libssh2 terminal
843    *
844    * @throws BridgeException
845    */
846   void open_libssh2_terminal();
847 
848   /**
849    * Terminate/Close the libssh2 terminal
850    *
851    * @throws BridgeException
852    */
853   void close_libssh2_terminal();
854 
855   /**
856    * Execute a remote command on the libssh2 connection
857    *
858    * @param command Command array to execute ([0] = command, [1-n] arguments)
859    * @return Output from executed command
860    */
861   std::string execute_libssh2_command(const std::vector<std::string>& command);
862 #endif
863 
864 #ifdef CASS_USE_LIBSSH2
865   /**
866    * Read the output (stdout and stderr) from the libssh2 terminal
867    *
868    * @return Output from the terminal (may not be in order)
869    */
870   std::string read_libssh2_terminal();
871 
872   /**
873    * Finalize the libssh2 library usage and socket used by libssh2
874    */
875   void finalize_libssh2();
876 #endif
877 
878   /**
879    * Execute the CCM command
880    *
881    * @param command Command array to execute ([0] = CCM command,
882    *                [1-n] arguments)
883    * @return Output from executing CCM command
884    */
885   std::string execute_ccm_command(const std::vector<std::string>& command);
886 
887   /**
888    * Get the active Cassandra cluster
889    *
890    * @return Currently active Cassandra cluster
891    */
892   std::string get_active_cluster();
893 
894   /**
895    * Get the list of available Cassandra clusters
896    *
897    * @return Array/Vector of available Cassandra clusters
898    */
899   std::vector<std::string> get_available_clusters();
900 
901   /**
902    * Get the list of available Cassandra clusters
903    *
904    * @param [out] active_cluster Current active cluster in the list
905    * @return Array/Vector of available Cassandra clusters
906    */
907   std::vector<std::string> get_available_clusters(std::string& active_cluster);
908 
909   /**
910    * Generate the name of the Cassandra cluster based on the number of nodes
911    * in each data center
912    *
913    * @param cassandra_version Cassandra version being used
914    * @param data_center_nodes Vector of nodes for each data center
915    * @param with_vnodes True if vnodes are enabled; false otherwise
916    * @param is_password_authenticator True if password authenticator is
917    *                                  enabled; false otherwise
918    * @param is_ssl True if SSL is enabled; false otherwise
919    * @param is_client_authentication True if client authentication is enabled;
920    *                                false otherwise
921    * @return Cluster name
922    */
923   std::string generate_cluster_name(CassVersion cassandra_version,
924                                     std::vector<unsigned short> data_center_nodes, bool with_vnodes,
925                                     bool is_password_authenticator, bool is_ssl,
926                                     bool is_client_authentication);
927 
928   /**
929    * Generate the nodes parameter for theCassandra cluster based on the number
930    * of nodes in each data center
931    *
932    * @param data_center_nodes Vector of nodes for each data center
933    * @param separator Separator to use between cluster nodes
934    * @return String of nodes separated by separator
935    */
936   std::string generate_cluster_nodes(std::vector<unsigned short> data_center_nodes,
937                                      char separator = ':');
938 
939   /**
940    * Generate the CCM update configuration command based on the Cassandra
941    * version requested
942    *
943    * @param cassandra_version Cassandra version to use
944    * @return Array/Vector containing the updateconf command
945    */
946   std::vector<std::string> generate_create_updateconf_command(CassVersion cassandra_version);
947 
948   /**
949    * Generate the command separated list for have a single or multiple
950    * workloads for the CCM setworkload command
951    *
952    * @param workloads Workloads to be set
953    * @return String representing the workloads for the setworkload command
954    */
955   std::string generate_dse_workloads(std::vector<DseWorkload> workloads);
956 
957   /**
958    * Get the next available node
959    *
960    * @return Next available node
961    * @throws BridgeException
962    * @see CLUSTER_NODE_LIMIT
963    */
964   unsigned int get_next_available_node();
965 
966   /**
967    * Generate the node name based on the node requested
968    *
969    * @param node Node to use
970    * @return Name of the node for CCM node commands
971    */
972   std::string generate_node_name(unsigned int node);
973 
974   /**
975    * Determine if a node is available
976    *
977    * @param node Cassandra node to check
978    * @return True if node is available; false otherwise
979    */
980   bool is_node_availabe(unsigned int node);
981 
982   /**
983    * Determine if a node is available
984    *
985    * @param ip_address IPv4 address of the Cassandra node
986    * @return True if node is available; false otherwise
987    */
988   bool is_node_availabe(const std::string& ip_address);
989 
990   /**
991    * Convert a string to lowercase
992    *
993    * @param input String to convert to lowercase
994    *
995    * TODO: Remove static declaration after deprecations are removed
996    */
997   static std::string to_lower(const std::string& input);
998 
999   /**
1000    * Remove the leading and trailing whitespace from a string
1001    *
1002    * @param input String to trim
1003    * @return Trimmed string
1004    *
1005    * TODO: Remove static declaration after deprecations are removed
1006    */
1007   static std::string trim(const std::string& input);
1008 
1009   /**
1010    * Concatenate an array/vector into a string
1011    *
1012    * @param elements Array/Vector elements to concatenate
1013    * @param delimiter Character to use between elements (default: <space>)
1014    * @return A string representation of all the array/vector elements
1015    */
1016   std::string implode(const std::vector<std::string>& elements, const char delimiter = ' ');
1017 
1018   /**
1019    * Split a string into an array/vector
1020    *
1021    * @param input String to convert to array/vector
1022    * @param delimiter Character to use split into elements (default: <space>)
1023    * @return An array/vector representation of the string
1024    *
1025    * TODO: Remove static declaration after deprecations are removed
1026    */
1027   static std::vector<std::string> explode(const std::string& input, const char delimiter = ' ');
1028 
1029   /**
1030    * Cross platform millisecond granularity sleep
1031    *
1032    * @param milliseconds Time in milliseconds to sleep
1033    */
1034   void msleep(unsigned int milliseconds);
1035 };
1036 } // namespace CCM
1037 
1038 #endif // __CCM_BRIDGE_HPP__
1039