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