refactor: drop global resource limits

Global limits make it harder to reason about the inheritance in the system. Rather than support global limits, Dokku should provide primitives to automatically set them on an app at provision time, or explicitly set them for an app. Both of these are likely best suited for a higher-level provisioner, or a community plugin.
This commit is contained in:
Jose Diaz-Gonzalez
2019-03-18 16:01:19 -04:00
parent 278a80cc25
commit c9bbddcfcb
7 changed files with 52 additions and 57 deletions

View File

@@ -3,11 +3,11 @@
> New as of 0.15.0
```
dokku resource:limit [--global] [--process-type <process-type,...>] [RESOURCE_OPTS...] <app>
dokku resource:reserve [--global] [--process-type <process-type,...>] [RESOURCE_OPTS...] <app>
dokku resource:limit-clear [--process-type <process-type,...>] [<app>]
dokku resource:reserve-clear [--process-type <process-type,...>] [<app>]
dokku resource:report [<app>]
resource:limit [--process-type <process-type>] [RESOURCE_OPTS...] <app> # Limit resources for a given app/process-type combination
resource:limit-clear [--process-type <process-type>] <app> # Limit resources for a given app/process-type combination
resource:report [<app>] [<flag>] # Displays a resource report for one or more apps
resource:reserve [--process-type <process-type>] [RESOURCE_OPTS...] <app> # Reserve resources for a given app/process-type combination
resource:reserve-clear [--process-type <process-type>] <app> # Reserve resources for a given app/process-type combination
```
The resource plugin is meant to allow users to limit or reserve resources for a given app/process-type combination.

View File

@@ -19,8 +19,11 @@ Manages resource settings for an app
Additional commands:`
helpContent = `
resource:limit [--global] [--process-type process-type] [RESOURCE_OPTS...] <app>, Limit resources for a given app/process-type combination
resource:reserve [--global] [--process-type process-type] [RESOURCE_OPTS...] <app>, Reserve resources for a given app/process-type combination
resource:limit [--process-type <process-type>] [RESOURCE_OPTS...] <app>, Limit resources for a given app/process-type combination
resource:limit-clear [--process-type <process-type>] <app>, Limit resources for a given app/process-type combination
resource:report [<app>] [<flag>], Displays a resource report for one or more apps
resource:reserve [--process-type <process-type>] [RESOURCE_OPTS...] <app>, Reserve resources for a given app/process-type combination
resource:reserve-clear [--process-type <process-type>] <app>, Reserve resources for a given app/process-type combination
`
)

View File

@@ -11,10 +11,9 @@ import (
func main() {
args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
global := args.Bool("global", false, "global: Whether to clear global settings or not")
args.Parse(os.Args[2:])
err := resource.CommandLimitClear(args.Args(), *processType, *global)
err := resource.CommandLimitClear(args.Args(), *processType)
if err != nil {
common.LogFail(err.Error())
}

View File

@@ -11,7 +11,6 @@ import (
func main() {
args := flag.NewFlagSet("resource:limit", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
global := args.Bool("global", false, "global: Whether to clear global settings or not")
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")
@@ -29,7 +28,7 @@ func main() {
NetworkEgress: *networkEgress,
}
err := resource.CommandLimit(args.Args(), *processType, resources, *global)
err := resource.CommandLimit(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}

View File

@@ -11,10 +11,9 @@ import (
func main() {
args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
global := args.Bool("global", false, "global: Whether to clear global settings or not")
args.Parse(os.Args[2:])
err := resource.CommandReserveClear(args.Args(), *processType, *global)
err := resource.CommandReserveClear(args.Args(), *processType)
if err != nil {
common.LogFail(err.Error())
}

View File

@@ -11,7 +11,6 @@ import (
func main() {
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
global := args.Bool("global", false, "global: Whether to clear global settings or not")
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")
@@ -29,7 +28,7 @@ func main() {
NetworkEgress: *networkEgress,
}
err := resource.CommandReserve(args.Args(), *processType, resources, *global)
err := resource.CommandReserve(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}

View File

@@ -7,8 +7,8 @@ import (
)
// CommandLimit implements resource:limit
func CommandLimit(args []string, processType string, r Resource, global bool) error {
appName, err := getAppName(args, global)
func CommandLimit(args []string, processType string, r Resource) error {
appName, err := getAppName(args)
if err != nil {
return err
}
@@ -17,8 +17,8 @@ func CommandLimit(args []string, processType string, r Resource, global bool) er
}
// CommandLimitClear implements resource:limit-clear
func CommandLimitClear(args []string, processType string, global bool) error {
appName, err := getAppName(args, global)
func CommandLimitClear(args []string, processType string) error {
appName, err := getAppName(args)
if err != nil {
return err
}
@@ -27,8 +27,8 @@ func CommandLimitClear(args []string, processType string, global bool) error {
}
// CommandReserve implements resource:reserve
func CommandReserve(args []string, processType string, r Resource, global bool) error {
appName, err := getAppName(args, global)
func CommandReserve(args []string, processType string, r Resource) error {
appName, err := getAppName(args)
if err != nil {
return err
}
@@ -37,8 +37,8 @@ func CommandReserve(args []string, processType string, r Resource, global bool)
}
// CommandReserveClear implements resource:reserve-clear
func CommandReserveClear(args []string, processType string, global bool) error {
appName, err := getAppName(args, global)
func CommandReserveClear(args []string, processType string) error {
appName, err := getAppName(args)
if err != nil {
return err
}
@@ -52,31 +52,40 @@ func clearByRequestType(appName string, processType string, requestType string)
noun = "reservation"
}
humanAppName := appName
if appName == "_all_" {
humanAppName = "default"
}
message := fmt.Sprintf("clearing %v %v", humanAppName, noun)
if processType != "_default_" {
message := fmt.Sprintf("clearing %v %v", appName, noun)
if processType != "_default_" && processType != "" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
common.LogInfo2Quiet(message)
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
}
for _, key := range resources {
property := propertyKey(processType, requestType, key)
err := common.PropertyDelete("resource", appName, property)
if processType == "" {
resources, err := common.PropertyGetAll("resource", appName)
if err != nil {
return err
}
for key, _ := range resources {
err := common.PropertyDelete("resource", appName, key)
if err != nil {
return err
}
}
} else {
resources := []string{
"cpu",
"memory",
"memory-swap",
"network",
"network-ingress",
"network-egress",
}
for _, key := range resources {
property := propertyKey(processType, requestType, key)
err := common.PropertyDelete("resource", appName, property)
if err != nil {
return err
}
}
}
return nil
}
@@ -112,10 +121,6 @@ func setRequestType(appName string, processType string, r Resource, requestType
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 != "_default_" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
@@ -142,11 +147,7 @@ func reportRequestType(appName string, processType string, requestType string) {
noun = "reservation"
}
humanAppName := appName
if appName == "_all_" {
humanAppName = "default"
}
message := fmt.Sprintf("resource %v %v information", noun, humanAppName)
message := fmt.Sprintf("resource %v %v information", noun, appName)
if processType != "_default_" {
message = fmt.Sprintf("%v (%v)", message, processType)
}
@@ -173,17 +174,12 @@ func propertyKey(processType string, requestType string, key string) string {
return fmt.Sprintf("%v.%v.%v", processType, requestType, key)
}
func getAppName(args []string, global bool) (string, error) {
appName := "_all_"
if global {
return appName, nil
}
func getAppName(args []string) (string, error) {
if len(args) < 1 {
return "", errors.New("Please specify an app to run the command on")
}
appName = args[0]
appName := args[0]
if err := common.VerifyAppName(appName); err != nil {
return "", err
}