blob: 87480d5c5f5135303ed231a7f7b9f2242f217d07 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Copyright 2017 the original author or authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18 "context"
19 "net"
20 "net/url"
21
22 "github.com/docker/docker/api/types"
23 "github.com/docker/docker/api/types/swarm"
24 "github.com/docker/docker/client"
25)
26
27type SwarmClient struct {
28 client *client.Client
29}
30
31func (c *SwarmClient) Init(aurl *url.URL) error {
32 var err error
33 c.client, err = client.NewEnvClient()
34 if err != nil {
35 return err
36 }
37
38 return nil
39}
40
41func (c *SwarmClient) GetInfo(labels map[string]string, networkLabels map[string]string) (*ClusterInfo, error) {
42 info := ClusterInfo{}
43
44 nodeState := make(map[string]bool)
45
46 services, err := c.client.ServiceList(context.Background(), types.ServiceListOptions{})
47 if err != nil {
48 log.Errorf("Error while quering services : %s", err.Error())
49 }
50
51 tasks, err := c.client.TaskList(context.Background(), types.TaskListOptions{})
52 if err != nil {
53 log.Error("Error while quering tasks")
54 }
55
56 nodes, err := c.client.NodeList(context.Background(), types.NodeListOptions{})
57 if err != nil {
58 log.Error("Error while quering nodes")
59 }
60
61 for _, node := range nodes {
62 nodeState[node.ID] = (node.Status.State == swarm.NodeStateReady)
63 log.Debugf("NODE STATUS: %s : %t", node.ID, nodeState[node.ID])
64 }
65
66 log.Debugf("SERVICE COUNT: %d", len(services))
67 for _, service := range services {
68 log.Debugf("NAME: %s, WANT: %s, HAVE: %s", service.Spec.Name, labels, service.Spec.Labels)
69 if labelMatch(service.Spec.Labels, labels) {
70 log.Debugf("MATCH: NAME: %s, EXPECTED: %d", service.Spec.Name, *service.Spec.Mode.Replicated.Replicas)
71 info.Expected += *service.Spec.Mode.Replicated.Replicas
72
73 for _, task := range tasks {
74 // If tasks is not associated with the matching serice, reject it
75 if task.ServiceID != service.ID {
76 continue
77 }
78
79 // If the task is not on a running node, reject it
80 if !nodeState[task.NodeID] || task.Status.State != swarm.TaskStateRunning {
81 log.Debugf("Found matching task '%s' [%s], on node '%s' [%t]",
82 task.ID, task.Status.State, task.NodeID, nodeState[task.NodeID])
83 continue
84 }
85 log.Debugf("Found matching task '%s' on node '%s', with a state of %s",
86 task.ID, task.NodeID, task.Status.State)
87
88 /*
89 * Need to discover an IP for the container to use for clustering
90 * purposes. The search is prioritized as:
91 * 1. If there is a labeled network then use the IP from that
92 * 2. If there is only a single network, besides the default ingress
93 * network, then use that
94 * 3. If there is only a single network, than use that.
95 * 4. Else ignore task as we can't deterine which network to
96 * use
97 */
98 found := false
99 count := len(networkLabels)
100 for _, network := range task.NetworksAttachments {
101 if count == 0 || labelMatch(network.Network.Spec.Labels, networkLabels) {
102 ip, _, _ := net.ParseCIDR(network.Addresses[0])
103 info.Nodes = append(info.Nodes, ip.String())
104 found = true
105 break
106 }
107 }
108 if !found {
109 log.Warnf("Unable to determine network (IP) information for task '%s'",
110 task.ID)
111 }
112 }
113 }
114 }
115
116 return &info, nil
117}
118
119func (c *SwarmClient) Close() error {
120 return nil
121}