Skip to content

Commit 307c960

Browse files
committed
add start of parsing schemas and artifacts into graph
This will generate the first schemas graph, and then prototype adding a single artifact (image reference and compatibility schema) onto it. Some design choices that I made are to store the mapping separate from the graph, that way we can always nuke them and start fresh without needing to recreate the graph. I also model a value (the leaf of the tree) as just another node, the idea being that we could extend the graph to include some new children. This sort of breaks the model that only the schemas should be nodes, but it is not so terrible an idea because in theory adding a value as a node on the fly could represent an updated cluster state (that is not present in the schema yet). THis might not be perfect but is a great start! I will next try to extract more of the artifacts and run this for a more reasonable image selection test case. Signed-off-by: vsoch <vsoch@users.noreply.github.com>
1 parent cc18333 commit 307c960

File tree

13 files changed

+376
-66
lines changed

13 files changed

+376
-66
lines changed

cmd/compspec/check/check.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package check
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"os"
67

8+
"github.com/supercontainers/compspec-go/pkg/graph"
79
"github.com/supercontainers/compspec-go/pkg/oras"
810
"github.com/supercontainers/compspec-go/pkg/types"
911
"sigs.k8s.io/yaml"
@@ -47,17 +49,59 @@ func Run(manifestFile string, hostFields []string, mediaType string) error {
4749
}
4850
fmt.Println(manifestList)
4951

52+
// Prepare a graph with our compspec schemas added
53+
g, err := graph.NewGraph()
54+
if err != nil {
55+
return err
56+
}
57+
5058
// Load the compatibility specs into a lookup by image
5159
// This assumes we allow one image per compability spec, not sure
5260
// if there is a use case to have an image twice with two (sounds weird)
5361
lookup := map[string]types.CompatibilityRequest{}
5462
for _, item := range manifestList.Images {
63+
5564
compspec, err := oras.LoadArtifact(item.Artifact, mediaType)
5665
if err != nil {
5766
fmt.Printf("warning, there was an issue loading the artifact for %s, skipping\n", item.Name)
5867
}
5968
lookup[item.Name] = compspec
69+
70+
// Add schemas to the graph
71+
for _, schema := range compspec.Metadata.Schemas {
72+
fmt.Printf("Adding schema to graph %s\n", schema)
73+
err = g.AddSchema(schema)
74+
if err != nil {
75+
return err
76+
}
77+
}
78+
79+
// When all schemas are added to a compatibility spec, we can walk graph to add metadata attributes
80+
// Each compspec has a list of compatibilities
81+
for _, compat := range compspec.Compatibilities {
82+
83+
// If we don't have the root node, no go
84+
if !g.HasNode(compat.Name) {
85+
return fmt.Errorf("Schema root node %s is missing from the graph, missing from schemas.", compat.Name)
86+
}
87+
88+
// Now add each attribute. Each attribute turns into a child node of the attribute
89+
// and if we are missing an attribute (meaning it isn't defined in the schema)
90+
// that is an error! item.Name is the container image to link to each node
91+
// in the traversal.
92+
for key, value := range compat.Attributes {
93+
err = g.AddAttribute(item.Name, compat.Name, key, value)
94+
}
95+
}
6096
}
97+
err = g.PrintMapping()
98+
if err != nil {
99+
return err
100+
}
101+
102+
// Print the graph
103+
printme, _ := json.MarshalIndent(g.Graph, "", "\t")
104+
fmt.Println(string(printme))
61105

62106
// TODO we will take this set of requests, load them into a graph,
63107
// and then query the graph based on user preferences (the host fields)

