Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dokku/omakase


https://github.com/dokku/omakase

Last synced: about 2 months ago
JSON representation

Awesome Lists containing this project

README

        

# omakase

> Note: this is a heavy work in progress. YMMV.
> Should we change the name? It's a "cute" name but doesn't really help end-users
> and could be seen as fetishisation of Japanese culture. New name suggestions
> welcome!

A method to pre-package and ship applications on Dokku.

## Background

While Ansible is all well and good, having something native to Dokku for shipping applications is awesome. The `omakase` package allows users to specify exactly what it means to be an app, while allowing for some minimal customization (which is against the `omakase` spirit but here we are).

This package provides the above functionality by exposing the modules from `ansible-dokku` within a single Golang binary. Users of `ansible-dokku` based task lists should be able to use their existing tasks with minimal changes, while organizations can decide to expose apps in easy to use methods for their users.

## Building

```shell
go build
```

## Usage

Create a `tasks.yml` file:

```yaml
---
- tasks:
- dokku_app:
app: inflector
- dokku_sync:
app: inflector
repository: http://github.com/cakephp/inflector.cakephp.org
```

Run it:

```shell
# from the same directory as the tasks.yml
omakase
```

A task file can also be specified via flag, and may be a file retrieved via http:

```shell
# alternate path
omakase --tasks path/to/task.yml

# html file
omakase --tasks http://dokku.com/omakase/example.yml
```

Some other ideas:

- This could be automatically applied from within a repository if a .dokku/tasks.yml was found. In such a case, certain tasks would be added to a denylist and would be ignored during the run (such as dokku_app or dokku_sync).
- Dokku may expose a command such as dokku app:install that would allow users to invoke omakase to install apps.
- A web ui could expose a web ui to customize remote task files and then call `omakase` directly on the generated output.

### Inputs

Each app recipe can have custom inputs as specified in the `tasks.yml`. Inputs should _not_ reference any variable context, and are extracted using a two-phase parsing method (extract-then-inject).

```yaml
---
- inputs:
- name: name
default: "inflector"
description: "Name of app to be created"
required: true
tasks:
- dokku_app:
app: {{ .name }}
- dokku_sync:
app: {{ .name }}
repository: http://github.com/cakephp/inflector.cakephp.org
```

With the above, the following method is used to override the `name` variable. Omitting will use the default value.

```shell
# from the same directory as the tasks.yml
omakase --name lollipop
```

Any inputs for a given task file will also show up in the `--help` output.

Inputs are injected using golang's `text/template` package via the `gliderlabs/sigil` library, and as such have access to everything `gliderlabs/sigil` does.

Inputs can have the following properties:

- name:
- type: `string`
- default: ``
- default:
- type: `bool|float|int|string`
- default: zero-value for the type
- description:
- type: `string`
- default: `""`
- required:
- type: `bool`
- default: `false`
- type:
- type: string
- default `string`
- options:
- `bool`
- `float`
- `int`
- `string`

If all inputs are specified on the CLI, then they are injected as is. Otherwise, unless the `--no-interactive` flag is specified, `omakase` will ask for values for each input, with the cli-specified values merged onto the task file default values as defaults.

Finally, the following input keys are reserved for internal usage:

- `help`
- `tasks`
- `v`
- `version`

### Tasks

All implemented tasks should closely follow those available via the `ansible-dokku` library. Additionally, `omakase` will expose a few custom tasks that are specific to this package to ease migration from pure ansible.

Tasks will have both a `name` and an execution context, where the context maps to a single implemented modules. Tasks can be templated out via the variables from the `inputs` section, and may also use any functions exposed by `gliderlabs/sigil`.

#### Adding a new task

Task executors should be added by creating an `tasks/${TASK_NAME}_task.go`. The Task name should be `lower_underscore_case`. By way of example, a `tasks/lollipop_task.go` would contain the following:

```go
package main

type LollipopTask struct {
App string `required:"true" yaml:"app"`
State string `required:"true" yaml:"state" default:"present"`
}

func (t LollipopTask) DesiredState() string {
return t.State
}

func (t LollipopTask) Execute() (string, error) {
return "", nil
}

func (t *LollipopTask) SetDefaultDesiredState(state string) {
if t.State == "" {
t.State = state
}
}

func init() {
RegisterTask(&LollipopTask{})
}
```

The `LollipopTask` struct contains the fields necessary for the task. The only necessary field is `State`, which holds the desired state of the task. All other fields are completely custom for the task at hand.

The `DesiredState()` function must return `t.State`.

The `Execute()` function should actually execute the task. The return values:

- `string`: a string holding the current state
- `error`: Whether an error occurred during processing

> Todo: How do we expose stdout? Should the Status object actually be more structured? Should it serialize to json directly for use by ansible?

The `init()` function registers the task for usage within a recipe.