Skip to content

Commit ab35777

Browse files
committed
playbook(memcache): support instances and instances_sequence
Signed-off-by: Ericwai <[email protected]>
1 parent 8d9c430 commit ab35777

File tree

10 files changed

+409
-31
lines changed

10 files changed

+409
-31
lines changed

internal/configure/hosts/hc_get.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/opencurve/curveadm/internal/configure/curveadm"
3030
"github.com/opencurve/curveadm/internal/utils"
3131
"github.com/opencurve/curveadm/pkg/module"
32+
"github.com/opencurve/curveadm/pkg/variable"
3233
)
3334

3435
func (hc *HostConfig) get(i *comm.Item) interface{} {
@@ -77,14 +78,17 @@ func (hc *HostConfig) GetBecomeUser() string { return hc.getString(CONFIG_BE
7778
func (hc *HostConfig) GetLabels() []string { return hc.labels }
7879
func (hc *HostConfig) GetEnvs() []string { return hc.envs }
7980

81+
func (hc *HostConfig) GetInstances() int { return hc.instances }
82+
func (hc *HostConfig) GetInstancesSequence() int { return hc.instancesSequence }
83+
func (hc *HostConfig) GetVariables() *variable.Variables { return hc.variables }
84+
8085
func (hc *HostConfig) GetUser() string {
8186
user := hc.getString(CONFIG_USER)
8287
if user == "${user}" {
8388
return utils.GetCurrentUser()
8489
}
8590
return user
8691
}
87-
8892
func (hc *HostConfig) GetSSHConfig() *module.SSHConfig {
8993
hostname := hc.GetSSHHostname()
9094
if len(hostname) == 0 {

internal/configure/hosts/hosts.go

Lines changed: 211 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3841
const (
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,84 @@ func (hc *HostConfig) convertEnvs() error {
107117
hc.envs = append(hc.envs, v)
108118
}
109119
}
120+
return nil
121+
}
122+
123+
func (hc *HostConfig) convertInstances() error {
124+
value := hc.config[KEY_INSTANCES]
125+
instancesStr, instances, ok := "", 0, false
126+
if instancesStr, ok = utils.All2Str(value); !ok {
127+
return errno.ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE.
128+
F("hosts[%d].%s = %v", hc.sequence, KEY_INSTANCES, value)
129+
}
130+
if instances, ok = utils.Str2Int(instancesStr); !ok {
131+
return errno.ERR_CONFIGURE_VALUE_REQUIRES_INTEGER.
132+
F("hosts[%d].%s = %v", hc.sequence, KEY_INSTANCES, value)
133+
}
134+
if instances <= 0 {
135+
return errno.ERR_CONFIGURE_VALUE_REQUIRES_POSITIVE_INTEGER.
136+
F("hosts[%d].%s = %v", hc.sequence, KEY_INSTANCES, value)
137+
}
138+
hc.instances = instances
139+
return nil
140+
}
110141

142+
// convert config item to its required type after rendering,
143+
// return error if convert failed
144+
func (hc *HostConfig) convert() error {
145+
for key, value := range hc.config {
146+
if key == KEY_LABELS || key == KEY_ENVS || key == KEY_INSTANCES {
147+
continue
148+
}
149+
if itemset.Get(key) == nil {
150+
return errno.ERR_UNSUPPORT_HOSTS_CONFIGURE_ITEM.
151+
F("hosts[%d].%s = %v", hc.sequence, key, value)
152+
}
153+
if v, err := itemset.Build(key, value); err != nil {
154+
return err
155+
} else {
156+
hc.config[key] = v
157+
}
158+
}
159+
privateKeyFile := hc.GetPrivateKeyFile()
160+
if len(hc.GetName()) == 0 {
161+
return errno.ERR_NAME_FIELD_MISSING.
162+
F("hosts[%d].host/name = nil", hc.sequence)
163+
}
164+
if len(hc.GetHostname()) == 0 {
165+
return errno.ERR_HOSTNAME_FIELD_MISSING.
166+
F("hosts[%d].hostname = nil", hc.sequence)
167+
}
168+
if !utils.IsValidAddress(hc.GetHostname()) {
169+
return errno.ERR_HOSTNAME_REQUIRES_VALID_IP_ADDRESS.
170+
F("hosts[%d].hostname = %s", hc.sequence, hc.GetHostname())
171+
}
172+
if hc.GetSSHPort() > os.GetMaxPortNum() {
173+
return errno.ERR_HOSTS_SSH_PORT_EXCEED_MAX_PORT_NUMBER.
174+
F("hosts[%d].ssh_port = %d", hc.sequence, hc.GetSSHPort())
175+
}
176+
if !strings.HasPrefix(privateKeyFile, "/") {
177+
return errno.ERR_PRIVATE_KEY_FILE_REQUIRE_ABSOLUTE_PATH.
178+
F("hosts[%d].private_key_file = %s", hc.sequence, privateKeyFile)
179+
}
180+
181+
if !hc.GetForwardAgent() {
182+
if !utils.PathExist(privateKeyFile) {
183+
return errno.ERR_PRIVATE_KEY_FILE_NOT_EXIST.
184+
F("%s: no such file", privateKeyFile)
185+
}
186+
if utils.GetFilePermissions(privateKeyFile) != PERMISSIONS_600 {
187+
return errno.ERR_PRIVATE_KEY_FILE_REQUIRE_600_PERMISSIONS.
188+
F("%s: mode (%d)", privateKeyFile, utils.GetFilePermissions(privateKeyFile))
189+
}
190+
}
111191
return nil
112192
}
113193

114194
func (hc *HostConfig) Build() error {
115195
for key, value := range hc.config {
116196
if key == KEY_LABELS { // convert labels
117-
if err := hc.convertLables(); err != nil {
197+
if err := hc.convertLabels(); err != nil {
118198
return err
119199
}
120200
hc.config[key] = nil // delete labels section
@@ -123,7 +203,13 @@ func (hc *HostConfig) Build() error {
123203
if err := hc.convertEnvs(); err != nil {
124204
return err
125205
}
126-
hc.config[key] = nil // delete labels section
206+
hc.config[key] = nil // delete envs section
207+
continue
208+
} else if key == KEY_INSTANCES { // convert instances
209+
if err := hc.convertInstances(); err != nil {
210+
return err
211+
}
212+
hc.config[key] = nil // delete instances section
127213
continue
128214
}
129215

@@ -142,47 +228,136 @@ func (hc *HostConfig) Build() error {
142228

143229
privateKeyFile := hc.GetPrivateKeyFile()
144230
if len(hc.GetName()) == 0 {
145-
return errno.ERR_HOST_FIELD_MISSING.
231+
return errno.ERR_NAME_FIELD_MISSING.
146232
F("hosts[%d].host/name = nil", hc.sequence)
147-
} else if len(hc.GetHostname()) == 0 {
233+
}
234+
if len(hc.GetHostname()) == 0 {
148235
return errno.ERR_HOSTNAME_FIELD_MISSING.
149236
F("hosts[%d].hostname = nil", hc.sequence)
150-
} else if !utils.IsValidAddress(hc.GetHostname()) {
237+
}
238+
if !utils.IsValidAddress(hc.GetHostname()) {
151239
return errno.ERR_HOSTNAME_REQUIRES_VALID_IP_ADDRESS.
152240
F("hosts[%d].hostname = %s", hc.sequence, hc.GetHostname())
153-
} else if hc.GetSSHPort() > os.GetMaxPortNum() {
241+
}
242+
if hc.GetSSHPort() > os.GetMaxPortNum() {
154243
return errno.ERR_HOSTS_SSH_PORT_EXCEED_MAX_PORT_NUMBER.
155244
F("hosts[%d].ssh_port = %d", hc.sequence, hc.GetSSHPort())
156-
} else if !strings.HasPrefix(privateKeyFile, "/") {
245+
}
246+
if !strings.HasPrefix(privateKeyFile, "/") {
157247
return errno.ERR_PRIVATE_KEY_FILE_REQUIRE_ABSOLUTE_PATH.
158248
F("hosts[%d].private_key_file = %s", hc.sequence, privateKeyFile)
159249
}
160250

161-
if hc.GetForwardAgent() == false {
251+
if !hc.GetForwardAgent() {
162252
if !utils.PathExist(privateKeyFile) {
163253
return errno.ERR_PRIVATE_KEY_FILE_NOT_EXIST.
164254
F("%s: no such file", privateKeyFile)
165-
} else if utils.GetFilePermissions(privateKeyFile) != PERMISSIONS_600 {
255+
}
256+
if utils.GetFilePermissions(privateKeyFile) != PERMISSIONS_600 {
166257
return errno.ERR_PRIVATE_KEY_FILE_REQUIRE_600_PERMISSIONS.
167258
F("%s: mode (%d)", privateKeyFile, utils.GetFilePermissions(privateKeyFile))
168259
}
169260
}
170261
return nil
171262
}
172263

264+
// "PORT=112${instancesSquence}" -> "PORT=11201"
265+
func (hc *HostConfig) renderVariables() error {
266+
//0. get vars
267+
vars := hc.GetVariables()
268+
if err := vars.Build(); err != nil {
269+
log.Error("Build variables failed",
270+
log.Field("error", err))
271+
return errno.ERR_RESOLVE_VARIABLE_FAILED.E(err)
272+
}
273+
//1. all config to str
274+
for k, v := range hc.config {
275+
if v == nil {
276+
continue
277+
}
278+
if strv, ok := utils.All2Str(v); !ok {
279+
return errno.ERR_UNSUPPORT_CONFIGURE_VALUE_TYPE.
280+
F("%s: %v", k, v)
281+
} else {
282+
hc.config[k] = strv
283+
}
284+
}
285+
//2. rendering
286+
//render labels and envs
287+
err := func(allStrs ...[]string) error {
288+
for k := range allStrs {
289+
strs := allStrs[k]
290+
for i := range strs {
291+
realValue, err := vars.Rendering(strs[i])
292+
if err != nil {
293+
return err
294+
}
295+
strs[i] = realValue
296+
}
297+
}
298+
return nil
299+
}(hc.labels, hc.envs)
300+
if err != nil {
301+
return errno.ERR_RENDERING_VARIABLE_FAILED.E(err)
302+
}
303+
//render config
304+
for k, v := range hc.config {
305+
if v == nil {
306+
continue
307+
}
308+
realv, err := vars.Rendering(v.(string))
309+
if err != nil {
310+
return errno.ERR_RENDERING_VARIABLE_FAILED.E(err)
311+
}
312+
hc.config[k] = realv
313+
build.DEBUG(build.DEBUG_TOPOLOGY,
314+
build.Field{Key: k, Value: v},
315+
build.Field{Key: k, Value: realv})
316+
}
317+
//3. convert config item to its required type after rendering,
318+
// return error if convert failed
319+
return hc.convert()
320+
}
321+
173322
func NewHostConfig(sequence int, config map[string]interface{}) *HostConfig {
323+
vars := variable.NewVariables()
324+
return &HostConfig{
325+
sequence: sequence,
326+
config: config,
327+
labels: []string{},
328+
envs: []string{},
329+
variables: vars,
330+
//instances and instancesSquence only used in the memcached deploy
331+
instances: 1,
332+
instancesSequence: 1,
333+
}
334+
}
335+
336+
// deepcopy a HostConfig with instancesSquence and return it (new variables)
337+
func copyHostConfig(src *HostConfig, instancesSquence int) *HostConfig {
338+
//deepcopy labels
339+
newlabels := make([]string, len(src.labels))
340+
copy(newlabels, src.labels)
341+
//deepcopy envs
342+
newenvs := make([]string, len(src.envs))
343+
copy(newenvs, src.envs)
344+
//create a new variables
345+
vars := variable.NewVariables()
174346
return &HostConfig{
175-
sequence: sequence,
176-
config: config,
177-
labels: []string{},
347+
sequence: src.sequence,
348+
config: utils.DeepCopy(src.config),
349+
labels: newlabels,
350+
envs: newenvs,
351+
variables: vars,
352+
instances: src.instances,
353+
instancesSequence: instancesSquence,
178354
}
179355
}
180356

181357
func ParseHosts(data string) ([]*HostConfig, error) {
182358
if len(data) == 0 {
183359
return nil, errno.ERR_EMPTY_HOSTS
184360
}
185-
186361
parser := viper.NewWithOptions(viper.KeyDelimiter("::"))
187362
parser.SetConfigType("yaml")
188363
err := parser.ReadConfig(bytes.NewBuffer([]byte(data)))
@@ -210,9 +385,23 @@ func ParseHosts(data string) ([]*HostConfig, error) {
210385
return nil, errno.ERR_DUPLICATE_NAME.
211386
F("duplicate host: %s", hc.GetName())
212387
}
213-
hcs = append(hcs, hc)
388+
//produce the instances of hc, append to hcs. (used in memcached deploy)
389+
instances := hc.GetInstances()
390+
for instancesSquence := 1; instancesSquence <= instances; instancesSquence++ {
391+
hc_new := copyHostConfig(hc, instancesSquence)
392+
hcs = append(hcs, hc_new)
393+
}
214394
exist[hc.GetName()] = true
215395
}
396+
//add Variables and Rendering
397+
for idx, hc := range hcs {
398+
if err = AddHostVariables(hcs, idx); err != nil {
399+
return nil, err // already is error code
400+
} else if err = hc.renderVariables(); err != nil {
401+
return nil, err // already is error code
402+
}
403+
hc.GetVariables().Debug()
404+
}
216405
build.DEBUG(build.DEBUG_HOSTS, hosts)
217406
return hcs, nil
218407
}

0 commit comments

Comments
 (0)