feat: simplify flag parsing in resource plugin

Commands should be written such that they take arguments as is.
This commit is contained in:
Jose Diaz-Gonzalez
2020-05-28 20:03:47 -04:00
parent 6636c48838
commit 94aa67d494
3 changed files with 156 additions and 148 deletions

View File

@@ -0,0 +1,130 @@
package resource
import (
"fmt"
"github.com/dokku/dokku/plugins/common"
)
func clearByResourceType(appName string, processType string, resourceType string) {
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("clearing %v %v", appName, noun)
if processType != "_default_" && processType != "" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
if processType == "" {
resources, err := common.PropertyGetAll("resource", appName)
if err != nil {
return
}
for key := range resources {
common.PropertyDelete("resource", appName, key)
}
} else {
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
"nvidia-gpu",
}
for _, key := range resources {
property := propertyKey(processType, resourceType, key)
common.PropertyDelete("resource", appName, property)
}
}
}
func setResourceType(appName string, processType string, r Resource, resourceType string) error {
if len(processType) == 0 {
processType = "_default_"
}
resources := map[string]string{
"cpu": r.CPU,
"memory": r.Memory,
"memory-swap": r.MemorySwap,
"network": r.Network,
"network-ingress": r.NetworkIngress,
"network-egress": r.NetworkEgress,
"nvidia-gpu": r.NvidiaGPU,
}
hasValues := false
for _, value := range resources {
if value != "" {
hasValues = true
}
}
if !hasValues {
reportResourceType(appName, processType, resourceType)
return nil
}
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("Setting resource %v for %v", noun, appName)
if processType != "_default_" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
for key, value := range resources {
if value == "" {
continue
}
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
property := propertyKey(processType, resourceType, key)
err := common.PropertyWrite("resource", appName, property, value)
if err != nil {
return err
}
}
return nil
}
func reportResourceType(appName string, processType string, resourceType string) {
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("resource %v %v information", noun, appName)
if processType == "_default_" {
message = fmt.Sprintf("%v [defaults]", message)
} else {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
"nvidia-gpu",
}
for _, key := range resources {
property := propertyKey(processType, resourceType, key)
value := common.PropertyGet("resource", appName, property)
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
}
return
}

View File

@@ -28,6 +28,7 @@ func main() {
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by")
nvidiaGpu := args.String("nvidia-gpu", "", "nvidia-gpu: The number of Nvidia GPUs to limit a process to")
args.Parse(os.Args[2:])
appName := args.Arg(0)
resources := resource.Resource{
CPU: *cpu,
@@ -39,17 +40,19 @@ func main() {
NvidiaGPU: *nvidiaGpu,
}
err = resource.CommandLimit(args.Args(), *processType, resources)
err = resource.CommandLimit(appName, *processType, resources)
case "limit-clear":
args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err = resource.CommandLimitClear(args.Args(), *processType)
appName := args.Arg(0)
err = resource.CommandLimitClear(appName, *processType)
case "report":
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
resource.CommandReport(appName, infoFlag)
args := flag.NewFlagSet("resource:report", flag.ExitOnError)
args.Parse(os.Args[2:])
appName := args.Arg(0)
infoFlag := args.Arg(1)
err = resource.CommandReport(appName, infoFlag)
case "reserve":
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
@@ -61,6 +64,7 @@ func main() {
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes")
nvidiaGpu := args.String("nvidia-gpu", "", "nvidia-gpu: The number of Nvidia GPUs to resource for a process")
args.Parse(os.Args[2:])
appName := args.Arg(0)
resources := resource.Resource{
CPU: *cpu,
@@ -72,12 +76,13 @@ func main() {
NvidiaGPU: *nvidiaGpu,
}
err = resource.CommandReserve(args.Args(), *processType, resources)
err = resource.CommandReserve(appName, *processType, resources)
case "reserve-clear":
args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err = resource.CommandReserveClear(args.Args(), *processType)
appName := args.Arg(0)
err = resource.CommandReserveClear(appName, *processType)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}

View File

@@ -1,27 +1,25 @@
package resource
import (
"fmt"
"errors"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// CommandLimit implements resource:limit
func CommandLimit(args []string, processType string, r Resource) error {
appName, err := getAppName(args)
if err != nil {
return err
func CommandLimit(appName string, processType string, r Resource) error {
if appName == "" {
return errors.New("Please specify an app to run the command on")
}
return setResourceType(appName, processType, r, "limit")
}
// CommandLimitClear implements resource:limit-clear
func CommandLimitClear(args []string, processType string) error {
appName, err := getAppName(args)
if err != nil {
return err
func CommandLimitClear(appName string, processType string) error {
if appName == "" {
return errors.New("Please specify an app to run the command on")
}
clearByResourceType(appName, processType, "limit")
@@ -52,145 +50,20 @@ func CommandReport(appName string, infoFlag string) error {
}
// CommandReserve implements resource:reserve
func CommandReserve(args []string, processType string, r Resource) error {
appName, err := getAppName(args)
if err != nil {
return err
func CommandReserve(appName string, processType string, r Resource) error {
if appName == "" {
return errors.New("Please specify an app to run the command on")
}
return setResourceType(appName, processType, r, "reserve")
}
// CommandReserveClear implements resource:reserve-clear
func CommandReserveClear(args []string, processType string) error {
appName, err := getAppName(args)
if err != nil {
return err
func CommandReserveClear(appName string, processType string) error {
if appName == "" {
return errors.New("Please specify an app to run the command on")
}
clearByResourceType(appName, processType, "reserve")
return nil
}
func clearByResourceType(appName string, processType string, resourceType string) {
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("clearing %v %v", appName, noun)
if processType != "_default_" && processType != "" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
if processType == "" {
resources, err := common.PropertyGetAll("resource", appName)
if err != nil {
return
}
for key := range resources {
common.PropertyDelete("resource", appName, key)
}
} else {
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
"nvidia-gpu",
}
for _, key := range resources {
property := propertyKey(processType, resourceType, key)
common.PropertyDelete("resource", appName, property)
}
}
}
func setResourceType(appName string, processType string, r Resource, resourceType string) error {
if len(processType) == 0 {
processType = "_default_"
}
resources := map[string]string{
"cpu": r.CPU,
"memory": r.Memory,
"memory-swap": r.MemorySwap,
"network": r.Network,
"network-ingress": r.NetworkIngress,
"network-egress": r.NetworkEgress,
"nvidia-gpu": r.NvidiaGPU,
}
hasValues := false
for _, value := range resources {
if value != "" {
hasValues = true
}
}
if !hasValues {
reportResourceType(appName, processType, resourceType)
return nil
}
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("Setting resource %v for %v", noun, appName)
if processType != "_default_" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
for key, value := range resources {
if value == "" {
continue
}
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
property := propertyKey(processType, resourceType, key)
err := common.PropertyWrite("resource", appName, property, value)
if err != nil {
return err
}
}
return nil
}
func reportResourceType(appName string, processType string, resourceType string) {
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"
}
message := fmt.Sprintf("resource %v %v information", noun, appName)
if processType == "_default_" {
message = fmt.Sprintf("%v [defaults]", message)
} else {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
"nvidia-gpu",
}
for _, key := range resources {
property := propertyKey(processType, resourceType, key)
value := common.PropertyGet("resource", appName, property)
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
}
return
}