diff --git a/README.md b/README.md index 7e554fa..875ccf6 100644 --- a/README.md +++ b/README.md @@ -107,10 +107,11 @@ The full list of labels are: ## Environment Variables -| Key | Description | Default | -|---------------------|-----------------------------------|------------------------------| -| `LOG_LEVEL` | The level of log verbosity | `Info` | -| `HOMER_BASE_CONFIG` | Where the base config is located | `/base.yml` | -| `HOMER_CONFIG` | Where the Homer config is located | `/config.yml` | -| `SERVICE_DISCOVERY` | Either `Docker` or `Consul` | `Docker` | -| `CONSUL_HOST` | Host for Consul connnection | `127.0.0.1:8500` | +| Key | Description | Default | +|---------------------|-----------------------------------------------|------------------------------| +| `LOG_LEVEL` | The level of log verbosity | `Info` | +| `HOMER_BASE_CONFIG` | Where the base config is located | `/base.yml` | +| `HOMER_CONFIG` | Where the Homer config is located | `/config.yml` | +| `SERVICE_DISCOVERY` | Either `Docker` or `Consul` | `Docker` | +| `HOMER_DOCKER_SWARM`| Docker Swarm supprt. Either `true` or `false` | `false` | +| `CONSUL_HOST` | Host for Consul connnection | `127.0.0.1:8500` | diff --git a/cmd/main.go b/cmd/main.go index 83bdb98..cac476f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -46,11 +46,15 @@ func main() { if conf.ServiceDiscovery == config.Docker { logger.Info("Start watching for container creations and deletions") - eventsc, errc := docker.WatchEvents(ctx, conf.Docker) + if conf.HomerDockerSwarmMode { + logger.Info("Docker Swarm mode enabled") + logger.Info("Start watching for service creations, updates, and removal") + } + eventsc, errc := docker.WatchEvents(ctx, conf.Docker, conf.HomerDockerSwarmMode) for { select { case event := <-eventsc: - if event.Action == "start" || event.Action == "die" || strings.HasPrefix(event.Action, "health_status") { + if event.Action == "start" || event.Action == "die" || strings.HasPrefix(event.Action, "health_status") || (event.Type == "service" && (event.Action == "create" || event.Action == "update" || event.Action == "remove")) { logger.Trace(fmt.Sprintf("%+v", event)) logger.Debug("A " + event.Action + " event occurred") logger.Info(fmt.Sprintf("Event '%s' received from %s. Generating Homer config...", event.Action, event.Actor.Attributes["name"])) @@ -103,6 +107,21 @@ func generateConfig(ctx context.Context, conf config.Config) error { logger.Debug(fmt.Sprintf("Inspected container %s", parsedContainer.Name)) parsedEntry = append(parsedEntry, parsedContainer) } + + if conf.HomerDockerSwarmMode { + logger.Debug("Getting Docker services") + services, err := docker.ListRunningServices(ctx, conf.Docker) + if err != nil { + logger.Fatal("Failed to list swarm services for Docker", err) + } + for _, service := range services { + parsedService, err := docker.ParseService(ctx, conf.Docker, service) + if err != nil { + logger.Error(fmt.Sprintf("Failed to inspect service %s", service.Spec.Name), err) + } + parsedEntry = append(parsedEntry, parsedService) + } + } } else if conf.ServiceDiscovery == config.Consul { logger.Debug("Getting Consul service") services := consul.ListServices(conf.Consul) diff --git a/internal/config/main.go b/internal/config/main.go index 630db2c..33e864d 100644 --- a/internal/config/main.go +++ b/internal/config/main.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/calvinbui/homer-docker-service-discovery/internal/consul" "github.com/calvinbui/homer-docker-service-discovery/internal/docker" "github.com/calvinbui/homer-docker-service-discovery/internal/logger" @@ -30,6 +31,8 @@ type Config struct { HomerBaseConfigPath string `env:"HOMER_BASE_CONFIG" envDefault:"/base.yml"` HomerConfigPath string `env:"HOMER_CONFIG" envDefault:"/config.yml"` + + HomerDockerSwarmMode bool `env:"HOMER_DOCKER_SWARM" envDefault:"false"` } func New() (Config, error) { diff --git a/internal/docker/events.go b/internal/docker/events.go index fc247b6..4fcaa15 100644 --- a/internal/docker/events.go +++ b/internal/docker/events.go @@ -9,9 +9,13 @@ import ( "github.com/docker/docker/client" ) -func WatchEvents(ctx context.Context, docker client.APIClient) (<-chan events.Message, <-chan error) { +func WatchEvents(ctx context.Context, docker client.APIClient, swarmMode bool) (<-chan events.Message, <-chan error) { f := filters.NewArgs() f.Add("type", "container") + if swarmMode { + f.Add("type", "service") + } + return docker.Events(ctx, types.EventsOptions{Filters: f}) } diff --git a/internal/docker/services.go b/internal/docker/services.go new file mode 100644 index 0000000..97195c4 --- /dev/null +++ b/internal/docker/services.go @@ -0,0 +1,42 @@ +package docker + +import ( + "context" + + "github.com/calvinbui/homer-docker-service-discovery/internal/entry" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/client" +) + +func ListRunningServices(ctx context.Context, docker client.APIClient) ([]swarm.Service, error) { + if ctx == nil { + ctx = context.Background() + } + + services, err := docker.ServiceList(ctx, types.ServiceListOptions{Status: true}) + + if err != nil { + return nil, err + } + + return services, nil +} + +func ParseService(ctx context.Context, docker client.APIClient, service swarm.Service) (entry.RawEntry, error) { + i, _, err := docker.ServiceInspectWithRaw(ctx, service.ID, types.ServiceInspectOptions{}) + + if err != nil { + return entry.RawEntry{}, err + } + + s := entry.RawEntry{ + Name: i.Spec.Annotations.Name, + } + + if i.Spec.Labels != nil { + s.Labels = i.Spec.Annotations.Labels + } + + return s, nil +}