Skip to content

Commit 8ccc044

Browse files
authored
Merge pull request #27 from compspec/wip-for-rainbow-register
wip: integration with rainbow
2 parents 2380578 + 6c8b8da commit 8ccc044

File tree

12 files changed

+86
-72
lines changed

12 files changed

+86
-72
lines changed

cmd/compspec/create/artifact.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
package create
22

33
import (
4-
"strings"
5-
4+
"github.com/compspec/compspec-go/pkg/plugin"
65
"github.com/compspec/compspec-go/plugins/creators/artifact"
76
)
87

98
// Artifact will create a compatibility artifact based on a request in YAML
109
// TODO likely want to refactor this into a proper create plugin
1110
func Artifact(specname string, fields []string, saveto string, allowFail bool) error {
1211

13-
// This is janky, oh well
14-
allowFailFlag := "false"
15-
if allowFail {
16-
allowFailFlag = "true"
17-
}
18-
1912
// assemble options for node creator
2013
creator, err := artifact.NewPlugin()
2114
if err != nil {
2215
return err
2316
}
24-
options := map[string]string{
25-
"specname": specname,
26-
"fields": strings.Join(fields, "||"),
27-
"saveto": saveto,
28-
"allowFail": allowFailFlag,
17+
18+
options := plugin.PluginOptions{
19+
StrOpts: map[string]string{
20+
"specname": specname,
21+
"saveto": saveto,
22+
},
23+
BoolOpts: map[string]bool{
24+
"allowFail": allowFail,
25+
},
26+
ListOpts: map[string][]string{
27+
"fields": fields,
28+
},
2929
}
3030
return creator.Create(options)
3131
}

cmd/compspec/create/nodes.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package create
22

33
import (
4+
"github.com/compspec/compspec-go/pkg/plugin"
45
"github.com/compspec/compspec-go/plugins/creators/cluster"
56
)
67

@@ -14,10 +15,12 @@ func Nodes(nodesDir, clusterName, nodeOutFile string) error {
1415
if err != nil {
1516
return err
1617
}
17-
options := map[string]string{
18-
"nodes-dir": nodesDir,
19-
"cluster-name": clusterName,
20-
"node-outfile": nodeOutFile,
18+
options := plugin.PluginOptions{
19+
StrOpts: map[string]string{
20+
"nodes-dir": nodesDir,
21+
"cluster-name": clusterName,
22+
"node-outfile": nodeOutFile,
23+
},
2124
}
2225
return creator.Create(options)
2326
}

docs/rainbow/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ compspec extract --name library --name nfd[cpu,memory,network,storage,system] --
4444
Now we are going to give compspec the directory, and ask it to create nodes. This will be in JSON graph format. This outputs to the terminal:
4545

4646
```bash
47-
compspec create nodes --cluster-name cluster-red --node-dir ./docs/rainbow/cluster/
47+
compspec create nodes --cluster-name cluster-red --node-dir ./docs/rainbow/cluster/ --nodes-output ./cluster-nodes.json
4848
```

pkg/graph/cluster.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"os"
7+
"strings"
78

89
"github.com/compspec/compspec-go/pkg/utils"
910
"github.com/converged-computing/jsongraph-go/jsongraph/metadata"
@@ -20,6 +21,9 @@ type ClusterGraph struct {
2021
// Top level counter for node labels (JGF v2) that maps to ids (JGF v1)
2122
nodeCounter int32
2223

24+
// Easy reference to root name
25+
rootName string
26+
2327
// Counters for specific resource types (e.g., rack, node)
2428
resourceCounters map[string]int32
2529
}
@@ -41,7 +45,7 @@ func (c *ClusterGraph) SaveGraph(path string) error {
4145
fmt.Printf("Graph %s already exists, will not overwrite\n", path)
4246
return nil
4347
}
44-
content, err := json.MarshalIndent(c.Graph, "", " ")
48+
content, err := json.MarshalIndent(c, "", " ")
4549
if err != nil {
4650
return err
4751
}
@@ -55,10 +59,15 @@ func (c *ClusterGraph) SaveGraph(path string) error {
5559

5660
// Path gets a new path
5761
func getNodePath(root, subpath string) string {
62+
var path string
5863
if subpath == "" {
59-
return fmt.Sprintf("/%s", root)
64+
path = fmt.Sprintf("/%s", root)
65+
} else {
66+
path = fmt.Sprintf("/%s/%s", root, subpath)
6067
}
61-
return fmt.Sprintf("/%s/%s", root, subpath)
68+
// Hack to allow for imperfection of slash placement
69+
path = strings.ReplaceAll(path, "//", "/")
70+
return path
6271
}
6372

6473
// AddNode adds a node to the graph
@@ -69,8 +78,9 @@ func (c *ClusterGraph) AddNode(
6978
size int32,
7079
exclusive bool,
7180
unit string,
81+
path string,
7282
) *graph.Node {
73-
node := c.getNode(resource, name, size, exclusive, unit)
83+
node := c.getNode(resource, name, size, exclusive, unit, path)
7484
c.Graph.Nodes[*node.Label] = *node
7585
return node
7686
}
@@ -88,6 +98,7 @@ func (c *ClusterGraph) getNode(
8898
size int32,
8999
exclusive bool,
90100
unit string,
101+
path string,
91102
) *graph.Node {
92103

93104
// Get the identifier for the resource type
@@ -101,24 +112,26 @@ func (c *ClusterGraph) getNode(
101112

102113
// The id in the metadata is the counter for that resource type
103114
resourceCounter := fmt.Sprintf("%d", counter)
115+
nameWithCount := fmt.Sprintf("%s%d", name, counter)
104116

105117
// The resource name is the type + the resource counter
106-
resourceName := fmt.Sprintf("%s%d", name, counter)
118+
// path should be assembled from parents up to this node
119+
resourceName := fmt.Sprintf("%s/%s%d", path, name, counter)
107120

108121
// New Metadata with expected fluxion data
109122
m := metadata.Metadata{}
110123
m.AddElement("type", resource)
111124
m.AddElement("basename", name)
112125
m.AddElement("id", resourceCounter)
113-
m.AddElement("name", resourceName)
126+
m.AddElement("name", nameWithCount)
114127

115128
// uniq_id should be the same as the label, but as an integer
116129
m.AddElement("uniq_id", count)
117130
m.AddElement("rank", -1)
118131
m.AddElement("exclusive", exclusive)
119132
m.AddElement("unit", unit)
120133
m.AddElement("size", size)
121-
m.AddElement("paths", map[string]string{"containment": getNodePath(name, "")})
134+
m.AddElement("paths", map[string]string{"containment": getNodePath(c.rootName, resourceName)})
122135

123136
// Update the resource counter
124137
counter += 1
@@ -154,7 +167,7 @@ func NewClusterGraph(name string) (ClusterGraph, error) {
154167
m.AddElement("exclusive", false)
155168
m.AddElement("unit", "")
156169
m.AddElement("size", 1)
157-
m.AddElement("paths", map[string]string{"containment": getNodePath(name, "")})
170+
m.AddElement("paths", map[string]string{"containment": getNodePath(clusterName, "")})
158171

159172
// Root cluster node
160173
label := "0"
@@ -166,7 +179,7 @@ func NewClusterGraph(name string) (ClusterGraph, error) {
166179
// Create a new cluster!
167180
// Start counting at 1 - index 0 is the cluster root
168181
resourceCounters := map[string]int32{"cluster": int32(1)}
169-
cluster := ClusterGraph{g, name, 1, resourceCounters}
182+
cluster := ClusterGraph{g, name, 1, clusterName, resourceCounters}
170183

171184
return cluster, nil
172185
}

pkg/plugin/plugin.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,16 @@ type PluginInterface interface {
2424
Sections() []string
2525

2626
// Creators take a map of named options
27-
Create(map[string]string) error
27+
Create(PluginOptions) error
28+
}
29+
30+
// PluginOptions allow packaging named values of different types
31+
// This is an alternative to using interfaces.
32+
type PluginOptions struct {
33+
BoolOpts map[string]bool
34+
StrOpts map[string]string
35+
IntOpts map[string]int32
36+
ListOpts map[string][]string
2837
}
2938

3039
// ExtractorData is returned by an extractor

plugins/creators/artifact/artifact.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package artifact
33
import (
44
"fmt"
55
"os"
6-
"strings"
76

87
"github.com/compspec/compspec-go/pkg/plugin"
98
"github.com/compspec/compspec-go/pkg/types"
@@ -37,21 +36,16 @@ func (c ArtifactCreator) IsCreator() bool { return true }
3736
func (c ArtifactCreator) IsExtractor() bool { return false }
3837

3938
// Create generates the desired output
40-
func (c ArtifactCreator) Create(options map[string]string) error {
39+
func (c ArtifactCreator) Create(options plugin.PluginOptions) error {
4140

4241
// unwrap options (we can be sure they are at least provided)
43-
specname := options["specname"]
44-
saveto := options["saveto"]
45-
fieldsCombined := options["fields"]
46-
fields := strings.Split(fieldsCombined, "||")
42+
specname := options.StrOpts["specname"]
43+
saveto := options.StrOpts["saveto"]
44+
fields := options.ListOpts["fields"]
4745

4846
// This is uber janky. We could use interfaces
4947
// But I just feel so lazy right now
50-
allowFailFlag := options["allowFail"]
51-
allowFail := false
52-
if allowFailFlag == "true" {
53-
allowFail = true
54-
}
48+
allowFail := options.BoolOpts["allowFail"]
5549

5650
// Cut out early if a spec not provided
5751
if specname == "" {

plugins/creators/cluster/cluster.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ func (c ClusterCreator) IsCreator() bool { return true }
3838
func (c ClusterCreator) IsExtractor() bool { return false }
3939

4040
// Create generates the desired output
41-
func (c ClusterCreator) Create(options map[string]string) error {
41+
func (c ClusterCreator) Create(options plugin.PluginOptions) error {
4242

4343
// unwrap options (we can be sure they are at least provided)
44-
nodesDir := options["nodes-dir"]
45-
clusterName := options["cluster-name"]
46-
nodeOutFile := options["node-outfile"]
44+
nodesDir := options.StrOpts["nodes-dir"]
45+
clusterName := options.StrOpts["cluster-name"]
46+
nodeOutFile := options.StrOpts["node-outfile"]
4747

4848
// Read in each node into a plugins.Result
4949
// Results map[string]plugin.PluginData `json:"extractors,omitempty"`
@@ -92,7 +92,8 @@ func (c ClusterCreator) Create(options map[string]string) error {
9292
// size (usually 1)
9393
// exclusive (usually false)
9494
// unit (usually empty or an amount)
95-
rack := *g.AddNode("rack", "rack", 1, false, "")
95+
// path (root and current resource path are added, so empty here)
96+
rack := *g.AddNode("rack", "rack", 1, false, "", "")
9697

9798
// Connect the rack to the parent, both ways.
9899
// I think this is because fluxion is Depth First and Upwards (dfu)
@@ -145,7 +146,8 @@ func (c ClusterCreator) Create(options map[string]string) error {
145146
}
146147

147148
// First add the rack -> node
148-
node := *g.AddNode("node", "node", 1, false, "")
149+
// We only have one rack here, so hard coded id for now
150+
node := *g.AddNode("node", "node", 1, false, "", "rack0")
149151
g.AddEdge(rack, node, "contains")
150152
g.AddEdge(node, rack, "in")
151153

@@ -171,21 +173,23 @@ func (c ClusterCreator) Create(options map[string]string) error {
171173
// TODO we should also get this in better detail, physical vs logical cores
172174
items := []string{}
173175
for i := 0; i < cpuCount; i++ {
174-
items = append(items, fmt.Sprintf("%s", i))
176+
items = append(items, fmt.Sprintf("%d", i))
175177
}
176178
// Mapping of socket to cores
177179
chunks := utils.Chunkify(items, socketCount)
178180
for _, chunk := range chunks {
179181

180182
// Create each socket attached to the node
181183
// rack -> node -> socket
182-
socketNode := *g.AddNode("socket", "socket", 1, false, "")
184+
path := fmt.Sprintf("rack0/node%s", *node.Label)
185+
socketNode := *g.AddNode("socket", "socket", 1, false, "", path)
183186
g.AddEdge(node, socketNode, "contains")
184187
g.AddEdge(socketNode, node, "in")
185188

186189
// Create each core attached to the socket
187190
for _, _ = range chunk {
188-
coreNode := *g.AddNode("core", "core", 1, false, "")
191+
path := fmt.Sprintf("rack0/node%s/socket%s", *node.Label, *socketNode.Label)
192+
coreNode := *g.AddNode("core", "core", 1, false, "", path)
189193
g.AddEdge(socketNode, coreNode, "contains")
190194
g.AddEdge(coreNode, socketNode, "in")
191195

plugins/extractors/kernel/kernel.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@ func (e KernelExtractor) Description() string {
2727
return ExtractorDescription
2828
}
2929

30-
func (e KernelExtractor) Create(options map[string]string) error {
31-
return nil
32-
}
33-
func (e KernelExtractor) IsCreator() bool { return false }
34-
func (e KernelExtractor) IsExtractor() bool { return true }
30+
func (e KernelExtractor) Create(plugin.PluginOptions) error { return nil }
31+
func (e KernelExtractor) IsCreator() bool { return false }
32+
func (e KernelExtractor) IsExtractor() bool { return true }
3533

3634
func (e KernelExtractor) Sections() []string {
3735
return e.sections

plugins/extractors/library/library.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,9 @@ func (e LibraryExtractor) Description() string {
3333
return ExtractorDescription
3434
}
3535

36-
func (e LibraryExtractor) Create(options map[string]string) error {
37-
return nil
38-
}
39-
40-
func (e LibraryExtractor) IsCreator() bool { return false }
41-
func (e LibraryExtractor) IsExtractor() bool { return true }
36+
func (e LibraryExtractor) Create(plugin.PluginOptions) error { return nil }
37+
func (e LibraryExtractor) IsCreator() bool { return false }
38+
func (e LibraryExtractor) IsExtractor() bool { return true }
4239

4340
// Validate ensures that the sections provided are in the list we know
4441
func (e LibraryExtractor) Validate() bool {

plugins/extractors/nfd/nfd.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,9 @@ func (e NFDExtractor) Description() string {
6969
return ExtractorDescription
7070
}
7171

72-
func (e NFDExtractor) Create(options map[string]string) error {
73-
return nil
74-
}
75-
76-
func (e NFDExtractor) IsCreator() bool { return false }
77-
func (e NFDExtractor) IsExtractor() bool { return true }
72+
func (e NFDExtractor) Create(plugin.PluginOptions) error { return nil }
73+
func (e NFDExtractor) IsCreator() bool { return false }
74+
func (e NFDExtractor) IsExtractor() bool { return true }
7875

7976
// Validate ensures that the sections provided are in the list we know
8077
func (e NFDExtractor) Validate() bool {

0 commit comments

Comments
 (0)