@@ -28,16 +28,20 @@ import (
28
28
"bytes"
29
29
"strings"
30
30
31
+ "github.com/spf13/viper"
32
+
31
33
"github.com/opencurve/curveadm/internal/build"
32
34
"github.com/opencurve/curveadm/internal/configure/os"
33
35
"github.com/opencurve/curveadm/internal/errno"
34
36
"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"
36
39
)
37
40
38
41
const (
39
- KEY_LABELS = "labels"
40
- KEY_ENVS = "envs"
42
+ KEY_LABELS = "labels"
43
+ KEY_ENVS = "envs"
44
+ KEY_INSTANCES = "instances"
41
45
42
46
PERMISSIONS_600 = 384 // -rw------- (256 + 128 = 384)
43
47
)
@@ -49,10 +53,16 @@ type (
49
53
}
50
54
51
55
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
56
66
}
57
67
)
58
68
@@ -71,7 +81,7 @@ func merge(parent, child map[string]interface{}) {
71
81
}
72
82
}
73
83
74
- func (hc * HostConfig ) convertLables () error {
84
+ func (hc * HostConfig ) convertLabels () error {
75
85
value := hc .config [KEY_LABELS ]
76
86
slice , ok := (value ).([]interface {})
77
87
if ! ok {
@@ -107,14 +117,137 @@ func (hc *HostConfig) convertEnvs() error {
107
117
hc .envs = append (hc .envs , v )
108
118
}
109
119
}
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
+ }
110
234
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
+ }
111
244
return nil
112
245
}
113
246
114
247
func (hc * HostConfig ) Build () error {
115
248
for key , value := range hc .config {
116
249
if key == KEY_LABELS { // convert labels
117
- if err := hc .convertLables (); err != nil {
250
+ if err := hc .convertLabels (); err != nil {
118
251
return err
119
252
}
120
253
hc .config [key ] = nil // delete labels section
@@ -123,7 +256,13 @@ func (hc *HostConfig) Build() error {
123
256
if err := hc .convertEnvs (); err != nil {
124
257
return err
125
258
}
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
127
266
continue
128
267
}
129
268
@@ -142,7 +281,7 @@ func (hc *HostConfig) Build() error {
142
281
143
282
privateKeyFile := hc .GetPrivateKeyFile ()
144
283
if len (hc .GetName ()) == 0 {
145
- return errno .ERR_HOST_FIELD_MISSING .
284
+ return errno .ERR_NAME_FIELD_MISSING .
146
285
F ("hosts[%d].host/name = nil" , hc .sequence )
147
286
} else if len (hc .GetHostname ()) == 0 {
148
287
return errno .ERR_HOSTNAME_FIELD_MISSING .
@@ -158,7 +297,7 @@ func (hc *HostConfig) Build() error {
158
297
F ("hosts[%d].private_key_file = %s" , hc .sequence , privateKeyFile )
159
298
}
160
299
161
- if hc .GetForwardAgent () == false {
300
+ if ! hc .GetForwardAgent () {
162
301
if ! utils .PathExist (privateKeyFile ) {
163
302
return errno .ERR_PRIVATE_KEY_FILE_NOT_EXIST .
164
303
F ("%s: no such file" , privateKeyFile )
@@ -170,19 +309,115 @@ func (hc *HostConfig) Build() error {
170
309
return nil
171
310
}
172
311
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
+
173
381
func NewHostConfig (sequence int , config map [string ]interface {}) * HostConfig {
382
+ vars := variable .NewVariables ()
383
+
174
384
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 ,
178
414
}
179
415
}
180
416
181
417
func ParseHosts (data string ) ([]* HostConfig , error ) {
182
418
if len (data ) == 0 {
183
419
return nil , errno .ERR_EMPTY_HOSTS
184
420
}
185
-
186
421
parser := viper .NewWithOptions (viper .KeyDelimiter ("::" ))
187
422
parser .SetConfigType ("yaml" )
188
423
err := parser .ReadConfig (bytes .NewBuffer ([]byte (data )))
@@ -210,9 +445,23 @@ func ParseHosts(data string) ([]*HostConfig, error) {
210
445
return nil , errno .ERR_DUPLICATE_NAME .
211
446
F ("duplicate host: %s" , hc .GetName ())
212
447
}
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
+ }
214
454
exist [hc .GetName ()] = true
215
455
}
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
+ }
216
465
build .DEBUG (build .DEBUG_HOSTS , hosts )
217
466
return hcs , nil
218
467
}
0 commit comments