Skip to content

Commit a9fb19d

Browse files
committed
add mpi extractor
Signed-off-by: vsoch <[email protected]>
1 parent 7b92a82 commit a9fb19d

File tree

6 files changed

+200
-10
lines changed

6 files changed

+200
-10
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,16 @@ The list command lists each extractor, and sections available for it.
8181
$ ./bin/compspec list
8282
```
8383
```console
84-
Compatibility Plugins
85-
TYPE NAME SECTION
86-
extrator kernel boot
87-
extrator kernel config
88-
extrator kernel modules
89-
extrator system cpu
90-
extrator system processor
91-
extrator system os
92-
TOTAL 6
84+
Compatibility Plugins
85+
TYPE NAME SECTION
86+
extrator kernel boot
87+
extrator kernel config
88+
extrator kernel modules
89+
extrator system cpu
90+
extrator system processor
91+
extrator system os
92+
extrator library mpi
93+
TOTAL 7
9394
```
9495

9596
Note that we will eventually add a description column - it's not really warranted yet!

pkg/utils/terminal.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package utils
2+
3+
import (
4+
"os/exec"
5+
)
6+
7+
// RunCommand runs an executable (name)
8+
func RunCommand(args []string) (string, error) {
9+
10+
executable := args[0]
11+
args = args[1:]
12+
13+
cmd := exec.Command(executable, args...)
14+
out, err := cmd.Output()
15+
if err != nil {
16+
return "", err
17+
}
18+
return string(out), nil
19+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package library
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
"regexp"
7+
"strings"
8+
9+
"github.com/supercontainers/compspec-go/pkg/extractor"
10+
"github.com/supercontainers/compspec-go/pkg/utils"
11+
)
12+
13+
const (
14+
MPIRunExec = "mpirun"
15+
)
16+
17+
var (
18+
regexIntelMPIVersion = regexp.MustCompile(`Version (.*) `)
19+
)
20+
21+
// getMPIInformation returns info on mpi versions and variant
22+
// yes, fairly janky, please improve upon! This is for a prototype
23+
func getMPIInformation() (extractor.ExtractorSection, error) {
24+
info := extractor.ExtractorSection{}
25+
26+
// Do we even have mpirun?
27+
path, err := exec.LookPath(MPIRunExec)
28+
if err != nil {
29+
return info, nil
30+
}
31+
32+
// Get output from the tool
33+
command := []string{MPIRunExec, "--version"}
34+
output, err := utils.RunCommand(command)
35+
if err != nil {
36+
return info, err
37+
}
38+
39+
// This is really simple - if we find Open MPI in a line, that's the variant
40+
lines := strings.Split(output, "\n")
41+
for _, line := range lines {
42+
line = strings.TrimSpace(line)
43+
if strings.Contains(line, "Open MPI") {
44+
info["mpi.variant"] = "OpenMPI"
45+
parts := strings.Split(line, " ")
46+
info["mpi.version"] = parts[len(parts)-1]
47+
return info, nil
48+
}
49+
50+
// Intel(R) MPI Library for Linux* OS, Version 2021.8 Build 20221129 (id: 339ec755a1)
51+
if strings.Contains(line, "Intel") {
52+
info["mpi.variant"] = "intel-mpi"
53+
match := regexIntelMPIVersion.FindStringSubmatch(line)
54+
if match != nil {
55+
parts := strings.Split(match[0], " ")
56+
info["mpi.version"] = parts[1]
57+
}
58+
return info, nil
59+
}
60+
61+
// Note that for mpich there is a LOT more metadata
62+
// Right now I'm assuming if we find Version: it's for Open MPI
63+
if strings.Contains(line, "Version:") {
64+
info["mpi.variant"] = "mpich"
65+
parts := strings.Split(line, " ")
66+
info["mpi.version"] = parts[len(parts)-1]
67+
return info, nil
68+
}
69+
70+
}
71+
72+
fmt.Println(output)
73+
fmt.Printf("%s is available at %s\n", MPIRunExec, path)
74+
return info, nil
75+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package library
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/supercontainers/compspec-go/pkg/extractor"
7+
"github.com/supercontainers/compspec-go/pkg/utils"
8+
)
9+
10+
const (
11+
ExtractorName = "library"
12+
MPISection = "mpi"
13+
)
14+
15+
var (
16+
validSections = []string{MPISection}
17+
)
18+
19+
type LibraryExtractor struct {
20+
sections []string
21+
}
22+
23+
func (e LibraryExtractor) Name() string {
24+
return ExtractorName
25+
}
26+
27+
func (e LibraryExtractor) Sections() []string {
28+
return e.sections
29+
}
30+
31+
// Validate ensures that the sections provided are in the list we know
32+
func (e LibraryExtractor) Validate() bool {
33+
invalids, valid := utils.StringArrayIsSubset(e.sections, validSections)
34+
for _, invalid := range invalids {
35+
fmt.Printf("Sections %s is not known for extractor plugin %s\n", invalid, e.Name())
36+
}
37+
return valid
38+
}
39+
40+
// Extract returns library metadata, for a set of named sections
41+
func (e LibraryExtractor) Extract(interface{}) (extractor.ExtractorData, error) {
42+
43+
sections := map[string]extractor.ExtractorSection{}
44+
data := extractor.ExtractorData{}
45+
46+
// Only extract the sections we asked for
47+
for _, name := range e.sections {
48+
if name == MPISection {
49+
section, err := getMPIInformation()
50+
if err != nil {
51+
return data, err
52+
}
53+
sections[MPISection] = section
54+
}
55+
}
56+
data.Sections = sections
57+
return data, nil
58+
}
59+
60+
// NewPlugin validates and returns a new plugin
61+
func NewPlugin(sections []string) (extractor.Extractor, error) {
62+
if len(sections) == 0 {
63+
sections = validSections
64+
}
65+
e := LibraryExtractor{sections: sections}
66+
if !e.Validate() {
67+
return nil, fmt.Errorf("plugin %s is not valid\n", e.Name())
68+
}
69+
return e, nil
70+
}

plugins/extractors/system/os.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
versionDebianFile = "/etc/debian_version"
2323
versionCentosFile = "/etc/centos-release"
2424
versionRHELFile = "/etc/redhat-release"
25+
versionRockyFile = "/etc/rocky-release"
2526
)
2627

2728
var (
@@ -30,6 +31,7 @@ var (
3031
regexVersion = regexp.MustCompile(`^VERSION_ID=(.*)$`)
3132
regexUbuntu = regexp.MustCompile(`[\( ]([\d\.]+)`)
3233
regexCentos = regexp.MustCompile(`^CentOS( Linux)? release ([\d\.]+)`)
34+
regexRocky = regexp.MustCompile(`^Rocky( Linux)? release ([\d\.]+)`)
3335
regexRHEL = regexp.MustCompile(`[\( ]([\d\.]+)`)
3436
linkerPaths = map[string]string{"amd64": linkerAMD64, "i386": linkeri386}
3537
)
@@ -112,6 +114,17 @@ func readOsRelease(prettyName string, vendor string) (string, error) {
112114
if match != nil {
113115
return match[2], nil
114116
}
117+
case "rocky":
118+
raw, err := os.ReadFile(versionRockyFile)
119+
if err != nil {
120+
return "", err
121+
}
122+
match := regexRocky.FindStringSubmatch(string(raw))
123+
if match != nil {
124+
// Rocky Linux release 9.3 (Blue Onyx)
125+
parts := strings.Split(match[2], " ")
126+
return parts[0], nil
127+
}
115128
case "rhel":
116129
raw, err := os.ReadFile(versionRHELFile)
117130
if err != nil {

plugins/plugins.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package plugins
33
import (
44
"strings"
55

6+
"github.com/supercontainers/compspec-go/plugins/extractors/library"
67
"github.com/supercontainers/compspec-go/plugins/extractors/kernel"
78
"github.com/supercontainers/compspec-go/plugins/extractors/system"
89
)
@@ -11,7 +12,8 @@ import (
1112
var (
1213
KernelExtractor = "kernel"
1314
SystemExtractor = "system"
14-
pluginNames = []string{KernelExtractor, SystemExtractor}
15+
LibraryExtractor = "library"
16+
pluginNames = []string{KernelExtractor, SystemExtractor, LibraryExtractor}
1517
)
1618

1719
// parseSections will return sections from the name string
@@ -72,6 +74,16 @@ func GetPlugins(names []string) (PluginsRequest, error) {
7274
pr := PluginRequest{Name: name, Extractor: p, Sections: sections}
7375
request = append(request, pr)
7476
}
77+
78+
if strings.HasPrefix(name, LibraryExtractor) {
79+
p, err := library.NewPlugin(sections)
80+
if err != nil {
81+
return request, err
82+
}
83+
// Save the name, the instantiated interface, and sections
84+
pr := PluginRequest{Name: name, Extractor: p, Sections: sections}
85+
request = append(request, pr)
86+
}
7587
}
7688
return request, nil
7789
}

0 commit comments

Comments
 (0)