diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index b3e9e9030..ab46dece2 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -78,7 +78,7 @@ The following config variables have special meanings and can be set in a variety | Name | Default | How to modify | Description | | ------------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | `DOKKU_ROOT` | `~dokku` | `/etc/environment` | The root directory where dokku will store application repositories, as well as certain configuration files. | -| `DOKKU_IMAGE` | `gliderlabs/herokuish` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | The default image to use when building herokuish containers. | +| `DOKKU_IMAGE` | `gliderlabs/herokuish` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | The default image to use when building herokuish containers. Deprecated in favor of using `buildpacks:stack-set` | | `DOKKU_LIB_ROOT` | `/var/lib/dokku` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | The directory where plugins, certain data, and general configuration is stored. | | `PLUGIN_PATH` | `$DOKKU_LIB_ROOT/plugins"` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | The top-level directory where plugins are stored. | | `PLUGIN_AVAILABLE_PATH` | `$PLUGIN_PATH/available"` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | The directory that holds all available plugins, including core. | diff --git a/docs/deployment/methods/herokuish-buildpacks.md b/docs/deployment/methods/herokuish-buildpacks.md index e72d3236c..f9fc632a7 100644 --- a/docs/deployment/methods/herokuish-buildpacks.md +++ b/docs/deployment/methods/herokuish-buildpacks.md @@ -9,6 +9,7 @@ buildpacks:list # List all buildpacks for an app buildpacks:remove # Remove a buildpack set on the app buildpacks:report [] [] # Displays a buildpack report for one or more apps buildpacks:set [--index 1] # Set new app buildpack at a given position defaulting to the first buildpack if no index is specified +buildpacks:stacks-set # Sets the stack of an app ``` > Warning: If using the `buildpacks` plugin, be sure to unset any `BUILDPACK_URL` and remove any such entries from a committed `.env` file. A specified `BUILDPACK_URL` will always override a `.buildpacks` file or the buildpacks plugin. @@ -123,6 +124,32 @@ The `buildpacks:clear` command can be used to clear all configured buildpacks fo dokku buildpacks:clear node-js-app ``` +### Customizing the Buildpack stack + +> New as of 0.23.0 + +The default stack in use by Herokuish buildpacks in Dokku is based on `gliderlabs/herokuish`. Typically, this is installed via an OS package which pulls the requisite Docker image. Users may desire to switch the stack to a custom version, either to update the stack operating system or to customize packages included with the stack. This can be performed via teh `buildpacks:stack-set` command. + +```shell +dokku buildpacks:stack-set node-js-app gliderlabs/herokuish:latest +``` + +The specified stack can also be unset by omitting the name of the stack when calling `buildpacks:stack-set`. + +```shell +dokku buildpacks:stack-set node-js-app +``` + +Finally, stacks can be set or unset globally as a fallback. This will take precedence over a globally set `DOKKU_IMAGE` environment variable (`gliderlabs/herokuish:latest` by default). + +```shell +# set globally +dokku buildpacks:stack-set --global gliderlabs/herokuish:latest + +# unset globally +dokku buildpacks:stack-set --global +``` + ### Displaying buildpack reports for an app You can get a report about the app's buildpacks status using the `buildpacks:report` command: @@ -133,11 +160,20 @@ dokku buildpacks:report ``` =====> node-js-app buildpacks information - Buildpacks list: https://github.com/heroku/heroku-buildpack-nodejs.git + Buildpacks computed stack: gliderlabs/herokuish:v0.5.23-20 + Buildpacks global stack: gliderlabs/herokuish:latest + Buildpacks list: https://github.com/heroku/heroku-buildpack-nodejs.git + Buildpacks stack: gliderlabs/herokuish:v0.5.23-20 =====> python-sample buildpacks information - Buildpacks list: https://github.com/heroku/heroku-buildpack-nodejs.git,https://github.com/heroku/heroku-buildpack-python.git + Buildpacks computed stack: gliderlabs/herokuish:v0.5.23-20 + Buildpacks global stack: gliderlabs/herokuish:latest + Buildpacks list: https://github.com/heroku/heroku-buildpack-nodejs.git,https://github.com/heroku/heroku-buildpack-python.git + Buildpacks stack: =====> ruby-sample buildpacks information + Buildpacks computed stack: gliderlabs/herokuish:v0.5.23-20 + Buildpacks global stack: gliderlabs/herokuish:latest Buildpacks list: + Buildpacks stack: ``` You can run the command for a specific app also. diff --git a/plugins/builder-herokuish/builder-build b/plugins/builder-herokuish/builder-build index b905f7f6c..76be1b392 100755 --- a/plugins/builder-herokuish/builder-build +++ b/plugins/builder-herokuish/builder-build @@ -21,9 +21,9 @@ trigger-builder-herokuish-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null - eval "$(config_export app "$APP")" + DOKKU_IMAGE="$(plugn trigger buildpack-stack-name "$APP")" - DOKKU_IMAGE="$(config_get "$APP" DOKKU_IMAGE || echo "$DOKKU_IMAGE")" + eval "$(config_export app "$APP")" plugn trigger builder-create-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE" NEW_DOKKU_IMAGE=$(plugn trigger builder-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE") [[ -n "$NEW_DOKKU_IMAGE" ]] && DOKKU_IMAGE="$NEW_DOKKU_IMAGE" diff --git a/plugins/buildpacks/Makefile b/plugins/buildpacks/Makefile index 700601cc5..5abb38ed3 100644 --- a/plugins/buildpacks/Makefile +++ b/plugins/buildpacks/Makefile @@ -1,5 +1,5 @@ -SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set -TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/post-extract triggers/report +SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set subcommands/stacks-set +TRIGGERS = triggers/buildpack-stack-name triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/post-extract triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = buildpacks diff --git a/plugins/buildpacks/buildpacks.go b/plugins/buildpacks/buildpacks.go new file mode 100644 index 000000000..8f4e3b956 --- /dev/null +++ b/plugins/buildpacks/buildpacks.go @@ -0,0 +1,13 @@ +package buildpacks + +var ( + // DefaultProperties is a map of all valid buildpacks properties with corresponding default property values + DefaultProperties = map[string]string{ + "stack": "", + } + + // GlobalProperties is a map of all valid global buildpacks properties + GlobalProperties = map[string]bool{ + "stack": true, + } +) diff --git a/plugins/buildpacks/report.go b/plugins/buildpacks/report.go index ca53623c2..084884b62 100644 --- a/plugins/buildpacks/report.go +++ b/plugins/buildpacks/report.go @@ -1,6 +1,7 @@ package buildpacks import ( + "os" "strings" "github.com/dokku/dokku/plugins/common" @@ -13,7 +14,10 @@ func ReportSingleApp(appName, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--buildpacks-list": reportList, + "--buildpacks-computed-stack": reportComputedStack, + "--buildpacks-global-stack": reportGlobalStack, + "--buildpacks-list": reportList, + "--buildpacks-stack": reportStack, } flagKeys := []string{} @@ -27,6 +31,28 @@ func ReportSingleApp(appName, infoFlag string) error { return common.ReportSingleApp("buildpacks", appName, infoFlag, infoFlags, flagKeys, trimPrefix, uppercaseFirstCharacter) } +func reportComputedStack(appName string) string { + if stack := common.PropertyGetDefault("buildpacks", appName, "stack", ""); stack != "" { + return stack + } + + if stack := common.PropertyGetDefault("buildpacks", "--global", "stack", ""); stack != "" { + return stack + } + + b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_IMAGE"}...) + if dokkuImage := strings.TrimSpace(string(b[:])); dokkuImage != "" { + common.LogWarn("Deprecated: use buildpacks:stacks-set instead of specifying DOKKU_IMAGE environment variable") + return dokkuImage + } + + return os.Getenv("DOKKU_IMAGE") +} + +func reportGlobalStack(appName string) string { + return common.PropertyGetDefault("buildpacks", "--global", "stack", "") +} + func reportList(appName string) string { buildpacks, err := common.PropertyListGet("buildpacks", appName, "buildpacks") if err != nil { @@ -35,3 +61,7 @@ func reportList(appName string) string { return strings.Join(buildpacks, ",") } + +func reportStack(appName string) string { + return common.PropertyGetDefault("buildpacks", appName, "stack", "") +} diff --git a/plugins/buildpacks/src/commands/commands.go b/plugins/buildpacks/src/commands/commands.go index 5d9cfac57..baf3144a0 100644 --- a/plugins/buildpacks/src/commands/commands.go +++ b/plugins/buildpacks/src/commands/commands.go @@ -24,6 +24,7 @@ Additional commands:` buildpacks:remove , Remove a buildpack set on the app buildpacks:report [] [], Displays a buildpack report for one or more apps buildpacks:set [--index 1] , Set new app buildpack at a given position defaulting to the first buildpack if no index is specified + buildpacks:stacks-set , Sets the stack of an app ` ) diff --git a/plugins/buildpacks/src/subcommands/subcommands.go b/plugins/buildpacks/src/subcommands/subcommands.go index 7bf7a2303..b17a3c5b3 100644 --- a/plugins/buildpacks/src/subcommands/subcommands.go +++ b/plugins/buildpacks/src/subcommands/subcommands.go @@ -57,6 +57,17 @@ func main() { appName := args.Arg(0) buildpack := args.Arg(1) err = buildpacks.CommandSet(appName, buildpack, *index) + case "stacks-set": + args := flag.NewFlagSet("buildpacks:stacks-set", flag.ExitOnError) + global := args.Bool("global", false, "--global: set a global property") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + stack := args.Arg(1) + if *global { + appName = "--global" + stack = args.Arg(0) + } + err = buildpacks.CommandStacksSet(appName, stack) default: common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand)) } diff --git a/plugins/buildpacks/src/triggers/triggers.go b/plugins/buildpacks/src/triggers/triggers.go index 63534684e..369038897 100644 --- a/plugins/buildpacks/src/triggers/triggers.go +++ b/plugins/buildpacks/src/triggers/triggers.go @@ -18,6 +18,9 @@ func main() { var err error switch trigger { + case "buildpack-stack-name": + appName := flag.Arg(0) + err = buildpacks.TriggerBuildpackStackName(appName) case "install": err = buildpacks.TriggerInstall() case "post-app-clone-setup": diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index a6caea1ba..3d1b81c39 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -138,3 +138,9 @@ func CommandSet(appName string, buildpack string, index int) error { return common.PropertyListSet("buildpacks", appName, "buildpacks", buildpack, index) } + +// CommandStacksSet implements buildpacks:stacks-set +func CommandStacksSet(appName string, stack string) error { + common.CommandPropertySet("buildpacks", appName, "stack", stack, DefaultProperties, GlobalProperties) + return common.PlugnTrigger("post-stack-set", []string{appName, stack}...) +} diff --git a/plugins/buildpacks/triggers.go b/plugins/buildpacks/triggers.go index 293c74dd6..195c41dec 100644 --- a/plugins/buildpacks/triggers.go +++ b/plugins/buildpacks/triggers.go @@ -5,10 +5,36 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/dokku/dokku/plugins/common" ) +// TriggerBuildpackStackName echos the stack name for the app +func TriggerBuildpackStackName(appName string) error { + if stack := common.PropertyGetDefault("buildpacks", appName, "stack", ""); stack != "" { + fmt.Println(stack) + return nil + } + + if stack := common.PropertyGetDefault("buildpacks", "--global", "stack", ""); stack != "" { + fmt.Println(stack) + return nil + } + + b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_IMAGE"}...) + dokkuImage := strings.TrimSpace(string(b[:])) + if dokkuImage != "" { + common.LogWarn("Deprecated: use buildpacks:stacks-set instead of specifying DOKKU_IMAGE environment variable") + fmt.Println(dokkuImage) + return nil + } + + fmt.Println(os.Getenv("DOKKU_IMAGE")) + + return nil +} + // TriggerInstall runs the install step for the buildpacks plugin func TriggerInstall() error { if err := common.PropertySetup("buildpacks"); err != nil {