mirror of https://github.com/docker/docs.git
Merge pull request #514 from technolo-g/Issue_499_Automate_golint_pr
Issue #500 Run golint on codebase
This commit is contained in:
commit
b655cbb7c5
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// APIVERSION is exported
|
||||||
const APIVERSION = "1.16"
|
const APIVERSION = "1.16"
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
|
@ -55,14 +56,14 @@ func getInfo(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
func getVersion(c *context, w http.ResponseWriter, r *http.Request) {
|
func getVersion(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
version := struct {
|
version := struct {
|
||||||
Version string
|
Version string
|
||||||
ApiVersion string
|
APIVersion string
|
||||||
GoVersion string
|
GoVersion string
|
||||||
GitCommit string
|
GitCommit string
|
||||||
Os string
|
Os string
|
||||||
Arch string
|
Arch string
|
||||||
}{
|
}{
|
||||||
Version: "swarm/" + version.VERSION,
|
Version: "swarm/" + version.VERSION,
|
||||||
ApiVersion: APIVERSION,
|
APIVersion: APIVERSION,
|
||||||
GoVersion: runtime.Version(),
|
GoVersion: runtime.Version(),
|
||||||
GitCommit: version.GITCOMMIT,
|
GitCommit: version.GITCOMMIT,
|
||||||
Os: runtime.GOOS,
|
Os: runtime.GOOS,
|
||||||
|
@ -316,7 +317,7 @@ func postContainersExec(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := struct{ Id string }{}
|
id := struct{ ID string }{}
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &id); err != nil {
|
if err := json.Unmarshal(data, &id); err != nil {
|
||||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -324,7 +325,7 @@ func postContainersExec(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add execID to the container, so the later exec/start will work
|
// add execID to the container, so the later exec/start will work
|
||||||
container.Info.ExecIDs = append(container.Info.ExecIDs, id.Id)
|
container.Info.ExecIDs = append(container.Info.ExecIDs, id.ID)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
|
|
|
@ -15,6 +15,7 @@ type eventsHandler struct {
|
||||||
cs map[string]chan struct{}
|
cs map[string]chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEventsHandler is exported
|
||||||
func NewEventsHandler() *eventsHandler {
|
func NewEventsHandler() *eventsHandler {
|
||||||
return &eventsHandler{
|
return &eventsHandler{
|
||||||
ws: make(map[string]io.Writer),
|
ws: make(map[string]io.Writer),
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WriteFlusher is exported
|
||||||
type WriteFlusher struct {
|
type WriteFlusher struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
w io.Writer
|
w io.Writer
|
||||||
|
@ -29,6 +30,7 @@ func (wf *WriteFlusher) Flush() {
|
||||||
wf.flusher.Flush()
|
wf.flusher.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWriteFlusher is exported
|
||||||
func NewWriteFlusher(w io.Writer) *WriteFlusher {
|
func NewWriteFlusher(w io.Writer) *WriteFlusher {
|
||||||
var flusher http.Flusher
|
var flusher http.Flusher
|
||||||
if f, ok := w.(http.Flusher); ok {
|
if f, ok := w.(http.Flusher); ok {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/docker/swarm/cluster"
|
"github.com/docker/swarm/cluster"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DefaultDockerPort is exported
|
||||||
const DefaultDockerPort = ":2375"
|
const DefaultDockerPort = ":2375"
|
||||||
|
|
||||||
func newListener(proto, addr string, tlsConfig *tls.Config) (net.Listener, error) {
|
func newListener(proto, addr string, tlsConfig *tls.Config) (net.Listener, error) {
|
||||||
|
@ -28,6 +29,7 @@ func newListener(proto, addr string, tlsConfig *tls.Config) (net.Listener, error
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenAndServe is exported
|
||||||
func ListenAndServe(c cluster.Cluster, hosts []string, enableCors bool, tlsConfig *tls.Config, eventsHandler *eventsHandler) error {
|
func ListenAndServe(c cluster.Cluster, hosts []string, enableCors bool, tlsConfig *tls.Config, eventsHandler *eventsHandler) error {
|
||||||
context := &context{
|
context := &context{
|
||||||
cluster: c,
|
cluster: c,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ContainerSorter is exported
|
||||||
type ContainerSorter []*dockerclient.Container
|
type ContainerSorter []*dockerclient.Container
|
||||||
|
|
||||||
func (s ContainerSorter) Len() int {
|
func (s ContainerSorter) Len() int {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cluster
|
||||||
|
|
||||||
import "github.com/samalba/dockerclient"
|
import "github.com/samalba/dockerclient"
|
||||||
|
|
||||||
|
// Cluster is exported
|
||||||
type Cluster interface {
|
type Cluster interface {
|
||||||
// Create a container
|
// Create a container
|
||||||
CreateContainer(config *dockerclient.ContainerConfig, name string) (*Container, error)
|
CreateContainer(config *dockerclient.ContainerConfig, name string) (*Container, error)
|
||||||
|
@ -12,8 +13,8 @@ type Cluster interface {
|
||||||
// Return all images
|
// Return all images
|
||||||
Images() []*Image
|
Images() []*Image
|
||||||
|
|
||||||
// Return one image matching `IdOrName`
|
// Return one image matching `IDOrName`
|
||||||
Image(IdOrName string) *Image
|
Image(IDOrName string) *Image
|
||||||
|
|
||||||
// Remove an image from the cluster
|
// Remove an image from the cluster
|
||||||
RemoveImage(image *Image) ([]*dockerclient.ImageDelete, error)
|
RemoveImage(image *Image) ([]*dockerclient.ImageDelete, error)
|
||||||
|
@ -21,8 +22,8 @@ type Cluster interface {
|
||||||
// Return all containers
|
// Return all containers
|
||||||
Containers() []*Container
|
Containers() []*Container
|
||||||
|
|
||||||
// Return container the matching `IdOrName`
|
// Return container the matching `IDOrName`
|
||||||
Container(IdOrName string) *Container
|
Container(IDOrName string) *Container
|
||||||
|
|
||||||
// Pull images
|
// Pull images
|
||||||
// `callback` can be called multiple time
|
// `callback` can be called multiple time
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cluster
|
||||||
|
|
||||||
import "github.com/samalba/dockerclient"
|
import "github.com/samalba/dockerclient"
|
||||||
|
|
||||||
|
// Container is exported
|
||||||
type Container struct {
|
type Container struct {
|
||||||
dockerclient.Container
|
dockerclient.Container
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,13 @@ package cluster
|
||||||
|
|
||||||
import "github.com/samalba/dockerclient"
|
import "github.com/samalba/dockerclient"
|
||||||
|
|
||||||
|
// Event is exported
|
||||||
type Event struct {
|
type Event struct {
|
||||||
dockerclient.Event
|
dockerclient.Event
|
||||||
Node Node
|
Node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventHandler is exported
|
||||||
type EventHandler interface {
|
type EventHandler interface {
|
||||||
Handle(*Event) error
|
Handle(*Event) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,22 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Image is exported
|
||||||
type Image struct {
|
type Image struct {
|
||||||
dockerclient.Image
|
dockerclient.Image
|
||||||
|
|
||||||
Node Node
|
Node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (image *Image) Match(IdOrName string) bool {
|
// Match is exported
|
||||||
size := len(IdOrName)
|
func (image *Image) Match(IDOrName string) bool {
|
||||||
|
size := len(IDOrName)
|
||||||
|
|
||||||
if image.Id == IdOrName || (size > 2 && strings.HasPrefix(image.Id, IdOrName)) {
|
if image.Id == IDOrName || (size > 2 && strings.HasPrefix(image.Id, IDOrName)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for _, repoTag := range image.RepoTags {
|
for _, repoTag := range image.RepoTags {
|
||||||
if repoTag == IdOrName || (size > 2 && strings.HasPrefix(repoTag, IdOrName)) {
|
if repoTag == IDOrName || (size > 2 && strings.HasPrefix(repoTag, IDOrName)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cluster
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
|
// Node is exported
|
||||||
type Node interface {
|
type Node interface {
|
||||||
ID() string
|
ID() string
|
||||||
Name() string
|
Name() string
|
||||||
|
@ -10,9 +11,9 @@ type Node interface {
|
||||||
Addr() string //to know where to connect with the proxy
|
Addr() string //to know where to connect with the proxy
|
||||||
|
|
||||||
Images() []*Image //used by the API
|
Images() []*Image //used by the API
|
||||||
Image(IdOrName string) *Image //used by the filters
|
Image(IDOrName string) *Image //used by the filters
|
||||||
Containers() []*Container //used by the filters
|
Containers() []*Container //used by the filters
|
||||||
Container(IdOrName string) *Container //used by the filters
|
Container(IDOrName string) *Container //used by the filters
|
||||||
|
|
||||||
TotalCpus() int64 //used by the strategy
|
TotalCpus() int64 //used by the strategy
|
||||||
UsedCpus() int64 //used by the strategy
|
UsedCpus() int64 //used by the strategy
|
||||||
|
@ -24,6 +25,7 @@ type Node interface {
|
||||||
IsHealthy() bool
|
IsHealthy() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SerializeNode is exported
|
||||||
func SerializeNode(node Node) string {
|
func SerializeNode(node Node) string {
|
||||||
return fmt.Sprintf("{%q:%q,%q:%q,%q:%q,%q:%q}",
|
return fmt.Sprintf("{%q:%q,%q:%q,%q:%q,%q:%q}",
|
||||||
"Name", node.Name(),
|
"Name", node.Name(),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cluster
|
||||||
|
|
||||||
import "crypto/tls"
|
import "crypto/tls"
|
||||||
|
|
||||||
|
// Options is exported
|
||||||
type Options struct {
|
type Options struct {
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
OvercommitRatio float64
|
OvercommitRatio float64
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Cluster is exported
|
||||||
type Cluster struct {
|
type Cluster struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ type Cluster struct {
|
||||||
store *state.Store
|
store *state.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCluster is exported
|
||||||
func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, eventhandler cluster.EventHandler, options *cluster.Options) cluster.Cluster {
|
func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, eventhandler cluster.EventHandler, options *cluster.Options) cluster.Cluster {
|
||||||
log.WithFields(log.Fields{"name": "swarm"}).Debug("Initializing cluster")
|
log.WithFields(log.Fields{"name": "swarm"}).Debug("Initializing cluster")
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ func NewCluster(scheduler *scheduler.Scheduler, store *state.Store, eventhandler
|
||||||
return cluster
|
return cluster
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for the events
|
// Handle callbacks for the events
|
||||||
func (c *Cluster) Handle(e *cluster.Event) error {
|
func (c *Cluster) Handle(e *cluster.Event) error {
|
||||||
if err := c.eventHandler.Handle(e); err != nil {
|
if err := c.eventHandler.Handle(e); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -62,7 +64,7 @@ func (c *Cluster) Handle(e *cluster.Event) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule a brand new container into the cluster.
|
// CreateContainer aka schedule a brand new container into the cluster.
|
||||||
func (c *Cluster) CreateContainer(config *dockerclient.ContainerConfig, name string) (*cluster.Container, error) {
|
func (c *Cluster) CreateContainer(config *dockerclient.ContainerConfig, name string) (*cluster.Container, error) {
|
||||||
|
|
||||||
c.RLock()
|
c.RLock()
|
||||||
|
@ -108,8 +110,8 @@ retry:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a container from the cluster. Containers should always be destroyed
|
// RemoveContainer aka Remove a container from the cluster. Containers should
|
||||||
// through the scheduler to guarantee atomicity.
|
// always be destroyed through the scheduler to guarantee atomicity.
|
||||||
func (c *Cluster) RemoveContainer(container *cluster.Container, force bool) error {
|
func (c *Cluster) RemoveContainer(container *cluster.Container, force bool) error {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
@ -186,17 +188,17 @@ func (c *Cluster) Images() []*cluster.Image {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image returns an image with IdOrName in the cluster
|
// Image returns an image with IDOrName in the cluster
|
||||||
func (c *Cluster) Image(IdOrName string) *cluster.Image {
|
func (c *Cluster) Image(IDOrName string) *cluster.Image {
|
||||||
// Abort immediately if the name is empty.
|
// Abort immediately if the name is empty.
|
||||||
if len(IdOrName) == 0 {
|
if len(IDOrName) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
for _, n := range c.nodes {
|
for _, n := range c.nodes {
|
||||||
if image := n.Image(IdOrName); image != nil {
|
if image := n.Image(IDOrName); image != nil {
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,6 +216,7 @@ func (c *Cluster) RemoveImage(image *cluster.Image) ([]*dockerclient.ImageDelete
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pull is exported
|
||||||
func (c *Cluster) Pull(name string, callback func(what, status string)) {
|
func (c *Cluster) Pull(name string, callback func(what, status string)) {
|
||||||
size := len(c.nodes)
|
size := len(c.nodes)
|
||||||
done := make(chan bool, size)
|
done := make(chan bool, size)
|
||||||
|
@ -251,17 +254,17 @@ func (c *Cluster) Containers() []*cluster.Container {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container returns the container with IdOrName in the cluster
|
// Container returns the container with IDOrName in the cluster
|
||||||
func (c *Cluster) Container(IdOrName string) *cluster.Container {
|
func (c *Cluster) Container(IDOrName string) *cluster.Container {
|
||||||
// Abort immediately if the name is empty.
|
// Abort immediately if the name is empty.
|
||||||
if len(IdOrName) == 0 {
|
if len(IDOrName) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
for _, n := range c.nodes {
|
for _, n := range c.nodes {
|
||||||
if container := n.Container(IdOrName); container != nil {
|
if container := n.Container(IDOrName); container != nil {
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,6 +285,7 @@ func (c *Cluster) listNodes() []cluster.Node {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Info is exported
|
||||||
func (c *Cluster) Info() [][2]string {
|
func (c *Cluster) Info() [][2]string {
|
||||||
info := [][2]string{{"\bNodes", fmt.Sprintf("%d", len(c.nodes))}}
|
info := [][2]string{{"\bNodes", fmt.Sprintf("%d", len(c.nodes))}}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ const (
|
||||||
requestTimeout = 10 * time.Second
|
requestTimeout = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewNode is exported
|
||||||
func NewNode(addr string, overcommitRatio float64) *node {
|
func NewNode(addr string, overcommitRatio float64) *node {
|
||||||
e := &node{
|
e := &node{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
|
@ -144,7 +145,7 @@ func (n *node) updateSpecs() error {
|
||||||
// Older versions of Docker don't expose the ID field and are not supported
|
// Older versions of Docker don't expose the ID field and are not supported
|
||||||
// by Swarm. Catch the error ASAP and refuse to connect.
|
// by Swarm. Catch the error ASAP and refuse to connect.
|
||||||
if len(info.ID) == 0 {
|
if len(info.ID) == 0 {
|
||||||
return fmt.Errorf("node %s is running an unsupported version of Docker Engine. Please upgrade.", n.addr)
|
return fmt.Errorf("node %s is running an unsupported version of Docker Engine. Please upgrade", n.addr)
|
||||||
}
|
}
|
||||||
n.id = info.ID
|
n.id = info.ID
|
||||||
n.name = info.Name
|
n.name = info.Name
|
||||||
|
@ -327,7 +328,7 @@ func (n *node) emitEvent(event string) {
|
||||||
|
|
||||||
// Return the sum of memory reserved by containers.
|
// Return the sum of memory reserved by containers.
|
||||||
func (n *node) UsedMemory() int64 {
|
func (n *node) UsedMemory() int64 {
|
||||||
var r int64 = 0
|
var r int64
|
||||||
n.RLock()
|
n.RLock()
|
||||||
for _, c := range n.containers {
|
for _, c := range n.containers {
|
||||||
r += c.Info.Config.Memory
|
r += c.Info.Config.Memory
|
||||||
|
@ -338,7 +339,7 @@ func (n *node) UsedMemory() int64 {
|
||||||
|
|
||||||
// Return the sum of CPUs reserved by containers.
|
// Return the sum of CPUs reserved by containers.
|
||||||
func (n *node) UsedCpus() int64 {
|
func (n *node) UsedCpus() int64 {
|
||||||
var r int64 = 0
|
var r int64
|
||||||
n.RLock()
|
n.RLock()
|
||||||
for _, c := range n.containers {
|
for _, c := range n.containers {
|
||||||
r += c.Info.Config.CpuShares
|
r += c.Info.Config.CpuShares
|
||||||
|
@ -437,10 +438,10 @@ func (n *node) Containers() []*cluster.Container {
|
||||||
return containers
|
return containers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container returns the container with IdOrName in the node.
|
// Container returns the container with IDOrName in the node.
|
||||||
func (n *node) Container(IdOrName string) *cluster.Container {
|
func (n *node) Container(IDOrName string) *cluster.Container {
|
||||||
// Abort immediately if the name is empty.
|
// Abort immediately if the name is empty.
|
||||||
if len(IdOrName) == 0 {
|
if len(IDOrName) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,13 +450,13 @@ func (n *node) Container(IdOrName string) *cluster.Container {
|
||||||
|
|
||||||
for _, container := range n.Containers() {
|
for _, container := range n.Containers() {
|
||||||
// Match ID prefix.
|
// Match ID prefix.
|
||||||
if strings.HasPrefix(container.Id, IdOrName) {
|
if strings.HasPrefix(container.Id, IDOrName) {
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match name, /name or engine/name.
|
// Match name, /name or engine/name.
|
||||||
for _, name := range container.Names {
|
for _, name := range container.Names {
|
||||||
if name == IdOrName || name == "/"+IdOrName || container.Node.ID()+name == IdOrName || container.Node.Name()+name == IdOrName {
|
if name == IDOrName || name == "/"+IDOrName || container.Node.ID()+name == IDOrName || container.Node.Name()+name == IDOrName {
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,13 +477,13 @@ func (n *node) Images() []*cluster.Image {
|
||||||
return images
|
return images
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image returns the image with IdOrName in the node
|
// Image returns the image with IDOrName in the node
|
||||||
func (n *node) Image(IdOrName string) *cluster.Image {
|
func (n *node) Image(IDOrName string) *cluster.Image {
|
||||||
n.RLock()
|
n.RLock()
|
||||||
defer n.RUnlock()
|
defer n.RUnlock()
|
||||||
|
|
||||||
for _, image := range n.images {
|
for _, image := range n.images {
|
||||||
if image.Match(IdOrName) {
|
if image.Match(IDOrName) {
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
consul "github.com/hashicorp/consul/api"
|
consul "github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ConsulDiscoveryService is exported
|
||||||
type ConsulDiscoveryService struct {
|
type ConsulDiscoveryService struct {
|
||||||
heartbeat time.Duration
|
heartbeat time.Duration
|
||||||
client *consul.Client
|
client *consul.Client
|
||||||
|
@ -22,6 +23,7 @@ func init() {
|
||||||
discovery.Register("consul", &ConsulDiscoveryService{})
|
discovery.Register("consul", &ConsulDiscoveryService{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *ConsulDiscoveryService) Initialize(uris string, heartbeat int) error {
|
func (s *ConsulDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
parts := strings.SplitN(uris, "/", 2)
|
parts := strings.SplitN(uris, "/", 2)
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
|
@ -52,6 +54,8 @@ func (s *ConsulDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
s.lastIndex = meta.LastIndex
|
s.lastIndex = meta.LastIndex
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch is exported
|
||||||
func (s *ConsulDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
func (s *ConsulDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
kv := s.client.KV()
|
kv := s.client.KV()
|
||||||
pairs, _, err := kv.List(s.prefix, nil)
|
pairs, _, err := kv.List(s.prefix, nil)
|
||||||
|
@ -70,6 +74,7 @@ func (s *ConsulDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return discovery.CreateEntries(addrs)
|
return discovery.CreateEntries(addrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *ConsulDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *ConsulDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
for _ = range s.waitForChange() {
|
for _ = range s.waitForChange() {
|
||||||
log.WithField("name", "consul").Debug("Discovery watch triggered")
|
log.WithField("name", "consul").Debug("Discovery watch triggered")
|
||||||
|
@ -80,6 +85,7 @@ func (s *ConsulDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func (s *ConsulDiscoveryService) Register(addr string) error {
|
func (s *ConsulDiscoveryService) Register(addr string) error {
|
||||||
kv := s.client.KV()
|
kv := s.client.KV()
|
||||||
p := &consul.KVPair{Key: path.Join(s.prefix, addr), Value: []byte(addr)}
|
p := &consul.KVPair{Key: path.Join(s.prefix, addr), Value: []byte(addr)}
|
||||||
|
|
|
@ -9,11 +9,13 @@ import (
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Entry is exported
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEntry is exported
|
||||||
func NewEntry(url string) (*Entry, error) {
|
func NewEntry(url string) (*Entry, error) {
|
||||||
host, port, err := net.SplitHostPort(url)
|
host, port, err := net.SplitHostPort(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,8 +28,10 @@ func (m Entry) String() string {
|
||||||
return fmt.Sprintf("%s:%s", m.Host, m.Port)
|
return fmt.Sprintf("%s:%s", m.Host, m.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WatchCallback is exported
|
||||||
type WatchCallback func(entries []*Entry)
|
type WatchCallback func(entries []*Entry)
|
||||||
|
|
||||||
|
// DiscoveryService is exported
|
||||||
type DiscoveryService interface {
|
type DiscoveryService interface {
|
||||||
Initialize(string, int) error
|
Initialize(string, int) error
|
||||||
Fetch() ([]*Entry, error)
|
Fetch() ([]*Entry, error)
|
||||||
|
@ -36,8 +40,10 @@ type DiscoveryService interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
discoveries map[string]DiscoveryService
|
discoveries map[string]DiscoveryService
|
||||||
ErrNotSupported = errors.New("discovery service not supported")
|
// ErrNotSupported is exported
|
||||||
|
ErrNotSupported = errors.New("discovery service not supported")
|
||||||
|
// ErrNotImplemented is exported
|
||||||
ErrNotImplemented = errors.New("not implemented in this discovery service")
|
ErrNotImplemented = errors.New("not implemented in this discovery service")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,6 +51,7 @@ func init() {
|
||||||
discoveries = make(map[string]DiscoveryService)
|
discoveries = make(map[string]DiscoveryService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func Register(scheme string, d DiscoveryService) error {
|
func Register(scheme string, d DiscoveryService) error {
|
||||||
if _, exists := discoveries[scheme]; exists {
|
if _, exists := discoveries[scheme]; exists {
|
||||||
return fmt.Errorf("scheme already registered %s", scheme)
|
return fmt.Errorf("scheme already registered %s", scheme)
|
||||||
|
@ -65,6 +72,7 @@ func parse(rawurl string) (string, string) {
|
||||||
return parts[0], parts[1]
|
return parts[0], parts[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is exported
|
||||||
func New(rawurl string, heartbeat int) (DiscoveryService, error) {
|
func New(rawurl string, heartbeat int) (DiscoveryService, error) {
|
||||||
scheme, uri := parse(rawurl)
|
scheme, uri := parse(rawurl)
|
||||||
|
|
||||||
|
@ -77,6 +85,7 @@ func New(rawurl string, heartbeat int) (DiscoveryService, error) {
|
||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEntries is exported
|
||||||
func CreateEntries(addrs []string) ([]*Entry, error) {
|
func CreateEntries(addrs []string) ([]*Entry, error) {
|
||||||
entries := []*Entry{}
|
entries := []*Entry{}
|
||||||
if addrs == nil {
|
if addrs == nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/swarm/discovery"
|
"github.com/docker/swarm/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EtcdDiscoveryService is exported
|
||||||
type EtcdDiscoveryService struct {
|
type EtcdDiscoveryService struct {
|
||||||
ttl uint64
|
ttl uint64
|
||||||
client *etcd.Client
|
client *etcd.Client
|
||||||
|
@ -20,6 +21,7 @@ func init() {
|
||||||
discovery.Register("etcd", &EtcdDiscoveryService{})
|
discovery.Register("etcd", &EtcdDiscoveryService{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *EtcdDiscoveryService) Initialize(uris string, heartbeat int) error {
|
func (s *EtcdDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
var (
|
var (
|
||||||
// split here because uris can contain multiples ips
|
// split here because uris can contain multiples ips
|
||||||
|
@ -51,6 +53,8 @@ func (s *EtcdDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch is exported
|
||||||
func (s *EtcdDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
func (s *EtcdDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
resp, err := s.client.Get(s.path, true, true)
|
resp, err := s.client.Get(s.path, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -64,6 +68,7 @@ func (s *EtcdDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return discovery.CreateEntries(addrs)
|
return discovery.CreateEntries(addrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *EtcdDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *EtcdDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
watchChan := make(chan *etcd.Response)
|
watchChan := make(chan *etcd.Response)
|
||||||
go s.client.Watch(s.path, 0, true, watchChan, nil)
|
go s.client.Watch(s.path, 0, true, watchChan, nil)
|
||||||
|
@ -76,6 +81,7 @@ func (s *EtcdDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func (s *EtcdDiscoveryService) Register(addr string) error {
|
func (s *EtcdDiscoveryService) Register(addr string) error {
|
||||||
_, err := s.client.Set(path.Join(s.path, addr), addr, s.ttl)
|
_, err := s.client.Set(path.Join(s.path, addr), addr, s.ttl)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/docker/swarm/discovery"
|
"github.com/docker/swarm/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FileDiscoveryService is exported
|
||||||
type FileDiscoveryService struct {
|
type FileDiscoveryService struct {
|
||||||
heartbeat int
|
heartbeat int
|
||||||
path string
|
path string
|
||||||
|
@ -17,6 +18,7 @@ func init() {
|
||||||
discovery.Register("file", &FileDiscoveryService{})
|
discovery.Register("file", &FileDiscoveryService{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *FileDiscoveryService) Initialize(path string, heartbeat int) error {
|
func (s *FileDiscoveryService) Initialize(path string, heartbeat int) error {
|
||||||
s.path = path
|
s.path = path
|
||||||
s.heartbeat = heartbeat
|
s.heartbeat = heartbeat
|
||||||
|
@ -33,6 +35,7 @@ func parseFileContent(content []byte) []string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch is exported
|
||||||
func (s *FileDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
func (s *FileDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
fileContent, err := ioutil.ReadFile(s.path)
|
fileContent, err := ioutil.ReadFile(s.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,6 +44,7 @@ func (s *FileDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return discovery.CreateEntries(parseFileContent(fileContent))
|
return discovery.CreateEntries(parseFileContent(fileContent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *FileDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *FileDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
|
for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
|
||||||
entries, err := s.Fetch()
|
entries, err := s.Fetch()
|
||||||
|
@ -50,6 +54,7 @@ func (s *FileDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func (s *FileDiscoveryService) Register(addr string) error {
|
func (s *FileDiscoveryService) Register(addr string) error {
|
||||||
return discovery.ErrNotImplemented
|
return discovery.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
// Generate takes care of IP generation
|
||||||
// IP generator
|
|
||||||
//
|
|
||||||
func Generate(pattern string) []string {
|
func Generate(pattern string) []string {
|
||||||
re, _ := regexp.Compile(`\[(.+):(.+)\]`)
|
re, _ := regexp.Compile(`\[(.+):(.+)\]`)
|
||||||
submatch := re.FindStringSubmatch(pattern)
|
submatch := re.FindStringSubmatch(pattern)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/docker/swarm/discovery"
|
"github.com/docker/swarm/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NodesDiscoveryService is exported
|
||||||
type NodesDiscoveryService struct {
|
type NodesDiscoveryService struct {
|
||||||
entries []*discovery.Entry
|
entries []*discovery.Entry
|
||||||
}
|
}
|
||||||
|
@ -14,6 +15,7 @@ func init() {
|
||||||
discovery.Register("nodes", &NodesDiscoveryService{})
|
discovery.Register("nodes", &NodesDiscoveryService{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *NodesDiscoveryService) Initialize(uris string, _ int) error {
|
func (s *NodesDiscoveryService) Initialize(uris string, _ int) error {
|
||||||
for _, input := range strings.Split(uris, ",") {
|
for _, input := range strings.Split(uris, ",") {
|
||||||
for _, ip := range discovery.Generate(input) {
|
for _, ip := range discovery.Generate(input) {
|
||||||
|
@ -27,13 +29,17 @@ func (s *NodesDiscoveryService) Initialize(uris string, _ int) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch is exported
|
||||||
func (s *NodesDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
func (s *NodesDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return s.entries, nil
|
return s.entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *NodesDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *NodesDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func (s *NodesDiscoveryService) Register(addr string) error {
|
func (s *NodesDiscoveryService) Register(addr string) error {
|
||||||
return discovery.ErrNotImplemented
|
return discovery.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,10 @@ import (
|
||||||
"github.com/docker/swarm/discovery"
|
"github.com/docker/swarm/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DISCOVERY_URL = "https://discovery-stage.hub.docker.com/v1"
|
// DiscoveryUrl is exported
|
||||||
|
const DiscoveryURL = "https://discovery-stage.hub.docker.com/v1"
|
||||||
|
|
||||||
|
// TokenDiscoveryService is exported
|
||||||
type TokenDiscoveryService struct {
|
type TokenDiscoveryService struct {
|
||||||
heartbeat int
|
heartbeat int
|
||||||
url string
|
url string
|
||||||
|
@ -24,12 +26,13 @@ func init() {
|
||||||
discovery.Register("token", &TokenDiscoveryService{})
|
discovery.Register("token", &TokenDiscoveryService{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *TokenDiscoveryService) Initialize(urltoken string, heartbeat int) error {
|
func (s *TokenDiscoveryService) Initialize(urltoken string, heartbeat int) error {
|
||||||
if i := strings.LastIndex(urltoken, "/"); i != -1 {
|
if i := strings.LastIndex(urltoken, "/"); i != -1 {
|
||||||
s.url = "https://" + urltoken[:i]
|
s.url = "https://" + urltoken[:i]
|
||||||
s.token = urltoken[i+1:]
|
s.token = urltoken[i+1:]
|
||||||
} else {
|
} else {
|
||||||
s.url = DISCOVERY_URL
|
s.url = DiscoveryURL
|
||||||
s.token = urltoken
|
s.token = urltoken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +66,7 @@ func (s *TokenDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return discovery.CreateEntries(addrs)
|
return discovery.CreateEntries(addrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *TokenDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *TokenDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
|
for _ = range time.Tick(time.Duration(s.heartbeat) * time.Second) {
|
||||||
entries, err := s.Fetch()
|
entries, err := s.Fetch()
|
||||||
|
@ -72,7 +76,7 @@ func (s *TokenDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterEntry adds a new entry identified by the into the discovery service
|
// Register adds a new entry identified by the into the discovery service
|
||||||
func (s *TokenDiscoveryService) Register(addr string) error {
|
func (s *TokenDiscoveryService) Register(addr string) error {
|
||||||
buf := strings.NewReader(addr)
|
buf := strings.NewReader(addr)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ func TestInitialize(t *testing.T) {
|
||||||
err := discovery.Initialize("token", 0)
|
err := discovery.Initialize("token", 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, discovery.token, "token")
|
assert.Equal(t, discovery.token, "token")
|
||||||
assert.Equal(t, discovery.url, DISCOVERY_URL)
|
assert.Equal(t, discovery.url, DiscoveryURL)
|
||||||
|
|
||||||
err = discovery.Initialize("custom/path/token", 0)
|
err = discovery.Initialize("custom/path/token", 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -23,7 +23,7 @@ func TestInitialize(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegister(t *testing.T) {
|
func TestRegister(t *testing.T) {
|
||||||
discovery := &TokenDiscoveryService{token: "TEST_TOKEN", url: DISCOVERY_URL}
|
discovery := &TokenDiscoveryService{token: "TEST_TOKEN", url: DiscoveryURL}
|
||||||
expected := "127.0.0.1:2675"
|
expected := "127.0.0.1:2675"
|
||||||
assert.NoError(t, discovery.Register(expected))
|
assert.NoError(t, discovery.Register(expected))
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/samuel/go-zookeeper/zk"
|
"github.com/samuel/go-zookeeper/zk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ZkDiscoveryService is exported
|
||||||
type ZkDiscoveryService struct {
|
type ZkDiscoveryService struct {
|
||||||
conn *zk.Conn
|
conn *zk.Conn
|
||||||
path []string
|
path []string
|
||||||
|
@ -39,6 +40,7 @@ func (s *ZkDiscoveryService) createFullpath() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (s *ZkDiscoveryService) Initialize(uris string, heartbeat int) error {
|
func (s *ZkDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
var (
|
var (
|
||||||
// split here because uris can contain multiples ips
|
// split here because uris can contain multiples ips
|
||||||
|
@ -72,6 +74,7 @@ func (s *ZkDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch is exported
|
||||||
func (s *ZkDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
func (s *ZkDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
addrs, _, err := s.conn.Children(s.fullpath())
|
addrs, _, err := s.conn.Children(s.fullpath())
|
||||||
|
|
||||||
|
@ -82,6 +85,7 @@ func (s *ZkDiscoveryService) Fetch() ([]*discovery.Entry, error) {
|
||||||
return discovery.CreateEntries(addrs)
|
return discovery.CreateEntries(addrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch is exported
|
||||||
func (s *ZkDiscoveryService) Watch(callback discovery.WatchCallback) {
|
func (s *ZkDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
|
|
||||||
addrs, _, eventChan, err := s.conn.ChildrenW(s.fullpath())
|
addrs, _, eventChan, err := s.conn.ChildrenW(s.fullpath())
|
||||||
|
@ -107,6 +111,7 @@ func (s *ZkDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register is exported
|
||||||
func (s *ZkDiscoveryService) Register(addr string) error {
|
func (s *ZkDiscoveryService) Register(addr string) error {
|
||||||
nodePath := path.Join(s.fullpath(), addr)
|
nodePath := path.Join(s.fullpath(), addr)
|
||||||
|
|
||||||
|
|
15
flags.go
15
flags.go
|
@ -54,23 +54,23 @@ var (
|
||||||
Name: "api-enable-cors, cors",
|
Name: "api-enable-cors, cors",
|
||||||
Usage: "enable CORS headers in the remote API",
|
Usage: "enable CORS headers in the remote API",
|
||||||
}
|
}
|
||||||
flTls = cli.BoolFlag{
|
flTLS = cli.BoolFlag{
|
||||||
Name: "tls",
|
Name: "tls",
|
||||||
Usage: "use TLS; implied by --tlsverify=true",
|
Usage: "use TLS; implied by --tlsverify=true",
|
||||||
}
|
}
|
||||||
flTlsCaCert = cli.StringFlag{
|
flTLSCaCert = cli.StringFlag{
|
||||||
Name: "tlscacert",
|
Name: "tlscacert",
|
||||||
Usage: "trust only remotes providing a certificate signed by the CA given here",
|
Usage: "trust only remotes providing a certificate signed by the CA given here",
|
||||||
}
|
}
|
||||||
flTlsCert = cli.StringFlag{
|
flTLSCert = cli.StringFlag{
|
||||||
Name: "tlscert",
|
Name: "tlscert",
|
||||||
Usage: "path to TLS certificate file",
|
Usage: "path to TLS certificate file",
|
||||||
}
|
}
|
||||||
flTlsKey = cli.StringFlag{
|
flTLSKey = cli.StringFlag{
|
||||||
Name: "tlskey",
|
Name: "tlskey",
|
||||||
Usage: "path to TLS key file",
|
Usage: "path to TLS key file",
|
||||||
}
|
}
|
||||||
flTlsVerify = cli.BoolFlag{
|
flTLSVerify = cli.BoolFlag{
|
||||||
Name: "tlsverify",
|
Name: "tlsverify",
|
||||||
Usage: "use TLS and verify the remote",
|
Usage: "use TLS and verify the remote",
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,9 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack for go vet
|
// hack for go vet
|
||||||
flFilterValue = cli.StringSlice([]string{"constraint", "affinity", "health", "port", "dependency"})
|
flFilterValue = cli.StringSlice([]string{"constraint", "affinity", "health", "port", "dependency"})
|
||||||
DEFAULT_FILTER_NUMBER = len(flFilterValue)
|
// DefaultFilterNumber is exported
|
||||||
|
DefaultFilterNumber = len(flFilterValue)
|
||||||
|
|
||||||
flFilter = cli.StringSliceFlag{
|
flFilter = cli.StringSliceFlag{
|
||||||
Name: "filter, f",
|
Name: "filter, f",
|
||||||
|
|
2
main.go
2
main.go
|
@ -108,7 +108,7 @@ func main() {
|
||||||
flStore, flCluster,
|
flStore, flCluster,
|
||||||
flStrategy, flFilter,
|
flStrategy, flFilter,
|
||||||
flHosts, flHeartBeat, flOverCommit,
|
flHosts, flHeartBeat, flOverCommit,
|
||||||
flTls, flTlsCaCert, flTlsCert, flTlsKey, flTlsVerify,
|
flTLS, flTLSCaCert, flTLSCert, flTLSKey, flTLSVerify,
|
||||||
flEnableCors},
|
flEnableCors},
|
||||||
Action: manage,
|
Action: manage,
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,7 @@ func (h *logHandler) Handle(e *cluster.Event) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the TLS certificates/keys and, if verify is true, the CA.
|
// Load the TLS certificates/keys and, if verify is true, the CA.
|
||||||
func loadTlsConfig(ca, cert, key string, verify bool) (*tls.Config, error) {
|
func loadTLSConfig(ca, cert, key string, verify bool) (*tls.Config, error) {
|
||||||
c, err := tls.LoadX509KeyPair(cert, key)
|
c, err := tls.LoadX509KeyPair(cert, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
|
return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
|
||||||
|
@ -64,7 +64,7 @@ func loadTlsConfig(ca, cert, key string, verify bool) (*tls.Config, error) {
|
||||||
|
|
||||||
func manage(c *cli.Context) {
|
func manage(c *cli.Context) {
|
||||||
var (
|
var (
|
||||||
tlsConfig *tls.Config = nil
|
tlsConfig *tls.Config
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func manage(c *cli.Context) {
|
||||||
if c.Bool("tlsverify") && !c.IsSet("tlscacert") {
|
if c.Bool("tlsverify") && !c.IsSet("tlscacert") {
|
||||||
log.Fatal("--tlscacert must be provided when using --tlsverify")
|
log.Fatal("--tlscacert must be provided when using --tlsverify")
|
||||||
}
|
}
|
||||||
tlsConfig, err = loadTlsConfig(
|
tlsConfig, err = loadTLSConfig(
|
||||||
c.String("tlscacert"),
|
c.String("tlscacert"),
|
||||||
c.String("tlscert"),
|
c.String("tlscert"),
|
||||||
c.String("tlskey"),
|
c.String("tlskey"),
|
||||||
|
@ -110,7 +110,7 @@ func manage(c *cli.Context) {
|
||||||
// see https://github.com/codegangsta/cli/issues/160
|
// see https://github.com/codegangsta/cli/issues/160
|
||||||
names := c.StringSlice("filter")
|
names := c.StringSlice("filter")
|
||||||
if c.IsSet("filter") || c.IsSet("f") {
|
if c.IsSet("filter") || c.IsSet("f") {
|
||||||
names = names[DEFAULT_FILTER_NUMBER:]
|
names = names[DefaultFilterNumber:]
|
||||||
}
|
}
|
||||||
fs, err := filter.New(names)
|
fs, err := filter.New(names)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
type AffinityFilter struct {
|
type AffinityFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
affinities, err := parseExprs("affinity", config.Env)
|
affinities, err := parseExprs("affinity", config.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type ConstraintFilter struct {
|
type ConstraintFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
func (f *ConstraintFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func (f *ConstraintFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
constraints, err := parseExprs("constraint", config.Env)
|
constraints, err := parseExprs("constraint", config.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type DependencyFilter struct {
|
type DependencyFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
func (f *DependencyFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func (f *DependencyFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
|
|
|
@ -9,10 +9,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// EQ is exported
|
||||||
EQ = iota
|
EQ = iota
|
||||||
|
// NOTEQ is exported
|
||||||
NOTEQ
|
NOTEQ
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OPERATORS is exported
|
||||||
var OPERATORS = []string{"==", "!="}
|
var OPERATORS = []string{"==", "!="}
|
||||||
|
|
||||||
type expr struct {
|
type expr struct {
|
||||||
|
@ -109,7 +112,6 @@ func (e *expr) Match(whats ...string) bool {
|
||||||
func isSoft(value string) bool {
|
func isSoft(value string) bool {
|
||||||
if value[0] == '~' {
|
if value[0] == '~' {
|
||||||
return true
|
return true
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,15 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
// Return a subset of nodes that were accepted by the filtering policy.
|
// Return a subset of nodes that were accepted by the filtering policy.
|
||||||
Filter(*dockerclient.ContainerConfig, []cluster.Node) ([]cluster.Node, error)
|
Filter(*dockerclient.ContainerConfig, []cluster.Node) ([]cluster.Node, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
filters map[string]Filter
|
filters map[string]Filter
|
||||||
|
// ErrNotSupported is exported
|
||||||
ErrNotSupported = errors.New("filter not supported")
|
ErrNotSupported = errors.New("filter not supported")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +30,7 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is exported
|
||||||
func New(names []string) ([]Filter, error) {
|
func New(names []string) ([]Filter, error) {
|
||||||
var selectedFilters []Filter
|
var selectedFilters []Filter
|
||||||
|
|
||||||
|
@ -42,7 +45,7 @@ func New(names []string) ([]Filter, error) {
|
||||||
return selectedFilters, nil
|
return selectedFilters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply a set of filters in batch.
|
// ApplyFilters applies a set of filters in batch.
|
||||||
func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// ErrNoHealthyNodeAvailable is exported
|
||||||
ErrNoHealthyNodeAvailable = errors.New("No healthy node available in the cluster")
|
ErrNoHealthyNodeAvailable = errors.New("No healthy node available in the cluster")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ var (
|
||||||
type HealthFilter struct {
|
type HealthFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
func (f *HealthFilter) Filter(_ *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func (f *HealthFilter) Filter(_ *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
result := []cluster.Node{}
|
result := []cluster.Node{}
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
type PortFilter struct {
|
type PortFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter is exported
|
||||||
func (p *PortFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
func (p *PortFilter) Filter(config *dockerclient.ContainerConfig, nodes []cluster.Node) ([]cluster.Node, error) {
|
||||||
for _, port := range config.HostConfig.PortBindings {
|
for _, port := range config.HostConfig.PortBindings {
|
||||||
for _, binding := range port {
|
for _, binding := range port {
|
||||||
|
|
|
@ -7,11 +7,13 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Scheduler is exported
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
strategy strategy.PlacementStrategy
|
strategy strategy.PlacementStrategy
|
||||||
filters []filter.Filter
|
filters []filter.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is exported
|
||||||
func New(strategy strategy.PlacementStrategy, filters []filter.Filter) *Scheduler {
|
func New(strategy strategy.PlacementStrategy, filters []filter.Filter) *Scheduler {
|
||||||
return &Scheduler{
|
return &Scheduler{
|
||||||
strategy: strategy,
|
strategy: strategy,
|
||||||
|
@ -19,7 +21,7 @@ func New(strategy strategy.PlacementStrategy, filters []filter.Filter) *Schedule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a nice home for our container.
|
// SelectNodeForContainer will find a nice home for our container.
|
||||||
func (s *Scheduler) SelectNodeForContainer(nodes []cluster.Node, config *dockerclient.ContainerConfig) (cluster.Node, error) {
|
func (s *Scheduler) SelectNodeForContainer(nodes []cluster.Node, config *dockerclient.ContainerConfig) (cluster.Node, error) {
|
||||||
accepted, err := filter.ApplyFilters(s.filters, config, nodes)
|
accepted, err := filter.ApplyFilters(s.filters, config, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -7,13 +7,16 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BinpackPlacementStrategy is exported
|
||||||
type BinpackPlacementStrategy struct {
|
type BinpackPlacementStrategy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (p *BinpackPlacementStrategy) Initialize() error {
|
func (p *BinpackPlacementStrategy) Initialize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlaceContainer is exported
|
||||||
func (p *BinpackPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
func (p *BinpackPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
||||||
weightedNodes, err := weighNodes(config, nodes)
|
weightedNodes, err := weighNodes(config, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,14 +9,16 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Randomly place the container into the cluster.
|
// RandomPlacementStrategy randomly places the container into the cluster.
|
||||||
type RandomPlacementStrategy struct{}
|
type RandomPlacementStrategy struct{}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (p *RandomPlacementStrategy) Initialize() error {
|
func (p *RandomPlacementStrategy) Initialize() error {
|
||||||
rand.Seed(time.Now().UTC().UnixNano())
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlaceContainer is exported
|
||||||
func (p *RandomPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
func (p *RandomPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
||||||
if size := len(nodes); size > 0 {
|
if size := len(nodes); size > 0 {
|
||||||
n := rand.Intn(len(nodes))
|
n := rand.Intn(len(nodes))
|
||||||
|
|
|
@ -7,13 +7,16 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SpreadPlacementStrategy is exported
|
||||||
type SpreadPlacementStrategy struct {
|
type SpreadPlacementStrategy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize is exported
|
||||||
func (p *SpreadPlacementStrategy) Initialize() error {
|
func (p *SpreadPlacementStrategy) Initialize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlaceContainer is exported
|
||||||
func (p *SpreadPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
func (p *SpreadPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []cluster.Node) (cluster.Node, error) {
|
||||||
weightedNodes, err := weighNodes(config, nodes)
|
weightedNodes, err := weighNodes(config, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PlacementStrategy is exported
|
||||||
type PlacementStrategy interface {
|
type PlacementStrategy interface {
|
||||||
Initialize() error
|
Initialize() error
|
||||||
// Given a container configuration and a set of nodes, select the target
|
// Given a container configuration and a set of nodes, select the target
|
||||||
|
@ -16,8 +17,10 @@ type PlacementStrategy interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
strategies map[string]PlacementStrategy
|
strategies map[string]PlacementStrategy
|
||||||
ErrNotSupported = errors.New("strategy not supported")
|
// ErrNotSupported is exported
|
||||||
|
ErrNotSupported = errors.New("strategy not supported")
|
||||||
|
// ErrNoResourcesAvailable is exported
|
||||||
ErrNoResourcesAvailable = errors.New("no resources available to schedule container")
|
ErrNoResourcesAvailable = errors.New("no resources available to schedule container")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,6 +33,7 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New is exported
|
||||||
func New(name string) (PlacementStrategy, error) {
|
func New(name string) (PlacementStrategy, error) {
|
||||||
if strategy, exists := strategies[name]; exists {
|
if strategy, exists := strategies[name]; exists {
|
||||||
log.WithField("name", name).Debugf("Initializing strategy")
|
log.WithField("name", name).Debugf("Initializing strategy")
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/samalba/dockerclient"
|
"github.com/samalba/dockerclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RequestedState is exported
|
||||||
type RequestedState struct {
|
type RequestedState struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
|
|
|
@ -14,12 +14,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNotFound = errors.New("not found")
|
// ErrNotFound is exported
|
||||||
|
ErrNotFound = errors.New("not found")
|
||||||
|
// ErrAlreadyExists is exported
|
||||||
ErrAlreadyExists = errors.New("already exists")
|
ErrAlreadyExists = errors.New("already exists")
|
||||||
ErrInvalidKey = errors.New("invalid key")
|
// ErrInvalidKey is exported
|
||||||
|
ErrInvalidKey = errors.New("invalid key")
|
||||||
)
|
)
|
||||||
|
|
||||||
// A simple key<->RequestedState store.
|
// Store is a simple key<->RequestedState store.
|
||||||
type Store struct {
|
type Store struct {
|
||||||
RootDir string
|
RootDir string
|
||||||
values map[string]*RequestedState
|
values map[string]*RequestedState
|
||||||
|
@ -27,6 +30,7 @@ type Store struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStore is exported
|
||||||
func NewStore(rootdir string) *Store {
|
func NewStore(rootdir string) *Store {
|
||||||
return &Store{
|
return &Store{
|
||||||
RootDir: rootdir,
|
RootDir: rootdir,
|
||||||
|
@ -102,7 +106,7 @@ func (s *Store) load(file string) (*RequestedState, error) {
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves an object from the store keyed by `key`.
|
// Get an object from the store keyed by `key`.
|
||||||
func (s *Store) Get(key string) (*RequestedState, error) {
|
func (s *Store) Get(key string) (*RequestedState, error) {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
defer s.RUnlock()
|
defer s.RUnlock()
|
||||||
|
@ -113,7 +117,7 @@ func (s *Store) Get(key string) (*RequestedState, error) {
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return all objects of the store.
|
// All objects of the store are returned.
|
||||||
func (s *Store) All() []*RequestedState {
|
func (s *Store) All() []*RequestedState {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
defer s.RUnlock()
|
defer s.RUnlock()
|
||||||
|
@ -157,7 +161,7 @@ func (s *Store) Add(key string, value *RequestedState) error {
|
||||||
return s.set(key, value)
|
return s.set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces an already existing object from the store.
|
// Replace an already existing object from the store.
|
||||||
func (s *Store) Replace(key string, value *RequestedState) error {
|
func (s *Store) Replace(key string, value *RequestedState) error {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
Loading…
Reference in New Issue