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 }