@@ -28,16 +28,20 @@ import (
2828	"bytes" 
2929	"strings" 
3030
31+ 	"github.com/spf13/viper" 
32+ 
3133	"github.com/opencurve/curveadm/internal/build" 
3234	"github.com/opencurve/curveadm/internal/configure/os" 
3335	"github.com/opencurve/curveadm/internal/errno" 
3436	"github.com/opencurve/curveadm/internal/utils" 
35- 	"github.com/spf13/viper" 
37+ 	log "github.com/opencurve/curveadm/pkg/log/glg" 
38+ 	"github.com/opencurve/curveadm/pkg/variable" 
3639)
3740
3841const  (
39- 	KEY_LABELS  =  "labels" 
40- 	KEY_ENVS    =  "envs" 
42+ 	KEY_LABELS     =  "labels" 
43+ 	KEY_ENVS       =  "envs" 
44+ 	KEY_INSTANCES  =  "instances" 
4145
4246	PERMISSIONS_600  =  384  // -rw------- (256 + 128 = 384) 
4347)
@@ -49,10 +53,16 @@ type (
4953	}
5054
5155	HostConfig  struct  {
52- 		sequence  int 
53- 		config    map [string ]interface {}
54- 		labels    []string 
55- 		envs      []string 
56+ 		sequence   int 
57+ 		config     map [string ]interface {}
58+ 		labels     []string 
59+ 		envs       []string 
60+ 		variables  * variable.Variables 
61+ 		//instances and instancesSequence only used in the memcached deploy 
62+ 		//instances is the num of memcached servers will be deployed in the same host 
63+ 		instances  int 
64+ 		//instancesSquence is the sequence num of memcached servers in the same host 
65+ 		instancesSequence  int 
5666	}
5767)
5868
@@ -71,7 +81,7 @@ func merge(parent, child map[string]interface{}) {
7181	}
7282}
7383
74- func  (hc  * HostConfig ) convertLables () error  {
84+ func  (hc  * HostConfig ) convertLabels () error  {
7585	value  :=  hc .config [KEY_LABELS ]
7686	slice , ok  :=  (value ).([]interface {})
7787	if  ! ok  {
@@ -107,14 +117,137 @@ func (hc *HostConfig) convertEnvs() error {
107117			hc .envs  =  append (hc .envs , v )
108118		}
109119	}
120+ 	return  nil 
121+ }
122+ 
123+ // read the instances value from hc.config 
124+ func  (hc  * HostConfig ) convertInstances () error  {
125+ 	value  :=  hc .config [KEY_INSTANCES ]
126+ 	v , ok  :=  utils .All2Str (value )
127+ 	if  ! ok  {
128+ 		return  errno .ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE .
129+ 			F ("hosts[%d].%s = %v" , hc .sequence , KEY_INSTANCES , value )
130+ 	}
131+ 	if  v , ok  :=  utils .Str2Int (v ); ! ok  {
132+ 		return  errno .ERR_CONFIGURE_VALUE_REQUIRES_INTEGER .
133+ 			F ("hosts[%d].%s = %v" , hc .sequence , KEY_INSTANCES , value )
134+ 	} else  if  v  <=  0  {
135+ 		return  errno .ERR_CONFIGURE_VALUE_REQUIRES_POSITIVE_INTEGER .
136+ 			F ("hosts[%d].%s = %v" , hc .sequence , KEY_INSTANCES , value )
137+ 	} else  {
138+ 		hc .instances  =  v 
139+ 		return  nil 
140+ 	}
141+ }
142+ 
143+ // convert config item to its require type after rendering, 
144+ // return error if convert failed 
145+ //func (hc *HostConfig) convert() error { 
146+ //	for _, item := range itemset.GetAll() { 
147+ //		k := item.Key() 
148+ //		value := hc.get(item) // return config value or default value 
149+ //		if value == nil { 
150+ //			continue 
151+ //		} 
152+ //		v, ok := utils.All2Str(value) 
153+ //		if !ok { 
154+ //			return errno.ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE. 
155+ //				F("%s: %v", k, value) 
156+ //		} 
157+ // 
158+ //		switch item.require { 
159+ //		case REQUIRE_ANY: 
160+ //			// do nothing 
161+ //		case REQUIRE_INT: 
162+ //			if intv, ok := utils.Str2Int(v); !ok { 
163+ //				return errno.ERR_CONFIGURE_VALUE_REQUIRES_INTEGER. 
164+ //					F("%s: %v", k, value) 
165+ //			} else { 
166+ //				hc.config[k] = intv 
167+ //			} 
168+ //		case REQUIRE_STRING: 
169+ //			if len(v) == 0 { 
170+ //				return errno.ERR_CONFIGURE_VALUE_REQUIRES_NON_EMPTY_STRING. 
171+ //					F("%s: %v", k, value) 
172+ //			} 
173+ //		case REQUIRE_BOOL: 
174+ //			if boolv, ok := utils.Str2Bool(v); !ok { 
175+ //				return errno.ERR_CONFIGURE_VALUE_REQUIRES_BOOL. 
176+ //					F("%s: %v", k, value) 
177+ //			} else { 
178+ //				hc.config[k] = boolv 
179+ //			} 
180+ //		case REQUIRE_POSITIVE_INTEGER: 
181+ //			if intv, ok := utils.Str2Int(v); !ok { 
182+ //				return errno.ERR_CONFIGURE_VALUE_REQUIRES_INTEGER. 
183+ //					F("%s: %v", k, value) 
184+ //			} else if intv <= 0 { 
185+ //				return errno.ERR_CONFIGURE_VALUE_REQUIRES_POSITIVE_INTEGER. 
186+ //					F("%s: %v", k, value) 
187+ //			} else { 
188+ //				hc.config[k] = intv 
189+ //			} 
190+ //		} 
191+ //	} 
192+ //	return nil 
193+ //} 
194+ 
195+ // convert config item to its required type after rendering, 
196+ // return error if convert failed 
197+ func  (hc  * HostConfig ) convert () error  {
198+ 	for  key , value  :=  range  hc .config  {
199+ 		if  key  ==  KEY_LABELS  {
200+ 			continue 
201+ 		} else  if  key  ==  KEY_ENVS  {
202+ 			continue 
203+ 		} else  if  key  ==  KEY_INSTANCES  {
204+ 			continue 
205+ 		}
206+ 		if  itemset .Get (key ) ==  nil  {
207+ 			return  errno .ERR_UNSUPPORT_HOSTS_CONFIGURE_ITEM .
208+ 				F ("hosts[%d].%s = %v" , hc .sequence , key , value )
209+ 		}
210+ 		v , err  :=  itemset .Build (key , value )
211+ 		if  err  !=  nil  {
212+ 			return  err 
213+ 		} else  {
214+ 			hc .config [key ] =  v 
215+ 		}
216+ 	}
217+ 	privateKeyFile  :=  hc .GetPrivateKeyFile ()
218+ 	if  len (hc .GetName ()) ==  0  {
219+ 		return  errno .ERR_NAME_FIELD_MISSING .
220+ 			F ("hosts[%d].host/name = nil" , hc .sequence )
221+ 	} else  if  len (hc .GetHostname ()) ==  0  {
222+ 		return  errno .ERR_HOSTNAME_FIELD_MISSING .
223+ 			F ("hosts[%d].hostname = nil" , hc .sequence )
224+ 	} else  if  ! utils .IsValidAddress (hc .GetHostname ()) {
225+ 		return  errno .ERR_HOSTNAME_REQUIRES_VALID_IP_ADDRESS .
226+ 			F ("hosts[%d].hostname = %s" , hc .sequence , hc .GetHostname ())
227+ 	} else  if  hc .GetSSHPort () >  os .GetMaxPortNum () {
228+ 		return  errno .ERR_HOSTS_SSH_PORT_EXCEED_MAX_PORT_NUMBER .
229+ 			F ("hosts[%d].ssh_port = %d" , hc .sequence , hc .GetSSHPort ())
230+ 	} else  if  ! strings .HasPrefix (privateKeyFile , "/" ) {
231+ 		return  errno .ERR_PRIVATE_KEY_FILE_REQUIRE_ABSOLUTE_PATH .
232+ 			F ("hosts[%d].private_key_file = %s" , hc .sequence , privateKeyFile )
233+ 	}
110234
235+ 	if  ! hc .GetForwardAgent () {
236+ 		if  ! utils .PathExist (privateKeyFile ) {
237+ 			return  errno .ERR_PRIVATE_KEY_FILE_NOT_EXIST .
238+ 				F ("%s: no such file" , privateKeyFile )
239+ 		} else  if  utils .GetFilePermissions (privateKeyFile ) !=  PERMISSIONS_600  {
240+ 			return  errno .ERR_PRIVATE_KEY_FILE_REQUIRE_600_PERMISSIONS .
241+ 				F ("%s: mode (%d)" , privateKeyFile , utils .GetFilePermissions (privateKeyFile ))
242+ 		}
243+ 	}
111244	return  nil 
112245}
113246
114247func  (hc  * HostConfig ) Build () error  {
115248	for  key , value  :=  range  hc .config  {
116249		if  key  ==  KEY_LABELS  { // convert labels 
117- 			if  err  :=  hc .convertLables (); err  !=  nil  {
250+ 			if  err  :=  hc .convertLabels (); err  !=  nil  {
118251				return  err 
119252			}
120253			hc .config [key ] =  nil  // delete labels section 
@@ -123,7 +256,13 @@ func (hc *HostConfig) Build() error {
123256			if  err  :=  hc .convertEnvs (); err  !=  nil  {
124257				return  err 
125258			}
126- 			hc .config [key ] =  nil  // delete labels section 
259+ 			hc .config [key ] =  nil  // delete envs section 
260+ 			continue 
261+ 		} else  if  key  ==  KEY_INSTANCES  { // convert instances 
262+ 			if  err  :=  hc .convertInstances (); err  !=  nil  {
263+ 				return  err 
264+ 			}
265+ 			hc .config [key ] =  nil  // delete instances section 
127266			continue 
128267		}
129268
@@ -142,7 +281,7 @@ func (hc *HostConfig) Build() error {
142281
143282	privateKeyFile  :=  hc .GetPrivateKeyFile ()
144283	if  len (hc .GetName ()) ==  0  {
145- 		return  errno .ERR_HOST_FIELD_MISSING .
284+ 		return  errno .ERR_NAME_FIELD_MISSING .
146285			F ("hosts[%d].host/name = nil" , hc .sequence )
147286	} else  if  len (hc .GetHostname ()) ==  0  {
148287		return  errno .ERR_HOSTNAME_FIELD_MISSING .
@@ -158,7 +297,7 @@ func (hc *HostConfig) Build() error {
158297			F ("hosts[%d].private_key_file = %s" , hc .sequence , privateKeyFile )
159298	}
160299
161- 	if  hc .GetForwardAgent ()  ==   false  {
300+ 	if  ! hc .GetForwardAgent () {
162301		if  ! utils .PathExist (privateKeyFile ) {
163302			return  errno .ERR_PRIVATE_KEY_FILE_NOT_EXIST .
164303				F ("%s: no such file" , privateKeyFile )
@@ -170,19 +309,115 @@ func (hc *HostConfig) Build() error {
170309	return  nil 
171310}
172311
312+ // "PORT=112${instancesSquence}" -> "PORT=11201" 
313+ func  (hc  * HostConfig ) renderVariables () error  {
314+ 	//0. get vars 
315+ 	vars  :=  hc .GetVariables ()
316+ 	if  err  :=  vars .Build (); err  !=  nil  {
317+ 		log .Error ("Build variables failed" ,
318+ 			log .Field ("error" , err ))
319+ 		return  errno .ERR_RESOLVE_VARIABLE_FAILED .E (err )
320+ 	}
321+ 	//1. all config to str 
322+ 	for  k , v  :=  range  hc .config  {
323+ 		if  v  ==  nil  {
324+ 			continue 
325+ 		}
326+ 		if  strv , ok  :=  utils .All2Str (v ); ok  {
327+ 			hc .config [k ] =  strv 
328+ 		} else  {
329+ 			return  errno .ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE .
330+ 				F ("%s: %v" , k , v )
331+ 		}
332+ 	}
333+ 	//2. rendering 
334+ 	//render labels 
335+ 	for  i  :=  range  hc .labels  {
336+ 		err  :=  func (value  * string ) error  {
337+ 			realValue , err  :=  vars .Rendering (* value )
338+ 			if  err  !=  nil  {
339+ 				return  err 
340+ 			}
341+ 			* value  =  realValue 
342+ 			return  nil 
343+ 		}(& hc .labels [i ])
344+ 		if  err  !=  nil  {
345+ 			return  errno .ERR_RENDERING_VARIABLE_FAILED .E (err )
346+ 		}
347+ 	}
348+ 	//render envs 
349+ 	for  i  :=  range  hc .envs  {
350+ 		err  :=  func (value  * string ) error  {
351+ 			realValue , err  :=  vars .Rendering (* value )
352+ 			if  err  !=  nil  {
353+ 				return  err 
354+ 			}
355+ 			* value  =  realValue 
356+ 			return  nil 
357+ 		}(& hc .envs [i ])
358+ 		if  err  !=  nil  {
359+ 			return  errno .ERR_RENDERING_VARIABLE_FAILED .E (err )
360+ 		}
361+ 	}
362+ 	//render config 
363+ 	for  k , v  :=  range  hc .config  {
364+ 		if  v  ==  nil  {
365+ 			continue 
366+ 		}
367+ 		realv , err  :=  vars .Rendering (v .(string ))
368+ 		if  err  !=  nil  {
369+ 			return  errno .ERR_RENDERING_VARIABLE_FAILED .E (err )
370+ 		}
371+ 		hc .config [k ] =  realv 
372+ 		build .DEBUG (build .DEBUG_TOPOLOGY ,
373+ 			build.Field {Key : k , Value : v },
374+ 			build.Field {Key : k , Value : realv })
375+ 	}
376+ 	//3. convert config item to its required type after rendering, 
377+ 	//	 return error if convert failed 
378+ 	return  hc .convert ()
379+ }
380+ 
173381func  NewHostConfig (sequence  int , config  map [string ]interface {}) * HostConfig  {
382+ 	vars  :=  variable .NewVariables ()
383+ 
174384	return  & HostConfig {
175- 		sequence : sequence ,
176- 		config :   config ,
177- 		labels :   []string {},
385+ 		sequence :  sequence ,
386+ 		config :    config ,
387+ 		labels :    []string {},
388+ 		envs :      []string {},
389+ 		variables : vars ,
390+ 		//instances and instancesSquence only used in the memcached deploy 
391+ 		instances :         1 ,
392+ 		instancesSequence : 1 ,
393+ 	}
394+ }
395+ 
396+ // deepcopy a HostConfig with instancesSquence and return it (new variables) 
397+ func  copyHostConfig (src  * HostConfig , instancesSquence  int ) * HostConfig  {
398+ 	//deepcopy labels 
399+ 	newlabels  :=  make ([]string , len (src .labels ))
400+ 	copy (newlabels , src .labels )
401+ 	//deepcopy envs 
402+ 	newenvs  :=  make ([]string , len (src .envs ))
403+ 	copy (newenvs , src .envs )
404+ 	//create a new variables 
405+ 	vars  :=  variable .NewVariables ()
406+ 	return  & HostConfig {
407+ 		sequence :          src .sequence ,
408+ 		config :            utils .DeepCopy (src .config ),
409+ 		labels :            newlabels ,
410+ 		envs :              newenvs ,
411+ 		variables :         vars ,
412+ 		instances :         src .instances ,
413+ 		instancesSequence : instancesSquence ,
178414	}
179415}
180416
181417func  ParseHosts (data  string ) ([]* HostConfig , error ) {
182418	if  len (data ) ==  0  {
183419		return  nil , errno .ERR_EMPTY_HOSTS 
184420	}
185- 
186421	parser  :=  viper .NewWithOptions (viper .KeyDelimiter ("::" ))
187422	parser .SetConfigType ("yaml" )
188423	err  :=  parser .ReadConfig (bytes .NewBuffer ([]byte (data )))
@@ -210,9 +445,23 @@ func ParseHosts(data string) ([]*HostConfig, error) {
210445			return  nil , errno .ERR_DUPLICATE_NAME .
211446				F ("duplicate host: %s" , hc .GetName ())
212447		}
213- 		hcs  =  append (hcs , hc )
448+ 		//produce the instances of hc, append to hcs. (used in memcached deploy) 
449+ 		instances  :=  hc .GetInstances ()
450+ 		for  instancesSquence  :=  1 ; instancesSquence  <=  instances ; instancesSquence ++  {
451+ 			hc_new  :=  copyHostConfig (hc , instancesSquence )
452+ 			hcs  =  append (hcs , hc_new )
453+ 		}
214454		exist [hc .GetName ()] =  true 
215455	}
456+ 	//add Variables and Rendering 
457+ 	for  idx , hc  :=  range  hcs  {
458+ 		if  err  =  AddHostVariables (hcs , idx ); err  !=  nil  {
459+ 			return  nil , err  // already is error code 
460+ 		} else  if  err  =  hc .renderVariables (); err  !=  nil  {
461+ 			return  nil , err  // already is error code 
462+ 		}
463+ 		hc .GetVariables ().Debug ()
464+ 	}
216465	build .DEBUG (build .DEBUG_HOSTS , hosts )
217466	return  hcs , nil 
218467}
0 commit comments