Skip to content

Commit 4bc7758

Browse files
Add gpuop-cfg list-images command for csv and clusterpolicy
Signed-off-by: Karthik Vetrivel <kvetrivel@nvidia.com>
1 parent f86da6d commit 4bc7758

File tree

6 files changed

+259
-146
lines changed

6 files changed

+259
-146
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
# Copyright (c), NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package images
18+
19+
import (
20+
"fmt"
21+
22+
v1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1"
23+
)
24+
25+
type OperandImage struct {
26+
Name string
27+
Image string
28+
}
29+
30+
func FromClusterPolicy(spec *v1.ClusterPolicySpec) ([]OperandImage, error) {
31+
type operand struct {
32+
name string
33+
spec interface{}
34+
}
35+
36+
operands := []operand{
37+
{"Driver", &spec.Driver},
38+
{"Toolkit", &spec.Toolkit},
39+
{"DevicePlugin", &spec.DevicePlugin},
40+
{"DCGMExporter", &spec.DCGMExporter},
41+
{"DCGM", &spec.DCGM},
42+
{"GPUFeatureDiscovery", &spec.GPUFeatureDiscovery},
43+
{"MIGManager", &spec.MIGManager},
44+
{"GPUDirectStorage", spec.GPUDirectStorage},
45+
{"VFIOManager", &spec.VFIOManager},
46+
{"SandboxDevicePlugin", &spec.SandboxDevicePlugin},
47+
{"VGPUDeviceManager", &spec.VGPUDeviceManager},
48+
}
49+
50+
var images []OperandImage
51+
for _, op := range operands {
52+
path, err := v1.ImagePath(op.spec)
53+
if err != nil {
54+
return nil, fmt.Errorf("failed to construct image path for %s: %v", op.name, err)
55+
}
56+
images = append(images, OperandImage{Name: op.name, Image: path})
57+
}
58+
59+
return images, nil
60+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
# Copyright (c), NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package images
18+
19+
import (
20+
"strings"
21+
22+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
23+
)
24+
25+
func FromCSV(csv *v1alpha1.ClusterServiceVersion) []string {
26+
var images []string
27+
28+
for _, image := range csv.Spec.RelatedImages {
29+
images = append(images, image.Image)
30+
}
31+
32+
deployment := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0]
33+
ctr := deployment.Spec.Template.Spec.Containers[0]
34+
images = append(images, ctr.Image)
35+
36+
for _, env := range ctr.Env {
37+
if !strings.HasSuffix(env.Name, "_IMAGE") {
38+
continue
39+
}
40+
images = append(images, env.Value)
41+
}
42+
43+
return images
44+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
# Copyright (c), NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package listimages
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"io"
23+
"os"
24+
25+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
26+
"github.com/sirupsen/logrus"
27+
cli "github.com/urfave/cli/v3"
28+
"sigs.k8s.io/yaml"
29+
30+
v1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1"
31+
"github.com/NVIDIA/gpu-operator/cmd/gpuop-cfg/internal/images"
32+
)
33+
34+
type options struct {
35+
input string
36+
}
37+
38+
func NewCommand(_ *logrus.Logger) *cli.Command {
39+
listImages := cli.Command{
40+
Name: "list-images",
41+
Usage: "List container images referenced in GPU Operator configuration files",
42+
}
43+
44+
listImages.Commands = []*cli.Command{
45+
buildCSV(),
46+
buildClusterPolicy(),
47+
}
48+
49+
return &listImages
50+
}
51+
52+
func buildCSV() *cli.Command {
53+
opts := options{}
54+
55+
c := cli.Command{
56+
Name: "csv",
57+
Usage: "List images from a ClusterServiceVersion manifest",
58+
Action: func(ctx context.Context, cmd *cli.Command) error {
59+
contents, err := getContents(opts.input)
60+
if err != nil {
61+
return fmt.Errorf("failed to read file: %v", err)
62+
}
63+
64+
spec := &v1alpha1.ClusterServiceVersion{}
65+
if err := yaml.Unmarshal(contents, spec); err != nil {
66+
return fmt.Errorf("failed to unmarshal csv: %v", err)
67+
}
68+
69+
for _, image := range images.FromCSV(spec) {
70+
fmt.Println(image)
71+
}
72+
return nil
73+
},
74+
}
75+
76+
c.Flags = []cli.Flag{
77+
&cli.StringFlag{
78+
Name: "input",
79+
Usage: "Specify the input file. If this is '-' the file is read from STDIN",
80+
Value: "-",
81+
Destination: &opts.input,
82+
},
83+
}
84+
85+
return &c
86+
}
87+
88+
func buildClusterPolicy() *cli.Command {
89+
opts := options{}
90+
91+
c := cli.Command{
92+
Name: "clusterpolicy",
93+
Usage: "List images from a ClusterPolicy manifest",
94+
Action: func(ctx context.Context, cmd *cli.Command) error {
95+
contents, err := getContents(opts.input)
96+
if err != nil {
97+
return fmt.Errorf("failed to read file: %v", err)
98+
}
99+
100+
spec := &v1.ClusterPolicy{}
101+
if err := yaml.Unmarshal(contents, spec); err != nil {
102+
return fmt.Errorf("failed to unmarshal clusterpolicy: %v", err)
103+
}
104+
105+
operandImages, err := images.FromClusterPolicy(&spec.Spec)
106+
if err != nil {
107+
return err
108+
}
109+
110+
for _, op := range operandImages {
111+
fmt.Println(op.Image)
112+
}
113+
return nil
114+
},
115+
}
116+
117+
c.Flags = []cli.Flag{
118+
&cli.StringFlag{
119+
Name: "input",
120+
Usage: "Specify the input file. If this is '-' the file is read from STDIN",
121+
Value: "-",
122+
Destination: &opts.input,
123+
},
124+
}
125+
126+
return &c
127+
}
128+
129+
func getContents(input string) ([]byte, error) {
130+
if input == "-" {
131+
return io.ReadAll(os.Stdin)
132+
}
133+
return os.ReadFile(input)
134+
}

cmd/gpuop-cfg/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
log "github.com/sirupsen/logrus"
2424
cli "github.com/urfave/cli/v3"
2525

26+
listimages "github.com/NVIDIA/gpu-operator/cmd/gpuop-cfg/list-images"
2627
"github.com/NVIDIA/gpu-operator/cmd/gpuop-cfg/validate"
2728
)
2829

@@ -66,6 +67,7 @@ func main() {
6667
// Define the subcommands
6768
c.Commands = []*cli.Command{
6869
validate.NewCommand(logger),
70+
listimages.NewCommand(logger),
6971
}
7072

7173
err := c.Run(context.Background(), os.Args)

0 commit comments

Comments
 (0)