mirror of
https://github.com/kubesphere/kubekey.git
synced 2025-12-26 01:22:51 +00:00
206 lines
5.8 KiB
Go
206 lines
5.8 KiB
Go
package variable
|
|
|
|
import (
|
|
"net"
|
|
"regexp"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
"k8s.io/apimachinery/pkg/util/rand"
|
|
"k8s.io/klog/v2"
|
|
|
|
_const "github.com/kubesphere/kubekey/v4/pkg/const"
|
|
"github.com/kubesphere/kubekey/v4/pkg/converter/tmpl"
|
|
)
|
|
|
|
// ***************************** GetFunc ***************************** //
|
|
|
|
// GetHostnames get all hostnames from a group or host
|
|
var GetHostnames = func(name []string) GetFunc {
|
|
if len(name) == 0 {
|
|
return emptyGetFunc
|
|
}
|
|
|
|
return func(v Variable) (any, error) {
|
|
vv, ok := v.(*variable)
|
|
if !ok {
|
|
return nil, errors.New("variable type error")
|
|
}
|
|
var hs []string
|
|
for _, n := range name {
|
|
// try parse hostname by Config.
|
|
if pn, err := tmpl.ParseFunc(Extension2Variables(vv.value.Config.Spec), n, func(b []byte) string { return string(b) }); err == nil {
|
|
n = pn
|
|
}
|
|
// add host to hs
|
|
if _, exists := vv.value.Hosts[n]; exists {
|
|
hs = append(hs, n)
|
|
}
|
|
// add group's host to gs
|
|
for gn, gv := range ConvertGroup(vv.value.Inventory) {
|
|
if gn == n {
|
|
hs = CombineSlice(hs, gv)
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
// Add the specified host in the specified group to the hs.
|
|
regexForIndex := regexp.MustCompile(`^(.*?)\[(\d+)\]$`)
|
|
if match := regexForIndex.FindStringSubmatch(strings.TrimSpace(n)); match != nil {
|
|
index, err := strconv.Atoi(match[2])
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to convert %q to int", match[2])
|
|
}
|
|
if group, ok := ConvertGroup(vv.value.Inventory)[match[1]]; ok {
|
|
if index >= len(group) {
|
|
return nil, errors.Errorf("index %v out of range for group %s", index, group)
|
|
}
|
|
hs = append(hs, group[index])
|
|
}
|
|
}
|
|
|
|
// add random host in group
|
|
regexForRandom := regexp.MustCompile(`^(.+?)\s*\|\s*random$`)
|
|
if match := regexForRandom.FindStringSubmatch(strings.TrimSpace(n)); match != nil {
|
|
if group, ok := ConvertGroup(vv.value.Inventory)[match[1]]; ok {
|
|
hs = append(hs, group[rand.Intn(len(group))])
|
|
}
|
|
}
|
|
}
|
|
|
|
return hs, nil
|
|
}
|
|
}
|
|
|
|
// GetAllVariable get all variable for a given host
|
|
var GetAllVariable = func(hostname string) GetFunc {
|
|
// getLocalIP get the ipv4 or ipv6 for localhost machine
|
|
getLocalIP := func(ipType string) string {
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
klog.ErrorS(err, "get network address error")
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
|
|
if ipType == _const.VariableIPv4 && ipNet.IP.To4() != nil {
|
|
return ipNet.IP.String()
|
|
}
|
|
|
|
if ipType == _const.VariableIPv6 && ipNet.IP.To16() != nil && ipNet.IP.To4() == nil {
|
|
return ipNet.IP.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
klog.V(4).Infof("cannot get local %s address", ipType)
|
|
|
|
return ""
|
|
}
|
|
|
|
// defaultHostVariable set default vars when hostname is "localhost"
|
|
defaultHostVariable := func(hostname string, hostVars map[string]any) {
|
|
if hostname == _const.VariableLocalHost {
|
|
if _, ok := hostVars[_const.VariableIPv4]; !ok {
|
|
hostVars[_const.VariableIPv4] = getLocalIP(_const.VariableIPv4)
|
|
}
|
|
if _, ok := hostVars[_const.VariableIPv6]; !ok {
|
|
hostVars[_const.VariableIPv6] = getLocalIP(_const.VariableIPv6)
|
|
}
|
|
}
|
|
if os, ok := hostVars[_const.VariableOS]; ok {
|
|
// try to set hostname by current actual hostname.
|
|
if osd, ok := os.(map[string]any); ok {
|
|
hostVars[_const.VariableHostName] = osd[_const.VariableOSHostName]
|
|
}
|
|
}
|
|
if _, ok := hostVars[_const.VariableInventoryName]; !ok {
|
|
hostVars[_const.VariableInventoryName] = hostname
|
|
}
|
|
if _, ok := hostVars[_const.VariableHostName]; !ok {
|
|
hostVars[_const.VariableHostName] = hostname
|
|
}
|
|
}
|
|
|
|
getHostsVariable := func(v *variable) map[string]any {
|
|
globalHosts := make(map[string]any)
|
|
for hostname := range v.value.Hosts {
|
|
hostVars := make(map[string]any)
|
|
// set groups vars
|
|
for _, gv := range v.value.Inventory.Spec.Groups {
|
|
if slices.Contains(gv.Hosts, hostname) {
|
|
hostVars = CombineVariables(hostVars, Extension2Variables(gv.Vars))
|
|
}
|
|
}
|
|
// find from remote
|
|
hostVars = CombineVariables(hostVars, v.value.Hosts[hostname].RemoteVars)
|
|
// merge from runtime
|
|
hostVars = CombineVariables(hostVars, v.value.Hosts[hostname].RuntimeVars)
|
|
|
|
// merge from inventory vars
|
|
hostVars = CombineVariables(hostVars, Extension2Variables(v.value.Inventory.Spec.Vars))
|
|
// merge from inventory host vars
|
|
hostVars = CombineVariables(hostVars, Extension2Variables(v.value.Inventory.Spec.Hosts[hostname]))
|
|
// merge from config
|
|
hostVars = CombineVariables(hostVars, Extension2Variables(v.value.Config.Spec))
|
|
// set default localhost
|
|
defaultHostVariable(hostname, hostVars)
|
|
globalHosts[hostname] = hostVars
|
|
}
|
|
|
|
return globalHosts
|
|
}
|
|
|
|
return func(v Variable) (any, error) {
|
|
vv, ok := v.(*variable)
|
|
if !ok {
|
|
return nil, errors.New("variable type error")
|
|
}
|
|
hosts := getHostsVariable(vv)
|
|
hostVars, ok := hosts[hostname].(map[string]any)
|
|
if !ok {
|
|
// cannot found hosts variable.
|
|
return make(map[string]any), nil
|
|
}
|
|
hostVars = CombineVariables(hostVars, map[string]any{
|
|
_const.VariableGlobalHosts: hosts,
|
|
})
|
|
hostVars = CombineVariables(hostVars, map[string]any{
|
|
_const.VariableGroups: ConvertGroup(vv.value.Inventory),
|
|
})
|
|
|
|
return hostVars, nil
|
|
}
|
|
}
|
|
|
|
// GetHostMaxLength get the max length for all hosts
|
|
var GetHostMaxLength = func() GetFunc {
|
|
return func(v Variable) (any, error) {
|
|
vv, ok := v.(*variable)
|
|
if !ok {
|
|
return nil, errors.New("variable type error")
|
|
}
|
|
var hostnameMaxLen int
|
|
for k := range vv.value.Hosts {
|
|
hostnameMaxLen = max(len(k), hostnameMaxLen)
|
|
}
|
|
|
|
return hostnameMaxLen, nil
|
|
}
|
|
}
|
|
|
|
// GetWorkDir returns the working directory from the configuration.
|
|
var GetWorkDir = func() GetFunc {
|
|
return func(v Variable) (any, error) {
|
|
vv, ok := v.(*variable)
|
|
if !ok {
|
|
return nil, errors.New("variable type error")
|
|
}
|
|
|
|
return _const.GetWorkdirFromConfig(vv.value.Config), nil
|
|
}
|
|
}
|