Skip to content

Commit

Permalink
⭐️ IBM AIX support (#1940)
Browse files Browse the repository at this point in the history
* ⭐️ aix platform detection

* ⭐️ support aix services
  • Loading branch information
chris-rock authored Sep 27, 2023
1 parent 0352fc9 commit ac8dfed
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 2 deletions.
38 changes: 36 additions & 2 deletions providers/os/detector/detector_all.go
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ var linuxFamily = &PlatformResolver{
var unixFamily = &PlatformResolver{
Name: inventory.FAMILY_UNIX,
IsFamily: true,
Children: []*PlatformResolver{bsdFamily, linuxFamily, solaris},
Children: []*PlatformResolver{bsdFamily, linuxFamily, solaris, aix},
Detect: func(r *PlatformResolver, pf *inventory.Platform, conn shared.Connection) (bool, error) {
// in order to support linux container image detection, we cannot run
// processes here, lets just read files to detect a system
Expand All @@ -1019,7 +1019,6 @@ var solaris = &PlatformResolver{
Detect: func(r *PlatformResolver, pf *inventory.Platform, conn shared.Connection) (bool, error) {
osrd := NewOSReleaseDetector(conn)

// check if we got vmkernel
unames, err := osrd.unames()
if err != nil {
return false, err
Expand Down Expand Up @@ -1062,6 +1061,41 @@ var solaris = &PlatformResolver{
},
}

var aixUnameParser = regexp.MustCompile(`(\d+)\s+(\d+)\s+(.*)`)

var aix = &PlatformResolver{
Name: "aix",
IsFamily: false,
Detect: func(r *PlatformResolver, pf *inventory.Platform, conn shared.Connection) (bool, error) {
osrd := NewOSReleaseDetector(conn)

unames, err := osrd.unames()
if err != nil {
return false, err
}

if strings.Contains(strings.ToLower(unames), "aix") == false {
return false, nil
}

pf.Name = "aix"
pf.Title = "AIX"

// try to read the architecture and version
unamervp, err := osrd.command("uname -rvp")
if err == nil {
m := aixUnameParser.FindStringSubmatch(unamervp)
if len(m) == 4 {
pf.Version = m[2] + "." + m[1]
pf.Version = pf.Version
pf.Arch = m[3]
}
}

return true, nil
},
}

var esxi = &PlatformResolver{
Name: "esxi",
IsFamily: false,
Expand Down
68 changes: 68 additions & 0 deletions providers/os/resources/packages/aix_packages.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package packages

import (
"bufio"
"fmt"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"io"
"strings"
)

const (
AixPkgFormat = "bff"
)

func parseAixPackages(r io.Reader) ([]Package, error) {
pkgs := []Package{}

scanner := bufio.NewScanner(r)
i := 0
for scanner.Scan() {
line := scanner.Text()
i++

if i == 1 {
continue
}

record := strings.Split(line, ":")

// Fileset, Level, PtfID, State, Type, Description, EFIXLocked
pkgs = append(pkgs, Package{
Name: record[1],
Version: record[2],
Description: strings.TrimSpace(record[6]),
Format: AixPkgFormat,
})

}
return pkgs, nil
}

type AixPkgManager struct {
conn shared.Connection
}

func (f *AixPkgManager) Name() string {
return "AIX Package Manager"
}

func (f *AixPkgManager) Format() string {
return AixPkgFormat
}

func (f *AixPkgManager) List() ([]Package, error) {
cmd, err := f.conn.RunCommand("lslpp -cl ")
if err != nil {
return nil, fmt.Errorf("could not read freebsd package list")
}

return parseAixPackages(cmd.Stdout)
}

func (f *AixPkgManager) Available() (map[string]PackageUpdate, error) {
return map[string]PackageUpdate{}, nil
}
30 changes: 30 additions & 0 deletions providers/os/resources/packages/aix_packages_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package packages

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestParseAixPackages(t *testing.T) {
f, err := os.Open("testdata/packages_aix.txt")
require.NoError(t, err)

m, err := parseAixPackages(f)
require.Nil(t, err)
assert.Equal(t, 16, len(m), "detected the right amount of packages")

var p Package
p = Package{
Name: "X11.apps.msmit",
Version: "7.3.0.0",
Description: "AIXwindows msmit Application",
Format: "bff",
}
assert.Contains(t, m, p)
}
2 changes: 2 additions & 0 deletions providers/os/resources/packages/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ func ResolveSystemPkgManager(conn shared.Connection) (OperatingSystemPkgManager,
pm = &CosPkgManager{conn: conn}
case asset.Platform.Name == "freebsd":
pm = &FreeBSDPkgManager{conn: conn}
case asset.Platform.Name == "aix":
pm = &AixPkgManager{conn: conn}
case asset.Platform.IsFamily("linux"):
// no clear package manager for linux platform found
// most likely we land here if we have a yocto-based system
Expand Down
17 changes: 17 additions & 0 deletions providers/os/resources/packages/testdata/packages_aix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#Fileset:Level:PTF Id:State:Type:Description:EFIX Locked
/usr/lib/objrepos:ICU4C.rte:7.3.0.0::COMMITTED:I:International Components for Unicode :
/usr/lib/objrepos:Java8_64.jre:8.0.0.636::COMMITTED:I:Java SDK 64-bit Java Runtime Environment :
/usr/lib/objrepos:Java8_64.sdk:8.0.0.636::COMMITTED:I:Java SDK 64-bit Development Kit :
/usr/lib/objrepos:X11.adt.bitmaps:7.3.0.0::COMMITTED:I:AIXwindows Application Development Toolkit Bitmap Files :
/usr/lib/objrepos:X11.adt.imake:7.3.0.0::COMMITTED:I:AIXwindows Application Development Toolkit imake :
/usr/lib/objrepos:X11.adt.include:7.3.0.0::COMMITTED:I:AIXwindows Application Development Toolkit Include Files :
/usr/lib/objrepos:X11.adt.lib:7.3.0.0::COMMITTED:I:AIXwindows Application Development Toolkit Libraries :
/usr/lib/objrepos:X11.apps.aixterm:7.3.0.0::COMMITTED:I:AIXwindows aixterm Application :
/usr/lib/objrepos:X11.apps.clients:7.3.0.0::COMMITTED:I:AIXwindows Client Applications :
/usr/lib/objrepos:X11.apps.config:7.3.0.0::COMMITTED:I:AIXwindows Configuration Applications :
/usr/lib/objrepos:X11.apps.custom:7.3.0.0::COMMITTED:I:AIXwindows Customizing Tool :
/usr/lib/objrepos:X11.apps.msmit:7.3.0.0::COMMITTED:I:AIXwindows msmit Application :
/usr/lib/objrepos:X11.apps.rte:7.3.0.0::COMMITTED:I:AIXwindows Runtime Configuration Applications :
/usr/lib/objrepos:X11.apps.util:7.3.0.0::COMMITTED:I:AIXwindows Utility Applications :
/usr/lib/objrepos:X11.apps.xdm:7.3.0.0::COMMITTED:I:AIXwindows xdm Application :
/usr/lib/objrepos:X11.apps.xterm:7.3.0.0::COMMITTED:I:AIXwindows xterm Application :
66 changes: 66 additions & 0 deletions providers/os/resources/services/aixlssrc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package services

import (
"bufio"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"io"
"regexp"
)

type AixServiceManager struct {
conn shared.Connection
}

func (s *AixServiceManager) Name() string {
return "System Resource Controller"
}

func (s *AixServiceManager) List() ([]*Service, error) {
cmd, err := s.conn.RunCommand("lssrc -a")
if err != nil {
return nil, err
}

entries := parseLssrc(cmd.Stdout)
services := make([]*Service, len(entries))
for i, entry := range entries {
services[i] = &Service{
Name: entry.Subsystem,
Enabled: entry.Status == "active",
Installed: true,
Running: entry.Status == "active",
Type: "aix",
}
}
return services, nil
}

type lssrcEntry struct {
Subsystem string
Group string
PID string
Status string
}

var lssrcRegex = regexp.MustCompile(`^\s([\w.-]+)(\s+[\w]+\s+){0,1}([\d]+){0,1}\s+([\w]+)$`)

func parseLssrc(input io.Reader) []lssrcEntry {
entries := []lssrcEntry{}
scanner := bufio.NewScanner(input)
for scanner.Scan() {
line := scanner.Text()
m := lssrcRegex.FindStringSubmatch(line)
if len(m) == 5 {
entries = append(entries, lssrcEntry{
Subsystem: m[1],
Group: m[2],
PID: m[3],
Status: m[4],
})
}
}
return entries
}
35 changes: 35 additions & 0 deletions providers/os/resources/services/aixlssrc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package services

import (
"github.com/stretchr/testify/assert"
"strings"
"testing"
)

func TestLssrcParse(t *testing.T) {
testOutput := `
Subsystem Group PID Status
syslogd ras 3932558 active
aso 4653462 active
biod nfs 5046692 active
rpc.lockd nfs 5636560 active
qdaemon spooler 5767630 active
ctrmc rsct 5439966 active
pmperfrec 6881768 active
IBM.HostRM rsct_rm 5898530 active
automountd autofs 7340402 active
lpd spooler inoperative
nimsh nimclient inoperative
nimhttp inoperative
timed tcpip inoperative
`
entries := parseLssrc(strings.NewReader(testOutput))
assert.Equal(t, 13, len(entries), "detected the right amount of services")
assert.Equal(t, "syslogd", entries[0].Subsystem, "service name detected")
assert.Equal(t, "active", entries[0].Status, "service status detected")
assert.Equal(t, "timed", entries[12].Subsystem, "service name detected")
assert.Equal(t, "inoperative", entries[12].Status, "service status detected")
}
2 changes: 2 additions & 0 deletions providers/os/resources/services/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ func ResolveManager(conn shared.Connection) (OSServiceManager, error) {
osm = &AlpineOpenrcServiceManager{conn: conn}
case asset.Platform.Name == "cos":
osm = ResolveSystemdServiceManager(conn)
case asset.Platform.Name == "aix":
osm = &AixServiceManager{conn: conn}
case asset.Platform.Name == "kali": // debian based with versions from 2015 onwards being systemd based
osm = ResolveSystemdServiceManager(conn)
}
Expand Down

0 comments on commit ac8dfed

Please sign in to comment.