diff --git a/.reflex b/.reflex index 0aa7f08a..2c01e3a6 100644 --- a/.reflex +++ b/.reflex @@ -1 +1 @@ --r '\.go$' -R '^node_modules/' -R '^static/' -R '^.cache/' -G '*_test.go' -s -- go run main.go --level debug +-r '\.go$' -R '^node_modules/' -R '^static/' -R '^.cache/' -G '*_test.go' -s -- go run main.go --level debug --showAll diff --git a/README.md b/README.md index 1f292f96..754b42b6 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Dozzle follows the [12-factor](https://12factor.net/) model. Configurations can | `--addr` | `DOZZLE_ADDR` | `:8080` | | `--base` | `DOZZLE_BASE` | `/` | | `--level` | `DOZZLE_LEVEL` | `info` | +| `--showAll` | `DOZZLE_SHOWALL` | `false` | | n/a | `DOCKER_API_VERSION` | `1.38` | | `--tailSize` | `DOZZLE_TAILSIZE` | `300` | | `--filter` | `DOZZLE_FILTER` | `""` | diff --git a/docker/client.go b/docker/client.go index e4e2fce9..a33855df 100644 --- a/docker/client.go +++ b/docker/client.go @@ -30,7 +30,7 @@ type dockerProxy interface { // Client is a proxy around the docker client type Client interface { - ListContainers() ([]Container, error) + ListContainers(showAll bool) ([]Container, error) FindContainer(string) (Container, error) ContainerLogs(context.Context, string, int) (<-chan string, <-chan error) Events(context.Context) (<-chan events.Message, <-chan error) @@ -61,7 +61,7 @@ func NewClientWithFilters(f map[string]string) Client { func (d *dockerClient) FindContainer(id string) (Container, error) { var container Container - containers, err := d.ListContainers() + containers, err := d.ListContainers(true) if err != nil { return container, err } @@ -81,9 +81,10 @@ func (d *dockerClient) FindContainer(id string) (Container, error) { return container, nil } -func (d *dockerClient) ListContainers() ([]Container, error) { +func (d *dockerClient) ListContainers(showAll bool) ([]Container, error) { containerListOptions := types.ContainerListOptions{ Filters: d.filters, + All: showAll, } list, err := d.cli.ContainerList(context.Background(), containerListOptions) if err != nil { diff --git a/docker/client_test.go b/docker/client_test.go index e65f64da..d41469db 100644 --- a/docker/client_test.go +++ b/docker/client_test.go @@ -44,7 +44,7 @@ func Test_dockerClient_ListContainers_null(t *testing.T) { proxy.On("ContainerList", mock.Anything, mock.Anything).Return(nil, nil) client := &dockerClient{proxy, filters.NewArgs()} - list, err := client.ListContainers() + list, err := client.ListContainers(true) assert.Empty(t, list, "list should be empty") require.NoError(t, err, "error should not return an error.") @@ -56,7 +56,7 @@ func Test_dockerClient_ListContainers_error(t *testing.T) { proxy.On("ContainerList", mock.Anything, mock.Anything).Return(nil, errors.New("test")) client := &dockerClient{proxy, filters.NewArgs()} - list, err := client.ListContainers() + list, err := client.ListContainers(true) assert.Nil(t, list, "list should be nil") require.Error(t, err, "test.") @@ -79,7 +79,7 @@ func Test_dockerClient_ListContainers_happy(t *testing.T) { proxy.On("ContainerList", mock.Anything, mock.Anything).Return(containers, nil) client := &dockerClient{proxy, filters.NewArgs()} - list, err := client.ListContainers() + list, err := client.ListContainers(true) require.NoError(t, err, "error should not return an error.") assert.Equal(t, list, []Container{ diff --git a/main.go b/main.go index 158a0f54..648189f7 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ var ( addr = "" base = "" level = "" + showAll = false tailSize = 300 filters map[string]string version = "dev" @@ -34,12 +35,14 @@ var ( type handler struct { client docker.Client + showAll bool box packr.Box } func init() { pflag.String("addr", ":8080", "http service address") pflag.String("base", "/", "base address of the application to mount") + pflag.Bool("showAll", false, "show all containers, even stopped") pflag.String("level", "info", "logging level") pflag.Int("tailSize", 300, "Tail size to use for initial container logs") pflag.StringToStringVar(&filters, "filter", map[string]string{}, "Container filters to use for showing logs") @@ -53,6 +56,7 @@ func init() { base = viper.GetString("base") level = viper.GetString("level") tailSize = viper.GetInt("tailSize") + showAll = viper.GetBool("showAll") // Until https://github.com/spf13/viper/issues/608 is fixed. We have to use this hacky way. // filters = viper.GetStringSlice("filter") @@ -96,14 +100,18 @@ func createRoutes(base string, h *handler) *mux.Router { func main() { log.Infof("Dozzle version %s", version) dockerClient := docker.NewClientWithFilters(filters) - _, err := dockerClient.ListContainers() + _, err := dockerClient.ListContainers(true) if err != nil { log.Fatalf("Could not connect to Docker Engine: %v", err) } box := packr.NewBox("./static") - r := createRoutes(base, &handler{dockerClient, box}) + r := createRoutes(base, &handler{ + client: dockerClient, + showAll: showAll, + box: box, + }) srv := &http.Server{Addr: addr, Handler: r} go func() { @@ -150,7 +158,7 @@ func (h *handler) index(w http.ResponseWriter, req *http.Request) { } func (h *handler) listContainers(w http.ResponseWriter, r *http.Request) { - containers, err := h.client.ListContainers() + containers, err := h.client.ListContainers(h.showAll) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/main_test.go b/main_test.go index d63ce14a..f4d0d09d 100644 --- a/main_test.go +++ b/main_test.go @@ -32,7 +32,7 @@ func (m *MockedClient) FindContainer(id string) (docker.Container, error) { return container, args.Error(1) } -func (m *MockedClient) ListContainers() ([]docker.Container, error) { +func (m *MockedClient) ListContainers(showAll bool) ([]docker.Container, error) { args := m.Called() containers, ok := args.Get(0).([]docker.Container) if !ok { @@ -246,7 +246,7 @@ func Test_createRoutes_index(t *testing.T) { box := packr.NewBox("./virtual") require.NoError(t, box.AddString("index.html", "index page"), "AddString should have no error.") - handler := createRoutes("/", &handler{mockedClient, box}) + handler := createRoutes("/", &handler{mockedClient, true, box}) req, err := http.NewRequest("GET", "/", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -259,7 +259,7 @@ func Test_createRoutes_redirect(t *testing.T) { mockedClient := new(MockedClient) box := packr.NewBox("./virtual") - handler := createRoutes("/foobar", &handler{mockedClient, box}) + handler := createRoutes("/foobar", &handler{mockedClient, true,box}) req, err := http.NewRequest("GET", "/foobar", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -273,7 +273,7 @@ func Test_createRoutes_foobar(t *testing.T) { box := packr.NewBox("./virtual") require.NoError(t, box.AddString("index.html", "foo page"), "AddString should have no error.") - handler := createRoutes("/foobar", &handler{mockedClient, box}) + handler := createRoutes("/foobar", &handler{mockedClient, true, box}) req, err := http.NewRequest("GET", "/foobar/", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -287,7 +287,7 @@ func Test_createRoutes_foobar_file(t *testing.T) { box := packr.NewBox("./virtual") require.NoError(t, box.AddString("/test", "test page"), "AddString should have no error.") - handler := createRoutes("/foobar", &handler{mockedClient, box}) + handler := createRoutes("/foobar", &handler{mockedClient, true, box}) req, err := http.NewRequest("GET", "/foobar/test", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -300,7 +300,7 @@ func Test_createRoutes_version(t *testing.T) { mockedClient := new(MockedClient) box := packr.NewBox("./virtual") - handler := createRoutes("/", &handler{mockedClient, box}) + handler := createRoutes("/", &handler{mockedClient, true, box}) req, err := http.NewRequest("GET", "/version", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder()