Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakout packages #123

Merged
merged 39 commits into from
Apr 12, 2016
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
96fef2e
Refactor of Pollable for modularization effort
tgross Mar 25, 2016
9b5ec8c
Move parsing and IPs functions into a utils package
tgross Mar 28, 2016
087af28
Refactor of Pollable for modularization effort
tgross Mar 25, 2016
7049768
Move parsing and IPs functions into a utils package
tgross Mar 28, 2016
ba491f8
Initial implementation of metrics (Prometheus support)
tgross Mar 28, 2016
6ff5adc
Support getting test coverage from multiple packages
tgross Mar 29, 2016
7060416
Catch panic from prometheus.MustRegister
tgross Mar 29, 2016
3ec95ec
Tests for parsing metrics and sensors
tgross Mar 29, 2016
ddc7134
Make running single package of tests easier via makefile
tgross Mar 29, 2016
1a3b21b
Make sure metrics check commands are reset after use
tgross Mar 29, 2016
27fb2d6
Use Register instead of MustRegister to avoid having to handle panic
tgross Mar 30, 2016
f24d13f
Testing for metrics recording and retrieval
tgross Mar 30, 2016
51b9b05
Major refactor for breaking out packages
tgross Mar 31, 2016
00ad815
Trim-up Godeps.json for packages
tgross Mar 31, 2016
0d3f215
Fix JSON error in discovery godeps
tgross Mar 31, 2016
e63d7b2
Namespace poll tests
tgross Mar 31, 2016
31b4345
Fix missing godep for discovery
tgross Mar 31, 2016
4136c1f
Fix version flag breakage
tgross Mar 31, 2016
2783e5e
Added metrics README
tgross Mar 31, 2016
0cd21ed
Rename metrics to telemetry
tgross Apr 5, 2016
afd7405
Remove metrics import from top-level main.go
tgross Apr 5, 2016
7539c0b
Update README
tgross Apr 5, 2016
12a5910
Fix broken telemetry server
tgross Apr 6, 2016
168df0d
Unit test to verify default sensor field names
tgross Apr 7, 2016
4e9d94d
Hard-code telemetry service name and path
tgross Apr 8, 2016
1d83185
Refactor telemetry config to move all parsing into package
tgross Apr 8, 2016
f2c55f9
Port telemetry implementation into the refactor
tgross Apr 8, 2016
6478346
Move Service and Backend parsing entirely into their own packages
tgross Apr 8, 2016
aefded6
Rename ServiceConfig->Service and BackendConfig->Backend
tgross Apr 8, 2016
1559e91
Move core/Main() into main package at main()
tgross Apr 8, 2016
7ab3a18
Namespace packages so canonical paths and go get should work
tgross Apr 8, 2016
7dd3fd2
Fix descent into src directory error
tgross Apr 8, 2016
787c5af
Telemetry README improvements
tgross Apr 8, 2016
40e720a
makefile: Fix up makefile targets
justenwalker Apr 9, 2016
1512959
Move integration test script
justenwalker Apr 9, 2016
c9be08d
Move makefile path logic into scripts
tgross Apr 11, 2016
44442be
Make http server global so we don't try to reload it
tgross Apr 11, 2016
e8e06c5
Unregister collectors preemptively prior to registration
tgross Apr 11, 2016
86029a5
Cleanup
tgross Apr 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,3 @@ Godeps/_workspace/

# fake paths from overlaying volumes in Docker
/src
containerbuddy/src/
41 changes: 30 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Using local scripts to test health or act on backend changes means that we can r

Containerbuddy is explicitly *not* a supervisor process. Although it can act as PID1 inside a container, if the shimmed process dies, so does Containerbuddy (and therefore the container itself). Containerbuddy will return the exit code of its shimmed process back to the Docker Engine or Triton, so that it appears as expected when you run `docker ps -a` and look for your exit codes. Containerbuddy also attaches stdout/stderr from your application to stdout/stderr of the container, so that `docker logs` works as expected.

### Configuring Containerbuddy
## Configuring Containerbuddy

Containerbuddy takes a single file argument (or a JSON string) as its configuration. All trailing arguments will be treated as the executable to shim and that executable's arguments.

