Files
cloudpods/pkg/util/cloudinit/cloudconfig.go
Qiu Jian 46aaba2474 make fmt
2018-12-12 23:24:34 +08:00

229 lines
4.9 KiB
Go

package cloudinit
import (
"bytes"
"encoding/base64"
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
/*
* cloudconfig
* Reference: https://cloudinit.readthedocs.io/en/latest/topics/examples.html
*
*/
type TSudoPolicy string
const (
CLOUD_CONFIG_HEADER = "#cloud-config\n"
USER_SUDO_NOPASSWD = TSudoPolicy("sudo_nopasswd")
USER_SUDO = TSudoPolicy("sudo")
USER_SUDO_DENY = TSudoPolicy("sudo_deny")
USER_SUDO_NONE = TSudoPolicy("")
)
type SWriteFile struct {
Path string
Permissions string
Owner string
Encoding string
Content string
}
type SUser struct {
Name string
Passwd string
LockPassword string
SshAuthorizedKeys []string
Sudo string
}
type SPhoneHome struct {
Url string
}
type SCloudConfig struct {
Users []SUser
WriteFiles []SWriteFile
Runcmd []string
Bootcmd []string
Packages []string
PhoneHome *SPhoneHome
DisableRoot int
SshPwauth int
}
func NewWriteFile(path string, content string, perm string, owner string, isBase64 bool) SWriteFile {
f := SWriteFile{}
f.Path = path
f.Permissions = perm
f.Owner = owner
if isBase64 {
f.Encoding = "b64"
f.Content = base64.StdEncoding.EncodeToString([]byte(content))
} else {
f.Content = content
}
return f
}
func NewUser(name string) SUser {
u := SUser{Name: name}
return u
}
func (u *SUser) SudoPolicy(policy TSudoPolicy) *SUser {
switch policy {
case USER_SUDO_NOPASSWD:
u.Sudo = "ALL=(ALL) NOPASSWD:ALL"
case USER_SUDO:
u.Sudo = "ALL=(ALL) ALL"
case USER_SUDO_DENY:
u.Sudo = "False"
default:
u.Sudo = ""
}
return u
}
func (u *SUser) SshKey(key string) *SUser {
if u.SshAuthorizedKeys == nil {
u.SshAuthorizedKeys = make([]string, 0)
}
u.SshAuthorizedKeys = append(u.SshAuthorizedKeys, key)
return u
}
func (u *SUser) Password(passwd string) *SUser {
if len(passwd) > 0 {
hash, err := seclib2.GeneratePassword(passwd)
if err != nil {
log.Errorf("GeneratePassword error %s", err)
} else {
u.Passwd = hash
}
u.LockPassword = "false"
}
return u
}
func (conf *SCloudConfig) UserData() string {
var buf bytes.Buffer
jsonConf := jsonutils.Marshal(conf)
buf.WriteString(CLOUD_CONFIG_HEADER)
buf.WriteString(jsonConf.YAMLString())
return buf.String()
}
func (conf *SCloudConfig) UserDataBase64() string {
data := conf.UserData()
return base64.StdEncoding.EncodeToString([]byte(data))
}
func ParseUserDataBase64(b64data string) (*SCloudConfig, error) {
data, err := base64.StdEncoding.DecodeString(b64data)
if err != nil {
return nil, err
}
return ParseUserData(string(data))
}
func ParseUserData(data string) (*SCloudConfig, error) {
if !strings.HasPrefix(data, CLOUD_CONFIG_HEADER) {
msg := "invalid userdata, not starting with #cloud-config"
log.Errorf(msg)
return nil, fmt.Errorf(msg)
}
jsonConf, err := jsonutils.ParseYAML(data)
if err != nil {
log.Errorf("parse userdata yaml error %s", err)
return nil, err
}
config := SCloudConfig{}
err = jsonConf.Unmarshal(&config)
if err != nil {
log.Errorf("unable to unmarchal userdata %s", err)
return nil, err
}
return &config, nil
}
func (conf *SCloudConfig) MergeUser(u SUser) {
for i := 0; i < len(conf.Users); i += 1 {
if u.Name == conf.Users[i].Name {
// find user, merge keys
for j := 0; j < len(u.SshAuthorizedKeys); j += 1 {
if !utils.IsInStringArray(u.SshAuthorizedKeys[j], conf.Users[i].SshAuthorizedKeys) {
conf.Users[i].SshAuthorizedKeys = append(conf.Users[i].SshAuthorizedKeys, u.SshAuthorizedKeys[j])
}
}
return
}
}
// no such user
conf.Users = append(conf.Users, u)
}
func (conf *SCloudConfig) MergeWriteFile(f SWriteFile, replace bool) {
for i := 0; i < len(conf.WriteFiles); i += 1 {
if conf.WriteFiles[i].Path == f.Path {
// find file
if replace {
conf.WriteFiles[i].Content = f.Content
conf.WriteFiles[i].Encoding = f.Encoding
conf.WriteFiles[i].Owner = f.Owner
conf.WriteFiles[i].Permissions = f.Permissions
}
return
}
}
// no such file
conf.WriteFiles = append(conf.WriteFiles, f)
}
func (conf *SCloudConfig) MergeRuncmd(cmd string) {
if !utils.IsInStringArray(cmd, conf.Runcmd) {
conf.Runcmd = append(conf.Runcmd, cmd)
}
}
func (conf *SCloudConfig) MergeBootcmd(cmd string) {
if !utils.IsInStringArray(cmd, conf.Bootcmd) {
conf.Bootcmd = append(conf.Bootcmd, cmd)
}
}
func (conf *SCloudConfig) MergePackage(pkg string) {
if !utils.IsInStringArray(pkg, conf.Packages) {
conf.Packages = append(conf.Packages, pkg)
}
}
func (conf *SCloudConfig) Merge(conf2 *SCloudConfig) {
for _, u := range conf2.Users {
conf.MergeUser(u)
}
for _, f := range conf2.WriteFiles {
conf.MergeWriteFile(f, false)
}
for _, c := range conf2.Runcmd {
conf.MergeRuncmd(c)
}
for _, c := range conf2.Bootcmd {
conf.MergeBootcmd(c)
}
for _, p := range conf2.Packages {
conf.MergePackage(p)
}
}