baremetal: change ipmi user password

This commit is contained in:
Zexi
2019-06-18 12:23:24 +08:00
parent 1d7fd20df4
commit fbbe3c3aab
7 changed files with 181 additions and 17 deletions
+14
View File
@@ -23,3 +23,17 @@ type SGMapItem struct {
Type int
LinuxDeviceName string
}
const (
IPMIUserPrivUser = "USER"
IPMIUSERPrivAdmin = "ADMINISTRATOR"
)
type IPMIUser struct {
Id int
Name string
Callin bool
LinkAuth bool
IPMIMsg bool
Priv string
}
+1 -1
View File
@@ -1056,7 +1056,7 @@ func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nic
if len(netType) > 0 {
params.Add(jsonutils.NewString(netType), "net_type")
}
log.Errorf("enable net if params: %s", params.String())
log.Infof("enable net if params: %s", params.String())
return modules.Hosts.PerformAction(session, b.GetId(), "enable-netif", params)
}
+19 -9
View File
@@ -113,11 +113,18 @@ func (task *sBaremetalPrepareTask) prepareBaremetalInfo(cli *ssh.Client) (*barem
}
return &baremetalPrepareInfo{
sysInfo, cpuInfo, dmiCPUInfo, memInfo, nicsInfo, diskInfo, storageDriver, ipmiInfo,
sysInfo,
cpuInfo,
dmiCPUInfo,
memInfo,
nicsInfo,
diskInfo,
storageDriver,
ipmiInfo,
}, nil
}
func (task *sBaremetalPrepareTask) ipmiNicDHCP(cli *ssh.Client, i *baremetalPrepareInfo) error {
func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremetalPrepareInfo) error {
if !i.ipmiInfo.Present {
return nil
}
@@ -153,9 +160,11 @@ func (task *sBaremetalPrepareTask) ipmiNicDHCP(cli *ssh.Client, i *baremetalPrep
Speed: 100,
Mtu: 1500,
}
task.sendNicInfo(ipmiNic, -1, types.NIC_TYPE_IPMI, true, "")
if err := task.sendNicInfo(ipmiNic, -1, types.NIC_TYPE_IPMI, true, ""); err != nil {
log.Errorf("Send IPMI nic %#v info: %v", ipmiNic, err)
}
rootId := ipmitool.GetRootId(ipmiSysInfo)
err = ipmitool.SetLanUserPasswd(sshIPMI, lanChannel, rootId, ipmiUser, ipmiPasswd)
err = ipmitool.CreateOrSetAdminUser(sshIPMI, lanChannel, rootId, ipmiUser, ipmiPasswd)
if err != nil {
// ignore the error
log.Errorf("Lan channel %d set user password error: %v", lanChannel, err)
@@ -197,7 +206,7 @@ func (task *sBaremetalPrepareTask) ipmiNicDHCP(cli *ssh.Client, i *baremetalPrep
if err != nil {
log.Errorf("Set lan channel %d dhcp error: %v", lanChannel, err)
}
time.Sleep(1 * time.Second)
time.Sleep(2 * time.Second)
nic := task.baremetal.GetIPMINic(conf.Mac)
maxTries := 180 // wait 3 minutes
for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
@@ -208,9 +217,11 @@ func (task *sBaremetalPrepareTask) ipmiNicDHCP(cli *ssh.Client, i *baremetalPrep
if err != nil {
log.Errorf("Do BMC reset error: %v", err)
}
time.Sleep(1 * time.Second)
}
for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
nic = task.baremetal.GetIPMINic(conf.Mac)
time.Sleep(1 * time.Second)
}
if nic != nil && len(nic.IpAddr) == 0 {
log.Errorf("DHCP wait IPMI address fail, retry ...")
@@ -262,8 +273,8 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
return err
}
// set ipmi nic DHCP
if err = task.ipmiNicDHCP(cli, infos); err != nil {
// set ipmi nic address and user password
if err = task.configIPMISetting(cli, infos); err != nil {
return err
}
@@ -550,8 +561,7 @@ func (task *sBaremetalPrepareTask) sendNicInfo(nic *types.SNicDevInfo, idx int,
if err != nil {
return err
}
task.baremetal.SaveDesc(resp)
return nil
return task.baremetal.SaveDesc(resp)
}
func (task *sBaremetalPrepareTask) sendStorageInfo(size int64) error {
+57 -7
View File
@@ -28,6 +28,7 @@ import (
"yunion.io/x/pkg/util/stringutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/baremetal/profiles"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/procutils"
@@ -307,17 +308,58 @@ func EnableLanAccess(exector IPMIExecutor, channel int) error {
return setLanAccess(exector, channel, "on")
}
func SetLanUserPasswd(exector IPMIExecutor, channel int, rootId int, user string, password string) error {
func ListLanUsers(exector IPMIExecutor, channel int) ([]compute.IPMIUser, error) {
args := newArgs("user", "list", channel)
ret, err := ExecuteCommands(exector, args)
if err != nil {
return nil, errors.Wrapf(err, "list user at channel %d", channel)
}
return sysutils.ParseIPMIUser(ret), nil
}
func CreateOrSetAdminUser(exector IPMIExecutor, channel int, rootId int, username string, password string) error {
users, err := ListLanUsers(exector, channel)
if err != nil {
return errors.Wrap(err, "List users")
}
if len(users) == 0 {
return errors.Errorf("Empty users at channel %d", channel)
}
var foundUser *compute.IPMIUser = nil
for _, user := range users {
tmp := user
if user.Name == username {
foundUser = &tmp
break
}
}
if foundUser == nil {
minEmptyUserId := -1
for _, user := range users {
if user.Name == "" {
minEmptyUserId = user.Id
break
}
}
if minEmptyUserId == -1 {
log.Warningf("Not found min empty user id, use root id %d to set", rootId)
minEmptyUserId = rootId
}
return SetIdUserPasswd(exector, channel, minEmptyUserId, username, password)
}
return SetLanUserAdminPasswd(exector, channel, foundUser.Id, password)
}
func SetLanUserAdminPasswd(exector IPMIExecutor, channel int, id int, password string) error {
var err error
password, err = stage_stringutils.EscapeEchoString(password)
if err != nil {
return fmt.Errorf("EscapeEchoString for password: %s, error: %v", password, err)
}
args := []Args{
newArgs("user", "enable", rootId),
newArgs("user", "set", "name", rootId, user),
newArgs("user", "set", "password", rootId, fmt.Sprintf("\"%s\"", password)),
newArgs("user", "priv", rootId, 4, channel),
newArgs("user", "enable", id),
newArgs("user", "set", "password", id, fmt.Sprintf("\"%s\"", password)),
newArgs("user", "priv", id, 4, channel),
}
err = doActions(exector, "set_lan_user_password", args...)
if err != nil {
@@ -326,19 +368,27 @@ func SetLanUserPasswd(exector IPMIExecutor, channel int, rootId int, user string
args = []Args{newArgs(
"raw", "0x06", "0x43",
fmt.Sprintf("0x%02x", 0xb0+channel),
fmt.Sprintf("0x%02x", rootId), "0x04", "0x00")}
fmt.Sprintf("0x%02x", id), "0x04", "0x00")}
err = doActions(exector, "set_lan_user_password2", args...)
if err == nil {
return nil
}
args = []Args{newArgs(
"channel", "setaccess", channel,
rootId, "link=on", "ipmi=on",
id, "link=on", "ipmi=on",
"callin=on", "privilege=4",
)}
return doActions(exector, "set_lan_user_password3", args...)
}
func SetIdUserPasswd(exector IPMIExecutor, channel int, id int, user string, password string) error {
args := newArgs("user", "set", "name", id, user)
if err := doActions(exector, fmt.Sprintf("set_id%d_name", id), args); err != nil {
return errors.Wrapf(err, "change root id %d to name %s", id, user)
}
return SetLanUserAdminPasswd(exector, channel, id, password)
}
func SetLanPasswd(exector IPMIExecutor, rootId int, password string) error {
password, err := stringutils2.EscapeEchoString(password)
if err != nil {
+5
View File
@@ -50,6 +50,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/onecloud/pkg/util/seclib2"
)
/*
@@ -2594,6 +2595,10 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc
if len(ipmiIpAddr) > 0 && !NetworkManager.IsValidOnPremiseNetworkIP(ipmiIpAddr) {
return nil, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
}
ipmiPasswd, _ := ipmiInfo.GetString("password")
if len(ipmiPasswd) > 0 && !seclib2.MeetComplxity(ipmiPasswd) {
return nil, httperrors.NewWeakPasswordError()
}
return manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
}
+31
View File
@@ -311,3 +311,34 @@ func Start(closeFd bool, args ...string) (p *os.Process, err error) {
}
return nil, err
}
func ParseIPMIUser(lines []string) []compute.IPMIUser {
ret := make([]compute.IPMIUser, 0)
for _, l := range lines {
if strings.HasPrefix(l, "ID") {
continue
}
fields := strings.Fields(l)
if strings.Contains(l, "Empty User") {
id, err := strconv.Atoi(fields[0])
if err != nil {
continue
}
ret = append(ret, compute.IPMIUser{Id: id})
continue
}
if len(fields) != 6 {
continue
}
id, err := strconv.Atoi(fields[0])
if err != nil {
continue
}
ret = append(ret, compute.IPMIUser{
Id: id,
Name: fields[1],
Priv: fields[5],
})
}
return ret
}
+54
View File
@@ -401,3 +401,57 @@ func TestParseSGMap(t *testing.T) {
})
}
}
func TestParseIPMIUser(t *testing.T) {
tests := []struct {
name string
args []string
want []compute.IPMIUser
}{
{
name: "empty line",
args: []string{"ID Name Callin Link Auth IPMI Msg Channel Priv Limit"},
want: []compute.IPMIUser{},
},
{
name: "users",
args: []string{
"ID Name Callin Link Auth IPMI Msg Channel Priv Limit",
"1 root true false true ADMINISTRATOR",
"2 admin true false true ADMINISTRATOR",
"3 true false true USER",
"4 (Empty User) true false false NO ACCESS",
"5 (Empty User) true false false NO ACCESS",
},
want: []compute.IPMIUser{
{
Id: 1,
Name: "root",
Priv: "ADMINISTRATOR",
},
{
Id: 2,
Name: "admin",
Priv: "ADMINISTRATOR",
},
{
Id: 4,
Name: "",
Priv: "",
},
{
Id: 5,
Name: "",
Priv: "",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseIPMIUser(tt.args); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseIPMIUser() = %v, want %v", got, tt.want)
}
})
}
}