Expand Down Expand Up @@ -90,11 +90,23 @@ The format of the JSON file configuration is as follows:
"poll": 10,
"onChange": "/opt/containerbuddy/reload-app.sh"
}
]
],
"telemetry": {
"port": 9090,
"sensors": [
{
"name": "metric_id",
"help": "help text",
"type": "counter",
"poll": 5,
"check": ["/bin/sensor.sh"]
}
]
}
}
```

Service fields:
#### Service fields:

- `name` is the name of the service as it will appear in Consul. Each instance of the service will have a unique ID made up from `name`+hostname of the container.
- `port` is the port the service will advertise to Consul.
Expand All @@ -104,13 +116,13 @@ Service fields:
- `ttl` is the time-to-live of a successful health check. This should be longer than the polling rate so that the polling process and the TTL aren't racing; otherwise Consul will mark the service as unhealthy.
- `tags` is an optional array of tags. If the discovery service supports it (Consul does), the service will register itself with these tags.

Backend fields:
#### Backend fields:

- `name` is the name of a backend service that this container depends on, as it will appear in Consul.
- `poll` is the time in seconds between polling for changes.
- `onChange` is the executable (and its arguments) that is called when there is a change in the list of IPs and ports for this backend.

Service Discovery Backends:
#### Service Discovery Backends:

Must supply only one of the following

Expand All @@ -134,7 +146,7 @@ Must supply only one of the following
- `endpoints` is the list of etcd nodes in your cluster
- `prefix` is the path that will be prefixed to all service discovery keys. This key is optional. (Default: `/containerbuddy`)

Logging Config (Optional):
#### Logging Config (Optional):

The logging config adjust the output format and verbosity of Containerbuddy logs.

Expand Down Expand Up @@ -181,7 +193,14 @@ exit status 1
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```

Other fields:
#### Telemetry (Optional):

