github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/roachprod/install/cassandra.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package install
    12  
    13  import (
    14  	"bufio"
    15  	"fmt"
    16  	"html/template"
    17  	"io/ioutil"
    18  	"log"
    19  	"os"
    20  	"time"
    21  
    22  	"github.com/cockroachdb/cockroach/pkg/cmd/roachprod/ssh"
    23  )
    24  
    25  // Cassandra TODO(peter): document
    26  type Cassandra struct{}
    27  
    28  // Start implements the ClusterImpl.NodeDir interface.
    29  func (Cassandra) Start(c *SyncedCluster, extraArgs []string) {
    30  	yamlPath, err := makeCassandraYAML(c)
    31  	if err != nil {
    32  		log.Fatal(err)
    33  	}
    34  	c.Put(yamlPath, "./cassandra.yaml")
    35  	_ = os.Remove(yamlPath)
    36  
    37  	display := fmt.Sprintf("%s: starting cassandra (be patient)", c.Name)
    38  	nodes := c.ServerNodes()
    39  	c.Parallel(display, len(nodes), 1, func(i int) ([]byte, error) {
    40  		host := c.host(nodes[i])
    41  		user := c.user(nodes[i])
    42  
    43  		if err := func() error {
    44  			session, err := ssh.NewSSHSession(user, host)
    45  			if err != nil {
    46  				return err
    47  			}
    48  			defer session.Close()
    49  
    50  			cmd := c.Env + `env ROACHPROD=true cassandra` +
    51  				` -Dcassandra.config=file://${PWD}/cassandra.yaml` +
    52  				` -Dcassandra.ring_delay_ms=3000` +
    53  				` > cassandra.stdout 2> cassandra.stderr`
    54  			_, err = session.CombinedOutput(cmd)
    55  			return err
    56  		}(); err != nil {
    57  			return nil, err
    58  		}
    59  
    60  		for {
    61  			up, err := func() (bool, error) {
    62  				session, err := ssh.NewSSHSession(user, host)
    63  				if err != nil {
    64  					return false, err
    65  				}
    66  				defer session.Close()
    67  
    68  				cmd := `nc -z $(hostname) 9042`
    69  				if _, err := session.CombinedOutput(cmd); err != nil {
    70  					// The common case here is going to be "exit status 1" until the
    71  					// cassandra process starts listening on the port. Logging would
    72  					// just generate noise.
    73  					return false, nil //nolint:returnerrcheck
    74  				}
    75  				return true, nil
    76  			}()
    77  			if err != nil {
    78  				return nil, err
    79  			}
    80  			if up {
    81  				break
    82  			}
    83  			time.Sleep(time.Second)
    84  		}
    85  		return nil, nil
    86  	})
    87  }
    88  
    89  // NodeDir implements the ClusterImpl.NodeDir interface.
    90  func (Cassandra) NodeDir(c *SyncedCluster, index int) string {
    91  	if c.IsLocal() {
    92  		// TODO(peter): This will require a bit of work to adjust paths in
    93  		// cassandra.yaml.
    94  		panic("Cassandra.NodeDir unimplemented")
    95  	}
    96  	return "/mnt/data1/cassandra"
    97  }
    98  
    99  // LogDir implements the ClusterImpl.NodeDir interface.
   100  func (Cassandra) LogDir(c *SyncedCluster, index int) string {
   101  	panic("Cassandra.LogDir unimplemented")
   102  }
   103  
   104  // CertsDir implements the ClusterImpl.NodeDir interface.
   105  func (Cassandra) CertsDir(c *SyncedCluster, index int) string {
   106  	panic("Cassandra.CertsDir unimplemented")
   107  }
   108  
   109  // NodeURL implements the ClusterImpl.NodeDir interface.
   110  func (Cassandra) NodeURL(_ *SyncedCluster, host string, port int) string {
   111  	return fmt.Sprintf("'cassandra://%s:%d'", host, port)
   112  }
   113  
   114  // NodePort implements the ClusterImpl.NodeDir interface.
   115  func (Cassandra) NodePort(c *SyncedCluster, index int) int {
   116  	// TODO(peter): This will require a bit of work to adjust ports in
   117  	// cassandra.yaml.
   118  	// if c.IsLocal() {
   119  	// }
   120  	return 9042
   121  }
   122  
   123  // NodeUIPort implements the ClusterImpl.NodeDir interface.
   124  func (Cassandra) NodeUIPort(c *SyncedCluster, index int) int {
   125  	return 0 // unimplemented
   126  }
   127  
   128  func makeCassandraYAML(c *SyncedCluster) (string, error) {
   129  	ip, err := c.GetInternalIP(c.ServerNodes()[0])
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	f, err := ioutil.TempFile("", "cassandra.yaml")
   135  	if err != nil {
   136  		return "", err
   137  	}
   138  	defer f.Close()
   139  
   140  	w := bufio.NewWriter(f)
   141  	if _, err := w.WriteString(cassandraDefaultYAML); err != nil {
   142  		return "", err
   143  	}
   144  	defer w.Flush()
   145  
   146  	t, err := template.New("cassandra.yaml").Parse(cassandraDiffYAML)
   147  	if err != nil {
   148  		log.Fatal(err)
   149  	}
   150  	m := map[string]interface{}{
   151  		"Seeds": ip,
   152  	}
   153  	if err := t.Execute(w, m); err != nil {
   154  		log.Fatal(err)
   155  	}
   156  	return f.Name(), nil
   157  }