diff --git a/Dockerfile.dind b/Dockerfile.dind index 10c6b9f..9773684 100644 --- a/Dockerfile.dind +++ b/Dockerfile.dind @@ -1,6 +1,8 @@ FROM docker:1.13.0-rc2-dind -ENV DOCKER_STORAGE_DRIVER=overlay2 +ARG docker_storage_driver=overlay2 + +ENV DOCKER_STORAGE_DRIVER=${docker-storage-driver} RUN apk add --no-cache git tmux py-pip apache2-utils vim build-base gettext-dev curl bash diff --git a/docker-compose.yml b/docker-compose.yml index 75b3133..e986c75 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: # use the latest golang image image: golang # go to the right place and starts the app - command: /bin/sh -c 'cd /go/src/github.com/franela/play-with-docker; go run -race api.go' + command: /bin/sh -c 'cd /go/src/github.com/franela/play-with-docker; go run api.go' ports: # app exposes port 3000 - "3000:3000" diff --git a/services/broadcast_info_task.go b/services/broadcast_info_task.go deleted file mode 100644 index 1e1c8dc..0000000 --- a/services/broadcast_info_task.go +++ /dev/null @@ -1,8 +0,0 @@ -package services - -type broadcastInfoTask struct { -} - -func (c *broadcastInfoTask) Run(i *Instance) { - wsServer.BroadcastTo(i.session.Id, "instance stats", i.Name, i.Mem, i.Cpu, i.IsManager, i.Ports) -} diff --git a/services/check_swarm_status_task.go b/services/check_swarm_status_task.go index ede3da0..610ca6e 100644 --- a/services/check_swarm_status_task.go +++ b/services/check_swarm_status_task.go @@ -1,6 +1,10 @@ package services -import "github.com/docker/docker/api/types/swarm" +import ( + "log" + + "github.com/docker/docker/api/types/swarm" +) type checkSwarmStatusTask struct { } @@ -12,6 +16,8 @@ func (c checkSwarmStatusTask) Run(i *Instance) { } else { i.IsManager = nil } + } else { + log.Println(err) } } diff --git a/services/check_swarm_used_ports.go b/services/check_swarm_used_ports.go new file mode 100644 index 0000000..e888b95 --- /dev/null +++ b/services/check_swarm_used_ports.go @@ -0,0 +1,15 @@ +package services + +import "log" + +type checkSwarmUsedPortsTask struct { +} + +func (c checkSwarmUsedPortsTask) Run(i *Instance) { + if i.IsManager != nil && *i.IsManager { + // This is a swarm manager instance, then check for ports + if err := SetInstanceSwarmPorts(i); err != nil { + log.Println(err) + } + } +} diff --git a/services/check_used_ports_task.go b/services/check_used_ports_task.go index bf27cb7..811f9bb 100644 --- a/services/check_used_ports_task.go +++ b/services/check_used_ports_task.go @@ -5,6 +5,8 @@ type checkUsedPortsTask struct { func (c checkUsedPortsTask) Run(i *Instance) { if ports, err := GetUsedPorts(i); err == nil { - i.Ports = ports + for _, p := range ports { + i.setUsedPort(p) + } } } diff --git a/services/docker.go b/services/docker.go index d461076..e4c6161 100644 --- a/services/docker.go +++ b/services/docker.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "log" + "strings" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -46,6 +47,55 @@ func GetDaemonInfo(i *Instance) (types.Info, error) { } return i.dockerClient.Info(context.Background()) } + +func SetInstanceSwarmPorts(i *Instance) error { + if i.dockerClient == nil { + return fmt.Errorf("Docker client for DinD (%s) is not ready", i.IP) + } + + hostnamesIdx := map[string]*Instance{} + for _, ins := range i.session.Instances { + hostnamesIdx[ins.Hostname] = ins + } + + nodesIdx := map[string]*Instance{} + nodes, nodesErr := i.dockerClient.NodeList(context.Background(), types.NodeListOptions{}) + if nodesErr != nil { + return nodesErr + } + for _, n := range nodes { + nodesIdx[n.ID] = hostnamesIdx[n.Description.Hostname] + } + + tasks, err := i.dockerClient.TaskList(context.Background(), types.TaskListOptions{}) + if err != nil { + return err + } + services := map[string][]uint16{} + for _, t := range tasks { + services[t.ServiceID] = []uint16{} + } + for serviceID, _ := range services { + s, _, err := i.dockerClient.ServiceInspectWithRaw(context.Background(), serviceID) + if err != nil { + return err + } + for _, p := range s.Endpoint.Ports { + services[serviceID] = append(services[serviceID], uint16(p.PublishedPort)) + } + } + for _, t := range tasks { + for _, n := range nodes { + ins := nodesIdx[n.ID] + for _, p := range services[t.ServiceID] { + ins.setUsedPort(p) + } + } + } + + return nil +} + func GetUsedPorts(i *Instance) ([]uint16, error) { if i.dockerClient == nil { return nil, fmt.Errorf("Docker client for DinD (%s) is not ready", i.IP) @@ -84,7 +134,7 @@ func CreateNetwork(name string) error { func ConnectNetwork(containerId, networkId string) error { err := c.NetworkConnect(context.Background(), networkId, containerId, &network.EndpointSettings{}) - if err != nil { + if err != nil && !strings.Contains(err.Error(), "already exists") { log.Printf("Connection container to network err [%s]\n", err) return err diff --git a/services/instance.go b/services/instance.go index b03757c..2342449 100644 --- a/services/instance.go +++ b/services/instance.go @@ -28,6 +28,19 @@ type Instance struct { Mem string `json:"mem"` Cpu string `json:"cpu"` Ports []uint16 `json:"ports"` + tempPorts []uint16 `json:"-"` +} + +func (i *Instance) setUsedPort(port uint16) { + rw.Lock() + defer rw.Unlock() + + for _, p := range i.tempPorts { + if p == port { + return + } + } + i.tempPorts = append(i.tempPorts, port) } func (i *Instance) IsConnected() bool { diff --git a/services/session.go b/services/session.go index de9eea3..57405ad 100644 --- a/services/session.go +++ b/services/session.go @@ -94,6 +94,12 @@ func (s *Session) SchedulePeriodicTasks() { }() } wg.Wait() + // broadcast all information + for _, ins := range s.Instances { + ins.Ports = ins.tempPorts + ins.tempPorts = []uint16{} + wsServer.BroadcastTo(ins.session.Id, "instance stats", ins.Name, ins.Mem, ins.Cpu, ins.IsManager, ins.Ports) + } } }() } @@ -123,7 +129,9 @@ func CloseSession(s *Session) error { s.rw.Lock() defer s.rw.Unlock() - s.ticker.Stop() + if s.ticker != nil { + s.ticker.Stop() + } wsServer.BroadcastTo(s.Id, "session end") log.Printf("Starting clean up of session [%s]\n", s.Id) for _, i := range s.Instances { @@ -238,6 +246,13 @@ func LoadSessionsFromDisk() error { } + // Connect PWD daemon to the new network + if err := ConnectNetwork("pwd", s.Id); err != nil { + log.Println("ERROR NETWORKING") + return err + } + log.Printf("Connected pwd to network [%s]\n", s.Id) + // Schedule peridic tasks execution s.SchedulePeriodicTasks() } diff --git a/services/task.go b/services/task.go index 0ee41fb..966197e 100644 --- a/services/task.go +++ b/services/task.go @@ -7,5 +7,5 @@ type periodicTask interface { var periodicTasks []periodicTask func init() { - periodicTasks = append(periodicTasks, &collectStatsTask{}, &checkSwarmStatusTask{}, &checkUsedPortsTask{}, &broadcastInfoTask{}) + periodicTasks = append(periodicTasks, &collectStatsTask{}, &checkSwarmStatusTask{}, &checkUsedPortsTask{}, &checkSwarmUsedPortsTask{}) }