If a `telemetry` option is provided, Containerbuddy will expose a [Prometheus](http://prometheus.io) HTTP client interface that can be used to scrape performance telemetry. The telemetry interface is advertised as a service to the discovery service similar to services configured via the `services` block. Each `sensor` for the telemetry service will run periodically and record values in the [Prometheus client library](https://github.com/prometheus/client_golang). A Prometheus server can then make HTTP requests to the telemetry endpoint.

Details of how to configure the telemetry endpoint and how the telemetry endpoint works can be found in the [telemetry README](https://github.com/joyent/containerbuddy/blob/master/telemetry/README.md).


#### Other fields:

- `onStart` is the executable (and its arguments) that will be called immediately prior to starting the shimmed application. This field is optional. If the `onStart` handler returns a non-zero exit code, Containerbuddy will exit.
- `preStop` is the executable (and its arguments) that will be called immediately **before** the shimmed application exits. This field is optional. Containerbuddy will wait until this program exits before terminating the shimmed application.
Expand Down Expand Up @@ -232,7 +251,7 @@ All executable fields, such as `onStart` and `onChange`, accept both a string or
]
```

### Template Configuration
#### Template Configuration

Containerbuddy configuration has template support. If you have an environment variable such as `FOO=BAR` then you can use `{{.FOO}}` in your configuration file and it will be substituted with `BAR`.

Expand All @@ -247,7 +266,7 @@ Containerbuddy configuration has template support. If you have an environment va

_Note: If you need more than just variable interpolation, check out the [Go text/template Docs](https://golang.org/pkg/text/template/)._

### Operating Containerbuddy
## Operating Containerbuddy

Containerbuddy accepts POSIX signals to change its runtime behavior. Currently, Containerbuddy accepts the following signals:

Expand All @@ -266,11 +285,11 @@ Docker will automatically deliver a `SIGTERM` with `docker stop`, not when using

*Caveat*: If Containerbuddy is wrapped as a shell command, such as: `/bin/sh -c '/opt/containerbuddy .... '` then `SIGTERM` will not reach Containerbuddy from `docker stop`. This is important for systems like Mesos which may use a shell command as the entrypoint under default configuration.

### Contributing
## Contributing

Please report any issues you encounter with Containerbuddy or its documentation by [opening a Github issue](https://github.com/joyent/containerbuddy/issues). Roadmap items will be maintained as [enhancements](https://github.com/joyent/containerbuddy/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement). PRs are welcome on any issue.

### Examples
## Examples

We've published a number of example applications demonstrating how Containerbuddy works.

Expand Down
15 changes: 15 additions & 0 deletions backends/Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
83 changes: 83 additions & 0 deletions backends/backends.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package backends

import (
"encoding/json"
"fmt"
"os/exec"

"github.com/joyent/containerbuddy/discovery"
"github.com/joyent/containerbuddy/utils"
)

// Backend represents a command to execute when another application changes
type Backend struct {
Name string `json:"name"`
Poll int `json:"poll"` // time in seconds
OnChangeExec json.RawMessage `json:"onChange"`
Tag string `json:"tag,omitempty"`
discoveryService discovery.DiscoveryService
lastState interface{}
onChangeCmd *exec.Cmd
}

func NewBackends(raw json.RawMessage, disc discovery.DiscoveryService) ([]*Backend, error) {
if raw == nil {
return []*Backend{}, nil
}
backends := make([]*Backend, 0)
if err := json.Unmarshal(raw, &backends); err != nil {
return nil, fmt.Errorf("Backend configuration error: %v", err)
}
for _, b := range backends {
if b.Name == "" {
return nil, fmt.Errorf("backend must have a `name`")
}
cmd, err := utils.ParseCommandArgs(b.OnChangeExec)
if err != nil {
return nil, fmt.Errorf("Could not parse `onChange` in backend %s: %s",
b.Name, err)
}
if cmd == nil {
return nil, fmt.Errorf("`onChange` is required in backend %s",
b.Name)
}
if b.Poll < 1 {
return nil, fmt.Errorf("`poll` must be > 0 in backend %s",
b.Name)
}
b.onChangeCmd = cmd
b.discoveryService = disc
}
return backends, nil
}

// PollTime implements Pollable for Backend
// It returns the backend's poll interval.
func (b Backend) PollTime() int {
return b.Poll
}

// PollAction implements Pollable for Backend.
// If the values in the discovery service have changed since the last run,
// we fire the on change handler.
func (b Backend) PollAction() {
if b.CheckForUpstreamChanges() {
b.OnChange()
}
}

// CheckForUpstreamChanges checks the service discovery endpoint for any changes
// in a dependent backend. Returns true when there has been a change.
func (b *Backend) CheckForUpstreamChanges() bool {
return b.discoveryService.CheckForUpstreamChanges(b.Name, b.Tag)
}

// OnChange runs the backend's onChange command, returning the results
func (b *Backend) OnChange() (int, error) {
defer func() {
// reset command object because it can't be reused
b.onChangeCmd = utils.ArgsToCmd(b.onChangeCmd.Args)
}()
exitCode, err := utils.Run(b.onChangeCmd)
return exitCode, err
}
73 changes: 73 additions & 0 deletions backends/backends_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package backends

import (
"os/exec"
"reflect"
"testing"

"github.com/joyent/containerbuddy/utils"
)

func TestOnChangeCmd(t *testing.T) {
cmd1 := utils.StrToCmd("./testdata/test.sh doStuff --debug")
backend := &Backend{
onChangeCmd: cmd1,
}
if _, err := backend.OnChange(); err != nil {
t.Errorf("Unexpected error OnChange: %s", err)
}
// Ensure we can run it more than once
if _, err := backend.OnChange(); err != nil {
t.Errorf("Unexpected error OnChange (x2): %s", err)
}
}

type TestFragmentBackends struct {
Backends []Backend
}

func TestBackendsParse(t *testing.T) {
jsonFragment := []byte(`[
{
"name": "upstreamA",
"poll": 11,
"onChange": "/bin/to/onChangeEvent/for/upstream/A.sh",
"tag": "dev"
},
{
"name": "upstreamB",
"poll": 79,
"onChange": "/bin/to/onChangeEvent/for/upstream/B.sh"
}
]`)

if backends, err := NewBackends(jsonFragment, nil); err != nil {
t.Fatalf("Could not parse backends JSON: %s", err)
} else {
validateCommandParsed(t, "onChange", backends[0].onChangeCmd,
[]string{"/bin/to/onChangeEvent/for/upstream/A.sh"})
validateCommandParsed(t, "onChange", backends[1].onChangeCmd,
[]string{"/bin/to/onChangeEvent/for/upstream/B.sh"})
}
}

// ------------------------------------------
// test helpers

func validateCommandParsed(t *testing.T, name string, parsed *exec.Cmd, expected []string) {
if expected == nil {
if parsed != nil {
t.Errorf("%s has Cmd, but expected nil", name)
}
return
}
if parsed == nil {
t.Errorf("%s not configured", name)
}
if parsed.Path != expected[0] {
t.Errorf("%s path not configured: %s != %s", name, parsed.Path, expected[0])
}
if !reflect.DeepEqual(parsed.Args, expected) {
t.Errorf("%s arguments not configured: %s != %s", name, parsed.Args, expected)
}
}
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions config/Godeps/Readme

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading