blob: e5f03e819e6c0fd41b4335f8bf9aaba9706786a3 [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())
David K. Bainbridge841959f2017-11-14 11:06:30 -080049 return nil, err
David K. Bainbridge215e0242017-09-05 23:18:24 -070050 }
51
52 tasks, err := c.client.TaskList(context.Background(), types.TaskListOptions{})
53 if err != nil {
54 log.Error("Error while quering tasks")
David K. Bainbridge841959f2017-11-14 11:06:30 -080055 return nil, err
David K. Bainbridge215e0242017-09-05 23:18:24 -070056 }
57
58 nodes, err := c.client.NodeList(context.Background(), types.NodeListOptions{})
59 if err != nil {
60 log.Error("Error while quering nodes")
David K. Bainbridge841959f2017-11-14 11:06:30 -080061 return nil, err
David K. Bainbridge215e0242017-09-05 23:18:24 -070062 }
63
64 for _, node := range nodes {
65 nodeState[node.ID] = (node.Status.State == swarm.NodeStateReady)
66 log.Debugf("NODE STATUS: %s : %t", node.ID, nodeState[node.ID])
67 }
68
69 log.Debugf("SERVICE COUNT: %d", len(services))
70 for _, service := range services {
71 log.Debugf("NAME: %s, WANT: %s, HAVE: %s", service.Spec.Name, labels, service.Spec.Labels)
72 if labelMatch(service.Spec.Labels, labels) {
73 log.Debugf("MATCH: NAME: %s, EXPECTED: %d", service.Spec.Name, *service.Spec.Mode.Replicated.Replicas)
74 info.Expected += *service.Spec.Mode.Replicated.Replicas
75
76 for _, task := range tasks {
77 // If tasks is not associated with the matching serice, reject it
78 if task.ServiceID != service.ID {
79 continue
80 }
81
82 // If the task is not on a running node, reject it
83 if !nodeState[task.NodeID] || task.Status.State != swarm.TaskStateRunning {
84 log.Debugf("Found matching task '%s' [%s], on node '%s' [%t]",
85 task.ID, task.Status.State, task.NodeID, nodeState[task.NodeID])
86 continue
87 }
88 log.Debugf("Found matching task '%s' on node '%s', with a state of %s",
89 task.ID, task.NodeID, task.Status.State)
90
91 /*
92 * Need to discover an IP for the container to use for clustering
93 * purposes. The search is prioritized as:
94 * 1. If there is a labeled network then use the IP from that
95 * 2. If there is only a single network, besides the default ingress
96 * network, then use that
97 * 3. If there is only a single network, than use that.
98 * 4. Else ignore task as we can't deterine which network to
99 * use
100 */
101 found := false
102 count := len(networkLabels)
103 for _, network := range task.NetworksAttachments {
104 if count == 0 || labelMatch(network.Network.Spec.Labels, networkLabels) {
105 ip, _, _ := net.ParseCIDR(network.Addresses[0])
106 info.Nodes = append(info.Nodes, ip.String())
107 found = true
108 break
109 }
110 }
111 if !found {
112 log.Warnf("Unable to determine network (IP) information for task '%s'",
113 task.ID)
114 }
115 }
116 }
117 }
118
119 return &info, nil
120}
121
122func (c *SwarmClient) Close() error {
123 return nil
124}