Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⭐️ IBM AIX support #1940

Merged
merged 2 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you going to add RPM packages as well? AIX supports those and it would be very handy to expose those.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @scotthain Great idea! Lets do this as follow-up

)

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
Loading