Skip to content

Commit

Permalink
Merge branch 'add-initial-cli' into 'main'
Browse files Browse the repository at this point in the history
Add initial CLI with assert and apply commands

See merge request nvidia/cloud-native/vgpu-device-manager!7
  • Loading branch information
cdesiniotis committed Aug 30, 2022
2 parents 39d0c5f + e522444 commit f6a6a74
Show file tree
Hide file tree
Showing 20 changed files with 1,248 additions and 60 deletions.
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ include $(CURDIR)/versions.mk
BUILDIMAGE_TAG ?= golang$(GOLANG_VERSION)
BUILDIMAGE ?= vgpu-device-manager-build

CMDS := $(patsubst ./cmd/%/,%,$(sort $(dir $(wildcard ./cmd/*/))))
CMD_TARGETS := $(patsubst %,cmd-%, $(CMDS))

CHECK_TARGETS := assert-fmt vet lint ineffassign misspell
MAKE_TARGETS := binaries build check fmt lint-internal test examples cmds coverage generate $(CHECK_TARGETS)

Expand All @@ -31,6 +34,10 @@ DOCKER_TARGETS := $(patsubst %, docker-%, $(TARGETS))

GOOS := linux

cmds: $(CMD_TARGETS)
$(CMD_TARGETS): cmd-%:
GOOS=$(GOOS) go build -ldflags "-s -w" $(COMMAND_BUILD_OPTIONS) $(MODULE)/cmd/$(*)

build:
GOOS=$(GOOS) go build $(MODULE)/...

Expand Down
69 changes: 69 additions & 0 deletions api/spec/v1/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package v1

import (
"gitlab.com/nvidia/cloud-native/vgpu-device-manager/pkg/types"
)

// MatchesDeviceFilter checks a 'VGPUConfigSpec' to see if its device filter matches the provided 'deviceID'.
func (vs *VGPUConfigSpec) MatchesDeviceFilter(deviceID types.DeviceID) bool {
var deviceFilter []string
switch df := vs.DeviceFilter.(type) {
case string:
if df != "" {
deviceFilter = append(deviceFilter, df)
}
case []string:
deviceFilter = df
}

if len(deviceFilter) == 0 {
return true
}

for _, df := range deviceFilter {
newDeviceID, _ := types.NewDeviceIDFromString(df)
if newDeviceID == deviceID {
return true
}
}

return false
}

// MatchesAllDevices checks a 'VGPUConfigSpec' to see if it matches on 'all' devices.
func (vs *VGPUConfigSpec) MatchesAllDevices() bool {
switch devices := vs.Devices.(type) {
case string:
return devices == "all"
}
return false
}

// MatchesDevices checks a 'VGPUConfigSpec' to see if it matches on a device at the specified 'index'.
func (vs *VGPUConfigSpec) MatchesDevices(index int) bool {
switch devices := vs.Devices.(type) {
case []int:
for _, d := range devices {
if index == d {
return true
}
}
}
return vs.MatchesAllDevices()
}
138 changes: 138 additions & 0 deletions cmd/nvidia-vgpu-dm/apply/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package apply

import (
"fmt"

"github.com/sirupsen/logrus"
cli "github.com/urfave/cli/v2"
"gitlab.com/nvidia/cloud-native/vgpu-device-manager/cmd/nvidia-vgpu-dm/assert"
)

var log = logrus.New()

// GetLogger returns the logger for the 'apply' command
func GetLogger() *logrus.Logger {
return log
}

// Flags for the 'apply' command
type Flags struct {
assert.Flags
}

// Context containing CLI flags and the selected VGPUConfig to apply
type Context struct {
assert.Context
Flags *Flags
}

// BuildCommand builds the 'apply' command
func BuildCommand() *cli.Command {
applyFlags := Flags{}

apply := cli.Command{}
apply.Name = "apply"
apply.Usage = "Apply changes (if necessary) for a specific vGPU device configuration from a configuration file"
apply.Action = func(c *cli.Context) error {
return applyWrapper(c, &applyFlags)
}

apply.Flags = []cli.Flag{
&cli.StringFlag{
Name: "config-file",
Aliases: []string{"f"},
Usage: "Path to the configuration file",
Destination: &applyFlags.ConfigFile,
EnvVars: []string{"VGPU_DM_CONFIG_FILE"},
},
&cli.StringFlag{
Name: "selected-config",
Aliases: []string{"c"},
Usage: "The label of the vgpu-config from the config file to apply to the node",
Destination: &applyFlags.SelectedConfig,
EnvVars: []string{"VGPU_DM_SELECTED_CONFIG"},
},
}

return &apply
}

// CheckFlags ensures that any required flags are provided and ensures they are well-formed.
func CheckFlags(f *Flags) error {
return assert.CheckFlags(&f.Flags)
}

// AssertVGPUConfig reuses calls from the 'assert' subcommand to check if the vGPU devices of a particular vGPU config are currently applied.
// The 'VGPUConfig' being checked is embedded in the 'Context' struct itself.
func (c *Context) AssertVGPUConfig() error {
return assert.AssertVGPUConfig(&c.Context)
}

// ApplyVGPUConfig applies a particular vGPU config to the node.
// The 'VGPUConfig' being applied is embedded in the 'Context' struct itself.
func (c *Context) ApplyVGPUConfig() error {
return ApplyVGPUConfig(c)
}

func applyWrapper(c *cli.Context, f *Flags) error {
err := CheckFlags(f)
if err != nil {
cli.ShowSubcommandHelp(c)
return err
}

log.Debugf("Parsing config file...")
spec, err := assert.ParseConfigFile(&f.Flags)
if err != nil {
return fmt.Errorf("error parsing config file: %v", err)
}

log.Debugf("Selecting specific vGPU config...")
vgpuConfig, err := assert.GetSelectedVGPUConfig(&f.Flags, spec)
if err != nil {
return fmt.Errorf("error selecting VGPU config: %v", err)
}

if f.ValidConfig {
log.Infof("Selected vGPU device configuration is valid")
return nil
}

context := Context{
Flags: f,
Context: assert.Context{
Context: c,
Flags: &f.Flags,
VGPUConfig: vgpuConfig,
},
}

log.Debugf("Checking current vGPU device configuration...")
err = context.AssertVGPUConfig()
if err != nil {
log.Infof("Applying vGPU device configuration...")
err := context.ApplyVGPUConfig()
if err != nil {
return err
}
}

log.Infof("Selected vGPU device configuration successfully applied")
return nil
}
50 changes: 50 additions & 0 deletions cmd/nvidia-vgpu-dm/apply/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package apply

import (
"fmt"

v1 "gitlab.com/nvidia/cloud-native/vgpu-device-manager/api/spec/v1"
"gitlab.com/nvidia/cloud-native/vgpu-device-manager/cmd/nvidia-vgpu-dm/assert"
"gitlab.com/nvidia/cloud-native/vgpu-device-manager/pkg/types"
"gitlab.com/nvidia/cloud-native/vgpu-device-manager/pkg/vgpu"
)

// ApplyVGPUConfig applies the selected vGPU config to the node
func ApplyVGPUConfig(c *Context) error {
return assert.WalkSelectedVGPUConfigForEachGPU(c.VGPUConfig, func(vc *v1.VGPUConfigSpec, i int, d types.DeviceID) error {
configManager := vgpu.NewNvlibVGPUConfigManager()
current, err := configManager.GetVGPUConfig(i)
if err != nil {
return fmt.Errorf("error getting vGPU config: %v", err)
}

if current.Equals(vc.VGPUDevices) {
log.Debugf(" Skipping -- already set to desired value")
return nil
}

log.Debugf(" Updating vGPU config: %v", vc.VGPUDevices)
err = configManager.SetVGPUConfig(i, vc.VGPUDevices)
if err != nil {
return fmt.Errorf("error setting VGPU config: %v", err)
}

return nil
})
}
Loading

0 comments on commit f6a6a74

Please sign in to comment.