docs/usage.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ The idea here is that you can add custom metadata fields during your build, whic
9292
"metadata": {
9393
"name": "lammps-prototype",
9494
"schemas": {
95-
"archspec.io": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
95+
"io.archspec": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
9696
"org.supercontainers": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
9797
}
9898
},
@@ -111,7 +111,7 @@ The idea here is that you can add custom metadata fields during your build, whic
111111
}
112112
},
113113
{
114-
"name": "archspec.io",
114+
"name": "io.archspec",
115115
"version": "0.0.0",
116116
"attributes": {
117117
"cpu.model": "13th Gen Intel(R) Core(TM) i5-1335U",
@@ -145,6 +145,8 @@ provide the parameters about the expected runtime host to them.
145145
./bin/compspec check -i ./examples/check-lammps/manifest.yaml
146146
```
147147

148+
TODO stopped here, need to do the whole check thing.
149+
148150
<details>
149151

150152
<summary>Example check output</summary>

examples/check-lammps/README.md

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,63 +27,56 @@ first, generating the artifact and [pushing to oras](https://oras.land/docs/how_
2727
mkdir -p ./specs
2828

2929
# arguments are the hasGpu command and the path for the artifact (relative to PWD)
30+
# TODO it looks like the arch is coming from my host, this would need to be run at build time alongside
31+
# the machine it was built on. We'd also want to make sure it's documented this is the case
3032
cmd=". /etc/profile && /tmp/data/generate-artifact.sh no /tmp/data/specs/compspec-intel-mpi-rocky-9-amd64.json"
3133
docker run -v $PWD:/tmp/data -it ghcr.io/rse-ops/lammps-matrix:intel-mpi-rocky-9-amd64 /bin/bash -c "$cmd"
3234

3335
# This generates ./specs/compspec-intel-mpi-rocky-9-amd64.json, let's push to a registry with oras
34-
oras push ghcr.io/rse-ops/lammps-matrix:intel-mpi-rocky-9-amd64-compspec-test --artifact-type application/org.supercontainers.compspec ./specs/compspec-intel-mpi-rocky-9-amd64.json:application/org.supercontainers.compspec
36+
oras push ghcr.io/rse-ops/lammps-matrix:intel-mpi-rocky-9-amd64-compspec --artifact-type application/org.supercontainers.compspec ./specs/compspec-intel-mpi-rocky-9-amd64.json:application/org.supercontainers.compspec
3537
```
3638

3739
Here is how we might see it:
3840

3941
```bash
40-
oras blob fetch --output - ghcr.io/rse-ops/lammps-matrix:intel-mpi-rocky-9-amd64-compspec@sha256:b68136afad3e4340f0dd4e09c5fea7faf12306cb4b0c1de616703b00d6ffef78
42+
oras blob fetch --output - ghcr.io/rse-ops/lammps-matrix:intel-mpi-rocky-9-amd64-compspec@sha256:376ea8d492aa8e8db312cecc34bbc729d18fc2b30e891deb2ffdffa38c7db3a5
4143
```
4244
```console
4345
{
4446
"version": "0.0.0",
4547
"kind": "CompatibilitySpec",
4648
"metadata": {
4749
"name": "lammps-prototype",
48-
"jsonSchema": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
50+
"schemas": {
51+
"io.archspec": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
52+
"org.supercontainers": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
53+
}
4954
},
5055
"compatibilities": [
5156
{
52-
"name": "org.supercontainers.mpi",
53-
"version": "0.0.0",
54-
"annotations": {
55-
"implementation": "intel-mpi",
56-
"version": "2021.8"
57-
}
58-
},
59-
{
60-
"name": "org.supercontainers.os",
61-
"version": "0.0.0",
62-
"annotations": {
63-
"name": "Rocky Linux 9.3 (Blue Onyx)",
64-
"release": "9.3",
65-
"vendor": "rocky",
66-
"version": "9.3"
67-
}
68-
},
69-
{
70-
"name": "org.supercontainers.hardware.gpu",
57+
"name": "org.supercontainers",
7158
"version": "0.0.0",
72-
"annotations": {
73-
"available": "no"
59+
"attributes": {
60+
"hardware.gpu.available": "no",
61+
"mpi.implementation": "intel-mpi",
62+
"mpi.version": "2021.8",
63+
"os.name": "Rocky Linux 9.3 (Blue Onyx)",
64+
"os.release": "9.3",
65+
"os.vendor": "rocky",
66+
"os.version": "9.3"
7467
}
7568
},
7669
{
77-
"name": "io.archspec.cpu",
70+
"name": "io.archspec",
7871
"version": "0.0.0",
79-
"annotations": {
80-
"model": "13th Gen Intel(R) Core(TM) i5-1335U",
81-
"target": "amd64",
82-
"vendor": "GenuineIntel"
72+
"attributes": {
73+
"cpu.model": "13th Gen Intel(R) Core(TM) i5-1335U",
74+
"cpu.target": "amd64",
75+
"cpu.vendor": "GenuineIntel"
8376
}
8477
}
8578
]
8679
}
8780
```
8881

89-
This is great! Next we will capture the URIs of these together in a manifest and put into our compspec tool. TBA!
82+
This is great! Next we will capture the URIs of these together in a manifest and put into our compspec tool.

examples/check-lammps/generate-artifact.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ hasGpu="${1:-no}"
55
path="${2:-./compatibility-spec.json}"
66

77
# Note that this is hard coded for amd64, for arm you would wantt o add -arm or ppc64le -ppc
8-
wget --quiet https://github.com/supercontainers/compspec-go/releases/download/1-26-2024-2/compspec
8+
wget --quiet https://github.com/supercontainers/compspec-go/releases/download/2-2-2024-1/compspec
99
chmod +x compspec
1010

1111
# Download the spec for our compatibility artifact

examples/check-lammps/specs/compspec-intel-mpi-rocky-9-amd64.json

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,32 @@
33
"kind": "CompatibilitySpec",
44
"metadata": {
55
"name": "lammps-prototype",
6-
"jsonSchema": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
6+
"schemas": {
7+
"io.archspec": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
8+
"org.supercontainers": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
9+
}
710
},
811
"compatibilities": [
912
{
10-
"name": "org.supercontainers.mpi",
11-
"version": "0.0.0",
12-
"annotations": {
13-
"implementation": "intel-mpi",
14-
"version": "2021.8"
15-
}
16-
},
17-
{
18-
"name": "org.supercontainers.os",
19-
"version": "0.0.0",
20-
"annotations": {
21-
"name": "Rocky Linux 9.3 (Blue Onyx)",
22-
"release": "9.3",
23-
"vendor": "rocky",
24-
"version": "9.3"
25-
}
26-
},
27-
{
28-
"name": "org.supercontainers.hardware.gpu",
13+
"name": "org.supercontainers",
2914
"version": "0.0.0",
30-
"annotations": {
31-
"available": "no"
15+
"attributes": {
16+
"hardware.gpu.available": "no",
17+
"mpi.implementation": "intel-mpi",
18+
"mpi.version": "2021.8",
19+
"os.name": "Rocky Linux 9.3 (Blue Onyx)",
20+
"os.release": "9.3",
21+
"os.vendor": "rocky",
22+
"os.version": "9.3"
3223
}
3324
},
3425
{
35-
"name": "io.archspec.cpu",
26+
"name": "io.archspec",
3627
"version": "0.0.0",
37-
"annotations": {
38-
"model": "13th Gen Intel(R) Core(TM) i5-1335U",
39-
"target": "amd64",
40-
"vendor": "GenuineIntel"
28+
"attributes": {
29+
"cpu.model": "13th Gen Intel(R) Core(TM) i5-1335U",
30+
"cpu.target": "amd64",
31+
"cpu.vendor": "GenuineIntel"
4132
}
4233
}
4334
]

examples/generated-compatibility-spec.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"metadata": {
55
"name": "lammps-prototype",
66
"schemas": {
7-
"archspec.io": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
7+
"io.archspec": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json",
88
"org.supercontainers": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json"
99
}
1010
},
@@ -23,7 +23,7 @@
2323
}
2424
},
2525
{
26-
"name": "archspec.io",
26+
"name": "io.archspec",
2727
"version": "0.0.0",
2828
"attributes": {
2929
"cpu.model": "13th Gen Intel(R) Core(TM) i5-1335U",

examples/lammps-experiment.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ metadata:
1010
# "Validate the namespaced attributes with these schemas"
1111
schemas:
1212
org.supercontainers: https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json
13-
archspec.io: https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json
13+
io.archspec: https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json
1414

1515
# These are not values, but mappings, from an extractor into the compspec we want
1616
compatibilities:
@@ -28,7 +28,7 @@ compatibilities:
2828
# Note that for now we are using the processor in index 0 to represent all
2929
# I'm not sure about cases where this set isn't homogeneous!
3030
# Since target is part of the container build, we will provide it
31-
- name: "archspec.io"
31+
- name: "io.archspec"
3232
version: "0.0.0"
3333
attributes:
3434
cpu.model: system.processor.0.model

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.20
55
require (
66
github.com/akamensky/argparse v1.4.0
77
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8
8+
github.com/converged-computing/jsongraph-go v0.0.0-20231221142916-249fef6889b3
89
github.com/jedib0t/go-pretty/v6 v6.5.3
910
github.com/moby/moby v25.0.0+incompatible
1011
github.com/opencontainers/image-spec v1.1.0-rc5

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK
44
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE=
55
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
66
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
7+
github.com/converged-computing/jsongraph-go v0.0.0-20231221142916-249fef6889b3 h1:frJJfyARuHmF2eohDCyltBLE6tRJKvA1shuS2aWQaf8=
8+
github.com/converged-computing/jsongraph-go v0.0.0-20231221142916-249fef6889b3/go.mod h1:+DhVyLXGVfBsfta4185jd33jqa94inshCcdvsXK2Irk=
79
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
810
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
911
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

pkg/graph/edges.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package graph
2+
3+
import (
4+
"github.com/converged-computing/jsongraph-go/jsongraph/v2/graph"
5+
)
6+
7+
// Get an edge with a specific containment (typically "contains" or "in")
8+
func getEdge(source string, dest string, containment string) graph.Edge {
9+
return graph.Edge{Source: source, Target: dest, Relation: containment}
10+
}

0 commit comments

Comments
 (0)