Rainbond/util/ansible/ansible.go
2019-08-10 20:56:06 +08:00

229 lines
5.7 KiB
Go

package ansible
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"sort"
"strconv"
"strings"
"time"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/goodrain/rainbond/util"
)
//WriteHostsFile write hosts file
func WriteHostsFile(filePath, installConfPath string, hosts []*client.HostNode) error {
if os.Getenv("NOT_WRITE_ANSIBLE_HOSTS") != "" {
return nil
}
config := GetAnsibleHostConfig(filePath)
for i := range hosts {
config.AddHost(hosts[i], installConfPath)
}
return config.WriteFile()
}
//Host ansible host config
type Host struct {
AnsibleHostIP net.IP
//ssh port
AnsibleHostPort int
HostID string
Role client.HostRule
CreateTime time.Time
AnsibleSSHPrivateKeyFile string
}
// String reutrn Host string
func (a *Host) String() string {
if strings.TrimSpace(a.AnsibleSSHPrivateKeyFile) == "" {
return fmt.Sprintf("%s ansible_host=%s ansible_port=%d ip=%s port=%d role=%s", a.HostID, a.AnsibleHostIP, a.AnsibleHostPort, a.AnsibleHostIP, a.AnsibleHostPort, a.Role)
}
return fmt.Sprintf("%s ansible_host=%s ansible_port=%d ip=%s port=%d role=%s ansible_ssh_private_key_file=%s", a.HostID, a.AnsibleHostIP, a.AnsibleHostPort, a.AnsibleHostIP, a.AnsibleHostPort, a.Role, a.AnsibleSSHPrivateKeyFile)
}
// HostsList hosts list
type HostsList []*Host
func (list HostsList) Len() int {
return len(list)
}
func (list HostsList) Less(i, j int) bool {
return list[i].CreateTime.Before(list[j].CreateTime)
}
func (list HostsList) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
//HostGroup ansible host group config
type HostGroup struct {
Name string
HostList HostsList
}
//AddHost add host
func (a *HostGroup) AddHost(h *Host) {
for _, old := range a.HostList {
if old.AnsibleHostIP.String() == h.AnsibleHostIP.String() {
return
}
}
a.HostList = append(a.HostList, h)
}
// String return HostList string
func (a *HostGroup) String() string {
rebuffer := bytes.NewBuffer(nil)
rebuffer.WriteString(fmt.Sprintf("[%s]\n", a.Name))
for i := range a.HostList {
if a.Name == "all" {
rebuffer.WriteString(a.HostList[i].String() + "\n")
} else {
rebuffer.WriteString(a.HostList[i].HostID + "\n")
}
}
rebuffer.WriteString("\n")
return rebuffer.String()
}
//HostConfig ansible hosts config
type HostConfig struct {
FileName string
GroupList map[string]*HostGroup
}
//GetAnsibleHostConfig get config
func GetAnsibleHostConfig(name string) *HostConfig {
return &HostConfig{
FileName: name,
GroupList: map[string]*HostGroup{
"all": &HostGroup{Name: "all"},
"manage": &HostGroup{Name: "manage"},
"new-manage": &HostGroup{Name: "new-manage"},
"gateway": &HostGroup{Name: "gateway"},
"new-gateway": &HostGroup{Name: "new-gateway"},
"compute": &HostGroup{Name: "compute"},
"new-compute": &HostGroup{Name: "new-compute"},
"etcd": &HostGroup{Name: "etcd"},
},
}
}
//Content return config file content
func (c *HostConfig) Content() string {
return c.ContentBuffer().String()
}
//ContentBuffer content buffer
func (c *HostConfig) ContentBuffer() *bytes.Buffer {
rebuffer := bytes.NewBuffer(nil)
for i := range c.GroupList {
sort.Sort(c.GroupList[i].HostList) // sort host by createTime
rebuffer.WriteString(c.GroupList[i].String())
}
return rebuffer
}
//WriteFile write config file
func (c *HostConfig) WriteFile() error {
if c.FileName == "" {
return fmt.Errorf("config file name can not be empty")
}
if err := util.CheckAndCreateDir(path.Dir(c.FileName)); err != nil {
return err
}
if err := ioutil.WriteFile(c.FileName+".tmp", c.ContentBuffer().Bytes(), 0755); err != nil {
return err
}
return os.Rename(c.FileName+".tmp", c.FileName)
}
func getSSHPort(configFile string) int {
if ok, _ := util.FileExists(configFile); !ok {
return 22
}
file, err := os.OpenFile(configFile, os.O_RDONLY, 0666)
if err != nil {
return 22
}
defer file.Close()
reader := bufio.NewReader(file)
for {
str, _, err := reader.ReadLine()
if err != nil {
break
}
line := strings.TrimSpace(string(str))
if strings.Contains(line, "=") && !strings.HasPrefix(line, "#") {
keyvalue := strings.SplitN(string(line), "=", 2)
if len(keyvalue) == 2 || keyvalue[0] == "INSTALL_SSH_PORT" {
port, err := strconv.Atoi(keyvalue[1])
if err != nil {
return 22
}
return port
}
}
}
return 22
}
//AddHost add host
func (c *HostConfig) AddHost(h *client.HostNode, installConfPath string) {
//check role
//check status
ansibleHost := &Host{
AnsibleHostIP: net.ParseIP(h.InternalIP),
AnsibleHostPort: getSSHPort(installConfPath),
HostID: h.ID,
Role: h.Role,
CreateTime: h.CreateTime,
AnsibleSSHPrivateKeyFile: h.KeyPath,
}
c.GroupList["all"].AddHost(ansibleHost)
checkNeedInstall := func(h *client.HostNode) bool {
return h.Status == client.NotInstalled || h.Status == client.InstallFailed || h.Status == client.Installing
}
if h.Role.HasRule("manage") {
if checkNeedInstall(h) {
c.GroupList["new-manage"].AddHost(ansibleHost)
} else {
c.GroupList["manage"].AddHost(ansibleHost)
}
if _, ok := h.Labels["noinstall_etcd"]; !ok {
c.GroupList["etcd"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("compute") {
if checkNeedInstall(h) {
c.GroupList["new-compute"].AddHost(ansibleHost)
} else {
c.GroupList["compute"].AddHost(ansibleHost)
}
}
if h.Role.HasRule("gateway") {
if checkNeedInstall(h) {
c.GroupList["new-gateway"].AddHost(ansibleHost)
} else {
c.GroupList["gateway"].AddHost(ansibleHost)
}
}
for i := range h.NodeStatus.Conditions {
if h.NodeStatus.Conditions[i].Type == "etcd" {
c.GroupList["etcd"].AddHost(ansibleHost)
break
}
}
}