refactor: decrease compile time for golang plugins

This change refactors the compiled golang plugins into 3 distinct binaries:

- commands: already existing
- subcommands/subcommands: entrypoint into all subcommands
- triggers: entrypoint into all triggers

It then further symlinks triggers and subcommands to the built binaries. This results in both a much faster build process as well as smaller package size.
This commit is contained in:
Jose Diaz-Gonzalez
2019-09-07 04:47:18 -04:00
parent f83a03a3dc
commit 6a7d2e5252
73 changed files with 865 additions and 1179 deletions

View File

@@ -1,6 +1,7 @@
/commands
/subcommands/*
/triggers/*
/triggers
/install
/post-delete
/report

View File

@@ -1,38 +1,6 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/limit subcommands/limit-clear subcommands/report subcommands/reserve subcommands/reserve-clear
TRIGGERS = triggers/docker-args-process-deploy triggers/install triggers/post-delete triggers/report triggers/resource-get-property
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/resource \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
BUILD = commands subcommands triggers
PLUGIN_NAME = resource
build: commands subcommands triggers
$(MAKE) triggers-copy
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands triggers docker-args-process-deploy docker-args-process-run install post-delete report resource-get-property
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
triggers: $(TRIGGERS)
triggers/%: src/triggers/*/%.go
go build $(GO_ARGS) -o $@ $<
triggers-copy:
cp triggers/* .
ln -sf docker-args-process-deploy docker-args-process-run
include ../../common.mk

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
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)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,35 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:limit", 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.CommandLimit(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,33 +0,0 @@
package main
import (
"flag"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// displays a resource report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
if strings.HasPrefix(appName, "--") {
common.LogFail("The resource:report command does not support flags without an app name")
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
resource.ReportSingleApp(appName, infoFlag)
}
return
}
resource.ReportSingleApp(appName, infoFlag)
}

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
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)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,35 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:reserve", 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.CommandReserve(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -0,0 +1,84 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
var err error
switch subcommand {
case "limit":
args := flag.NewFlagSet("resource:limit", 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.CommandLimit(args.Args(), *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)
case "report":
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
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")
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.CommandReserve(args.Args(), *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)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,14 +0,0 @@
package main
import (
"fmt"
"github.com/dokku/dokku/plugins/common"
)
// runs the install step for the resource plugin
func main() {
if err := common.PropertySetup("resource"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the resource plugin: %s", err.Error()))
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
)
// destroys the resource property for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
err := common.PropertyDestroy("resource", appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/resource"
)
// displays a resource report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(0)
resource.ReportSingleApp(appName, "")
}

View File

@@ -1,26 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// writes the resource key to stdout for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
resourceType := flag.Arg(2)
key := flag.Arg(3)
value, err := resource.GetResourceValue(appName, processType, resourceType, key)
if err != nil {
common.LogFail(err.Error())
}
fmt.Fprintln(os.Stdout, value)
}

View File

@@ -0,0 +1,46 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// main entrypoint to all triggers
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
var err error
switch trigger {
case "docker-args-process-deploy":
appName := flag.Arg(0)
processType := flag.Arg(3)
err = resource.TriggerDockerArgsProcessDeploy(appName, processType)
case "install":
err = resource.TriggerInstall()
case "post-delete":
appName := flag.Arg(0)
err = resource.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
resource.ReportSingleApp(appName, "")
case "resource-get-property":
appName := flag.Arg(0)
processType := flag.Arg(1)
resourceType := flag.Arg(2)
key := flag.Arg(3)
err = resource.TriggerResourceGetProperty(appName, processType, resourceType, key)
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -2,6 +2,8 @@ package resource
import (
"fmt"
"strings"
"github.com/dokku/dokku/plugins/common"
)
@@ -26,6 +28,27 @@ func CommandLimitClear(args []string, processType string) error {
return nil
}
// CommandReport displays a resource report for one or more apps
func CommandReport(appName string, infoFlag string) {
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
ReportSingleApp(appName, infoFlag)
}
return
}
ReportSingleApp(appName, infoFlag)
}
// CommandReserve implements resource:reserve
func CommandReserve(args []string, processType string, r Resource) error {
appName, err := getAppName(args)

View File

@@ -1,7 +1,7 @@
package main
package resource
import (
"flag"
"errors"
"fmt"
"io/ioutil"
"os"
@@ -10,26 +10,22 @@ import (
"github.com/dokku/dokku/plugins/common"
)
// outputs the process-specific docker options
func main() {
// TriggerDockerArgsProcessDeploy outputs the process-specific docker options
func TriggerDockerArgsProcessDeploy(appName string, processType string) error {
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
common.LogFail(err.Error())
return err
}
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(3)
if os.Getenv("DOKKU_OMIT_RESOURCE_ARGS") == "1" {
fmt.Print(string(stdin))
return
return nil
}
resources, err := common.PropertyGetAll("resource", appName)
if err != nil {
fmt.Print(string(stdin))
return
return nil
}
limits := make(map[string]string)
@@ -86,4 +82,29 @@ func main() {
}
fmt.Print(string(stdin))
return nil
}
// TriggerInstall runs the install step for the resource plugin
func TriggerInstall() error {
if err := common.PropertySetup("resource"); err != nil {
return errors.New(fmt.Sprintf("Unable to install the resource plugin: %s", err.Error()))
}
return nil
}
// TriggerPostDelete destroys the resource property for a given app container
func TriggerPostDelete(appName string) error {
return common.PropertyDestroy("resource", appName)
}
// writes the resource key to stdout for a given app container
func TriggerResourceGetProperty(appName string, processType string, resourceType string, key string) error {
value, err := GetResourceValue(appName, processType, resourceType, key)
if err != nil {
return err
}
fmt.Fprintln(os.Stdout, value)
return nil
}