From 17abacb8946ed89496fcbf07a0288fafe24cb7b0 Mon Sep 17 00:00:00 2001
From: Brian Goff <cpuguy83@gmail.com>
Date: Tue, 11 Apr 2017 17:21:21 -0400
Subject: [PATCH] Add logdrivers to /info

This is required for swarmkit to be able to filter based on log driver.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
---
 api/types/types.go                            |  2 ++
 cli/command/system/info.go                    |  4 ++++
 daemon/cluster/executor/container/executor.go |  9 ++++++--
 daemon/info.go                                |  2 ++
 daemon/logger/factory.go                      | 17 ++++++++++++++
 .../docker_cli_plugins_logdriver_test.go      | 22 +++++++++++++++++++
 6 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/api/types/types.go b/api/types/types.go
index bbaf2c5531..9493bd95e2 100644
--- a/api/types/types.go
+++ b/api/types/types.go
@@ -238,6 +238,8 @@ type PluginsInfo struct {
 	Network []string
 	// List of Authorization plugins registered
 	Authorization []string
+	// List of Log plugins registered
+	Log []string
 }
 
 // ExecStartCheck is a temp struct used by execStart
diff --git a/cli/command/system/info.go b/cli/command/system/info.go
index 8498dd8c55..8ded8124dc 100644
--- a/cli/command/system/info.go
+++ b/cli/command/system/info.go
@@ -90,6 +90,10 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
 		fmt.Fprintf(dockerCli.Out(), "\n")
 	}
 
+	fmt.Fprintf(dockerCli.Out(), " Log:")
+	fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Log, " "))
+	fmt.Fprintf(dockerCli.Out(), "\n")
+
 	fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState)
 	if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive && info.Swarm.LocalNodeState != swarm.LocalNodeStateLocked {
 		fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID)
diff --git a/daemon/cluster/executor/container/executor.go b/daemon/cluster/executor/container/executor.go
index 6be0f3156c..98e0d10f1a 100644
--- a/daemon/cluster/executor/container/executor.go
+++ b/daemon/cluster/executor/container/executor.go
@@ -52,6 +52,7 @@ func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
 	// the plugin list by default.
 	addPlugins("Network", append([]string{"overlay"}, info.Plugins.Network...))
 	addPlugins("Authorization", info.Plugins.Authorization)
+	addPlugins("Log", info.Plugins.Log)
 
 	// add v2 plugins
 	v2Plugins, err := e.backend.PluginManager().List(filters.NewArgs())
@@ -62,11 +63,15 @@ func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
 					continue
 				}
 				plgnTyp := typ.Capability
-				if typ.Capability == "volumedriver" {
+				switch typ.Capability {
+				case "volumedriver":
 					plgnTyp = "Volume"
-				} else if typ.Capability == "networkdriver" {
+				case "networkdriver":
 					plgnTyp = "Network"
+				case "logdriver":
+					plgnTyp = "Log"
 				}
+
 				plugins[api.PluginDescription{
 					Type: plgnTyp,
 					Name: plgn.Name,
diff --git a/daemon/info.go b/daemon/info.go
index 919e8ed3d1..b6c2565f44 100644
--- a/daemon/info.go
+++ b/daemon/info.go
@@ -12,6 +12,7 @@ import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/cli/debug"
 	"github.com/docker/docker/container"
+	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/pkg/fileutils"
 	"github.com/docker/docker/pkg/parsers/kernel"
@@ -175,6 +176,7 @@ func (daemon *Daemon) showPluginsInfo() types.PluginsInfo {
 	pluginsInfo.Volume = volumedrivers.GetDriverList()
 	pluginsInfo.Network = daemon.GetNetworkDriverList()
 	pluginsInfo.Authorization = daemon.configStore.GetAuthorizationPlugins()
+	pluginsInfo.Log = logger.ListDrivers()
 
 	return pluginsInfo
 }
diff --git a/daemon/logger/factory.go b/daemon/logger/factory.go
index 32d51effa8..32001590d9 100644
--- a/daemon/logger/factory.go
+++ b/daemon/logger/factory.go
@@ -2,6 +2,7 @@ package logger
 
 import (
 	"fmt"
+	"sort"
 	"sync"
 
 	containertypes "github.com/docker/docker/api/types/container"
@@ -23,6 +24,22 @@ type logdriverFactory struct {
 	m            sync.Mutex
 }
 
+func (lf *logdriverFactory) list() []string {
+	ls := make([]string, 0, len(lf.registry))
+	lf.m.Lock()
+	for name := range lf.registry {
+		ls = append(ls, name)
+	}
+	lf.m.Unlock()
+	sort.Strings(ls)
+	return ls
+}
+
+// ListDrivers gets the list of registered log driver names
+func ListDrivers() []string {
+	return factory.list()
+}
+
 func (lf *logdriverFactory) register(name string, c Creator) error {
 	if lf.driverRegistered(name) {
 		return fmt.Errorf("logger: log driver named '%s' is already registered", name)
diff --git a/integration-cli/docker_cli_plugins_logdriver_test.go b/integration-cli/docker_cli_plugins_logdriver_test.go
index c5029e2527..d74256656a 100644
--- a/integration-cli/docker_cli_plugins_logdriver_test.go
+++ b/integration-cli/docker_cli_plugins_logdriver_test.go
@@ -1,9 +1,13 @@
 package main
 
 import (
+	"encoding/json"
+	"net/http"
 	"strings"
 
+	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/integration-cli/checker"
+	"github.com/docker/docker/integration-cli/request"
 	"github.com/go-check/check"
 )
 
@@ -25,3 +29,21 @@ func (s *DockerSuite) TestPluginLogDriver(c *check.C) {
 	dockerCmd(c, "plugin", "disable", pluginName)
 	dockerCmd(c, "plugin", "rm", pluginName)
 }
+
+// Make sure log drivers are listed in info, and v2 plugins are not.
+func (s *DockerSuite) TestPluginLogDriverInfoList(c *check.C) {
+	testRequires(c, IsAmd64, DaemonIsLinux)
+	pluginName := "cpuguy83/docker-logdriver-test"
+
+	dockerCmd(c, "plugin", "install", pluginName)
+	status, body, err := request.SockRequest("GET", "/info", nil, daemonHost())
+	c.Assert(status, checker.Equals, http.StatusOK)
+	c.Assert(err, checker.IsNil)
+
+	var info types.Info
+	err = json.Unmarshal(body, &info)
+	c.Assert(err, checker.IsNil)
+	drivers := strings.Join(info.Plugins.Log, " ")
+	c.Assert(drivers, checker.Contains, "json-file")
+	c.Assert(drivers, checker.Not(checker.Contains), pluginName)
+}