mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-28 19:45:07 +08:00
feature: support baremetal profile (#20687)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compute
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/printutils"
|
||||
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
baremetalmodules "yunion.io/x/onecloud/pkg/mcclient/modules/compute/baremetal"
|
||||
baremetaloptions "yunion.io/x/onecloud/pkg/mcclient/options/compute/baremetal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewResourceCmd(&baremetalmodules.BaremetalProfiles)
|
||||
cmd.List(new(baremetaloptions.BaremetalProfileListOptions))
|
||||
cmd.Show(new(baremetaloptions.BaremetalProfileIdOptions))
|
||||
cmd.Delete(new(baremetaloptions.BaremetalProfileIdOptions))
|
||||
|
||||
type BaremetalProfileMatchOpts struct {
|
||||
OEMNAME string
|
||||
MODEL string
|
||||
}
|
||||
R(&BaremetalProfileMatchOpts{}, "baremetal-profile-match", "find match baremetal profile by oemname and model", func(s *mcclient.ClientSession, args *BaremetalProfileMatchOpts) error {
|
||||
specs, err := baremetalmodules.BaremetalProfiles.GetMatchProfiles(s, args.OEMNAME, args.MODEL)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetMatchProfiles")
|
||||
}
|
||||
listResults := printutils.ListResult{}
|
||||
for _, spec := range specs {
|
||||
listResults.Data = append(listResults.Data, jsonutils.Marshal(spec))
|
||||
}
|
||||
printList(&listResults, nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultBaremetalProfileId = "default"
|
||||
)
|
||||
|
||||
type BaremetalProfileListInput struct {
|
||||
apis.StandaloneAnonResourceListInput
|
||||
|
||||
OemName []string `json:"oem_name"`
|
||||
Model []string `json:"model"`
|
||||
}
|
||||
|
||||
func (input *BaremetalProfileListInput) Normalize() {
|
||||
for i := range input.OemName {
|
||||
input.OemName[i] = strings.TrimSpace(input.OemName[i])
|
||||
}
|
||||
for i := range input.Model {
|
||||
input.Model[i] = strings.TrimSpace(input.Model[i])
|
||||
}
|
||||
}
|
||||
|
||||
type BaremetalProfileCreateInput struct {
|
||||
apis.StandaloneAnonResourceCreateInput
|
||||
|
||||
OemName string
|
||||
Model string
|
||||
LanChannel uint8
|
||||
RootId int
|
||||
RootName string
|
||||
StrongPass bool
|
||||
}
|
||||
|
||||
type BaremetalProfileUpdateInput struct {
|
||||
apis.StandaloneAnonResourceBaseUpdateInput
|
||||
|
||||
LanChannel uint8
|
||||
RootId *int
|
||||
RootName string
|
||||
StrongPass *bool
|
||||
}
|
||||
|
||||
type BaremetalProfileDetails struct {
|
||||
SBaremetalProfile
|
||||
}
|
||||
|
||||
func (detail BaremetalProfileDetails) ToSpec() BaremetalProfileSpec {
|
||||
channels := make([]uint8, 0)
|
||||
if detail.LanChannel > 0 {
|
||||
channels = append(channels, detail.LanChannel)
|
||||
}
|
||||
if detail.LanChannel2 > 0 {
|
||||
channels = append(channels, detail.LanChannel2)
|
||||
}
|
||||
if detail.LanChannel3 > 0 {
|
||||
channels = append(channels, detail.LanChannel3)
|
||||
}
|
||||
return BaremetalProfileSpec{
|
||||
OemName: detail.OemName,
|
||||
Model: detail.Model,
|
||||
LanChannels: channels,
|
||||
RootName: detail.RootName,
|
||||
RootId: detail.RootId,
|
||||
StrongPass: detail.StrongPass,
|
||||
}
|
||||
}
|
||||
|
||||
type BaremetalProfileSpec struct {
|
||||
OemName string
|
||||
Model string
|
||||
LanChannels []uint8
|
||||
RootName string
|
||||
RootId int
|
||||
StrongPass bool
|
||||
}
|
||||
|
||||
type BaremetalProfileSpecs []BaremetalProfileSpec
|
||||
|
||||
func (a BaremetalProfileSpecs) Len() int { return len(a) }
|
||||
func (a BaremetalProfileSpecs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a BaremetalProfileSpecs) Less(i, j int) bool {
|
||||
if a[i].OemName != a[j].OemName {
|
||||
return a[i].OemName < a[j].OemName
|
||||
}
|
||||
if a[i].Model != a[j].Model {
|
||||
return a[i].Model < a[j].Model
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var PredefinedProfiles = []BaremetalProfileSpec{
|
||||
{
|
||||
OemName: "",
|
||||
LanChannels: []uint8{1, 2, 8},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_INSPUR,
|
||||
LanChannels: []uint8{8, 1},
|
||||
RootName: "admin",
|
||||
RootId: 2,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_LENOVO,
|
||||
LanChannels: []uint8{1, 8},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_HP,
|
||||
LanChannels: []uint8{1, 2},
|
||||
RootName: "root",
|
||||
RootId: 1,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_HUAWEI,
|
||||
LanChannels: []uint8{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_FOXCONN,
|
||||
LanChannels: []uint8{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_QEMU,
|
||||
LanChannels: []uint8{8, 1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
},
|
||||
{
|
||||
OemName: types.OEM_NAME_H3C,
|
||||
LanChannels: []uint8{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by model-api-gen. DO NOT EDIT.
|
||||
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
)
|
||||
|
||||
// SBaremetalProfile is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models/baremetal.SBaremetalProfile.
|
||||
type SBaremetalProfile struct {
|
||||
apis.SStandaloneAnonResourceBase
|
||||
// 品牌名称(English)
|
||||
OemName string `json:"oem_name"`
|
||||
Model string `json:"model"`
|
||||
LanChannel byte `json:"lan_channel"`
|
||||
LanChannel2 byte `json:"lan_channel2"`
|
||||
LanChannel3 byte `json:"lan_channel3"`
|
||||
// BMC Root账号名称,默认为 root
|
||||
RootName string `json:"root_name"`
|
||||
// BMC Root账号ID,默认为 2
|
||||
RootId int `json:"root_id"`
|
||||
// 是否要求强密码
|
||||
StrongPass bool `json:"strong_pass"`
|
||||
}
|
||||
@@ -414,7 +414,7 @@ type HostIpmiAttributes struct {
|
||||
// presence
|
||||
IpmiPresent *bool `json:"ipmi_present"`
|
||||
// lan channel
|
||||
IpmiLanChannel *int `json:"ipmi_lan_channel"`
|
||||
IpmiLanChannel *uint8 `json:"ipmi_lan_channel"`
|
||||
// verified
|
||||
IpmiVerified *bool `json:"ipmi_verified"`
|
||||
// Redfish API support
|
||||
|
||||
@@ -269,6 +269,8 @@ type SCloudaccount struct {
|
||||
// 跳过部分资源同步
|
||||
SkipSyncResources *SkipSyncResources `json:"skip_sync_resources"`
|
||||
EnableAutoSyncResource *bool `json:"enable_auto_sync_resource,omitempty"`
|
||||
// 云平台默认区域id
|
||||
RegionId string `json:"region_id"`
|
||||
}
|
||||
|
||||
// SCloudimage is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudimage.
|
||||
|
||||
@@ -134,7 +134,9 @@ func (agent *SBaremetalAgent) StartService() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Baremetal manager load config error: %v", err)
|
||||
}
|
||||
if err := manager.initBaremetals(files); err != nil {
|
||||
|
||||
ctx := context.Background()
|
||||
if err := manager.initBaremetals(ctx, files); err != nil {
|
||||
log.Warningf("init baremetals by files err: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ func (job *SStatusProbeJob) Do(ctx context.Context, now time.Time) error {
|
||||
pps := PowerStatusToBaremetalStatus(ps)
|
||||
if pps != bStatus {
|
||||
log.Debugf("Detected baremetal status change!")
|
||||
job.baremetal.SyncAllStatus(ps)
|
||||
job.baremetal.SyncAllStatus(ctx, ps)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -30,9 +31,10 @@ func init() {
|
||||
delayTaskWorkerMan = appsrv.NewWorkerManager("DelayTaskWorkerManager", 8, 1024, false)
|
||||
}
|
||||
|
||||
type ProcessFunc func(data jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
type ProcessFunc func(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
|
||||
type delayTask struct {
|
||||
ctx context.Context
|
||||
process ProcessFunc
|
||||
taskId string
|
||||
session *mcclient.ClientSession
|
||||
@@ -40,7 +42,7 @@ type delayTask struct {
|
||||
}
|
||||
|
||||
func (t *delayTask) Run() {
|
||||
ret, err := t.process(t.data)
|
||||
ret, err := t.process(t.ctx, t.data)
|
||||
if err != nil {
|
||||
modules.ComputeTasks.TaskFailed(t.session, t.taskId, err)
|
||||
return
|
||||
|
||||
@@ -109,7 +109,7 @@ func handleBaremetalNotify(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
task := bm.GetTask()
|
||||
if task == nil {
|
||||
task = tasks.NewBaremetalServerPrepareTask(bm)
|
||||
bm.SyncStatus(baremetalstatus.PREPARE, "")
|
||||
bm.SyncStatus(ctx, baremetalstatus.PREPARE, "")
|
||||
}
|
||||
log.Infof("Get notify from pxe rom os, start exec task: %s", task.GetName())
|
||||
task.SSHExecute(remoteAddr, key, nil)
|
||||
@@ -157,7 +157,7 @@ func handleBaremetalResetBMC(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
}
|
||||
|
||||
func handleBaremetalIpmiProbe(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
bm.StartBaremetalIpmiProbeTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
bm.StartBaremetalIpmiProbeTask(ctx, ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
ctx.ResponseOk()
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func handleBaremetalJnlpTask(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
}
|
||||
|
||||
func handleServerCreate(ctx *Context, bm *baremetal.SBaremetalInstance) {
|
||||
err := bm.StartServerCreateTask(ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
err := bm.StartServerCreateTask(ctx, ctx.UserCred(), ctx.TaskId(), ctx.Data())
|
||||
if err != nil {
|
||||
ctx.ResponseError(httperrors.NewGeneralError(err))
|
||||
return
|
||||
@@ -238,7 +238,7 @@ func handleServerStatus(ctx *Context, bm *baremetal.SBaremetalInstance, _ bareme
|
||||
}
|
||||
|
||||
func handleBaremetalRegister(ctx *Context, input *baremetal.BmRegisterInput) {
|
||||
ctx.DelayProcess(func(data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
ctx.DelayProcess(func(_ context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
baremetal.GetBaremetalManager().RegisterBaremetal(ctx, ctx.userCred, input)
|
||||
return nil, nil
|
||||
}, nil)
|
||||
|
||||
@@ -88,7 +88,7 @@ func bmObjMiddlewareWithFetch(h bmObjHandlerFunc, fetch bool) appsrv.FilterHandl
|
||||
baremetal := newCtx.GetBaremetalManager().GetBaremetalById(bmId)
|
||||
if baremetal == nil {
|
||||
if fetch {
|
||||
err := newCtx.GetBaremetalManager().InitBaremetal(bmId, false)
|
||||
err := newCtx.GetBaremetalManager().InitBaremetal(newCtx, bmId, false)
|
||||
if err != nil {
|
||||
newCtx.ResponseError(err)
|
||||
return
|
||||
|
||||
+109
-86
@@ -17,6 +17,7 @@ package baremetal
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -43,6 +44,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
apiidenty "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
@@ -114,16 +116,16 @@ func (m *SBaremetalManager) GetZoneName() string {
|
||||
return m.Agent.Zone.Name
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) loadConfigs() ([]os.FileInfo, error) {
|
||||
func (m *SBaremetalManager) loadConfigs() ([]fs.DirEntry, error) {
|
||||
m.killAllIPMITool()
|
||||
files, err := ioutil.ReadDir(m.configPath)
|
||||
files, err := os.ReadDir(m.configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) initBaremetals(files []os.FileInfo) error {
|
||||
func (m *SBaremetalManager) initBaremetals(ctx context.Context, files []fs.DirEntry) error {
|
||||
bmIds := make([]string, 0)
|
||||
for _, file := range files {
|
||||
if file.IsDir() && regutils.MatchUUID(file.Name()) {
|
||||
@@ -134,7 +136,7 @@ func (m *SBaremetalManager) initBaremetals(files []os.FileInfo) error {
|
||||
errsChannel := make(chan error, len(bmIds))
|
||||
initBaremetal := func(i int) {
|
||||
bmId := bmIds[i]
|
||||
err := m.InitBaremetal(bmId, true)
|
||||
err := m.InitBaremetal(ctx, bmId, true)
|
||||
if err != nil {
|
||||
errsChannel <- err
|
||||
return
|
||||
@@ -151,7 +153,7 @@ func (m *SBaremetalManager) initBaremetals(files []os.FileInfo) error {
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) InitBaremetal(bmId string, update bool) error {
|
||||
func (m *SBaremetalManager) InitBaremetal(ctx context.Context, bmId string, update bool) error {
|
||||
session := m.GetClientSession()
|
||||
var err error
|
||||
var desc jsonutils.JSONObject
|
||||
@@ -167,7 +169,7 @@ func (m *SBaremetalManager) InitBaremetal(bmId string, update bool) error {
|
||||
if !isBaremetal {
|
||||
return errors.Error("not a baremetal???")
|
||||
}
|
||||
bmInstance, err := m.AddBaremetal(desc)
|
||||
bmInstance, err := m.AddBaremetal(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -213,15 +215,15 @@ func (m *SBaremetalManager) fetchBaremetal(session *mcclient.ClientSession, bmId
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) AddBaremetal(desc jsonutils.JSONObject) (pxe.IBaremetalInstance, error) {
|
||||
func (m *SBaremetalManager) AddBaremetal(ctx context.Context, desc jsonutils.JSONObject) (pxe.IBaremetalInstance, error) {
|
||||
id, err := desc.GetString("id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Not found baremetal id in desc %s", desc)
|
||||
}
|
||||
if instance, ok := m.baremetals.Get(id); ok {
|
||||
return instance, instance.SaveDesc(desc)
|
||||
return instance, instance.SaveDesc(ctx, desc)
|
||||
}
|
||||
bm, err := newBaremetalInstance(m, desc)
|
||||
bm, err := newBaremetalInstance(ctx, m, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -337,7 +339,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
return
|
||||
}
|
||||
|
||||
ipmiLanChannel, ipmiMac, err := m.checkIpmiInfo(input.Username, input.Password, input.IpAddr)
|
||||
ipmiLanChannel, ipmiMac, err := m.checkIpmiInfo(ctx, input.Username, input.Password, input.IpAddr)
|
||||
if input.isTimeout() {
|
||||
return
|
||||
} else if err != nil {
|
||||
@@ -360,9 +362,9 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
|
||||
)
|
||||
var bmId string
|
||||
if !registered {
|
||||
bmId, err = registerTask.CreateBaremetal()
|
||||
bmId, err = registerTask.CreateBaremetal(ctx)
|
||||
} else {
|
||||
bmId, err = registerTask.UpdateBaremetal()
|
||||
bmId, err = registerTask.UpdateBaremetal(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
input.responseErr(ctx, httperrors.NewInternalServerError("%v", err))
|
||||
@@ -452,14 +454,18 @@ func (m *SBaremetalManager) checkSshInfo(input *BmRegisterInput) (*ssh.Client, e
|
||||
return sshCLi, nil
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) checkIpmiInfo(username, password, ipAddr string) (int, net.HardwareAddr, error) {
|
||||
func (m *SBaremetalManager) checkIpmiInfo(ctx context.Context, username, password, ipAddr string) (uint8, net.HardwareAddr, error) {
|
||||
lanPlusTool := ipmitool.NewLanPlusIPMI(ipAddr, username, password)
|
||||
sysInfo, err := ipmitool.GetSysInfo(lanPlusTool)
|
||||
if err != nil {
|
||||
return -1, nil, err
|
||||
return 0, nil, errors.Wrap(err, "GetSysInfo")
|
||||
}
|
||||
profile, err := profiles.GetProfile(ctx, sysInfo)
|
||||
if err != nil {
|
||||
return 0, nil, errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
|
||||
for _, lanChannel := range ipmitool.GetLanChannels(sysInfo) {
|
||||
for _, lanChannel := range profile.LanChannels {
|
||||
config, err := ipmitool.GetLanConfig(lanPlusTool, lanChannel)
|
||||
if err != nil {
|
||||
log.Errorf("GetLanConfig failed %s", err)
|
||||
@@ -470,7 +476,7 @@ func (m *SBaremetalManager) checkIpmiInfo(username, password, ipAddr string) (in
|
||||
}
|
||||
return lanChannel, config.Mac, nil
|
||||
}
|
||||
return -1, nil, fmt.Errorf("Ipmi can't fetch lan config")
|
||||
return 0, nil, fmt.Errorf("Ipmi can't fetch lan config")
|
||||
}
|
||||
|
||||
func (m *SBaremetalManager) Stop() {
|
||||
@@ -521,10 +527,12 @@ type SBaremetalInstance struct {
|
||||
server baremetaltypes.IBaremetalServer
|
||||
serverLock *sync.Mutex
|
||||
|
||||
profile *baremetalapi.BaremetalProfileSpec
|
||||
|
||||
cronJobs []IBaremetalCronJob
|
||||
}
|
||||
|
||||
func newBaremetalInstance(man *SBaremetalManager, desc jsonutils.JSONObject) (*SBaremetalInstance, error) {
|
||||
func newBaremetalInstance(ctx context.Context, man *SBaremetalManager, desc jsonutils.JSONObject) (*SBaremetalInstance, error) {
|
||||
bm := &SBaremetalInstance{
|
||||
manager: man,
|
||||
desc: desc.(*jsonutils.JSONDict),
|
||||
@@ -541,7 +549,7 @@ func newBaremetalInstance(man *SBaremetalManager, desc jsonutils.JSONObject) (*S
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = bm.SaveDesc(desc)
|
||||
err = bm.SaveDesc(ctx, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -614,17 +622,29 @@ func (b *SBaremetalInstance) GetStatus() string {
|
||||
return status
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) AutoSaveDesc() error {
|
||||
return b.SaveDesc(nil)
|
||||
func (b *SBaremetalInstance) AutoSaveDesc(ctx context.Context) error {
|
||||
return b.SaveDesc(ctx, nil)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SaveDesc(desc jsonutils.JSONObject) error {
|
||||
func (b *SBaremetalInstance) SaveDesc(ctx context.Context, desc jsonutils.JSONObject) error {
|
||||
b.descLock.Lock()
|
||||
defer b.descLock.Unlock()
|
||||
if desc != nil {
|
||||
b.desc = desc.(*jsonutils.JSONDict)
|
||||
|
||||
if b.desc.Contains("sys_info") {
|
||||
sysInfo := types.SSystemInfo{}
|
||||
err := b.desc.Unmarshal(&sysInfo, "sys_info")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unmarshal sys_info")
|
||||
}
|
||||
b.profile, err = profiles.GetProfile(ctx, &sysInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
}
|
||||
}
|
||||
return ioutil.WriteFile(b.GetDescFilePath(), []byte(b.desc.String()), 0644)
|
||||
return os.WriteFile(b.GetDescFilePath(), []byte(b.desc.String()), 0644)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) loadServer() {
|
||||
@@ -634,7 +654,7 @@ func (b *SBaremetalInstance) loadServer() {
|
||||
return
|
||||
}
|
||||
descPath := b.GetServerDescFilePath()
|
||||
desc, err := ioutil.ReadFile(descPath)
|
||||
desc, err := os.ReadFile(descPath)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to read server desc %s: %v", descPath, err)
|
||||
return
|
||||
@@ -668,7 +688,7 @@ func (b *SBaremetalInstance) SaveSSHConfig(remoteAddr string, key string) error
|
||||
RemoteIP: remoteAddr,
|
||||
}
|
||||
conf := jsonutils.Marshal(sshConf)
|
||||
err = ioutil.WriteFile(b.GetSSHConfigFilePath(), []byte(conf.String()), 0644)
|
||||
err = os.WriteFile(b.GetSSHConfigFilePath(), []byte(conf.String()), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -679,7 +699,7 @@ func (b *SBaremetalInstance) SaveSSHConfig(remoteAddr string, key string) error
|
||||
|
||||
func (b *SBaremetalInstance) GetSSHConfig() (*types.SSHConfig, error) {
|
||||
path := b.GetSSHConfigFilePath()
|
||||
content, err := ioutil.ReadFile(path)
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
@@ -774,7 +794,7 @@ func (b *SBaremetalInstance) SyncSSHConfig(conf types.SSHConfig) error {
|
||||
|
||||
func (b *SBaremetalInstance) SyncStatusBackground() {
|
||||
go func() {
|
||||
b.AutoSyncAllStatus()
|
||||
b.AutoSyncAllStatus(context.Background())
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -785,12 +805,12 @@ func (b *SBaremetalInstance) InitializeServer(s *mcclient.ClientSession, name st
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) ServerLoadDesc() error {
|
||||
func (b *SBaremetalInstance) ServerLoadDesc(ctx context.Context) error {
|
||||
res, err := modules.Hosts.Get(b.manager.GetClientSession(), b.GetId(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.SaveDesc(res)
|
||||
b.SaveDesc(ctx, res)
|
||||
sid, err := res.GetString("server_id")
|
||||
if err == nil {
|
||||
sDesc := jsonutils.NewDict()
|
||||
@@ -830,11 +850,11 @@ func PowerStatusToServerStatus(bm *SBaremetalInstance, status string) string {
|
||||
return baremetalstatus.UNKNOWN
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) AutoSyncStatus() {
|
||||
b.SyncStatus("", "")
|
||||
func (b *SBaremetalInstance) AutoSyncStatus(ctx context.Context) {
|
||||
b.SyncStatus(ctx, "", "")
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SyncStatus(status string, reason string) {
|
||||
func (b *SBaremetalInstance) SyncStatus(ctx context.Context, status string, reason string) {
|
||||
if status == "" {
|
||||
powerStatus, err := b.GetPowerStatus()
|
||||
if err != nil {
|
||||
@@ -843,7 +863,7 @@ func (b *SBaremetalInstance) SyncStatus(status string, reason string) {
|
||||
status = PowerStatusToBaremetalStatus(powerStatus)
|
||||
}
|
||||
b.desc.Set("status", jsonutils.NewString(status))
|
||||
b.AutoSaveDesc()
|
||||
b.AutoSaveDesc(ctx)
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(status), "status")
|
||||
if reason != "" {
|
||||
@@ -857,16 +877,16 @@ func (b *SBaremetalInstance) SyncStatus(status string, reason string) {
|
||||
log.Infof("Update baremetal %s to status %s", b.GetId(), status)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) AutoSyncAllStatus() {
|
||||
b.SyncAllStatus("")
|
||||
func (b *SBaremetalInstance) AutoSyncAllStatus(ctx context.Context) {
|
||||
b.SyncAllStatus(ctx, "")
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedSyncStatus(_ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
b.AutoSyncAllStatus()
|
||||
func (b *SBaremetalInstance) DelayedSyncStatus(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
b.AutoSyncAllStatus(ctx)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SyncAllStatus(status string) {
|
||||
func (b *SBaremetalInstance) SyncAllStatus(ctx context.Context, status string) {
|
||||
var err error
|
||||
if status == "" {
|
||||
status, err = b.GetPowerStatus()
|
||||
@@ -874,7 +894,7 @@ func (b *SBaremetalInstance) SyncAllStatus(status string) {
|
||||
log.Errorf("Get power status error: %v", err)
|
||||
}
|
||||
}
|
||||
b.SyncStatus(PowerStatusToBaremetalStatus(status), "")
|
||||
b.SyncStatus(ctx, PowerStatusToBaremetalStatus(status), "")
|
||||
b.SyncServerStatus(PowerStatusToServerStatus(b, status))
|
||||
}
|
||||
|
||||
@@ -1295,6 +1315,7 @@ func (b *SBaremetalInstance) SetTask(task tasks.ITask) {
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) InitAdminNetif(
|
||||
ctx context.Context,
|
||||
cliMac net.HardwareAddr,
|
||||
wireId string,
|
||||
nicType compute.TNicType,
|
||||
@@ -1312,7 +1333,7 @@ func (b *SBaremetalInstance) InitAdminNetif(
|
||||
baremetalstatus.UNKNOWN}) &&
|
||||
b.GetTask() == nil && b.GetServer() == nil {
|
||||
b.SetTask(tasks.NewBaremetalServerPrepareTask(b))
|
||||
b.SyncStatus(baremetalstatus.PREPARE, "")
|
||||
b.SyncStatus(ctx, baremetalstatus.PREPARE, "")
|
||||
}
|
||||
|
||||
nic := b.GetNicByMac(cliMac)
|
||||
@@ -1321,14 +1342,14 @@ func (b *SBaremetalInstance) InitAdminNetif(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.postAttachWire(cliMac, nicType, netType, importIpAddr)
|
||||
return b.postAttachWire(ctx, cliMac, nicType, netType, importIpAddr)
|
||||
} else if nic.IpAddr == "" {
|
||||
return b.postAttachWire(cliMac, nicType, netType, importIpAddr)
|
||||
return b.postAttachWire(ctx, cliMac, nicType, netType, importIpAddr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) RegisterNetif(cliMac net.HardwareAddr, wireId string) error {
|
||||
func (b *SBaremetalInstance) RegisterNetif(ctx context.Context, cliMac net.HardwareAddr, wireId string) error {
|
||||
var nicType compute.TNicType
|
||||
nic := b.GetNicByMac(cliMac)
|
||||
if nic != nil {
|
||||
@@ -1339,7 +1360,7 @@ func (b *SBaremetalInstance) RegisterNetif(cliMac net.HardwareAddr, wireId strin
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.SaveDesc(desc)
|
||||
return b.SaveDesc(ctx, desc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1357,7 +1378,7 @@ func (b *SBaremetalInstance) attachWire(mac net.HardwareAddr, wireId string, nic
|
||||
return modules.Hosts.PerformAction(session, b.GetId(), "add-netif", params)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) postAttachWire(mac net.HardwareAddr, nicType compute.TNicType, netType api.TNetworkType, ipAddr string) error {
|
||||
func (b *SBaremetalInstance) postAttachWire(ctx context.Context, mac net.HardwareAddr, nicType compute.TNicType, netType api.TNetworkType, ipAddr string) error {
|
||||
if ipAddr == "" {
|
||||
switch nicType {
|
||||
case api.NIC_TYPE_IPMI:
|
||||
@@ -1376,7 +1397,7 @@ func (b *SBaremetalInstance) postAttachWire(mac net.HardwareAddr, nicType comput
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.SaveDesc(desc)
|
||||
return b.SaveDesc(ctx, desc)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nicType compute.TNicType, netType api.TNetworkType) (jsonutils.JSONObject, error) {
|
||||
@@ -1410,13 +1431,8 @@ func (b *SBaremetalInstance) GetIPMIConfig() *types.SIPMIInfo {
|
||||
log.Debugf("GetIPMIConfig password is nil")
|
||||
return nil
|
||||
}
|
||||
if conf.Username == "" {
|
||||
sysInfo := types.SSystemInfo{}
|
||||
err := b.desc.Unmarshal(&sysInfo, "sys_info")
|
||||
if err != nil {
|
||||
log.Errorf("Unmarshal get sys_info error: %v", err)
|
||||
}
|
||||
conf.Username = profiles.GetRootName(&sysInfo)
|
||||
if conf.Username == "" && b.profile != nil {
|
||||
conf.Username = b.profile.RootName
|
||||
}
|
||||
if conf.IpAddr == "" {
|
||||
nicIPAddr := b.GetIPMINicIPAddr()
|
||||
@@ -1628,19 +1644,19 @@ func (b *SBaremetalInstance) sshRun(hostCmd string, serverCmd string) ([]string,
|
||||
)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) adjustUEFIWrapper(cli *ssh.Client, f func() error) error {
|
||||
func (b *SBaremetalInstance) adjustUEFIWrapper(ctx context.Context, cli *ssh.Client, f func() error) error {
|
||||
isUEFI, err := uefi.RemoteIsUEFIBoot(cli)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Check is uefi boot")
|
||||
}
|
||||
if !isUEFI {
|
||||
return b.CleanUEFIInfo()
|
||||
return b.CleanUEFIInfo(ctx)
|
||||
}
|
||||
return f()
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(hostCli *ssh.Client) error {
|
||||
return b.adjustUEFIWrapper(hostCli, func() error {
|
||||
func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(ctx context.Context, hostCli *ssh.Client) error {
|
||||
return b.adjustUEFIWrapper(ctx, hostCli, func() error {
|
||||
mgr, err := uefi.NewEFIBootMgrFromRemote(hostCli, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NewEFIBootMgrFromRemote")
|
||||
@@ -1648,14 +1664,14 @@ func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(hostCli *ssh.Client) err
|
||||
if err := uefi.RemoteSetCurrentBootAtFirst(hostCli, mgr); err != nil {
|
||||
return errors.Wrap(err, "Set current boot order at first")
|
||||
}
|
||||
return b.SendUEFIInfo(mgr)
|
||||
return b.SendUEFIInfo(ctx, mgr)
|
||||
})
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) updateUEFIInfo(uefiData jsonutils.JSONObject) error {
|
||||
func (b *SBaremetalInstance) updateUEFIInfo(ctx context.Context, uefiData jsonutils.JSONObject) error {
|
||||
desc := b.desc
|
||||
desc.Add(uefiData, "uefi_info")
|
||||
if err := b.SaveDesc(desc); err != nil {
|
||||
if err := b.SaveDesc(ctx, desc); err != nil {
|
||||
return errors.Wrap(err, "Save uefi_info")
|
||||
}
|
||||
updateData := jsonutils.NewDict()
|
||||
@@ -1666,26 +1682,26 @@ func (b *SBaremetalInstance) updateUEFIInfo(uefiData jsonutils.JSONObject) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) CleanUEFIInfo() error {
|
||||
if err := b.updateUEFIInfo(jsonutils.NewDict()); err != nil {
|
||||
func (b *SBaremetalInstance) CleanUEFIInfo(ctx context.Context) error {
|
||||
if err := b.updateUEFIInfo(ctx, jsonutils.NewDict()); err != nil {
|
||||
return errors.Wrap(err, "CleanUEFIInfo")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SendUEFIInfo(mgr *uefi.BootMgr) error {
|
||||
func (b *SBaremetalInstance) SendUEFIInfo(ctx context.Context, mgr *uefi.BootMgr) error {
|
||||
info, err := mgr.ToEFIBootMgrInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.updateUEFIInfo(jsonutils.Marshal(info)); err != nil {
|
||||
if err := b.updateUEFIInfo(ctx, jsonutils.Marshal(info)); err != nil {
|
||||
return errors.Wrap(err, "SendUEFIInfo")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) adjustServerUEFIBootOrder(srvCli *ssh.Client) error {
|
||||
return b.adjustUEFIWrapper(srvCli, func() error {
|
||||
func (b *SBaremetalInstance) adjustServerUEFIBootOrder(ctx context.Context, srvCli *ssh.Client) error {
|
||||
return b.adjustUEFIWrapper(ctx, srvCli, func() error {
|
||||
info, err := b.GetUEFIInfo()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetUEFIInfo from local desc")
|
||||
@@ -1701,22 +1717,22 @@ func (b *SBaremetalInstance) adjustServerUEFIBootOrder(srvCli *ssh.Client) error
|
||||
})
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) AdjustUEFIBootOrder() error {
|
||||
func (b *SBaremetalInstance) AdjustUEFIBootOrder(ctx context.Context) error {
|
||||
_, err := b.sshRunWrapper(
|
||||
func(hostCli *ssh.Client) ([]string, error) {
|
||||
return nil, b.AdjustUEFICurrentBootOrder(hostCli)
|
||||
return nil, b.AdjustUEFICurrentBootOrder(ctx, hostCli)
|
||||
},
|
||||
func(srvCli *ssh.Client) ([]string, error) {
|
||||
return nil, b.adjustServerUEFIBootOrder(srvCli)
|
||||
return nil, b.adjustServerUEFIBootOrder(ctx, srvCli)
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SSHReboot() error {
|
||||
func (b *SBaremetalInstance) SSHReboot(ctx context.Context) error {
|
||||
if !b.HasBMC() {
|
||||
// try adjust uefi boot order before reboot
|
||||
if err := b.AdjustUEFIBootOrder(); err != nil {
|
||||
if err := b.AdjustUEFIBootOrder(ctx); err != nil {
|
||||
return errors.Wrap(err, "Adjust uefi boot order")
|
||||
}
|
||||
}
|
||||
@@ -1771,7 +1787,7 @@ func (b *SBaremetalInstance) GetRedfishCli(ctx context.Context) redfish.IRedfish
|
||||
conf.Username, conf.Password, false)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetIPMILanChannel() int {
|
||||
func (b *SBaremetalInstance) GetIPMILanChannel() uint8 {
|
||||
conf := b.GetIPMIConfig()
|
||||
if conf == nil {
|
||||
return 0
|
||||
@@ -1941,7 +1957,7 @@ func (b *SBaremetalInstance) GetMemGb() string {
|
||||
return strconv.FormatInt(memMb/1024, 10)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedRemove(_ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (b *SBaremetalInstance) DelayedRemove(_ context.Context, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
b.remove()
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1982,10 +1998,10 @@ func (b *SBaremetalInstance) StartBaremetalResetBMCTask(userCred mcclient.TokenC
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) StartBaremetalIpmiProbeTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
|
||||
func (b *SBaremetalInstance) StartBaremetalIpmiProbeTask(ctx context.Context, userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
|
||||
session := b.manager.GetClientSession()
|
||||
data, _ = b.manager.fetchBaremetal(session, b.GetId())
|
||||
if err := b.SaveDesc(data); err != nil {
|
||||
if err := b.SaveDesc(ctx, data); err != nil {
|
||||
return err
|
||||
}
|
||||
b.StartNewTask(tasks.NewBaremetalIpmiProbeTask, userCred, taskId, data)
|
||||
@@ -1997,12 +2013,12 @@ func (b *SBaremetalInstance) StartBaremetalCdromTask(userCred mcclient.TokenCred
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedServerReset(_ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (b *SBaremetalInstance) DelayedServerReset(ctx context.Context, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
err := b.DoPXEBoot()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) StartServerCreateTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
|
||||
func (b *SBaremetalInstance) StartServerCreateTask(ctx context.Context, userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
|
||||
b.serverLock.Lock()
|
||||
defer b.serverLock.Unlock()
|
||||
if b.server != nil {
|
||||
@@ -2018,7 +2034,7 @@ func (b *SBaremetalInstance) StartServerCreateTask(userCred mcclient.TokenCreden
|
||||
}
|
||||
b.server = server
|
||||
b.desc.Set("server_id", jsonutils.NewString(b.server.GetId()))
|
||||
if err := b.AutoSaveDesc(); err != nil {
|
||||
if err := b.AutoSaveDesc(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
b.StartNewTask(tasks.NewBaremetalServerCreateTask, userCred, taskId, data)
|
||||
@@ -2063,15 +2079,22 @@ func (b *SBaremetalInstance) StartServerDestroyTask(userCred mcclient.TokenCrede
|
||||
b.StartNewTask(tasks.NewBaremetalServerDestroyTask, userCred, taskId, data)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedSyncIPMIInfo(data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (b *SBaremetalInstance) DelayedSyncIPMIInfo(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
ipmiCli := b.GetIPMITool()
|
||||
lanChannel := b.GetIPMILanChannel()
|
||||
sysInfo, err := ipmitool.GetSysInfo(ipmiCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "GetSysInfo")
|
||||
}
|
||||
profile, err := profiles.GetProfile(ctx, sysInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
if lanChannel <= 0 {
|
||||
lanChannel = ipmitool.GetDefaultLanChannel(sysInfo)
|
||||
if len(profile.LanChannels) == 0 {
|
||||
return nil, errors.Wrap(errors.ErrInvalidStatus, "baremetal profile not valid lan channel?")
|
||||
}
|
||||
lanChannel = profile.LanChannels[0]
|
||||
}
|
||||
retObj := make(map[string]string)
|
||||
if ipAddr, _ := data.GetString("ip_addr"); ipAddr != "" {
|
||||
@@ -2083,7 +2106,7 @@ func (b *SBaremetalInstance) DelayedSyncIPMIInfo(data jsonutils.JSONObject) (jso
|
||||
retObj["ipmi_ip_addr"] = ipAddr
|
||||
}
|
||||
if passwd, _ := data.GetString("password"); passwd != "" {
|
||||
err = ipmitool.SetLanPasswd(ipmiCli, ipmitool.GetRootId(sysInfo), passwd)
|
||||
err = ipmitool.SetLanPasswd(ipmiCli, profile.RootId, passwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2092,16 +2115,16 @@ func (b *SBaremetalInstance) DelayedSyncIPMIInfo(data jsonutils.JSONObject) (jso
|
||||
return jsonutils.Marshal(retObj), nil
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedSyncDesc(data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (b *SBaremetalInstance) DelayedSyncDesc(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if data == nil {
|
||||
session := b.manager.GetClientSession()
|
||||
data, _ = b.manager.fetchBaremetal(session, b.GetId())
|
||||
}
|
||||
err := b.SaveDesc(data)
|
||||
err := b.SaveDesc(ctx, data)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) DelayedServerStatus(data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (b *SBaremetalInstance) DelayedServerStatus(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
ps, err := b.GetPowerStatus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2112,7 +2135,7 @@ func (b *SBaremetalInstance) DelayedServerStatus(data jsonutils.JSONObject) (jso
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) SendNicInfo(nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool) error {
|
||||
func (b *SBaremetalInstance) SendNicInfo(ctx context.Context, nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(nic.Mac.String()), "mac")
|
||||
params.Add(jsonutils.NewInt(int64(nic.Speed)), "rate")
|
||||
@@ -2149,7 +2172,7 @@ func (b *SBaremetalInstance) SendNicInfo(nic *types.SNicDevInfo, idx int, nicTyp
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.SaveDesc(resp)
|
||||
return b.SaveDesc(ctx, resp)
|
||||
}
|
||||
|
||||
func bindMount(src, dst string) error {
|
||||
|
||||
@@ -15,117 +15,68 @@
|
||||
package profiles
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
baremetalmodules "yunion.io/x/onecloud/pkg/mcclient/modules/compute/baremetal"
|
||||
)
|
||||
|
||||
type IPMIProfile struct {
|
||||
LanChannel []int
|
||||
RootName string
|
||||
RootId int
|
||||
StrongPass bool
|
||||
}
|
||||
|
||||
func DefaultProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1, 2, 8},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
func GetProfile(ctx context.Context, sysinfo *types.SSystemInfo) (*baremetalapi.BaremetalProfileSpec, error) {
|
||||
adminSession := auth.GetAdminSession(ctx, options.Options.Region)
|
||||
specs, err := baremetalmodules.BaremetalProfiles.GetMatchProfiles(adminSession, sysinfo.OemName, sysinfo.Model)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetMatchProfile %s %s", sysinfo.OemName, sysinfo.Model)
|
||||
}
|
||||
}
|
||||
|
||||
func InspurProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{8, 1},
|
||||
RootName: "admin",
|
||||
RootId: 2,
|
||||
if len(specs) > 0 {
|
||||
return &specs[len(specs)-1], nil
|
||||
}
|
||||
return nil, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func LenovoProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1, 8},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
func GetLanChannels(ctx context.Context, sysinfo *types.SSystemInfo) ([]uint8, error) {
|
||||
profile, err := GetProfile(ctx, sysinfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
return profile.LanChannels, nil
|
||||
}
|
||||
|
||||
func HpProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1, 2},
|
||||
RootName: "root",
|
||||
RootId: 1,
|
||||
func GetDefaultLanChannel(ctx context.Context, sysinfo *types.SSystemInfo) (uint8, error) {
|
||||
channels, err := GetLanChannels(ctx, sysinfo)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "GetLanChannels")
|
||||
}
|
||||
}
|
||||
|
||||
func HuaweiProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
if len(channels) > 0 {
|
||||
return channels[0], nil
|
||||
}
|
||||
return 0, errors.ErrNotFound
|
||||
}
|
||||
|
||||
func FoxconnProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
func GetRootId(ctx context.Context, sysinfo *types.SSystemInfo) (int, error) {
|
||||
profile, err := GetProfile(ctx, sysinfo)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
return profile.RootId, nil
|
||||
}
|
||||
|
||||
func QemuProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
LanChannel: []int{8, 1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
func GetRootName(ctx context.Context, sysinfo *types.SSystemInfo) (string, error) {
|
||||
profile, err := GetProfile(ctx, sysinfo)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
return profile.RootName, nil
|
||||
}
|
||||
|
||||
func H3CProfile() IPMIProfile {
|
||||
return IPMIProfile{
|
||||
// LanChannel: []int{8, 1},
|
||||
LanChannel: []int{1},
|
||||
RootName: "root",
|
||||
RootId: 2,
|
||||
StrongPass: true,
|
||||
func IsStrongPass(ctx context.Context, sysinfo *types.SSystemInfo) (bool, error) {
|
||||
profile, err := GetProfile(ctx, sysinfo)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
PROFILES map[string]IPMIProfile = map[string]IPMIProfile{
|
||||
types.OEM_NAME_INSPUR: InspurProfile(),
|
||||
types.OEM_NAME_LENOVO: LenovoProfile(),
|
||||
types.OEM_NAME_HP: HpProfile(),
|
||||
types.OEM_NAME_HUAWEI: HuaweiProfile(),
|
||||
types.OEM_NAME_FOXCONN: FoxconnProfile(),
|
||||
types.OEM_NAME_QEMU: QemuProfile(),
|
||||
types.OEM_NAME_H3C: H3CProfile(),
|
||||
}
|
||||
)
|
||||
|
||||
func GetProfile(sysinfo *types.SSystemInfo) IPMIProfile {
|
||||
profile, ok := PROFILES[sysinfo.OemName]
|
||||
if ok {
|
||||
return profile
|
||||
}
|
||||
return DefaultProfile()
|
||||
}
|
||||
|
||||
func GetLanChannel(sysinfo *types.SSystemInfo) []int {
|
||||
return GetProfile(sysinfo).LanChannel
|
||||
}
|
||||
|
||||
func GetRootId(sysinfo *types.SSystemInfo) int {
|
||||
return GetProfile(sysinfo).RootId
|
||||
}
|
||||
|
||||
func GetRootName(sysinfo *types.SSystemInfo) string {
|
||||
return GetProfile(sysinfo).RootName
|
||||
}
|
||||
|
||||
func IsStrongPass(sysinfo *types.SSystemInfo) bool {
|
||||
return GetProfile(sysinfo).StrongPass
|
||||
return profile.StrongPass, nil
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -69,7 +70,7 @@ type dhcpRequest struct {
|
||||
netConfig *types.SNetworkConfig
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) ServeDHCP(pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interface) (dhcp.Packet, []string, error) {
|
||||
func (h *DHCPHandler) ServeDHCP(ctx context.Context, pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interface) (dhcp.Packet, []string, error) {
|
||||
req, err := h.newRequest(pkt, h.baremetalManager)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] new request by packet error: %v", err)
|
||||
@@ -81,7 +82,7 @@ func (h *DHCPHandler) ServeDHCP(pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interfac
|
||||
return nil, nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", req.ClientMac)
|
||||
}
|
||||
log.Infof("[DHCP] from relay %s packet, mac: %s", req.RelayAddr, req.ClientMac)
|
||||
conf, targets, err := req.fetchConfig(h.baremetalManager.GetClientSession())
|
||||
conf, targets, err := req.fetchConfig(ctx, h.baremetalManager.GetClientSession())
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "fetchConfig for %s", req.ClientMac.String())
|
||||
}
|
||||
@@ -185,7 +186,7 @@ func formatUuidString(uuidBytes []byte) string {
|
||||
}, "-")
|
||||
}
|
||||
|
||||
func (req *dhcpRequest) fetchConfig(session *mcclient.ClientSession) (*dhcp.ResponseConfig, []string, error) {
|
||||
func (req *dhcpRequest) fetchConfig(ctx context.Context, session *mcclient.ClientSession) (*dhcp.ResponseConfig, []string, error) {
|
||||
// 1. find_network_conf
|
||||
netConf, err := req.findNetworkConf(session, false)
|
||||
if err != nil {
|
||||
@@ -209,7 +210,7 @@ func (req *dhcpRequest) fetchConfig(session *mcclient.ClientSession) (*dhcp.Resp
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "createOrUpdateBaremetal for %s", req.ClientMac.String())
|
||||
}
|
||||
err = req.doInitBaremetalAdminNetif(bmDesc)
|
||||
err = req.doInitBaremetalAdminNetif(ctx, bmDesc)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "doInitBaremetalAdminNetif for %s", req.ClientMac.String())
|
||||
}
|
||||
@@ -241,13 +242,13 @@ func (req *dhcpRequest) fetchConfig(session *mcclient.ClientSession) (*dhcp.Resp
|
||||
req.baremetalInstance = bmInstance
|
||||
ipmiNic := req.baremetalInstance.GetIPMINic(req.ClientMac)
|
||||
if ipmiNic != nil && ipmiNic.Mac == req.ClientMac.String() {
|
||||
err = req.baremetalInstance.InitAdminNetif(
|
||||
err = req.baremetalInstance.InitAdminNetif(ctx,
|
||||
req.ClientMac, req.netConfig.WireId, api.NIC_TYPE_IPMI, api.NETWORK_TYPE_IPMI, false, "")
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "InitAdminNetif for %s", req.ClientMac.String())
|
||||
}
|
||||
} else {
|
||||
err = req.baremetalInstance.RegisterNetif(req.ClientMac, req.netConfig.WireId)
|
||||
err = req.baremetalInstance.RegisterNetif(ctx, req.ClientMac, req.netConfig.WireId)
|
||||
if err != nil {
|
||||
log.Errorf("RegisterNetif %s error: %v", req.ClientMac.String(), err)
|
||||
return nil, nil, errors.Wrapf(err, "RegisterNetif for %s", req.ClientMac.String())
|
||||
@@ -424,13 +425,13 @@ func (req *dhcpRequest) updateBaremetal(session *mcclient.ClientSession, id stri
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
func (req *dhcpRequest) doInitBaremetalAdminNetif(desc jsonutils.JSONObject) error {
|
||||
func (req *dhcpRequest) doInitBaremetalAdminNetif(ctx context.Context, desc jsonutils.JSONObject) error {
|
||||
var err error
|
||||
req.baremetalInstance, err = req.baremetalManager.AddBaremetal(desc)
|
||||
req.baremetalInstance, err = req.baremetalManager.AddBaremetal(ctx, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = req.baremetalInstance.InitAdminNetif(
|
||||
err = req.baremetalInstance.InitAdminNetif(ctx,
|
||||
req.ClientMac, req.netConfig.WireId, api.NIC_TYPE_ADMIN, api.NETWORK_TYPE_PXE, false, "")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package pxe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
@@ -85,7 +86,7 @@ const (
|
||||
type IBaremetalManager interface {
|
||||
GetZoneId() string
|
||||
GetBaremetalByMac(mac net.HardwareAddr) IBaremetalInstance
|
||||
AddBaremetal(desc jsonutils.JSONObject) (IBaremetalInstance, error)
|
||||
AddBaremetal(ctx context.Context, desc jsonutils.JSONObject) (IBaremetalInstance, error)
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
}
|
||||
|
||||
@@ -94,8 +95,8 @@ type IBaremetalInstance interface {
|
||||
GetIPMINic(cliMac net.HardwareAddr) *types.SNic
|
||||
GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error)
|
||||
GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error)
|
||||
InitAdminNetif(cliMac net.HardwareAddr, wireId string, nicType compute.TNicType, netType computeapi.TNetworkType, isDoImport bool, ipAddr string) error
|
||||
RegisterNetif(cliMac net.HardwareAddr, wireId string) error
|
||||
InitAdminNetif(ctx context.Context, cliMac net.HardwareAddr, wireId string, nicType compute.TNicType, netType computeapi.TNetworkType, isDoImport bool, ipAddr string) error
|
||||
RegisterNetif(ctx context.Context, cliMac net.HardwareAddr, wireId string) error
|
||||
GetTFTPResponse() string
|
||||
}
|
||||
|
||||
|
||||
@@ -342,8 +342,8 @@ func (self *SBaremetalTaskBase) EnsurePowerUp() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalTaskBase) EnsureSSHReboot() error {
|
||||
if err := self.Baremetal.SSHReboot(); err != nil {
|
||||
func (self *SBaremetalTaskBase) EnsureSSHReboot(ctx context.Context) error {
|
||||
if err := self.Baremetal.SSHReboot(ctx); err != nil {
|
||||
return errors.Wrap(err, "Ensure ssh reboot")
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ func (self *SBaremetalPXEBootTaskBase) InitPXEBootTask(ctx context.Context, args
|
||||
|
||||
if !self.Baremetal.HasBMC() {
|
||||
// Try remote ssh reboot
|
||||
if err := self.Baremetal.SSHReboot(); err != nil {
|
||||
if err := self.Baremetal.SSHReboot(ctx); err != nil {
|
||||
return errors.Wrap(err, "Try ssh reboot")
|
||||
}
|
||||
} else {
|
||||
@@ -491,6 +491,6 @@ func (self *SBaremetalPXEBootTaskBase) GetName() string {
|
||||
return "BaremetalPXEBootTaskBase"
|
||||
}
|
||||
|
||||
func AdjustUEFIBootOrder(term *ssh.Client, bm IBaremetal) error {
|
||||
return bm.AdjustUEFICurrentBootOrder(term)
|
||||
func AdjustUEFIBootOrder(ctx context.Context, term *ssh.Client, bm IBaremetal) error {
|
||||
return bm.AdjustUEFICurrentBootOrder(ctx, term)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term
|
||||
return errors.Wrap(err, "Do deploy")
|
||||
}
|
||||
|
||||
if err := AdjustUEFIBootOrder(term, self.Baremetal); err != nil {
|
||||
if err := AdjustUEFIBootOrder(ctx, term, self.Baremetal); err != nil {
|
||||
return errors.Wrap(err, "Adjust UEFI boot order")
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term
|
||||
return errors.Wrap(err, "Ensure power up")
|
||||
}
|
||||
}
|
||||
self.Baremetal.AutoSyncAllStatus()
|
||||
self.Baremetal.AutoSyncAllStatus(ctx)
|
||||
} else {
|
||||
if onFinishAction == "shutdown" {
|
||||
log.Infof("None BMC baremetal can't shutdown when deploying")
|
||||
@@ -147,12 +147,12 @@ func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term
|
||||
// do restart
|
||||
// hack: ssh reboot to disk
|
||||
self.needPXEBoot = false
|
||||
if err := self.EnsureSSHReboot(); err != nil {
|
||||
if err := self.EnsureSSHReboot(ctx); err != nil {
|
||||
return errors.Wrap(err, "Try ssh reboot")
|
||||
}
|
||||
}
|
||||
}
|
||||
self.Baremetal.SyncAllStatus(types.POWER_STATUS_ON)
|
||||
self.Baremetal.SyncAllStatus(ctx, types.POWER_STATUS_ON)
|
||||
}
|
||||
SetTaskComplete(self, result)
|
||||
return nil
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
|
||||
@@ -169,7 +171,7 @@ func (task *sBaremetalPrepareTask) prepareBaremetalInfo(cli *ssh.Client) (*barem
|
||||
return prepareInfo, nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremetalPrepareInfo) error {
|
||||
func (task *sBaremetalPrepareTask) configIPMISetting(ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo) error {
|
||||
if !i.ipmiInfo.Present {
|
||||
return nil
|
||||
}
|
||||
@@ -185,12 +187,16 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
)
|
||||
sshIPMI := ipmitool.NewSSHIPMI(cli)
|
||||
setIPMILanPortShared(sshIPMI, sysInfo)
|
||||
ipmiUser, ipmiPasswd, ipmiIpAddr := task.getIPMIUserPasswd(i.ipmiInfo, sysInfo)
|
||||
profile, err := profiles.GetProfile(ctx, sysInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
ipmiUser, ipmiPasswd, ipmiIpAddr := task.getIPMIUserPasswd(i.ipmiInfo, profile)
|
||||
ipmiInfo.Username = ipmiUser
|
||||
ipmiInfo.Password = ipmiPasswd
|
||||
|
||||
var ipmiLanChannel int = -1
|
||||
for _, lanChannel := range ipmitool.GetLanChannels(sysInfo) {
|
||||
var ipmiLanChannel uint8 = 0
|
||||
for _, lanChannel := range profile.LanChannels {
|
||||
log.Infof("Try lan channel %d ...", lanChannel)
|
||||
conf, err := ipmitool.GetLanConfig(sshIPMI, lanChannel)
|
||||
if err != nil {
|
||||
@@ -207,11 +213,11 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
Speed: 100,
|
||||
Mtu: 1500,
|
||||
}
|
||||
if err := task.sendNicInfo(ipmiNic, -1, api.NIC_TYPE_IPMI, true, "", false); err != nil {
|
||||
if err := task.sendNicInfo(ctx, ipmiNic, -1, api.NIC_TYPE_IPMI, true, "", false); err != nil {
|
||||
// ignore the error
|
||||
log.Errorf("Send IPMI nic %#v info: %v", ipmiNic, err)
|
||||
}
|
||||
rootId := ipmitool.GetRootId(sysInfo)
|
||||
rootId := profile.RootId
|
||||
err = ipmitool.CreateOrSetAdminUser(sshIPMI, lanChannel, rootId, ipmiUser, ipmiPasswd)
|
||||
if err != nil {
|
||||
// ignore the error
|
||||
@@ -232,7 +238,7 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
}
|
||||
if len(tryAddrs) > 0 && !o.Options.ForceDhcpProbeIpmi {
|
||||
for _, tryAddr := range tryAddrs {
|
||||
tryResult := task.tryLocalIpmiAddr(sshIPMI, ipmiNic, lanChannel,
|
||||
tryResult := task.tryLocalIpmiAddr(ctx, sshIPMI, ipmiNic, lanChannel,
|
||||
ipmiUser, ipmiPasswd, tryAddr)
|
||||
if tryResult {
|
||||
ipmiInfo.IpAddr = tryAddr
|
||||
@@ -240,7 +246,7 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
break
|
||||
}
|
||||
}
|
||||
if ipmiLanChannel >= 0 {
|
||||
if ipmiLanChannel > 0 {
|
||||
// found and set config on lanChannel
|
||||
break
|
||||
}
|
||||
@@ -309,7 +315,7 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
ipmiInfo.IpAddr = nic.IpAddr
|
||||
ipmiLanChannel = lanChannel
|
||||
}
|
||||
if ipmiLanChannel == -1 {
|
||||
if ipmiLanChannel == 0 {
|
||||
return fmt.Errorf("Fail to get IPMI address from DHCP")
|
||||
}
|
||||
ipmiInfo.LanChannel = ipmiLanChannel
|
||||
@@ -317,7 +323,7 @@ func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremet
|
||||
return nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
func (task *sBaremetalPrepareTask) DoPrepare(ctx context.Context, cli *ssh.Client) error {
|
||||
infos, err := task.prepareBaremetalInfo(cli)
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
|
||||
@@ -325,12 +331,12 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
}
|
||||
|
||||
// set ipmi nic address and user password
|
||||
if err = task.configIPMISetting(cli, infos); err != nil {
|
||||
if err = task.configIPMISetting(ctx, cli, infos); err != nil {
|
||||
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
|
||||
return errors.Wrap(err, "Config IPMI setting")
|
||||
}
|
||||
|
||||
if err = task.updateBmInfo(cli, infos); err != nil {
|
||||
if err = task.updateBmInfo(ctx, cli, infos); err != nil {
|
||||
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
|
||||
return err
|
||||
}
|
||||
@@ -341,7 +347,7 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
log.Errorf("SetNTP fail: %s", err)
|
||||
}
|
||||
|
||||
if err = AdjustUEFIBootOrder(cli, task.baremetal); err != nil {
|
||||
if err = AdjustUEFIBootOrder(ctx, cli, task.baremetal); err != nil {
|
||||
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
|
||||
return errors.Wrap(err, "Adjust UEFI boot order")
|
||||
}
|
||||
@@ -375,7 +381,7 @@ func (task *sBaremetalPrepareTask) findAdminNic(cli *ssh.Client, nicsInfo []*typ
|
||||
return -1, nil, errors.Error("admin nic not found???")
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPrepareInfo) error {
|
||||
func (task *sBaremetalPrepareTask) updateBmInfo(ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo) error {
|
||||
adminNic := task.baremetal.GetAdminNic()
|
||||
if adminNic == nil || (adminNic != nil && !adminNic.LinkUp) {
|
||||
adminIdx, adminNicDev, err := task.findAdminNic(cli, i.nicsInfo)
|
||||
@@ -383,7 +389,7 @@ func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPre
|
||||
return errors.Wrap(err, "task.findAdminNic")
|
||||
}
|
||||
accessIp := cli.GetConfig().Host
|
||||
err = task.sendNicInfo(adminNicDev, adminIdx, api.NIC_TYPE_ADMIN, false, accessIp, true)
|
||||
err = task.sendNicInfo(ctx, adminNicDev, adminIdx, api.NIC_TYPE_ADMIN, false, accessIp, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "send Admin Nic Info")
|
||||
}
|
||||
@@ -445,14 +451,14 @@ func (task *sBaremetalPrepareTask) updateBmInfo(cli *ssh.Client, i *baremetalPre
|
||||
// }
|
||||
removedMacs := task.removeObsoleteNics(i)
|
||||
for idx := range removedMacs {
|
||||
err = task.removeNicInfo(removedMacs[idx])
|
||||
err = task.removeNicInfo(ctx, removedMacs[idx])
|
||||
if err != nil {
|
||||
log.Errorf("Fail to remove Netif %s: %s", removedMacs[idx], err)
|
||||
return errors.Wrap(err, "task.removeNicInfo")
|
||||
}
|
||||
}
|
||||
for idx := range i.nicsInfo {
|
||||
err = task.sendNicInfo(i.nicsInfo[idx], idx, "", false, "", false)
|
||||
err = task.sendNicInfo(ctx, i.nicsInfo[idx], idx, "", false, "", false)
|
||||
if err != nil {
|
||||
log.Errorf("Send nicinfo idx: %d, %#v error: %v", idx, i.nicsInfo[idx], err)
|
||||
return errors.Wrap(err, "task.sendNicInfo")
|
||||
@@ -494,7 +500,7 @@ func (task *sBaremetalPrepareTask) removeObsoleteNics(i *baremetalPrepareInfo) [
|
||||
return removes
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) tryLocalIpmiAddr(sshIPMI *ipmitool.SSHIPMI, ipmiNic *types.SNicDevInfo, lanChannel int, ipmiUser, ipmiPasswd, tryAddr string) bool {
|
||||
func (task *sBaremetalPrepareTask) tryLocalIpmiAddr(ctx context.Context, sshIPMI *ipmitool.SSHIPMI, ipmiNic *types.SNicDevInfo, lanChannel uint8, ipmiUser, ipmiPasswd, tryAddr string) bool {
|
||||
log.Infof("IP addr found in IPMI config, try use %s as IPMI address", tryAddr)
|
||||
ipConf, err := task.getIPMIIPConfig(tryAddr)
|
||||
if err != nil {
|
||||
@@ -548,7 +554,7 @@ func (task *sBaremetalPrepareTask) tryLocalIpmiAddr(sshIPMI *ipmitool.SSHIPMI, i
|
||||
if tried < maxTries {
|
||||
// make sure the ipaddr is a IPMI address
|
||||
// enable the netif
|
||||
err := task.sendNicInfo(ipmiNic, -1, api.NIC_TYPE_IPMI, false, tryAddr, true)
|
||||
err := task.sendNicInfo(ctx, ipmiNic, -1, api.NIC_TYPE_IPMI, false, tryAddr, true)
|
||||
if err != nil {
|
||||
log.Errorf("Fail to set existing BMC IP address to %s", tryAddr)
|
||||
} else {
|
||||
@@ -558,14 +564,14 @@ func (task *sBaremetalPrepareTask) tryLocalIpmiAddr(sshIPMI *ipmitool.SSHIPMI, i
|
||||
return false
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) getIPMIUserPasswd(oldIPMIConf *types.SIPMIInfo, sysInfo *types.SSystemInfo) (string, string, string) {
|
||||
func (task *sBaremetalPrepareTask) getIPMIUserPasswd(oldIPMIConf *types.SIPMIInfo, profile *baremetalapi.BaremetalProfileSpec) (string, string, string) {
|
||||
var (
|
||||
ipmiUser string
|
||||
ipmiPasswd string
|
||||
ipmiIpAddr string
|
||||
)
|
||||
ipmiUser = profiles.GetRootName(sysInfo)
|
||||
isStrongPass := profiles.IsStrongPass(sysInfo)
|
||||
ipmiUser = profile.RootName
|
||||
isStrongPass := profile.StrongPass
|
||||
if !isStrongPass && o.Options.DefaultIpmiPassword != "" {
|
||||
ipmiPasswd = o.Options.DefaultIpmiPassword
|
||||
} else if isStrongPass && o.Options.DefaultStrongIpmiPassword != "" {
|
||||
@@ -785,7 +791,7 @@ func isIPMIEnable(cli *ssh.Client) (bool, error) {
|
||||
return sysutils.ParseDMIIPMIInfo(ret), nil
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) removeNicInfo(mac string) error {
|
||||
func (task *sBaremetalPrepareTask) removeNicInfo(ctx context.Context, mac string) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(mac), "mac")
|
||||
resp, err := modules.Hosts.PerformAction(
|
||||
@@ -797,13 +803,13 @@ func (task *sBaremetalPrepareTask) removeNicInfo(mac string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.baremetal.SaveDesc(resp)
|
||||
return task.baremetal.SaveDesc(ctx, resp)
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) sendNicInfo(
|
||||
func (task *sBaremetalPrepareTask) sendNicInfo(ctx context.Context,
|
||||
nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool,
|
||||
) error {
|
||||
return task.baremetal.SendNicInfo(nic, idx, nicType, reset, ipAddr, reserve)
|
||||
return task.baremetal.SendNicInfo(ctx, nic, idx, nicType, reset, ipAddr, reserve)
|
||||
}
|
||||
|
||||
func (task *sBaremetalPrepareTask) sendStorageInfo(size int64) error {
|
||||
|
||||
@@ -22,9 +22,11 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -49,7 +51,7 @@ type sBaremetalRegisterTask struct {
|
||||
IpmiIpAddr string
|
||||
IpmiMac net.HardwareAddr
|
||||
|
||||
IpmiLanChannel int
|
||||
IpmiLanChannel uint8
|
||||
|
||||
AdminWire string
|
||||
IpmiWire string
|
||||
@@ -60,7 +62,7 @@ type sBaremetalRegisterTask struct {
|
||||
func NewBaremetalRegisterTask(
|
||||
userCred mcclient.TokenCredential, bmManager IBmManager, sshCli *ssh.Client,
|
||||
hostname, remoteIp, ipmiUsername, ipmiPassword, ipmiIpAddr string,
|
||||
ipmiMac net.HardwareAddr, ipmiLanChannel int, adminWire, ipmiWire string) *sBaremetalRegisterTask {
|
||||
ipmiMac net.HardwareAddr, ipmiLanChannel uint8, adminWire, ipmiWire string) *sBaremetalRegisterTask {
|
||||
return &sBaremetalRegisterTask{
|
||||
sBaremetalPrepareTask: sBaremetalPrepareTask{userCred: userCred},
|
||||
BmManager: bmManager,
|
||||
@@ -112,7 +114,7 @@ func (s *sBaremetalRegisterTask) getAccessDevMacAddr(ip string) (string, error)
|
||||
return segs[1], nil
|
||||
}
|
||||
|
||||
func (s *sBaremetalRegisterTask) CreateBaremetal() (string, error) {
|
||||
func (s *sBaremetalRegisterTask) CreateBaremetal(ctx context.Context) (string, error) {
|
||||
zoneId := s.BmManager.GetZoneId()
|
||||
ret, err := s.SshCli.Run("/lib/mos/lsnic")
|
||||
if err != nil {
|
||||
@@ -148,24 +150,24 @@ func (s *sBaremetalRegisterTask) CreateBaremetal() (string, error) {
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Create baremetal failed: %s", err)
|
||||
}
|
||||
pxeBm, err := s.BmManager.AddBaremetal(res)
|
||||
pxeBm, err := s.BmManager.AddBaremetal(ctx, res)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("BmManager add baremetal failed: %s", err)
|
||||
}
|
||||
|
||||
err = pxeBm.InitAdminNetif(
|
||||
err = pxeBm.InitAdminNetif(ctx,
|
||||
s.accessNic.Mac, s.AdminWire, api.NIC_TYPE_ADMIN, api.NETWORK_TYPE_PXE, true, s.RemoteIp)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("BmManager add admin netif failed: %s", err)
|
||||
}
|
||||
err = pxeBm.InitAdminNetif(
|
||||
err = pxeBm.InitAdminNetif(ctx,
|
||||
s.IpmiMac, s.IpmiWire, api.NIC_TYPE_IPMI, api.NETWORK_TYPE_IPMI, true, s.IpmiIpAddr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("BmManager add ipmi netif failed: %s", err)
|
||||
}
|
||||
for _, nic := range nicinfo {
|
||||
if nic.Dev != s.accessNic.Dev {
|
||||
pxeBm.RegisterNetif(nic.Mac, s.AdminWire)
|
||||
pxeBm.RegisterNetif(ctx, nic.Mac, s.AdminWire)
|
||||
}
|
||||
}
|
||||
s.baremetal = pxeBm.(IBaremetal)
|
||||
@@ -173,14 +175,14 @@ func (s *sBaremetalRegisterTask) CreateBaremetal() (string, error) {
|
||||
return bmInstanceId, nil
|
||||
}
|
||||
|
||||
func (s *sBaremetalRegisterTask) UpdateBaremetal() (string, error) {
|
||||
func (s *sBaremetalRegisterTask) UpdateBaremetal(ctx context.Context) (string, error) {
|
||||
accessMac, err := s.getAccessDevMacAddr(s.RemoteIp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "getAccessDevMacAddr")
|
||||
}
|
||||
accessMacAddr, err := net.ParseMAC(accessMac)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed parse access mac %s", accessMac)
|
||||
return "", errors.Wrapf(err, "Failed parse access mac %s", accessMac)
|
||||
}
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
@@ -188,14 +190,14 @@ func (s *sBaremetalRegisterTask) UpdateBaremetal() (string, error) {
|
||||
params.Set("scope", jsonutils.NewString("system"))
|
||||
res, err := modules.Hosts.List(s.BmManager.GetClientSession(), params)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Fetch baremetal failed %s", err)
|
||||
return "", errors.Wrap(err, "Fetch baremetal failed")
|
||||
}
|
||||
if len(res.Data) == 0 {
|
||||
return "", fmt.Errorf("Cann't find baremetal by access mac %s", accessMacAddr)
|
||||
return "", errors.Wrapf(errors.ErrNotFound, "Cann't find baremetal by access mac %s", accessMacAddr)
|
||||
}
|
||||
pxeBm, err := s.BmManager.AddBaremetal(res.Data[0])
|
||||
pxeBm, err := s.BmManager.AddBaremetal(ctx, res.Data[0])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("BmManager add baremetal failed: %s", err)
|
||||
return "", errors.Wrap(err, "BmManager add baremetal failed")
|
||||
}
|
||||
|
||||
s.baremetal = pxeBm.(IBaremetal)
|
||||
@@ -229,12 +231,12 @@ func (s *sBaremetalRegisterTask) DoPrepare(ctx context.Context, cli *ssh.Client,
|
||||
infos.ipmiInfo.RedfishApi = redfishSupport
|
||||
infos.ipmiInfo.CdromBoot = cdromSupport
|
||||
|
||||
s.updateIpmiInfo(cli)
|
||||
s.updateIpmiInfo(ctx, cli)
|
||||
|
||||
return s.updateBmInfo(cli, infos, registered)
|
||||
return s.updateBmInfo(ctx, cli, infos, registered)
|
||||
}
|
||||
|
||||
func (s *sBaremetalRegisterTask) updateIpmiInfo(cli *ssh.Client) {
|
||||
func (s *sBaremetalRegisterTask) updateIpmiInfo(ctx context.Context, cli *ssh.Client) {
|
||||
ipmiTool := ipmitool.NewSSHIPMI(cli)
|
||||
sysInfo, err := ipmitool.GetSysInfo(ipmiTool)
|
||||
if err == nil && o.Options.IpmiLanPortShared {
|
||||
@@ -253,21 +255,25 @@ func (s *sBaremetalRegisterTask) updateIpmiInfo(cli *ssh.Client) {
|
||||
}
|
||||
|
||||
var conf *types.SIPMILanConfig
|
||||
for _, lanChannel := range ipmitool.GetLanChannels(sysInfo) {
|
||||
conf, _ = ipmitool.GetLanConfig(ipmiTool, lanChannel)
|
||||
if conf == nil || len(conf.Mac) == 0 {
|
||||
continue
|
||||
profile, err := profiles.GetProfile(ctx, sysInfo)
|
||||
if profile != nil {
|
||||
for _, lanChannel := range profile.LanChannels {
|
||||
conf, _ = ipmitool.GetLanConfig(ipmiTool, lanChannel)
|
||||
if conf == nil || len(conf.Mac) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if conf == nil || len(conf.Mac) == 0 {
|
||||
log.Errorln("Fail to get IPMI lan config !!!")
|
||||
} else {
|
||||
nic.Mac = conf.Mac
|
||||
}
|
||||
s.sendNicInfo(nic, -1, api.NIC_TYPE_IPMI, false, "", false)
|
||||
s.sendNicInfo(ctx, nic, -1, api.NIC_TYPE_IPMI, false, "", false)
|
||||
}
|
||||
|
||||
func (s *sBaremetalRegisterTask) updateBmInfo(cli *ssh.Client, i *baremetalPrepareInfo, registered bool) error {
|
||||
func (s *sBaremetalRegisterTask) updateBmInfo(ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo, registered bool) error {
|
||||
updateInfo := make(map[string]interface{})
|
||||
updateInfo["access_ip"] = s.RemoteIp
|
||||
updateInfo["cpu_count"] = i.cpuInfo.Count
|
||||
@@ -293,7 +299,7 @@ func (s *sBaremetalRegisterTask) updateBmInfo(cli *ssh.Client, i *baremetalPrepa
|
||||
log.Errorf("sendStorageInfo error: %v", err)
|
||||
}
|
||||
for idx := range i.nicsInfo {
|
||||
err = s.sendNicInfo(i.nicsInfo[idx], idx, "", false, "", false)
|
||||
err = s.sendNicInfo(ctx, i.nicsInfo[idx], idx, "", false, "", false)
|
||||
if err != nil {
|
||||
log.Errorf("Send nicinfo idx: %d, %#v error: %v", idx, i.nicsInfo[idx], err)
|
||||
}
|
||||
@@ -301,20 +307,20 @@ func (s *sBaremetalRegisterTask) updateBmInfo(cli *ssh.Client, i *baremetalPrepa
|
||||
if registered {
|
||||
return nil
|
||||
}
|
||||
return s.initBaremetalServer()
|
||||
return s.initBaremetalServer(ctx)
|
||||
}
|
||||
|
||||
func (s *sBaremetalRegisterTask) initBaremetalServer() error {
|
||||
func (s *sBaremetalRegisterTask) initBaremetalServer(ctx context.Context) error {
|
||||
if err := s.baremetal.InitializeServer(s.getSession(), s.Hostname); err != nil {
|
||||
return fmt.Errorf("Baremteal Create Server Failed %s", err)
|
||||
}
|
||||
// if err := s.baremetal.SaveSSHConfig("", ""); err != nil {
|
||||
// log.Errorf("Save ssh config failed %s", err)
|
||||
// }
|
||||
if err := s.baremetal.ServerLoadDesc(); err != nil {
|
||||
if err := s.baremetal.ServerLoadDesc(ctx); err != nil {
|
||||
log.Errorf("Server load desc failed %s", err)
|
||||
}
|
||||
s.baremetal.SyncStatus("running", "Register success")
|
||||
s.baremetal.SyncStatus(ctx, "running", "Register success")
|
||||
log.Infof("%s Load baremetal info success ...", s.baremetal.GetId())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func (self *SBaremetalCdromTask) DoInsertISO(ctx context.Context, args interface
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "MountVirtualCdrom")
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (self *SBaremetalCdromTask) DoEjectISO(ctx context.Context, args interface{
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "UmountVirtualCdrom")
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -50,32 +51,32 @@ func (self *SBaremetalServerCreateTask) RemoveEFIOSEntry() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerCreateTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
func (self *SBaremetalServerCreateTask) DoDeploys(ctx context.Context, term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
// Build raid
|
||||
tool, err := self.Baremetal.GetServer().DoDiskConfig(term)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
return nil, self.onError(ctx, term, err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
if err := self.Baremetal.GetServer().DoEraseDisk(term); err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
return nil, self.onError(ctx, term, err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
parts, err := self.Baremetal.GetServer().DoPartitionDisk(tool, term, self.IsDisableImageCache())
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
return nil, self.onError(ctx, term, err)
|
||||
}
|
||||
data := jsonutils.NewDict()
|
||||
disks, err := self.Baremetal.GetServer().SyncPartitionSize(term, parts)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
return nil, self.onError(ctx, term, err)
|
||||
}
|
||||
data.Add(jsonutils.Marshal(disks), "disks")
|
||||
rootImageId := self.Baremetal.GetServer().GetRootTemplateId()
|
||||
if len(rootImageId) > 0 {
|
||||
deployInfo, err := self.Baremetal.GetServer().DoDeploy(tool, term, self.data, true)
|
||||
if err != nil {
|
||||
return nil, self.onError(term, err)
|
||||
return nil, self.onError(ctx, term, err)
|
||||
}
|
||||
if deployInfo != nil {
|
||||
data.Update(deployInfo)
|
||||
@@ -100,11 +101,11 @@ func (self *SBaremetalServerCreateTask) PostDeploys(term *ssh.Client) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerCreateTask) onError(term *ssh.Client, err error) error {
|
||||
func (self *SBaremetalServerCreateTask) onError(ctx context.Context, term *ssh.Client, err error) error {
|
||||
log.Errorf("Create server error: %+v", err)
|
||||
if err1 := self.Baremetal.GetServer().DoEraseDisk(term); err1 != nil {
|
||||
log.Warningf("EraseDisk error: %v", err1)
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
@@ -39,7 +40,7 @@ type IBaremetal interface {
|
||||
GetAdminNic() *types.SNic
|
||||
GetName() string
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
SaveDesc(desc jsonutils.JSONObject) error
|
||||
SaveDesc(ctx context.Context, desc jsonutils.JSONObject) error
|
||||
GetNics() []types.SNic
|
||||
GetNicByMac(net.HardwareAddr) *types.SNic
|
||||
GetRawIPMIConfig() *types.SIPMIInfo
|
||||
@@ -47,10 +48,10 @@ type IBaremetal interface {
|
||||
SetExistingIPMIIPAddr(ipAddr string)
|
||||
GetServer() baremetaltypes.IBaremetalServer
|
||||
|
||||
SyncStatus(status, reason string)
|
||||
AutoSyncStatus()
|
||||
SyncAllStatus(status string)
|
||||
AutoSyncAllStatus()
|
||||
SyncStatus(ctx context.Context, status, reason string)
|
||||
AutoSyncStatus(ctx context.Context)
|
||||
SyncAllStatus(ctx context.Context, status string)
|
||||
AutoSyncAllStatus(ctx context.Context)
|
||||
|
||||
GetPowerStatus() (string, error)
|
||||
DoPowerShutdown(soft bool) error
|
||||
@@ -61,25 +62,25 @@ type IBaremetal interface {
|
||||
GetAccessIp() string
|
||||
EnablePxeBoot() bool
|
||||
GenerateBootISO() error
|
||||
SendNicInfo(nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool) error
|
||||
SendNicInfo(ctx context.Context, nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool) error
|
||||
DoNTPConfig() error
|
||||
GetImageUrl(needImageCache bool) string
|
||||
|
||||
RemoveServer()
|
||||
InitializeServer(session *mcclient.ClientSession, name string) error
|
||||
SaveSSHConfig(remoteAddr string, key string) error
|
||||
ServerLoadDesc() error
|
||||
ServerLoadDesc(ctx context.Context) error
|
||||
GetDHCPServerIP() (net.IP, error)
|
||||
|
||||
HasBMC() bool
|
||||
SSHReachable() (bool, error)
|
||||
SSHReboot() error
|
||||
SSHReboot(ctx context.Context) error
|
||||
SSHShutdown() error
|
||||
AdjustUEFICurrentBootOrder(cli *ssh.Client) error
|
||||
AdjustUEFICurrentBootOrder(ctx context.Context, cli *ssh.Client) error
|
||||
}
|
||||
|
||||
type IBmManager interface {
|
||||
GetZoneId() string
|
||||
AddBaremetal(jsonutils.JSONObject) (pxe.IBaremetalInstance, error)
|
||||
AddBaremetal(context.Context, jsonutils.JSONObject) (pxe.IBaremetalInstance, error)
|
||||
GetClientSession() *mcclient.ClientSession
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -97,7 +99,7 @@ func (self *SBaremetalIpmiProbeTask) doRedfishIpmiProbe(ctx context.Context, drv
|
||||
if len(confs) == 0 {
|
||||
return false, errors.Wrap(httperrors.ErrNotFound, "no IPMI lan")
|
||||
}
|
||||
err = self.sendIpmiNicInfo(&confs[0])
|
||||
err = self.sendIpmiNicInfo(ctx, &confs[0])
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "self.sendIpmiNicInfo")
|
||||
}
|
||||
@@ -143,18 +145,18 @@ func (self *SBaremetalIpmiProbeTask) doRedfishIpmiProbe(ctx context.Context, drv
|
||||
for i := range sysInfo.EthernetNICs {
|
||||
mac, err := net.ParseMAC(sysInfo.EthernetNICs[i])
|
||||
if err == nil {
|
||||
err = self.sendNicInfo(i, mac)
|
||||
err = self.sendNicInfo(ctx, i, mac)
|
||||
if err != nil {
|
||||
return true, errors.Wrapf(err, "sendNicInfo %d %s", i, mac)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.Baremetal.SyncStatus("", "Probe Redfish finished")
|
||||
self.Baremetal.SyncStatus(ctx, "", "Probe Redfish finished")
|
||||
SetTaskComplete(self, nil)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalIpmiProbeTask) sendIpmiNicInfo(lanConf *types.SIPMILanConfig) error {
|
||||
func (self *SBaremetalIpmiProbeTask) sendIpmiNicInfo(ctx context.Context, lanConf *types.SIPMILanConfig) error {
|
||||
speed := lanConf.SpeedMbps
|
||||
if speed <= 0 {
|
||||
speed = 100
|
||||
@@ -166,18 +168,18 @@ func (self *SBaremetalIpmiProbeTask) sendIpmiNicInfo(lanConf *types.SIPMILanConf
|
||||
Speed: speed,
|
||||
Mtu: 1500,
|
||||
}
|
||||
err := self.Baremetal.SendNicInfo(ipmiNic, -1, api.NIC_TYPE_IPMI, true, lanConf.IPAddr, true)
|
||||
err := self.Baremetal.SendNicInfo(ctx, ipmiNic, -1, api.NIC_TYPE_IPMI, true, lanConf.IPAddr, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SendNicInfo")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SBaremetalIpmiProbeTask) sendNicInfo(index int, mac net.HardwareAddr) error {
|
||||
func (self *SBaremetalIpmiProbeTask) sendNicInfo(ctx context.Context, index int, mac net.HardwareAddr) error {
|
||||
nicInfo := &types.SNicDevInfo{
|
||||
Mac: mac,
|
||||
}
|
||||
err := self.Baremetal.SendNicInfo(nicInfo, index, "", false, "", false)
|
||||
err := self.Baremetal.SendNicInfo(ctx, nicInfo, index, "", false, "", false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SendNicInfo")
|
||||
}
|
||||
@@ -186,14 +188,20 @@ func (self *SBaremetalIpmiProbeTask) sendNicInfo(index int, mac net.HardwareAddr
|
||||
|
||||
func (self *SBaremetalIpmiProbeTask) doRawIpmiProbe(ctx context.Context, cli ipmitool.IPMIExecutor) error {
|
||||
sysInfo, err := ipmitool.GetSysInfo(cli)
|
||||
var profile *baremetalapi.BaremetalProfileSpec
|
||||
if err != nil {
|
||||
// ignore error for qemu
|
||||
log.Errorf("ipmitool.GetSysInfo error %s", err)
|
||||
} else {
|
||||
profile, err = profiles.GetProfile(ctx, sysInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetProfile")
|
||||
}
|
||||
}
|
||||
guid := ipmitool.GetSysGuid(cli)
|
||||
var conf *types.SIPMILanConfig
|
||||
var channel int
|
||||
for _, lanChannel := range ipmitool.GetLanChannels(sysInfo) {
|
||||
var channel uint8
|
||||
for _, lanChannel := range profile.LanChannels {
|
||||
conf, err = ipmitool.GetLanConfig(cli, lanChannel)
|
||||
if err != nil {
|
||||
// ignore error
|
||||
@@ -206,7 +214,7 @@ func (self *SBaremetalIpmiProbeTask) doRawIpmiProbe(ctx context.Context, cli ipm
|
||||
if conf == nil {
|
||||
return errors.Wrap(httperrors.ErrNotFound, "no IPMI lan")
|
||||
}
|
||||
err = self.sendIpmiNicInfo(conf)
|
||||
err = self.sendIpmiNicInfo(ctx, conf)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "self.sendIpmiNicInfo")
|
||||
}
|
||||
@@ -244,7 +252,7 @@ func (self *SBaremetalIpmiProbeTask) doRawIpmiProbe(ctx context.Context, cli ipm
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "modules.Hosts.Update")
|
||||
}
|
||||
self.Baremetal.SyncStatus("", "Probie IPMI finished")
|
||||
self.Baremetal.SyncStatus(ctx, "", "Probie IPMI finished")
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (self *SBaremetalMaintenanceTask) OnPXEBoot(ctx context.Context, term *ssh.
|
||||
if jsonutils.QueryBoolean(self.data, "guest_running", false) {
|
||||
dataObj["guest_running"] = true
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
SetTaskComplete(self, jsonutils.Marshal(dataObj))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ func (self *SBaremetalServerPrepareTask) GetName() string {
|
||||
|
||||
// OnPXEBootRequest called by notify api handler
|
||||
func (self *SBaremetalServerPrepareTask) OnPXEBootRequest(ctx context.Context, cli *ssh.Client, args interface{}) error {
|
||||
err := newBaremetalPrepareTask(self.Baremetal, self.userCred).DoPrepare(cli)
|
||||
err := newBaremetalPrepareTask(self.Baremetal, self.userCred).DoPrepare(ctx, cli)
|
||||
if err != nil {
|
||||
log.Errorf("Prepare failed: %v", err)
|
||||
self.Baremetal.SyncStatus(status.PREPARE_FAIL, err.Error())
|
||||
self.Baremetal.SyncStatus(ctx, status.PREPARE_FAIL, err.Error())
|
||||
return err
|
||||
}
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -43,13 +45,13 @@ func (self *SBaremetalReprepareTask) GetName() string {
|
||||
return "BaremetalReprepareTask"
|
||||
}
|
||||
|
||||
func (self *SBaremetalReprepareTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
func (self *SBaremetalReprepareTask) DoDeploys(ctx context.Context, term *ssh.Client) (jsonutils.JSONObject, error) {
|
||||
task := newBaremetalPrepareTask(self.Baremetal, self.userCred)
|
||||
err := task.DoPrepare(term)
|
||||
err := task.DoPrepare(ctx, term)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (self *SBaremetalReprepareTask) PostDeploys(term *ssh.Client) error {
|
||||
self.Baremetal.AutoSyncStatus()
|
||||
func (self *SBaremetalReprepareTask) PostDeploys(ctx context.Context, term *ssh.Client) error {
|
||||
self.Baremetal.AutoSyncStatus(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (self *SBaremetalServerStartTask) DoBoot(ctx context.Context, args interfac
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := self.Baremetal.SSHReboot(); err != nil {
|
||||
if err := self.Baremetal.SSHReboot(ctx); err != nil {
|
||||
return errors.Wrap(err, "Try reboot")
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (self *SBaremetalServerStartTask) WaitForStart(ctx context.Context, args in
|
||||
}
|
||||
|
||||
func (self *SBaremetalServerStartTask) OnStartComplete(ctx context.Context, args interface{}) error {
|
||||
self.Baremetal.SyncAllStatus(types.POWER_STATUS_ON)
|
||||
self.Baremetal.SyncAllStatus(ctx, types.POWER_STATUS_ON)
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ func (task *SBaremetalUnmaintenanceTask) DoUnmaintenance(ctx context.Context, ar
|
||||
}
|
||||
} else {
|
||||
if task.Baremetal.GetServer() != nil {
|
||||
if err := task.EnsureSSHReboot(); err != nil {
|
||||
if err := task.EnsureSSHReboot(ctx); err != nil {
|
||||
return errors.Wrap(err, "Do unmaintenance for none BMC server")
|
||||
}
|
||||
}
|
||||
}
|
||||
task.Baremetal.SyncStatus(baremetalstatus.RUNNING, "")
|
||||
task.Baremetal.SyncStatus(ctx, baremetalstatus.RUNNING, "")
|
||||
SetTaskComplete(task, nil)
|
||||
return nil
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (self *SBaremetalUnmaintenanceTask) WaitForStop(ctx context.Context, args i
|
||||
}
|
||||
|
||||
func (self *SBaremetalUnmaintenanceTask) OnStopComplete(ctx context.Context, args interface{}) error {
|
||||
self.Baremetal.SyncStatus(baremetalstatus.READY, "")
|
||||
self.Baremetal.SyncStatus(ctx, baremetalstatus.READY, "")
|
||||
SetTaskComplete(self, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -22,15 +22,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"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"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
@@ -197,7 +195,7 @@ func GetSysInfo(exector IPMIExecutor) (*types.SSystemInfo, error) {
|
||||
return &info, err
|
||||
}
|
||||
|
||||
func GetLanChannels(sysinfo *types.SSystemInfo) []int {
|
||||
/*func GetLanChannels(sysinfo *types.SSystemInfo) []int {
|
||||
return profiles.GetLanChannel(sysinfo)
|
||||
}
|
||||
|
||||
@@ -207,9 +205,9 @@ func GetDefaultLanChannel(sysinfo *types.SSystemInfo) int {
|
||||
|
||||
func GetRootId(sysinfo *types.SSystemInfo) int {
|
||||
return profiles.GetRootId(sysinfo)
|
||||
}
|
||||
}*/
|
||||
|
||||
func GetLanConfig(exector IPMIExecutor, channel int) (*types.SIPMILanConfig, error) {
|
||||
func GetLanConfig(exector IPMIExecutor, channel uint8) (*types.SIPMILanConfig, error) {
|
||||
args := newArgs("lan", "print", channel)
|
||||
lines, err := ExecuteCommands(exector, args)
|
||||
if err != nil {
|
||||
@@ -278,14 +276,14 @@ func doActions(exector IPMIExecutor, actionName string, args ...Args) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetLanDHCP(exector IPMIExecutor, lanChannel int) error {
|
||||
func SetLanDHCP(exector IPMIExecutor, lanChannel uint8) error {
|
||||
args := newArgs("lan", "set", lanChannel, "ipsrc", "dhcp")
|
||||
return doActions(exector, "set_lan_dhcp", args)
|
||||
}
|
||||
|
||||
func SetLanStatic(
|
||||
exector IPMIExecutor,
|
||||
channel int,
|
||||
channel uint8,
|
||||
ip string,
|
||||
mask string,
|
||||
gateway string,
|
||||
@@ -313,12 +311,12 @@ func SetLanStatic(
|
||||
return doActions(exector, "set_lan_static", argss...)
|
||||
}
|
||||
|
||||
func SetLanStaticIP(exector IPMIExecutor, channel int, ip string) error {
|
||||
func SetLanStaticIP(exector IPMIExecutor, channel uint8, ip string) error {
|
||||
args := newArgs("lan", "set", channel, "ipaddr", ip)
|
||||
return doActions(exector, "set_lan_static_ip", args)
|
||||
}
|
||||
|
||||
func setLanAccess(exector IPMIExecutor, channel int, access string) error {
|
||||
func setLanAccess(exector IPMIExecutor, channel uint8, access string) error {
|
||||
args := []Args{
|
||||
newArgs("lan", "set", channel, "access", access),
|
||||
// newArgs("lan", "set", channel, "auth", "ADMIN", "MD5"),
|
||||
@@ -326,11 +324,11 @@ func setLanAccess(exector IPMIExecutor, channel int, access string) error {
|
||||
return doActions(exector, "set_lan_access", args...)
|
||||
}
|
||||
|
||||
func EnableLanAccess(exector IPMIExecutor, channel int) error {
|
||||
func EnableLanAccess(exector IPMIExecutor, channel uint8) error {
|
||||
return setLanAccess(exector, channel, "on")
|
||||
}
|
||||
|
||||
func ListLanUsers(exector IPMIExecutor, channel int) ([]compute.IPMIUser, error) {
|
||||
func ListLanUsers(exector IPMIExecutor, channel uint8) ([]compute.IPMIUser, error) {
|
||||
args := newArgs("user", "list", channel)
|
||||
ret, err := ExecuteCommands(exector, args)
|
||||
if err != nil {
|
||||
@@ -339,7 +337,7 @@ func ListLanUsers(exector IPMIExecutor, channel int) ([]compute.IPMIUser, error)
|
||||
return sysutils.ParseIPMIUser(ret), nil
|
||||
}
|
||||
|
||||
func CreateOrSetAdminUser(exector IPMIExecutor, channel int, rootId int, username string, password string) error {
|
||||
func CreateOrSetAdminUser(exector IPMIExecutor, channel uint8, rootId int, username string, password string) error {
|
||||
users, err := ListLanUsers(exector, channel)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "List users")
|
||||
@@ -372,7 +370,7 @@ func CreateOrSetAdminUser(exector IPMIExecutor, channel int, rootId int, usernam
|
||||
return SetLanUserAdminPasswd(exector, channel, foundUser.Id, password)
|
||||
}
|
||||
|
||||
func SetLanUserAdminPasswd(exector IPMIExecutor, channel int, id int, password string) error {
|
||||
func SetLanUserAdminPasswd(exector IPMIExecutor, channel uint8, id int, password string) error {
|
||||
var err error
|
||||
password, err = stringutils2.EscapeEchoString(password)
|
||||
if err != nil {
|
||||
@@ -403,7 +401,7 @@ func SetLanUserAdminPasswd(exector IPMIExecutor, channel int, id int, password s
|
||||
return doActions(exector, "set_lan_user_password3", args...)
|
||||
}
|
||||
|
||||
func SetIdUserPasswd(exector IPMIExecutor, channel int, id int, user string, password string) error {
|
||||
func SetIdUserPasswd(exector IPMIExecutor, channel uint8, 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)
|
||||
|
||||
@@ -26,7 +26,7 @@ type SIPMIInfo struct {
|
||||
Password string `json:"password,omitempty"`
|
||||
IpAddr string `json:"ip_addr,omitempty"`
|
||||
Present bool `json:"present,omitempty"`
|
||||
LanChannel int `json:"lan_channel,omitzero"`
|
||||
LanChannel uint8 `json:"lan_channel,omitzero"`
|
||||
Verified bool `json:"verified,omitfalse"`
|
||||
RedfishApi bool `json:"redfish_api,omitfalse"`
|
||||
CdromBoot bool `json:"cdrom_boot,omitfalse"`
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/compute/models/baremetal"
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
type SBaremetalProfileManager struct {
|
||||
db.SStandaloneAnonResourceBaseManager
|
||||
}
|
||||
|
||||
type SBaremetalProfile struct {
|
||||
db.SStandaloneAnonResourceBase
|
||||
|
||||
// 品牌名称(English)
|
||||
OemName string `width:"64" charset:"ascii" nullable:"false" default:"" index:"true" list:"user" create:"required"`
|
||||
|
||||
Model string `width:"64" charset:"utf8" list:"user" create:"optional"`
|
||||
|
||||
LanChannel uint8 `list:"user" update:"user" create:"optional"`
|
||||
|
||||
LanChannel2 uint8 `list:"user" update:"user" create:"optional"`
|
||||
|
||||
LanChannel3 uint8 `list:"user" update:"user" create:"optional"`
|
||||
|
||||
// BMC Root账号名称,默认为 root
|
||||
RootName string `width:"64" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required" default:"root"`
|
||||
// BMC Root账号ID,默认为 2
|
||||
RootId int `list:"user" update:"user" create:"optional" default:"2"`
|
||||
// 是否要求强密码
|
||||
StrongPass bool `list:"user" update:"user" create:"optional"`
|
||||
}
|
||||
|
||||
var BaremetalProfileManager *SBaremetalProfileManager
|
||||
|
||||
func init() {
|
||||
BaremetalProfileManager = &SBaremetalProfileManager{
|
||||
SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
|
||||
SBaremetalProfile{},
|
||||
"baremetal_profiles_tbl",
|
||||
"baremetal_profile",
|
||||
"baremetal_profiles",
|
||||
),
|
||||
}
|
||||
BaremetalProfileManager.SetVirtualObject(BaremetalProfileManager)
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) ListItemFilter(
|
||||
ctx context.Context,
|
||||
q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential,
|
||||
query baremetalapi.BaremetalProfileListInput,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
q, err := bpm.SStandaloneAnonResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneAnonResourceListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SStandaloneAnonResourceBaseManager.ListItemFilter")
|
||||
}
|
||||
|
||||
query.Normalize()
|
||||
|
||||
if len(query.OemName) > 0 {
|
||||
q = q.In("oem_name", query.OemName)
|
||||
}
|
||||
if len(query.Model) > 0 {
|
||||
q = q.In("model", query.Model)
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) OrderByExtraFields(
|
||||
ctx context.Context,
|
||||
q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential,
|
||||
query baremetalapi.BaremetalProfileListInput,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
var err error
|
||||
|
||||
q, err = bpm.SStandaloneAnonResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneAnonResourceListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SStandaloneAnonResourceBaseManager.OrderByExtraFields")
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
||||
var err error
|
||||
|
||||
q, err = bpm.SStandaloneAnonResourceBaseManager.QueryDistinctExtraField(q, field)
|
||||
if err == nil {
|
||||
return q, nil
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
|
||||
var err error
|
||||
q, err = bpm.SStandaloneAnonResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) InitializeData() error {
|
||||
for _, spec := range baremetalapi.PredefinedProfiles {
|
||||
bp := SBaremetalProfile{}
|
||||
bp.Id = strings.ToLower(spec.OemName)
|
||||
if len(bp.Id) == 0 {
|
||||
bp.Id = baremetalapi.DefaultBaremetalProfileId
|
||||
}
|
||||
bp.OemName = strings.ToLower(spec.OemName)
|
||||
if len(spec.LanChannels) > 0 {
|
||||
bp.LanChannel = spec.LanChannels[0]
|
||||
}
|
||||
if len(spec.LanChannels) > 1 {
|
||||
bp.LanChannel2 = spec.LanChannels[1]
|
||||
}
|
||||
if len(spec.LanChannels) > 2 {
|
||||
bp.LanChannel3 = spec.LanChannels[2]
|
||||
}
|
||||
bp.RootName = spec.RootName
|
||||
bp.RootId = spec.RootId
|
||||
bp.StrongPass = spec.StrongPass
|
||||
bp.SetModelManager(bpm, &bp)
|
||||
|
||||
err := bpm.TableSpec().InsertOrUpdate(context.Background(), &bp)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "insert default baremetal profile %s", jsonutils.Marshal(bp))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) ValidateCreateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
ownerId mcclient.IIdentityProvider,
|
||||
query jsonutils.JSONObject,
|
||||
input baremetalapi.BaremetalProfileCreateInput,
|
||||
) (baremetalapi.BaremetalProfileCreateInput, error) {
|
||||
var err error
|
||||
input.StandaloneAnonResourceCreateInput, err = bpm.SStandaloneAnonResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneAnonResourceCreateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "StandaloneAnonResourceBaseManager.ValidateCreateData")
|
||||
}
|
||||
input.OemName = strings.ToLower(strings.TrimSpace(input.OemName))
|
||||
input.Model = strings.ToLower(strings.TrimSpace(input.Model))
|
||||
// ensure uniquess
|
||||
uniqQuery := bpm.fetchByOemNameAndModelQuery(input.OemName, input.Model, true)
|
||||
cnt, err := uniqQuery.CountWithError()
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "CountWithError")
|
||||
}
|
||||
if cnt > 0 {
|
||||
return input, errors.Wrapf(httperrors.ErrConflict, "%s/%s already exists", input.OemName, input.Model)
|
||||
}
|
||||
if input.LanChannel == 0 {
|
||||
return input, errors.Wrap(httperrors.ErrInputParameter, "lan_channel must be set")
|
||||
}
|
||||
if len(input.RootName) == 0 {
|
||||
return input, errors.Wrap(httperrors.ErrInputParameter, "root_name must be set")
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (bpm *SBaremetalProfileManager) fetchByOemNameAndModelQuery(oemName, model string, exact bool) *sqlchemy.SQuery {
|
||||
q := bpm.Query()
|
||||
if exact {
|
||||
q = q.Equals("oem_name", oemName)
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.IsEmpty(q.Field("oem_name")),
|
||||
sqlchemy.Equals(q.Field("oem_name"), oemName),
|
||||
))
|
||||
}
|
||||
if exact {
|
||||
q = q.Equals("model", model)
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.IsEmpty(q.Field("model")),
|
||||
sqlchemy.Equals(q.Field("model"), model),
|
||||
))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (bp *SBaremetalProfile) ValidateUpdateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input baremetalapi.BaremetalProfileUpdateInput,
|
||||
) (baremetalapi.BaremetalProfileUpdateInput, error) {
|
||||
var err error
|
||||
input.StandaloneAnonResourceBaseUpdateInput, err = bp.SStandaloneAnonResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneAnonResourceBaseUpdateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "SStandaloneAnonResourceBase.ValidateUpdateData")
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
|
||||
"yunion.io/x/onecloud/pkg/compute/models/baremetal"
|
||||
)
|
||||
|
||||
func InitDB() error {
|
||||
@@ -78,6 +79,8 @@ func InitDB() error {
|
||||
GroupnetworkManager,
|
||||
|
||||
ElasticcacheManager,
|
||||
|
||||
baremetal.BaremetalProfileManager,
|
||||
} {
|
||||
now := time.Now()
|
||||
err := manager.InitializeData()
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/compute/capabilities"
|
||||
"yunion.io/x/onecloud/pkg/compute/misc"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
baremetalmodels "yunion.io/x/onecloud/pkg/compute/models/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/compute/specs"
|
||||
"yunion.io/x/onecloud/pkg/compute/sshkeys"
|
||||
@@ -243,6 +244,8 @@ func InitHandlers(app *appsrv.Application) {
|
||||
models.MiscResourceManager,
|
||||
|
||||
models.SSLCertificateManager,
|
||||
|
||||
baremetalmodels.BaremetalProfileManager,
|
||||
} {
|
||||
db.RegisterModelManager(manager)
|
||||
handler := db.NewModelHandler(manager)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package hostdhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
@@ -83,7 +84,7 @@ func (r *SDHCPRelay) Setup(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SDHCPRelay) ServeDHCP(pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
func (r *SDHCPRelay) ServeDHCP(ctx context.Context, pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr, intf)
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package hostdhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
@@ -237,7 +238,7 @@ func (s *SGuestDHCPServer) IsDhcpPacket(pkt dhcp.Packet) bool {
|
||||
return pkt != nil && (pkt.Type() == dhcp.Request || pkt.Type() == dhcp.Discover)
|
||||
}
|
||||
|
||||
func (s *SGuestDHCPServer) ServeDHCP(pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
func (s *SGuestDHCPServer) ServeDHCP(ctx context.Context, pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
pkg, err := s.serveDHCPInternal(pkt, addr, intf)
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/mcclient/modules/compute/baremetal"
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
baremetaloptions "yunion.io/x/onecloud/pkg/mcclient/options/compute/baremetal"
|
||||
)
|
||||
|
||||
type BaremetalProfileManager struct {
|
||||
modulebase.ResourceManager
|
||||
}
|
||||
|
||||
func (m *BaremetalProfileManager) GetMatchProfiles(s *mcclient.ClientSession, oemName string, model string) ([]baremetalapi.BaremetalProfileSpec, error) {
|
||||
params := baremetaloptions.BaremetalProfileListOptions{}
|
||||
limit := 0
|
||||
params.Limit = &limit
|
||||
params.OemName = []string{"", oemName}
|
||||
if len(model) > 0 {
|
||||
params.Model = []string{"", model}
|
||||
}
|
||||
|
||||
results, err := m.List(s, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "List")
|
||||
}
|
||||
ret := make([]baremetalapi.BaremetalProfileSpec, 0)
|
||||
for i := range results.Data {
|
||||
details := baremetalapi.BaremetalProfileDetails{}
|
||||
err := results.Data[i].Unmarshal(&details)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unmarshal")
|
||||
}
|
||||
ret = append(ret, details.ToSpec())
|
||||
}
|
||||
sort.Sort(baremetalapi.BaremetalProfileSpecs(ret))
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
var (
|
||||
BaremetalProfiles BaremetalProfileManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
BaremetalProfiles = BaremetalProfileManager{modules.NewComputeManager("baremetal_profile", "baremetal_profiles",
|
||||
[]string{
|
||||
"oem_name",
|
||||
"model",
|
||||
"lan_channel",
|
||||
"root_id",
|
||||
"root_name",
|
||||
"string_pass",
|
||||
},
|
||||
[]string{},
|
||||
)}
|
||||
|
||||
modules.RegisterCompute(&BaremetalProfiles)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/mcclient/options/compute/baremetal"
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
)
|
||||
|
||||
type BaremetalProfileListOptions struct {
|
||||
options.BaseListOptions
|
||||
|
||||
OemName []string
|
||||
Model []string
|
||||
}
|
||||
|
||||
func (opts *BaremetalProfileListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.ListStructToParams(opts)
|
||||
}
|
||||
|
||||
type BaremetalProfileIdOptions struct {
|
||||
options.BaseIdOptions
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
@@ -88,7 +89,7 @@ func NewDHCPServer2(iface string, dhcpServerPort, dhcpRelayPort uint16) (*DHCPSe
|
||||
}
|
||||
|
||||
type DHCPHandler interface {
|
||||
ServeDHCP(pkt Packet, addr *net.UDPAddr, intf *net.Interface) (Packet, []string, error)
|
||||
ServeDHCP(ctx context.Context, pkt Packet, addr *net.UDPAddr, intf *net.Interface) (Packet, []string, error)
|
||||
}
|
||||
|
||||
func (s *DHCPServer) ListenAndServe(handler DHCPHandler) error {
|
||||
@@ -101,6 +102,7 @@ func (s *DHCPServer) GetConn() *Conn {
|
||||
}
|
||||
|
||||
func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
ctx := context.WithValue(context.Background(), "dhcp_server", s)
|
||||
for {
|
||||
pkt, addr, mac, intf, err := s.conn.RecvDHCP()
|
||||
if err != nil {
|
||||
@@ -119,7 +121,7 @@ func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
}
|
||||
}()
|
||||
|
||||
resp, targets, err := handler.ServeDHCP(pkt, addr, intf)
|
||||
resp, targets, err := handler.ServeDHCP(ctx, pkt, addr, intf)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %v", err)
|
||||
return
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
func init() {
|
||||
type LanOptions struct {
|
||||
CHANNEL int `help:"lan channel"`
|
||||
CHANNEL uint8 `help:"lan channel"`
|
||||
}
|
||||
shellutils.R(&LanOptions{}, "set-lan-dhcp", "Set lan channel DHCP", func(client ipmitool.IPMIExecutor, args *LanOptions) error {
|
||||
return ipmitool.SetLanDHCP(client, args.CHANNEL)
|
||||
|
||||
@@ -131,6 +131,7 @@ class ModelAPI(FuncDispatcher):
|
||||
run_swagger_gen(['yunion.io/x/cloudmux/pkg/cloudprovider'], 'yunion.io/x/onecloud/pkg/apis/cloudprovider')
|
||||
self.run(pkg=["keystone", "models"], out=["identity"])
|
||||
self.run_model("compute")
|
||||
self.run(pkg=["compute", "models", "baremetal"], out=["compute", "baremetal"])
|
||||
self.run_model("image")
|
||||
self.run_model("cloudid")
|
||||
self.run_model("notify")
|
||||
|
||||
Reference in New Issue
Block a user