mirror of
https://github.com/kubesphere/kubekey.git
synced 2025-12-26 01:22:51 +00:00
feat: support pre_install & post_install scripts by global config (#2872)
This commit is contained in:
parent
bd780ee397
commit
86dbf89026
|
|
@ -20,8 +20,19 @@
|
||||||
mode: 0755
|
mode: 0755
|
||||||
register: post_install_copy_result
|
register: post_install_copy_result
|
||||||
|
|
||||||
|
- name: Post | Copy post-installation config scripts to remote hosts
|
||||||
|
copy:
|
||||||
|
src: >-
|
||||||
|
{{ .scripts_dir }}/{{ .item.script }}
|
||||||
|
dest: >-
|
||||||
|
/etc/kubekey/scripts/post_install_{{ .item.script }}
|
||||||
|
mode: 0755
|
||||||
|
loop: "{{ .post_install | toJson }}"
|
||||||
|
when: "{{ getStringSlice .groups .item.group | default list | has .inventory_hostname }}"
|
||||||
|
register: post_install_config_copy_result
|
||||||
|
|
||||||
- name: Post | Execute post-installation scripts on remote hosts
|
- name: Post | Execute post-installation scripts on remote hosts
|
||||||
when: .post_install_copy_result.error | empty
|
when: or (.post_install_copy_result.error | empty) (and .post_install_config_copy_result (.post_install_config_copy_result.error | empty))
|
||||||
command: |
|
command: |
|
||||||
for file in /etc/kubekey/scripts/post_install_*.sh; do
|
for file in /etc/kubekey/scripts/post_install_*.sh; do
|
||||||
if [ -f "$file" ]; then
|
if [ -f "$file" ]; then
|
||||||
|
|
@ -29,4 +40,4 @@
|
||||||
chmod +x "$file"
|
chmod +x "$file"
|
||||||
"$file"
|
"$file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,19 @@
|
||||||
mode: 0755
|
mode: 0755
|
||||||
register: pre_install_copy_result
|
register: pre_install_copy_result
|
||||||
|
|
||||||
|
- name: Pre | Copy pre-installation config scripts to remote hosts
|
||||||
|
copy:
|
||||||
|
src: >-
|
||||||
|
{{ .work_dir }}/scripts/{{ .item.script }}
|
||||||
|
dest: >-
|
||||||
|
/etc/kubekey/scripts/pre_install_{{ .item.script }}
|
||||||
|
mode: 0755
|
||||||
|
loop: "{{ .pre_install | toJson }}"
|
||||||
|
when: "{{ getStringSlice .groups .item.group | default list | has .inventory_hostname }}"
|
||||||
|
register: pre_install_config_copy_result
|
||||||
|
|
||||||
- name: Pre | Execute pre-installation scripts on remote hosts
|
- name: Pre | Execute pre-installation scripts on remote hosts
|
||||||
when: .pre_install_copy_result.error | empty
|
when: or (.pre_install_copy_result.error | empty) (and .pre_install_config_copy_result (.pre_install_config_copy_result.error | empty))
|
||||||
command: |
|
command: |
|
||||||
for file in /etc/kubekey/scripts/pre_install_*.sh; do
|
for file in /etc/kubekey/scripts/pre_install_*.sh; do
|
||||||
if [ -f "$file" ]; then
|
if [ -f "$file" ]; then
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ work_dir: /root/kubekey
|
||||||
binary_dir: >-
|
binary_dir: >-
|
||||||
{{ .work_dir }}/kubekey
|
{{ .work_dir }}/kubekey
|
||||||
scripts_dir: >-
|
scripts_dir: >-
|
||||||
{{ .binary_dir }}/scripts
|
{{ .work_dir }}/scripts
|
||||||
tmp_dir: /tmp/kubekey
|
tmp_dir: /tmp/kubekey
|
||||||
|
|
||||||
# Mapping of common machine architecture names to their standard forms
|
# Mapping of common machine architecture names to their standard forms
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ func funcMap() template.FuncMap {
|
||||||
f["subtractList"] = subtractList
|
f["subtractList"] = subtractList
|
||||||
f["fileExist"] = fileExist
|
f["fileExist"] = fileExist
|
||||||
f["unquote"] = unquote
|
f["unquote"] = unquote
|
||||||
|
f["getStringSlice"] = getStringSlice
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
@ -131,3 +132,10 @@ func unquote(input any) string {
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getStringSlice(d map[string][]string, key string) []string {
|
||||||
|
if val, ok := d[key]; ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,16 @@ func TestParseValue(t *testing.T) {
|
||||||
},
|
},
|
||||||
excepted: []byte("bar"),
|
excepted: []byte("bar"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "get string slice from dictionary",
|
||||||
|
input: "{{ getStringSlice .foo \"foo\" }}",
|
||||||
|
variable: map[string]any{
|
||||||
|
"foo": map[string][]string{
|
||||||
|
"foo": {"bar1", "bar2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
excepted: []byte("[bar1 bar2]"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "multi level 2",
|
name: "multi level 2",
|
||||||
input: "{{ index .foo \"foo\" }}",
|
input: "{{ index .foo \"foo\" }}",
|
||||||
|
|
|
||||||
|
|
@ -166,21 +166,19 @@ func (e *taskExecutor) execTaskHost(i int, h string) func(ctx context.Context) {
|
||||||
resErr = errors.Errorf("host: %s variable is not a map", h)
|
resErr = errors.Errorf("host: %s variable is not a map", h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check when condition
|
|
||||||
if skip, err := e.dealWhen(had); err != nil {
|
|
||||||
resErr = err
|
|
||||||
return
|
|
||||||
} else if skip {
|
|
||||||
stdout = modules.StdoutSkip
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// execute module in loop with loop item.
|
// execute module in loop with loop item.
|
||||||
// if loop is empty. execute once, and the item is null
|
// if loop is empty. execute once, and the item is null
|
||||||
for _, item := range e.dealLoop(had) {
|
for _, item := range e.dealLoop(had) {
|
||||||
resErr = e.executeModule(ctx, e.task, item, h, &stdout, &stderr)
|
resSkip, exeErr := e.executeModule(ctx, e.task, item, h, &stdout, &stderr)
|
||||||
if resErr != nil {
|
if exeErr != nil {
|
||||||
|
resErr = exeErr
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// loop execute once, skip task
|
||||||
|
if item == nil && resSkip {
|
||||||
|
stdout = modules.StdoutSkip
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -260,18 +258,18 @@ func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, _
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeModule executes a single module task on a specific host.
|
// executeModule executes a single module task on a specific host.
|
||||||
func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.Task, item any, host string, stdout, stderr *string) (resErr error) {
|
func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.Task, item any, host string, stdout, stderr *string) (resSkip bool, resErr error) {
|
||||||
// Set loop item variable if one was provided
|
// Set loop item variable if one was provided
|
||||||
if item != nil {
|
if item != nil {
|
||||||
// Convert item to runtime variable
|
// Convert item to runtime variable
|
||||||
node, err := converter.ConvertMap2Node(map[string]any{_const.VariableItem: item})
|
node, err := converter.ConvertMap2Node(map[string]any{_const.VariableItem: item})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to convert loop item")
|
return false, errors.Wrap(err, "failed to convert loop item")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge item into host's runtime variables
|
// Merge item into host's runtime variables
|
||||||
if err := e.variable.Merge(variable.MergeRuntimeVariable([]yaml.Node{node}, host)); err != nil {
|
if err := e.variable.Merge(variable.MergeRuntimeVariable([]yaml.Node{node}, host)); err != nil {
|
||||||
return errors.Wrap(err, "failed to set loop item to variable")
|
return false, errors.Wrap(err, "failed to set loop item to variable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up loop item variable after execution
|
// Clean up loop item variable after execution
|
||||||
|
|
@ -295,13 +293,20 @@ func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.T
|
||||||
// Get all variables for this host, including any loop item
|
// Get all variables for this host, including any loop item
|
||||||
ha, err := e.variable.Get(variable.GetAllVariable(host))
|
ha, err := e.variable.Get(variable.GetAllVariable(host))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to get host %s variable", host)
|
return false, errors.Wrapf(err, "failed to get host %s variable", host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert host variables to map type
|
// Convert host variables to map type
|
||||||
had, ok := ha.(map[string]any)
|
had, ok := ha.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Wrapf(err, "host %s variable is not a map", host)
|
return false, errors.Wrapf(err, "host %s variable is not a map", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check when condition
|
||||||
|
if skip, err := e.dealWhen(had); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if skip {
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the actual module with the prepared context
|
// Execute the actual module with the prepared context
|
||||||
|
|
@ -313,7 +318,7 @@ func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.T
|
||||||
Playbook: *e.playbook,
|
Playbook: *e.playbook,
|
||||||
LogOutput: e.logOutput,
|
LogOutput: e.logOutput,
|
||||||
})
|
})
|
||||||
return e.dealFailedWhen(had, resErr)
|
return false, e.dealFailedWhen(had, resErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dealLoop parses the loop specification into a slice of items to iterate over.
|
// dealLoop parses the loop specification into a slice of items to iterate over.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue