From 1fd62f7988f5670f98eb528c1c271ea283587798 Mon Sep 17 00:00:00 2001 From: Zexi Date: Thu, 23 May 2019 14:51:20 +0800 Subject: [PATCH] baremetal: fix build HPSARaid and enable serial console errors --- pkg/baremetal/manager.go | 23 ++++++---- pkg/baremetal/tasks/base.go | 10 ++-- pkg/baremetal/tasks/basedeploy.go | 10 ++-- pkg/baremetal/tasks/create.go | 1 + .../utils/detect_storages/detect_storages.go | 3 +- pkg/baremetal/utils/ipmitool/ipmitool.go | 31 ++++++------- pkg/baremetal/utils/raid/hpssactl/hpssactl.go | 34 +++++++++----- pkg/baremetal/utils/raid/megactl/megactl.go | 2 +- pkg/baremetal/utils/raid/mvcli/mvcli.go | 2 +- pkg/baremetal/utils/raid/raid.go | 11 +++++ pkg/baremetal/utils/raid/raid_test.go | 46 +++++++++++++++++++ pkg/hostman/guestfs/fsdriver/linux.go | 23 +++++++++- pkg/util/ssh/ssh.go | 10 +++- pkg/util/sysutils/sysutils.go | 17 ++++++- pkg/util/sysutils/sysutils_test.go | 35 ++++++++++++++ 15 files changed, 204 insertions(+), 54 deletions(-) create mode 100644 pkg/baremetal/utils/raid/raid_test.go diff --git a/pkg/baremetal/manager.go b/pkg/baremetal/manager.go index bf5375f7f1..6f2c3bc89e 100644 --- a/pkg/baremetal/manager.go +++ b/pkg/baremetal/manager.go @@ -25,9 +25,11 @@ import ( "sync" "time" + "github.com/pkg/errors" + "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/pkg/util/errors" + yerrors "yunion.io/x/pkg/util/errors" "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/util/seclib" "yunion.io/x/pkg/util/sets" @@ -120,7 +122,7 @@ func (m *SBaremetalManager) loadConfigs() error { errs = append(errs, <-errsChannel) } } - return errors.NewAggregate(errs) + return yerrors.NewAggregate(errs) } func (m *SBaremetalManager) initBaremetal(session *mcclient.ClientSession, bmId string) error { @@ -1016,6 +1018,7 @@ func (b *SBaremetalInstance) StartNewTask(factory tasks.TaskFactory, taskId stri go func() { task, err := factory(b, taskId, data) if err != nil { + log.Errorf("New task %#v error: %v", factory, err) tasks.SetTaskFail(task, err) return } @@ -1328,40 +1331,40 @@ func (s *SBaremetalServer) DoPartitionDisk(term *ssh.Client) ([]*disktool.Partit storages = append(storages, pcie...) confs, err := s.GetDiskConfig() if err != nil { - return nil, err + return nil, errors.Wrapf(err, "do disk config") } layouts, err := baremetal.CalculateLayout(confs, storages) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "CalculateLayout") } tool := disktool.NewSSHPartitionTool(term) tool.FetchDiskConfs(baremetal.GetDiskConfigurations(layouts)) err = tool.RetrieveDiskInfo() if err != nil { - return nil, err + return nil, errors.Wrapf(err, "RetrieveDiskInfo") } disks, _ := s.desc.GetArray("disks") if len(disks) == 0 { - return nil, fmt.Errorf("Empty disks in desc") + return nil, errors.New("Empty disks in desc") } rootDisk := disks[0] rootSize, _ := rootDisk.Int("size") err = s.doCreateRoot(term, tool.GetRootDisk().GetDevName()) if err != nil { - return nil, fmt.Errorf("Failed to create root: %v", err) + return nil, errors.Wrapf(err, "Failed to create root") } tool.RetrievePartitionInfo() parts := tool.GetPartitions() if len(parts) == 0 { - return nil, fmt.Errorf("Root disk create failed, no partitions") + return nil, errors.New("Root disk create failed, no partitions") } log.Infof("Resize root to %d MB", rootSize) if err := tool.ResizePartition(0, rootSize); err != nil { - return nil, fmt.Errorf("Fail to resize root to %d, err: %v", rootSize, err) + return nil, errors.Wrapf(err, "Fail to resize root to %d", rootSize) } if len(disks) > 1 { for _, disk := range disks[1:] { @@ -1374,7 +1377,7 @@ func (s *SBaremetalServer) DoPartitionDisk(term *ssh.Client) ([]*disktool.Partit driver, _ := disk.GetString("driver") log.Infof("Create partition %d %s", sz, fs) if err := tool.CreatePartition(-1, sz, fs, true, driver, uuid); err != nil { - return nil, fmt.Errorf("Fail to create disk %s: %v", disk.String(), err) + return nil, errors.Wrapf(err, "Fail to create disk %s", disk.String()) } } } diff --git a/pkg/baremetal/tasks/base.go b/pkg/baremetal/tasks/base.go index e209098d93..33dddc7753 100644 --- a/pkg/baremetal/tasks/base.go +++ b/pkg/baremetal/tasks/base.go @@ -21,6 +21,8 @@ import ( "sync" "time" + "github.com/pkg/errors" + "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -287,18 +289,18 @@ func (self *SBaremetalTaskBase) EnsurePowerUp() error { log.Infof("EnsurePowerUp: bootdev=pxe") status, err := self.Baremetal.GetPowerStatus() if err != nil { - return err + return errors.Wrapf(err, "Get power status") } for status == "" || status == types.POWER_STATUS_OFF { if status == types.POWER_STATUS_OFF { err = self.Baremetal.DoPXEBoot() if err != nil { - return err + return errors.Wrapf(err, "Do PXE boot") } } status, err = self.Baremetal.GetPowerStatus() if err != nil { - return err + return errors.Wrapf(err, "Get power status") } if status == "" || status == types.POWER_STATUS_OFF { time.Sleep(40 * time.Second) @@ -367,7 +369,7 @@ func (self *SBaremetalPXEBootTaskBase) InitPXEBootTask(pxeBootTask IPXEBootTask, return self, fmt.Errorf("EnsurePowerShutdown: %v", err) } if err := self.EnsurePowerUp(); err != nil { - return self, fmt.Errorf("EnsurePowerUp to pxe: %v", err) + return self, errors.Wrapf(err, "EnsurePowerUp to pxe") } // this stage will be called by baremetalInstance when pxe start notify self.SetSSHStage(pxeBootTask.OnPXEBoot) diff --git a/pkg/baremetal/tasks/basedeploy.go b/pkg/baremetal/tasks/basedeploy.go index d0957c7488..c80c1fa6a8 100644 --- a/pkg/baremetal/tasks/basedeploy.go +++ b/pkg/baremetal/tasks/basedeploy.go @@ -17,6 +17,8 @@ package tasks import ( "context" + "github.com/pkg/errors" + "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/utils" @@ -64,25 +66,25 @@ func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term log.Infof("%s called on stage pxeboot, args: %v", self.GetName(), args) result, err := self.serverDeployTask.DoDeploys(term) if err != nil { - return err + return errors.Wrap(err, "Do deploy") } _, err = term.Run( "/bin/sync", "/sbin/sysctl -w vm.drop_caches=3", ) if err != nil { - return err + return errors.Wrap(err, "Sync disk") } onFinishAction := self.GetFinishAction() if utils.IsInStringArray(onFinishAction, []string{"restart", "shutdown"}) { err = self.EnsurePowerShutdown(false) if err != nil { - return err + return errors.Wrap(err, "Ensure power off") } if onFinishAction == "restart" { err = self.EnsurePowerUp() if err != nil { - return err + return errors.Wrap(err, "Ensure power up") } } } diff --git a/pkg/baremetal/tasks/create.go b/pkg/baremetal/tasks/create.go index 1692155300..c4dce505f0 100644 --- a/pkg/baremetal/tasks/create.go +++ b/pkg/baremetal/tasks/create.go @@ -74,6 +74,7 @@ func (self *SBaremetalServerCreateTask) DoDeploys(term *ssh.Client) (jsonutils.J } func (self *SBaremetalServerCreateTask) onError(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) } diff --git a/pkg/baremetal/utils/detect_storages/detect_storages.go b/pkg/baremetal/utils/detect_storages/detect_storages.go index dd0d840494..74d3a08938 100644 --- a/pkg/baremetal/utils/detect_storages/detect_storages.go +++ b/pkg/baremetal/utils/detect_storages/detect_storages.go @@ -70,8 +70,7 @@ func DetectStorageInfo(term *ssh.Client, wait bool) ([]*baremetal.BaremetalStora raidDrivers = append(raidDrivers, drv.GetName()) } - log.Infof("Get Raid drivers: %v", raidDrivers) - + log.Infof("Get Raid drivers: %v, collecting disks info ...", raidDrivers) pcieRet, err := term.Run("/lib/mos/lsdisk --pcie") if err != nil { return nil, nil, nil, fmt.Errorf("Fail to retrieve PCIE DISK info") diff --git a/pkg/baremetal/utils/ipmitool/ipmitool.go b/pkg/baremetal/utils/ipmitool/ipmitool.go index bf40823992..22f124bac7 100644 --- a/pkg/baremetal/utils/ipmitool/ipmitool.go +++ b/pkg/baremetal/utils/ipmitool/ipmitool.go @@ -21,6 +21,8 @@ import ( "strings" "time" + "github.com/pkg/errors" + "yunion.io/x/log" "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/stringutils" @@ -444,7 +446,7 @@ func DoReboot(exector IPMIExecutor) error { var err error status, err = GetChassisPowerStatus(exector) if err != nil { - return err + log.Errorf("DoReboot get power status 1st: %v", err) } isValidStatus := func(s string) bool { @@ -455,25 +457,24 @@ func DoReboot(exector IPMIExecutor) error { time.Sleep(1 * time.Second) status, err = GetChassisPowerStatus(exector) if err != nil { - return err + log.Errorf("DoReboot %d tries to get power status: %v", tried, err) } } if !isValidStatus(status) { - return fmt.Errorf("Unexpected status: %s", status) + return fmt.Errorf("Unexpected power status: %q", status) } // do shutdown if status == types.POWER_STATUS_ON { - err = DoHardShutdown(exector) - if err != nil { - return err + if err := DoHardShutdown(exector); err != nil { + log.Errorf("DoHardShutdown: %v", err) } time.Sleep(1 * time.Second) for tried := 0; tried < maxTries; tried++ { status, err = GetChassisPowerStatus(exector) if err != nil { - return err + log.Errorf("DoReboot %d tries to get power status: %v", tried, err) } if status == types.POWER_STATUS_OFF { break @@ -483,28 +484,24 @@ func DoReboot(exector IPMIExecutor) error { } // do power on - status, err = GetChassisPowerStatus(exector) - if err != nil { - return err - } + status, _ = GetChassisPowerStatus(exector) for tried := 0; status != types.POWER_STATUS_ON && tried < maxTries; tried++ { - err = DoPowerOn(exector) - if err != nil { - return err + if err := DoPowerOn(exector); err != nil { + log.Errorf("DoReboot %d tries to power on: %v", tried, err) } time.Sleep(1 * time.Second) status, err = GetChassisPowerStatus(exector) if err != nil { - return err + log.Errorf("DoReboot %d tries to get power status: %v", tried, err) } } status, err = GetChassisPowerStatus(exector) if err != nil { - return err + return errors.Wrap(err, "Get power status after power on") } if status != types.POWER_STATUS_ON { - return fmt.Errorf("do reboot fail to poweron, current status: %s", status) + return errors.Errorf("do reboot fail to poweron, current status: %s", status) } return nil } diff --git a/pkg/baremetal/utils/raid/hpssactl/hpssactl.go b/pkg/baremetal/utils/raid/hpssactl/hpssactl.go index bfa5e98398..a46e7d3bec 100644 --- a/pkg/baremetal/utils/raid/hpssactl/hpssactl.go +++ b/pkg/baremetal/utils/raid/hpssactl/hpssactl.go @@ -20,7 +20,10 @@ import ( "strconv" "strings" + "github.com/pkg/errors" + "yunion.io/x/log" + "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/stringutils" "yunion.io/x/pkg/utils" @@ -39,6 +42,11 @@ type HPSARaidPhyDev struct { func newHPSARaidPhyDev(addr string, adapter int, rotate bool) *HPSARaidPhyDev { b := raid.NewRaidBasePhyDev(baremetal.DISK_DRIVER_HPSARAID) b.Adapter = adapter + if rotate { + b.Rotate = tristate.True + } else { + b.Rotate = tristate.False + } return &HPSARaidPhyDev{ RaidBasePhyDev: b, addr: addr, @@ -133,16 +141,20 @@ func (adapter *HPSARaidAdaptor) ParsePhyDevs() error { adapter.parsePhyDevs(ret, isRotate) return nil } - cmd1 := GetCommand("controller", "slot=%d", fmt.Sprintf("%d", adapter.index), "ssdphysicaldrive", "all", "show", "detail") - cmd2 := GetCommand("controller", "slot=%d", fmt.Sprintf("%d", adapter.index), "physicaldrive", "all", "show", "detail") - var err error - if err = parseByCmd(cmd1, false); err != nil { - log.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err) + cmd1 := GetCommand("controller", fmt.Sprintf("slot=%d", adapter.index), "ssdphysicaldrive", "all", "show", "detail") + cmd2 := GetCommand("controller", fmt.Sprintf("slot=%d", adapter.index), "physicaldrive", "all", "show", "detail") + var err1 error + var err2 error + if err1 = parseByCmd(cmd1, false); err1 != nil { + err1 = errors.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err1) } - if err = parseByCmd(cmd2, true); err != nil { - log.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err) + if err2 = parseByCmd(cmd2, true); err2 != nil { + err2 = errors.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err2) } - return err + if err1 != nil && err2 != nil { + return errors.Errorf("ssd: %v, hdd: %v", err1, err2) + } + return nil } func (adapter *HPSARaidAdaptor) parsePhyDevs(lines []string, isRotate bool) { @@ -153,7 +165,7 @@ func (adapter *HPSARaidAdaptor) parsePhyDevs(lines []string, isRotate bool) { phydev = newHPSARaidPhyDev(m["addr"], adapter.index, isRotate) } else if phydev != nil && phydev.parseLine(line) && phydev.isComplete() { oldDev := adapter.getPhyDevByAddr(phydev.addr) - if oldDev != nil { + if oldDev == nil { adapter.devs = append(adapter.devs, phydev) } phydev = nil @@ -263,7 +275,7 @@ func (adapter *HPSARaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, c } func (adapter *HPSARaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error { - return adapter.buildRaid("10", devs, conf) + return adapter.buildRaid("1+0", devs, conf) } func (adapter *HPSARaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage) error { @@ -315,7 +327,7 @@ func (adapter *HPSARaidAdaptor) RemoveLogicVolumes() error { if err != nil { return fmt.Errorf("Failed to get logic volumes: %v", err) } - for i := len(lvs) - 1; i >= 0; i-- { + for _, i := range raid.ReverseIntArray(lvs) { if err := adapter.removeLogicVolume(i); err != nil { return fmt.Errorf("Remove %d logical volume: %v", i, err) } diff --git a/pkg/baremetal/utils/raid/megactl/megactl.go b/pkg/baremetal/utils/raid/megactl/megactl.go index d4088bbc88..8f30f1ab7f 100644 --- a/pkg/baremetal/utils/raid/megactl/megactl.go +++ b/pkg/baremetal/utils/raid/megactl/megactl.go @@ -602,7 +602,7 @@ func (adapter *MegaRaidAdaptor) RemoveLogicVolumes() error { if err != nil { return err } - for i := len(lvIdx) - 1; i >= 0; i-- { + for _, i := range raiddrivers.ReverseIntArray(lvIdx) { cmd := GetCommand("-CfgLdDel", fmt.Sprintf("-L%d", i), "-Force", fmt.Sprintf("-a%d", adapter.index)) cmds = append(cmds, cmd) } diff --git a/pkg/baremetal/utils/raid/mvcli/mvcli.go b/pkg/baremetal/utils/raid/mvcli/mvcli.go index 7b88839ecb..70dfb67704 100644 --- a/pkg/baremetal/utils/raid/mvcli/mvcli.go +++ b/pkg/baremetal/utils/raid/mvcli/mvcli.go @@ -186,7 +186,7 @@ func (adapter *MarvelRaidAdaptor) RemoveLogicVolumes() error { if err != nil { return fmt.Errorf("Failed to get logic volumes: %v", err) } - for i := len(lvs) - 1; i >= 0; i-- { + for _, i := range raid.ReverseIntArray(lvs) { if err := adapter.removeLogicVolume(i); err != nil { return fmt.Errorf("Remove %d logical volume: %v", i, err) } diff --git a/pkg/baremetal/utils/raid/raid.go b/pkg/baremetal/utils/raid/raid.go index 8965e963c7..32830a94ed 100644 --- a/pkg/baremetal/utils/raid/raid.go +++ b/pkg/baremetal/utils/raid/raid.go @@ -103,3 +103,14 @@ func GetModules(term *ssh.Client) []string { } return ret } + +func ReverseIntArray(input []int) []int { + s := make([]int, len(input)) + for i := range input { + s[i] = input[i] + } + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + return s +} diff --git a/pkg/baremetal/utils/raid/raid_test.go b/pkg/baremetal/utils/raid/raid_test.go new file mode 100644 index 0000000000..edac3acb31 --- /dev/null +++ b/pkg/baremetal/utils/raid/raid_test.go @@ -0,0 +1,46 @@ +// 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 raid + +import ( + "reflect" + "testing" +) + +func TestReverseIntArray(t *testing.T) { + tests := []struct { + name string + input []int + want []int + }{ + { + name: "empty input", + input: []int{}, + want: []int{}, + }, + { + name: "reverse", + input: []int{1, 2, 3}, + want: []int{3, 2, 1}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ReverseIntArray(tt.input); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ReverseIntArray() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/hostman/guestfs/fsdriver/linux.go b/pkg/hostman/guestfs/fsdriver/linux.go index 840915fce4..0e9f3dc603 100644 --- a/pkg/hostman/guestfs/fsdriver/linux.go +++ b/pkg/hostman/guestfs/fsdriver/linux.go @@ -371,7 +371,9 @@ func (l *sLinuxRootFs) getSerialPorts(rootFs IDiskPartition) []string { log.Errorf("Get %s error: %v", confpath, err) return nil } - return sysutils.GetSerialPorts(strings.Split(string(content), "\n")) + ttys := sysutils.GetSerialPorts(strings.Split(string(content), "\n")) + log.Infof("Get serial ports content:\n%s, find serial ttys: %#v", string(content), ttys) + return ttys } func (l *sLinuxRootFs) enableSerialConsoleInitCentos(rootFs IDiskPartition) error { @@ -390,10 +392,26 @@ exec /sbin/agetty /dev/%s 115200 vt100`, tty, tty, tty) return err } +func (l *sLinuxRootFs) enableSerialConsoleRootLogin(rootFs IDiskPartition, tty string) error { + secureTTYFile := "/etc/securetty" + content, err := rootFs.FileGetContents(secureTTYFile, false) + if err != nil { + return errors.Wrapf(err, "get contents of %s", secureTTYFile) + } + secureTTYs := sysutils.GetSecureTTYs(strings.Split(string(content), "\n")) + if utils.IsInStringArray(tty, secureTTYs) { + return nil + } + return rootFs.FilePutContents(secureTTYFile, fmt.Sprintf("\n%s", tty), true, false) +} + func (l *sLinuxRootFs) enableSerialConsoleInit(rootFs IDiskPartition) error { // https://help.ubuntu.com/community/SerialConsoleHowto var err error for _, tty := range l.getSerialPorts(rootFs) { + if err := l.enableSerialConsoleRootLogin(rootFs, tty); err != nil { + log.Errorf("Enable %s root login: %v", tty, err) + } content := fmt.Sprintf( `start on stopped rc or RUNLEVEL=[12345] stop on runlevel [!12345] @@ -415,6 +433,9 @@ func (l *sLinuxRootFs) disableSerialConsoleInit(rootFs IDiskPartition) { func (l *sLinuxRootFs) enableSerialConsoleSystemd(rootFs IDiskPartition) error { for _, tty := range l.getSerialPorts(rootFs) { + if err := l.enableSerialConsoleRootLogin(rootFs, tty); err != nil { + log.Errorf("Enable %s root login: %v", tty, err) + } sPath := fmt.Sprintf("/etc/systemd/system/getty.target.wants/getty@%s.service", tty) if rootFs.Exists(sPath, false) { rootFs.Remove(sPath, false) diff --git a/pkg/util/ssh/ssh.go b/pkg/util/ssh/ssh.go index 68bc87c819..e4c95839de 100644 --- a/pkg/util/ssh/ssh.go +++ b/pkg/util/ssh/ssh.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "github.com/pkg/errors" "golang.org/x/crypto/ssh" "yunion.io/x/log" @@ -131,8 +132,13 @@ func (s *Client) run(parseOutput bool, cmds ...string) ([]string, error) { session.Stderr = &stdErr err = session.Run(cmd) if err != nil { - err = fmt.Errorf("%q error: %v, Stderr: %s", cmd, err, stdErr.String()) - log.Errorf("%v", err) + var outputErr error + errMsg := stdErr.String() + if len(stdOut.String()) != 0 { + errMsg = fmt.Sprintf("%s %s", errMsg, stdOut.String()) + } + outputErr = errors.New(errMsg) + err = errors.Errorf("%q error: %v, cmd error: %v", cmd, err, outputErr) return nil, err } if parseOutput { diff --git a/pkg/util/sysutils/sysutils.go b/pkg/util/sysutils/sysutils.go index 439354b663..2502a3605b 100644 --- a/pkg/util/sysutils/sysutils.go +++ b/pkg/util/sysutils/sysutils.go @@ -233,10 +233,25 @@ func ParseSCSIDiskInfo(lines []string) []*types.SDiskInfo { return ParseDiskInfo(lines, baremetal.DISK_DRIVER_LINUX) } +func GetSecureTTYs(lines []string) []string { + ttys := []string{} + for _, l := range lines { + if len(l) == 0 { + continue + } + if strings.HasPrefix(l, "#") { + continue + } + ttys = append(ttys, l) + } + return ttys +} + func GetSerialPorts(lines []string) []string { + // http://wiki.networksecuritytoolkit.org/index.php/Console_Output_and_Serial_Terminals ret := []string{} for _, l := range lines { - if strings.Contains(l, "CTS") { + if strings.Contains(l, "CTS") || strings.Contains(l, "RTS") { pos := strings.Index(l, ":") if pos < 0 { continue diff --git a/pkg/util/sysutils/sysutils_test.go b/pkg/util/sysutils/sysutils_test.go index 2294d8fd59..7c4adf3516 100644 --- a/pkg/util/sysutils/sysutils_test.go +++ b/pkg/util/sysutils/sysutils_test.go @@ -273,3 +273,38 @@ func TestParseNicInfo(t *testing.T) { }) } } + +func TestGetSecureTTYs(t *testing.T) { + tests := []struct { + name string + lines []string + want []string + }{ + { + name: "empty tty", + lines: []string{"", "#comment"}, + want: []string{}, + }, + { + name: "ttys", + lines: []string{ + "tty1", + "ttyS0", + "console", + "#tty0", + }, + want: []string{ + "tty1", + "ttyS0", + "console", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetSecureTTYs(tt.lines); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetSecureTTYs() = %v, want %v", got, tt.want) + } + }) + } +}