mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
feat(region,baremetal,climc): support baremetal root disk matcher (#20480)
This commit is contained in:
@@ -310,6 +310,21 @@ type BaremetalDiskConfig struct {
|
||||
Direct *bool `json:"direct,omitempty"`
|
||||
}
|
||||
|
||||
type RootDiskMatcherSizeMBRange struct {
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
}
|
||||
|
||||
const (
|
||||
BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER = "baremetal_root_disk_matcher"
|
||||
)
|
||||
|
||||
type BaremetalRootDiskMatcher struct {
|
||||
Device string `json:"device"`
|
||||
SizeMB int64 `json:"size_mb"`
|
||||
SizeMBRange *RootDiskMatcherSizeMBRange `json:"size_mb_range"`
|
||||
}
|
||||
|
||||
type ServerConfigs struct {
|
||||
// 调度使用指定的云账号
|
||||
PreferManager string `json:"prefer_manager_id"`
|
||||
@@ -405,6 +420,9 @@ type ServerConfigs struct {
|
||||
// 裸金属磁盘配置列表
|
||||
BaremetalDiskConfigs []*BaremetalDiskConfig `json:"baremetal_disk_configs"`
|
||||
|
||||
// 裸金属系统盘匹配器
|
||||
BaremetalRootDiskMatcher *BaremetalRootDiskMatcher `json:"baremetal_root_disk_matcher"`
|
||||
|
||||
// 主机组列表, 参数可以是主机组名称或ID,建议使用ID
|
||||
InstanceGroupIds []string `json:"groups"`
|
||||
|
||||
|
||||
@@ -2546,6 +2546,34 @@ func (s *SBaremetalServer) GetRootTemplateId() string {
|
||||
return id
|
||||
}
|
||||
|
||||
func (s *SBaremetalServer) GetMetadata() (*jsonutils.JSONDict, error) {
|
||||
metadata, err := s.desc.Get("metadata")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get desc.metadata")
|
||||
}
|
||||
return metadata.(*jsonutils.JSONDict), nil
|
||||
}
|
||||
|
||||
func (s *SBaremetalServer) GetRootDiskMatcher() (*api.BaremetalRootDiskMatcher, error) {
|
||||
metadata, err := s.GetMetadata()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get metadata")
|
||||
}
|
||||
if !metadata.Contains(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER) {
|
||||
return nil, errors.Wrapf(errors.ErrNotFound, "not found %s in metadata", api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
|
||||
}
|
||||
jStr, _ := metadata.GetString(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
|
||||
jObj, err := jsonutils.ParseString(jStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parse json string: %s", jStr)
|
||||
}
|
||||
matcher := new(api.BaremetalRootDiskMatcher)
|
||||
if err := jObj.Unmarshal(matcher); err != nil {
|
||||
return nil, errors.Wrapf(err, "unmarshal to matcher")
|
||||
}
|
||||
return matcher, nil
|
||||
}
|
||||
|
||||
func (s *SBaremetalServer) GetDiskConfig() ([]*api.BaremetalDiskConfig, error) {
|
||||
layouts := make([]baremetal.Layout, 0)
|
||||
err := s.desc.Unmarshal(&layouts, "disk_config")
|
||||
@@ -2598,7 +2626,11 @@ func (s *SBaremetalServer) NewConfigedSSHPartitionTool(term *ssh.Client) (*diskt
|
||||
}
|
||||
}
|
||||
|
||||
tool, err := disktool.NewSSHPartitionTool(term, layouts)
|
||||
matcher, err := s.GetRootDiskMatcher()
|
||||
if errors.Cause(err) != errors.ErrNotFound {
|
||||
log.Errorf("GetRootDiskMatcher: %v", err)
|
||||
}
|
||||
tool, err := disktool.NewSSHPartitionTool(term, layouts, matcher)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "NewSSHPartitionTool")
|
||||
}
|
||||
@@ -2651,7 +2683,11 @@ func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) (*disktool.SSHPartitio
|
||||
}
|
||||
}
|
||||
|
||||
tool, err := disktool.NewSSHPartitionTool(term, layouts)
|
||||
matcher, err := s.GetRootDiskMatcher()
|
||||
if errors.Cause(err) != errors.ErrNotFound {
|
||||
log.Errorf("GetRootDiskMatcher: %v", err)
|
||||
}
|
||||
tool, err := disktool.NewSSHPartitionTool(term, layouts, matcher)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "NewSSHPartitionTool")
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ func (tool *PartitionTool) parseLsDisk(lines []string, driver string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tool *PartitionTool) FetchDiskConfs(diskConfs []baremetal.DiskConfiguration) *PartitionTool {
|
||||
func (tool *PartitionTool) FetchDiskConfs(diskConfs []baremetal.DiskConfiguration, rootMatcher *api.BaremetalRootDiskMatcher) *PartitionTool {
|
||||
for _, d := range diskConfs {
|
||||
disk := newDiskPartitions(d.Driver, d.Adapter, d.RaidConfig, d.Size, d.Block, d.DiskType, tool)
|
||||
tool.disks = append(tool.disks, disk)
|
||||
@@ -681,9 +681,56 @@ func (tool *PartitionTool) FetchDiskConfs(diskConfs []baremetal.DiskConfiguratio
|
||||
}
|
||||
tool.diskTable[key] = append(tool.diskTable[key], disk)
|
||||
}
|
||||
// reorder tool.disks
|
||||
if rootMatcher != nil {
|
||||
tool.reorderRootDisk(rootMatcher)
|
||||
}
|
||||
return tool
|
||||
}
|
||||
|
||||
func (tool *PartitionTool) reorderRootDisk(matcher *api.BaremetalRootDiskMatcher) {
|
||||
var rootDiskIdx = 0
|
||||
|
||||
isDiskMatch := func(disk *DiskPartitions, matcher *api.BaremetalRootDiskMatcher) bool {
|
||||
if matcher.Device != "" {
|
||||
if disk.dev == matcher.Device {
|
||||
return true
|
||||
}
|
||||
if disk.devName == matcher.Device {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if matcher.SizeMB > 0 {
|
||||
if disk.sizeMB == matcher.SizeMB {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if matcher.SizeMBRange != nil {
|
||||
if disk.sizeMB >= matcher.SizeMBRange.Start && disk.sizeMB <= matcher.SizeMBRange.End {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for idx, disk := range tool.disks {
|
||||
if isDiskMatch(disk, matcher) {
|
||||
rootDiskIdx = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Infof("Select %d as root disk", rootDiskIdx)
|
||||
newDisks := make([]*DiskPartitions, 0)
|
||||
newDisks = append(newDisks, tool.disks[rootDiskIdx])
|
||||
for idx := range tool.disks {
|
||||
if idx == rootDiskIdx {
|
||||
continue
|
||||
}
|
||||
newDisks = append(newDisks, tool.disks[idx])
|
||||
}
|
||||
tool.disks = newDisks
|
||||
}
|
||||
|
||||
func (tool *PartitionTool) IsAllDisksReady() bool {
|
||||
for idx, d := range tool.disks {
|
||||
if !d.IsReady() {
|
||||
@@ -788,9 +835,9 @@ func newSSHPartitionTool(term *ssh.Client) *SSHPartitionTool {
|
||||
return tool
|
||||
}
|
||||
|
||||
func NewSSHPartitionTool(term *ssh.Client, layouts []baremetal.Layout) (*SSHPartitionTool, error) {
|
||||
func NewSSHPartitionTool(term *ssh.Client, layouts []baremetal.Layout, rootMatcher *api.BaremetalRootDiskMatcher) (*SSHPartitionTool, error) {
|
||||
tool := newSSHPartitionTool(term)
|
||||
tool.FetchDiskConfs(baremetal.GetDiskConfigurations(layouts))
|
||||
tool.FetchDiskConfs(baremetal.GetDiskConfigurations(layouts), rootMatcher)
|
||||
if err := tool.RetrieveDiskInfo(); err != nil {
|
||||
return nil, errors.Wrapf(err, "RetrieveDiskInfo")
|
||||
}
|
||||
|
||||
@@ -371,6 +371,47 @@ func ParseIsolatedDevice(desc string, idx int) (*compute.IsolatedDeviceConfig, e
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
func ParseBaremetalRootDiskMatcher(line string) (*compute.BaremetalRootDiskMatcher, error) {
|
||||
ret := new(compute.BaremetalRootDiskMatcher)
|
||||
for _, seg := range strings.Split(line, ",") {
|
||||
info := strings.Split(seg, "=")
|
||||
if len(info) != 2 {
|
||||
return nil, errors.Errorf("invalid option %s", seg)
|
||||
}
|
||||
key := info[0]
|
||||
val := info[1]
|
||||
switch key {
|
||||
case "size":
|
||||
sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parse size %s", val)
|
||||
}
|
||||
ret.SizeMB = int64(sizeMB)
|
||||
case "device", "dev":
|
||||
ret.Device = val
|
||||
case "size_start":
|
||||
sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parse size_start %s", val)
|
||||
}
|
||||
if ret.SizeMBRange == nil {
|
||||
ret.SizeMBRange = new(compute.RootDiskMatcherSizeMBRange)
|
||||
}
|
||||
ret.SizeMBRange.Start = int64(sizeMB)
|
||||
case "size_end":
|
||||
sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parse size_end %s", val)
|
||||
}
|
||||
if ret.SizeMBRange == nil {
|
||||
ret.SizeMBRange = new(compute.RootDiskMatcherSizeMBRange)
|
||||
}
|
||||
ret.SizeMBRange.End = int64(sizeMB)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func ParseBaremetalDiskConfig(desc string) (*compute.BaremetalDiskConfig, error) {
|
||||
bdc := new(compute.BaremetalDiskConfig)
|
||||
bdc.Type = compute.DISK_TYPE_HYBRID
|
||||
|
||||
@@ -241,3 +241,44 @@ func TestParseIsolatedDevice(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseBaremetalRootDiskMatcher(t *testing.T) {
|
||||
tests := []struct {
|
||||
args string
|
||||
want *compute.BaremetalRootDiskMatcher
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
args: "size=100G",
|
||||
want: &compute.BaremetalRootDiskMatcher{SizeMB: 102400},
|
||||
},
|
||||
{
|
||||
args: "device=/dev/sda",
|
||||
want: &compute.BaremetalRootDiskMatcher{Device: "/dev/sda"},
|
||||
},
|
||||
{
|
||||
args: "size_end=100G",
|
||||
want: &compute.BaremetalRootDiskMatcher{SizeMBRange: &compute.RootDiskMatcherSizeMBRange{End: 102400}},
|
||||
},
|
||||
{
|
||||
args: "size_end=100G,size_start=50G",
|
||||
want: &compute.BaremetalRootDiskMatcher{
|
||||
SizeMBRange: &compute.RootDiskMatcherSizeMBRange{
|
||||
Start: 51200,
|
||||
End: 102400,
|
||||
}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.args, func(t *testing.T) {
|
||||
got, err := ParseBaremetalRootDiskMatcher(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseBaremetalRootDiskMatcher() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseBaremetalRootDiskMatcher() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
@@ -683,3 +684,12 @@ func ValidateDiskConfigs(confs []*api.BaremetalDiskConfig) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateRootDiskMatcher(input *api.BaremetalRootDiskMatcher) error {
|
||||
if input.SizeMBRange != nil {
|
||||
if input.SizeMBRange.Start > input.SizeMBRange.End {
|
||||
return errors.Errorf("size_mb_range.start %d is large than size_mb_range.end %d", input.SizeMBRange.Start, input.SizeMBRange.End)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -417,6 +417,11 @@ func (self *SBaremetalGuestDriver) ValidateCreateData(ctx context.Context, userC
|
||||
return nil, httperrors.NewInputParameterError("Invalid raid config: %v", err)
|
||||
}
|
||||
}
|
||||
if input.BaremetalRootDiskMatcher != nil {
|
||||
if err := baremetal.ValidateRootDiskMatcher(input.BaremetalRootDiskMatcher); err != nil {
|
||||
return nil, httperrors.NewInputParameterError("Invalid root disk matcher: %v", err)
|
||||
}
|
||||
}
|
||||
//if len(input.Disks) <= 0 {
|
||||
// return nil, httperrors.NewInputParameterError("Root disk must be present")
|
||||
//}
|
||||
|
||||
@@ -2412,6 +2412,10 @@ func (guest *SGuest) PostCreate(ctx context.Context, userCred mcclient.TokenCred
|
||||
if jsonutils.QueryBoolean(data, imageapi.IMAGE_DISABLE_USB_KBD, false) {
|
||||
guest.SetMetadata(ctx, imageapi.IMAGE_DISABLE_USB_KBD, "true", userCred)
|
||||
}
|
||||
matcherJson, _ := data.Get(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
|
||||
if matcherJson != nil {
|
||||
guest.SetMetadata(ctx, api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER, matcherJson, userCred)
|
||||
}
|
||||
|
||||
userData, _ := data.GetString("user_data")
|
||||
if len(userData) > 0 {
|
||||
|
||||
@@ -353,7 +353,8 @@ type ServerConfigs struct {
|
||||
AutoSwitchToBackupOnHostDown bool `help:"Auto switch to backup server on host down"`
|
||||
Daemon *bool `help:"Set as a daemon server" json:"is_daemon"`
|
||||
|
||||
RaidConfig []string `help:"Baremetal raid config" json:"-"`
|
||||
RaidConfig []string `help:"Baremetal raid config" json:"-"`
|
||||
RootDiskMatcher string `help:"Baremetal root disk matcher, e.g. 'device=/dev/sdb' 'size=900G' 'size_start=800G,size_end=900G'" json:"-"`
|
||||
}
|
||||
|
||||
func (o ServerConfigs) Data() (*computeapi.ServerConfigs, error) {
|
||||
@@ -377,6 +378,13 @@ func (o ServerConfigs) Data() (*computeapi.ServerConfigs, error) {
|
||||
data.BaremetalDiskConfigs = append(data.BaremetalDiskConfigs, raidConf)
|
||||
}
|
||||
}
|
||||
if len(o.RootDiskMatcher) > 0 {
|
||||
matcher, err := cmdline.ParseBaremetalRootDiskMatcher(o.RootDiskMatcher)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data.BaremetalRootDiskMatcher = matcher
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user