github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/roachprod/install/expander.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  	"fmt"
    15  	"regexp"
    16  	"strings"
    17  
    18  	"github.com/cockroachdb/errors"
    19  )
    20  
    21  var parameterRe = regexp.MustCompile(`{[^}]*}`)
    22  var pgURLRe = regexp.MustCompile(`{pgurl(:[-,0-9]+)?}`)
    23  var pgHostRe = regexp.MustCompile(`{pghost(:[-,0-9]+)?}`)
    24  var pgPortRe = regexp.MustCompile(`{pgport(:[-,0-9]+)?}`)
    25  var uiPortRe = regexp.MustCompile(`{uiport(:[-,0-9]+)?}`)
    26  var storeDirRe = regexp.MustCompile(`{store-dir}`)
    27  var logDirRe = regexp.MustCompile(`{log-dir}`)
    28  var certsDirRe = regexp.MustCompile(`{certs-dir}`)
    29  
    30  // expander expands a string which contains templated parameters for cluster
    31  // attributes like pgurl, pghost, pgport, uiport, store-dir, and log-dir with
    32  // the corresponding values.
    33  type expander struct {
    34  	node int
    35  
    36  	pgURLs  map[int]string
    37  	pgHosts map[int]string
    38  	pgPorts map[int]string
    39  	uiPorts map[int]string
    40  }
    41  
    42  // expanderFunc is a function which may expand a string with a templated value.
    43  type expanderFunc func(*SyncedCluster, string) (expanded string, didExpand bool, err error)
    44  
    45  // expand will expand arg if it contains an expander template.
    46  func (e *expander) expand(c *SyncedCluster, arg string) (string, error) {
    47  	var err error
    48  	s := parameterRe.ReplaceAllStringFunc(arg, func(s string) string {
    49  		if err != nil {
    50  			return ""
    51  		}
    52  		expanders := []expanderFunc{
    53  			e.maybeExpandPgURL,
    54  			e.maybeExpandPgHost,
    55  			e.maybeExpandPgPort,
    56  			e.maybeExpandUIPort,
    57  			e.maybeExpandStoreDir,
    58  			e.maybeExpandLogDir,
    59  			e.maybeExpandCertsDir,
    60  		}
    61  		for _, f := range expanders {
    62  			v, expanded, fErr := f(c, s)
    63  			if fErr != nil {
    64  				err = fErr
    65  				return ""
    66  			}
    67  			if expanded {
    68  				return v
    69  			}
    70  		}
    71  		return s
    72  	})
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  	return s, nil
    77  }
    78  
    79  // maybeExpandMap is used by other expanderFuncs to return a space separated
    80  // list of strings which correspond to the values in m for each node specified
    81  // by nodeSpec.
    82  func (e *expander) maybeExpandMap(
    83  	c *SyncedCluster, m map[int]string, nodeSpec string,
    84  ) (string, error) {
    85  	if nodeSpec == "" {
    86  		nodeSpec = "all"
    87  	} else {
    88  		nodeSpec = nodeSpec[1:]
    89  	}
    90  
    91  	nodes, err := ListNodes(nodeSpec, len(c.VMs))
    92  	if err != nil {
    93  		return "", err
    94  	}
    95  
    96  	var result []string
    97  	for _, i := range nodes {
    98  		if s, ok := m[i]; ok {
    99  			result = append(result, s)
   100  		}
   101  	}
   102  	if len(result) != len(nodes) {
   103  		return "", errors.Errorf("failed to expand nodes %v, given node map %v", nodes, m)
   104  	}
   105  	return strings.Join(result, " "), nil
   106  }
   107  
   108  // maybeExpandPgURL is an expanderFunc for {pgurl:<nodeSpec>}
   109  func (e *expander) maybeExpandPgURL(c *SyncedCluster, s string) (string, bool, error) {
   110  	m := pgURLRe.FindStringSubmatch(s)
   111  	if m == nil {
   112  		return s, false, nil
   113  	}
   114  
   115  	if e.pgURLs == nil {
   116  		e.pgURLs = c.pgurls(allNodes(len(c.VMs)))
   117  	}
   118  
   119  	s, err := e.maybeExpandMap(c, e.pgURLs, m[1])
   120  	return s, err == nil, err
   121  }
   122  
   123  // maybeExpandPgHost is an expanderFunc for {pghost:<nodeSpec>}
   124  func (e *expander) maybeExpandPgHost(c *SyncedCluster, s string) (string, bool, error) {
   125  	m := pgHostRe.FindStringSubmatch(s)
   126  	if m == nil {
   127  		return s, false, nil
   128  	}
   129  
   130  	if e.pgHosts == nil {
   131  		e.pgHosts = c.pghosts(allNodes(len(c.VMs)))
   132  	}
   133  
   134  	s, err := e.maybeExpandMap(c, e.pgHosts, m[1])
   135  	return s, err == nil, err
   136  }
   137  
   138  // maybeExpandPgURL is an expanderFunc for {pgport:<nodeSpec>}
   139  func (e *expander) maybeExpandPgPort(c *SyncedCluster, s string) (string, bool, error) {
   140  	m := pgPortRe.FindStringSubmatch(s)
   141  	if m == nil {
   142  		return s, false, nil
   143  	}
   144  
   145  	if e.pgPorts == nil {
   146  		e.pgPorts = make(map[int]string, len(c.VMs))
   147  		for _, i := range allNodes(len(c.VMs)) {
   148  			e.pgPorts[i] = fmt.Sprint(c.Impl.NodePort(c, i))
   149  		}
   150  	}
   151  
   152  	s, err := e.maybeExpandMap(c, e.pgPorts, m[1])
   153  	return s, err == nil, err
   154  }
   155  
   156  // maybeExpandPgURL is an expanderFunc for {uiport:<nodeSpec>}
   157  func (e *expander) maybeExpandUIPort(c *SyncedCluster, s string) (string, bool, error) {
   158  	m := uiPortRe.FindStringSubmatch(s)
   159  	if m == nil {
   160  		return s, false, nil
   161  	}
   162  
   163  	if e.uiPorts == nil {
   164  		e.uiPorts = make(map[int]string, len(c.VMs))
   165  		for _, i := range allNodes(len(c.VMs)) {
   166  			e.uiPorts[i] = fmt.Sprint(c.Impl.NodeUIPort(c, i))
   167  		}
   168  	}
   169  
   170  	s, err := e.maybeExpandMap(c, e.uiPorts, m[1])
   171  	return s, err == nil, err
   172  }
   173  
   174  // maybeExpandStoreDir is an expanderFunc for "{store-dir}"
   175  func (e *expander) maybeExpandStoreDir(c *SyncedCluster, s string) (string, bool, error) {
   176  	if !storeDirRe.MatchString(s) {
   177  		return s, false, nil
   178  	}
   179  	return c.Impl.NodeDir(c, e.node), true, nil
   180  }
   181  
   182  // maybeExpandLogDir is an expanderFunc for "{log-dir}"
   183  func (e *expander) maybeExpandLogDir(c *SyncedCluster, s string) (string, bool, error) {
   184  	if !logDirRe.MatchString(s) {
   185  		return s, false, nil
   186  	}
   187  	return c.Impl.LogDir(c, e.node), true, nil
   188  }
   189  
   190  // maybeExpandCertsDir is an expanderFunc for "{certs-dir}"
   191  func (e *expander) maybeExpandCertsDir(c *SyncedCluster, s string) (string, bool, error) {
   192  	if !certsDirRe.MatchString(s) {
   193  		return s, false, nil
   194  	}
   195  	return c.Impl.CertsDir(c, e.node), true, nil
   196  }