feat: implement default limit management

Also add generic report information when no flags are specified
This commit is contained in:
Jose Diaz-Gonzalez
2019-03-13 19:57:17 -04:00
parent b36ab54b87
commit 9808ecde81
6 changed files with 215 additions and 26 deletions

View File

@@ -3,12 +3,12 @@
> New as of 0.15.0
```
dokku resource:limit --process-type <process-type,...> [RESOURCE_OPTS...] <app>
dokku resource:reserve --process-type <process-type,...> [RESOURCE_OPTS...] <app>
dokku resource:limit-defaults [RESOURCE_OPTS...]
dokku resource:reserve-defaults [RESOURCE_OPTS...]
dokku resource:limit-clear [<app>]
dokku resource:reserve-clear [<app>]
dokku resource:limit [--process-type <process-type,...>] [RESOURCE_OPTS...] <app>
dokku resource:reserve [--process-type <process-type,...>] [RESOURCE_OPTS...] <app>
dokku resource:limit-defaults [--process-type <process-type,...>] [RESOURCE_OPTS...]
dokku resource:reserve-defaults [--process-type <process-type,...>] [RESOURCE_OPTS...]
dokku resource:limit-clear [--process-type <process-type,...>] [<app>]
dokku resource:reserve-clear [--process-type <process-type,...>] [<app>]
dokku resource:report [<app>]
```
@@ -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

View File

@@ -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 \

View File

@@ -21,6 +21,8 @@ Additional commands:`
helpContent = `
resource:limit [--process-type process-type] [RESOURCE_OPTS...] <app>, Limit resources for a given app/process-type combination
resource:reserve [--process-type process-type] [RESOURCE_OPTS...] <app>, Reserve resources for a given app/process-type combination
resource:limit-defaults [--process-type process-type] [RESOURCE_OPTS...] <app>, Limit resources for a given app/process-type combination
resource:reserve-defaults [--process-type process-type] [RESOURCE_OPTS...] <app>, Reserve resources for a given app/process-type combination
`
)

View File

@@ -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())
}
}

View File

@@ -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())
}
}

View File

@@ -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]