From 9808ecde811269f612edd819cb402d80123617a1 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 13 Mar 2019 19:57:17 -0400 Subject: [PATCH] feat: implement default limit management Also add generic report information when no flags are specified --- docs/advanced-usage/resource-management.md | 72 ++++++++++++-- plugins/resource/Makefile | 2 +- plugins/resource/src/commands/commands.go | 2 + .../limit-defaults/limit-defaults.go | 35 +++++++ .../reserve-defaults/reserve-defaults.go | 35 +++++++ plugins/resource/subcommands.go | 95 ++++++++++++++++--- 6 files changed, 215 insertions(+), 26 deletions(-) create mode 100644 plugins/resource/src/subcommands/limit-defaults/limit-defaults.go create mode 100644 plugins/resource/src/subcommands/reserve-defaults/reserve-defaults.go diff --git a/docs/advanced-usage/resource-management.md b/docs/advanced-usage/resource-management.md index 91a9bc9c4..a646a303c 100644 --- a/docs/advanced-usage/resource-management.md +++ b/docs/advanced-usage/resource-management.md @@ -3,12 +3,12 @@ > New as of 0.15.0 ``` -dokku resource:limit --process-type [RESOURCE_OPTS...] -dokku resource:reserve --process-type [RESOURCE_OPTS...] -dokku resource:limit-defaults [RESOURCE_OPTS...] -dokku resource:reserve-defaults [RESOURCE_OPTS...] -dokku resource:limit-clear [] -dokku resource:reserve-clear [] +dokku resource:limit [--process-type ] [RESOURCE_OPTS...] +dokku resource:reserve [--process-type ] [RESOURCE_OPTS...] +dokku resource:limit-defaults [--process-type ] [RESOURCE_OPTS...] +dokku resource:reserve-defaults [--process-type ] [RESOURCE_OPTS...] +dokku resource:limit-clear [--process-type ] [] +dokku resource:reserve-clear [--process-type ] [] dokku resource:report [] ``` @@ -68,17 +68,43 @@ dokku resource:limit --cpu 100 --memory 100 --process-type worker node-js-app memory: 100 ``` +Running the `resource:limits` command without any flags will display the currently configured app reservation. + +```shell +dokku resource:limits node-js-app +=====> resource limits node-js-app information + cpu: 100 + memory: 100 + memory-swap: + network: + network-ingress: + network-egress: +``` + #### Default Resource Limits By default, Dokku does not limit any resources, though these can be specified at the server level via the `resource:limit-defaults` command. As with the `resource:limit` command, any and all resource request types can be specified. ```shell -dokku resource:limit-defaults --memory 100 +dokku resource:limit-defaults --memory 200 ``` ``` =====> Setting default resource limits - memory: 100 + memory: 200 +``` + +Running the `resource:limit-defaults` command without any flags will display the currently configured default limits. + +```shell +dokku resource:limit-defaults +=====> resource limits default information + cpu: + memory: 200 + memory-swap: + network: + network-ingress: + network-egress: ``` ### Clearing Resource Limits @@ -142,17 +168,43 @@ dokku resource:reserve --cpu 100 --memory 100 --process-type worker node-js-app memory: 100 ``` +Running the `resource:reserve` command without any flags will display the currently configured app reservation. + +```shell +dokku resource:reserve node-js-app +=====> resource reservation node-js-app information + cpu: 100 + memory: 100 + memory-swap: + network: + network-ingress: + network-egress: +``` + #### Default Resource Reservations By default, Dokku does not reserve any resources, though these can be specified at the server level via the `resource:reserve-defaults` command. As with the `resource:reserve` command, any and all resource request types can be specified. ```shell -dokku resource:reserve-defaults --memory 100 +dokku resource:reserve-defaults --memory 200 ``` ``` =====> Setting default resource reservation - memory: 100 + memory: 200 +``` + +Running the `resource:reserve-defaults` command without any flags will display the currently configured default reservation. + +```shell +dokku resource:reserve-defaults +=====> resource reservation default information + cpu: + memory: 200 + memory-swap: + network: + network-ingress: + network-egress: ``` #### Clearing Resource Reservations diff --git a/plugins/resource/Makefile b/plugins/resource/Makefile index fde0627dd..dca4586ed 100644 --- a/plugins/resource/Makefile +++ b/plugins/resource/Makefile @@ -2,7 +2,7 @@ include ../../common.mk GO_ARGS ?= -a -SUBCOMMANDS = subcommands/limit subcommands/reserve +SUBCOMMANDS = subcommands/limit subcommands/limit-defaults subcommands/reserve subcommands/reserve-defaults TRIGGERS = triggers/install triggers/post-delete build-in-docker: clean docker run --rm \ diff --git a/plugins/resource/src/commands/commands.go b/plugins/resource/src/commands/commands.go index 3a13ddf6e..0387b7735 100644 --- a/plugins/resource/src/commands/commands.go +++ b/plugins/resource/src/commands/commands.go @@ -21,6 +21,8 @@ Additional commands:` helpContent = ` resource:limit [--process-type process-type] [RESOURCE_OPTS...] , Limit resources for a given app/process-type combination resource:reserve [--process-type process-type] [RESOURCE_OPTS...] , Reserve resources for a given app/process-type combination + resource:limit-defaults [--process-type process-type] [RESOURCE_OPTS...] , Limit resources for a given app/process-type combination + resource:reserve-defaults [--process-type process-type] [RESOURCE_OPTS...] , Reserve resources for a given app/process-type combination ` ) diff --git a/plugins/resource/src/subcommands/limit-defaults/limit-defaults.go b/plugins/resource/src/subcommands/limit-defaults/limit-defaults.go new file mode 100644 index 000000000..9efaa8c0e --- /dev/null +++ b/plugins/resource/src/subcommands/limit-defaults/limit-defaults.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "os" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/resource" +) + +func main() { + args := flag.NewFlagSet("resource:limit-defaults", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to manage") + cpu := args.String("cpu", "", "cpu: The amount of cpu to limit processes by") + memory := args.String("memory", "", "memory: The amount of memory to limit processes by") + memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to limit processes by") + network := args.String("network", "", "network: The amount of network bandwidth to limit processes by") + networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to limit processes by") + networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by") + args.Parse(os.Args[2:]) + + resources := resource.Resource{ + CPU: *cpu, + Memory: *memory, + MemorySwap: *memorySwap, + Network: *network, + NetworkIngress: *networkIngress, + NetworkEgress: *networkEgress, + } + + err := resource.CommandLimitDefaults(args.Args(), *processType, resources) + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/resource/src/subcommands/reserve-defaults/reserve-defaults.go b/plugins/resource/src/subcommands/reserve-defaults/reserve-defaults.go new file mode 100644 index 000000000..f7edb412a --- /dev/null +++ b/plugins/resource/src/subcommands/reserve-defaults/reserve-defaults.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "os" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/resource" +) + +func main() { + args := flag.NewFlagSet("resource:reserve-defaults", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to manage") + cpu := args.String("cpu", "", "cpu: The amount of cpu to reserve for processes") + memory := args.String("memory", "", "memory: The amount of memory to reserve for processes") + memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to reserve for processes") + network := args.String("network", "", "network: The amount of network bandwidth to reserve for processes") + networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to reserve for processes") + networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes") + args.Parse(os.Args[2:]) + + resources := resource.Resource{ + CPU: *cpu, + Memory: *memory, + MemorySwap: *memorySwap, + Network: *network, + NetworkIngress: *networkIngress, + NetworkEgress: *networkEgress, + } + + err := resource.CommandReserveDefaults(args.Args(), *processType, resources) + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/resource/subcommands.go b/plugins/resource/subcommands.go index b53cc95b9..df014668f 100644 --- a/plugins/resource/subcommands.go +++ b/plugins/resource/subcommands.go @@ -8,15 +8,6 @@ import ( // CommandLimit implements resource:limit func CommandLimit(args []string, processType string, r Resource) (err error) { - return setRequestType(args, processType, r, "limit") -} - -// CommandReserve implements resource:reserve -func CommandReserve(args []string, processType string, r Resource) (err error) { - return setRequestType(args, processType, r, "reserve") -} - -func setRequestType(args []string, processType string, r Resource, requestType string) (err error) { var appName string appName, err = getAppName(args) if err != nil { @@ -27,6 +18,35 @@ func setRequestType(args []string, processType string, r Resource, requestType s common.LogFail(err.Error()) } + return setRequestType(appName, processType, r, "limit") +} + +// CommandLimitDefaults implements resource:limit-defaults +func CommandLimitDefaults(args []string, processType string, r Resource) (err error) { + return setRequestType("_all_", "", r, "limit") +} + +// CommandReserve implements resource:reserve +func CommandReserve(args []string, processType string, r Resource) (err error) { + var appName string + appName, err = getAppName(args) + if err != nil { + return + } + + if err = common.VerifyAppName(appName); err != nil { + common.LogFail(err.Error()) + } + + return setRequestType(appName, processType, r, "reserve") +} + +// CommandReserveDefaults implements resource:reserve-defaults +func CommandReserveDefaults(args []string, processType string, r Resource) (err error) { + return setRequestType("_all_", "", r, "reserve") +} + +func setRequestType(appName string, processType string, r Resource, requestType string) (err error) { if len(processType) == 0 { processType = "_all_" } @@ -48,21 +68,29 @@ func setRequestType(args []string, processType string, r Resource, requestType s } if !hasValues { - return errors.New("Please specify a resource to modify") + return reportRequestType(appName, processType, requestType) } - if requestType == "limit" { - common.LogInfo2Quiet(fmt.Sprintf("Setting resource limits for %v", appName)) - } else if requestType == "reserve" { - common.LogInfo2Quiet(fmt.Sprintf("Setting resource reservation for %v", appName)) + noun := "limits" + if requestType == "reserve" { + noun = "reservation" } + message := fmt.Sprintf("Setting resource %v for %v", noun, appName) + if appName == "_all_" { + message = fmt.Sprintf("Setting default resource %v", noun) + } + + if processType != "_all_" { + message = fmt.Sprintf("%v (%v)", message, processType) + } + common.LogInfo2Quiet(message) for key, value := range resources { if value != "" { common.LogVerbose(fmt.Sprintf("%v: %v", key, value)) } - property := fmt.Sprintf("%v.%v.%v", processType, requestType, key) + property := propertyKey(processType, requestType, key) err = common.PropertyWrite("resource", appName, property, value) if err != nil { return @@ -72,6 +100,43 @@ func setRequestType(args []string, processType string, r Resource, requestType s return } +func reportRequestType(appName string, processType string, requestType string) (err error) { + noun := "limits" + if requestType == "reserve" { + noun = "reservation" + } + + humanAppName := appName + if appName == "_all_" { + humanAppName = "default" + } + message := fmt.Sprintf("resource %v %v information", noun, humanAppName) + if processType != "_all_" { + message = fmt.Sprintf("%v (%v)", message, processType) + } + common.LogInfo2Quiet(message) + + resources := map[string]bool{ + "cpu": true, + "memory": true, + "memory-swap": true, + "network": true, + "network-ingress": true, + "network-egress": true, + } + + for key, _ := range resources { + property := propertyKey(processType, requestType, key) + value := common.PropertyGet("resource", appName, property) + common.LogVerbose(fmt.Sprintf("%v: %v", key, value)) + } + return nil +} + +func propertyKey(processType string, requestType string, key string) string { + return fmt.Sprintf("%v.%v.%v", processType, requestType, key) +} + func getAppName(args []string) (appName string, err error) { if len(args) >= 1 { appName = args[0]