mirror of
https://github.com/glanceapp/glance.git
synced 2025-06-21 10:27:45 +02:00
Docker containers: remote socket, category
and running-only
This commit is contained in:
parent
77fb199cb3
commit
18436e91e0
@ -1886,12 +1886,66 @@ If any of the child containers are down, their status will propagate up to the p
|
||||
| ---- | ---- | -------- | ------- |
|
||||
| hide-by-default | boolean | no | false |
|
||||
| sock-path | string | no | /var/run/docker.sock |
|
||||
| category | string | no | |
|
||||
| running-only | boolean | no | false |
|
||||
|
||||
##### `hide-by-default`
|
||||
Whether to hide the containers by default. If set to `true` you'll have to manually add a `glance.hide: false` label to each container you want to display. By default all containers will be shown and if you want to hide a specific container you can add a `glance.hide: true` label.
|
||||
|
||||
##### `sock-path`
|
||||
The path to the Docker socket.
|
||||
The path to the Docker socket. This can also be a [remote socket](https://docs.docker.com/engine/daemon/remote-access/) or proxied socket using something like [docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy).
|
||||
|
||||
###### `category`
|
||||
Filter to only the containers which have this category specified via the `glance.category` label. Useful if you want to have multiple containers widgets, each showing a different set of containers.
|
||||
|
||||
<details>
|
||||
<summary>View example</summary>
|
||||
<br>
|
||||
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
labels:
|
||||
glance.name: Jellyfin
|
||||
glance.icon: si:jellyfin
|
||||
glance.url: https://jellyfin.domain.com
|
||||
glance.category: media
|
||||
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
labels:
|
||||
glance.name: Gitea
|
||||
glance.icon: si:gitea
|
||||
glance.url: https://gitea.domain.com
|
||||
glance.category: dev-tools
|
||||
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:latest
|
||||
labels:
|
||||
glance.name: Vaultwarden
|
||||
glance.icon: si:vaultwarden
|
||||
glance.url: https://vaultwarden.domain.com
|
||||
glance.category: dev-tools
|
||||
```
|
||||
|
||||
Then you can use the `category` property to filter the containers:
|
||||
|
||||
```yaml
|
||||
- type: docker-containers
|
||||
title: Dev tool containers
|
||||
category: dev-tools
|
||||
|
||||
- type: docker-containers
|
||||
title: Media containers
|
||||
category: media
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
##### `running-only`
|
||||
Whether to only show running containers. If set to `true` only containers that are currently running will be displayed. If set to `false` all containers will be displayed regardless of their state.
|
||||
|
||||
#### Labels
|
||||
| Name | Description |
|
||||
@ -1904,6 +1958,7 @@ The path to the Docker socket.
|
||||
| glance.hide | Whether to hide the container. If set to `true` the container will not be displayed. Defaults to `false`. |
|
||||
| glance.id | The custom ID of the container. Used to group containers under a single parent. |
|
||||
| glance.parent | The ID of the parent container. Used to group containers under a single parent. |
|
||||
| glance.category | The category of the container. Used to filter containers by category. |
|
||||
|
||||
### DNS Stats
|
||||
Display statistics from a self-hosted ad-blocking DNS resolver such as AdGuard Home, Pi-hole, or Technitium.
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -17,6 +18,8 @@ var dockerContainersWidgetTemplate = mustParseTemplate("docker-containers.html",
|
||||
type dockerContainersWidget struct {
|
||||
widgetBase `yaml:",inline"`
|
||||
HideByDefault bool `yaml:"hide-by-default"`
|
||||
RunningOnly bool `yaml:"running-only"`
|
||||
Category string `yaml:"category"`
|
||||
SockPath string `yaml:"sock-path"`
|
||||
Containers dockerContainerList `yaml:"-"`
|
||||
}
|
||||
@ -32,7 +35,7 @@ func (widget *dockerContainersWidget) initialize() error {
|
||||
}
|
||||
|
||||
func (widget *dockerContainersWidget) update(ctx context.Context) {
|
||||
containers, err := fetchDockerContainers(widget.SockPath, widget.HideByDefault)
|
||||
containers, err := fetchDockerContainers(widget.SockPath, widget.HideByDefault, widget.Category, widget.RunningOnly)
|
||||
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||
return
|
||||
}
|
||||
@ -54,6 +57,7 @@ const (
|
||||
dockerContainerLabelIcon = "glance.icon"
|
||||
dockerContainerLabelID = "glance.id"
|
||||
dockerContainerLabelParent = "glance.parent"
|
||||
dockerContainerLabelCategory = "glance.category"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -137,8 +141,8 @@ func dockerContainerStateToStateIcon(state string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func fetchDockerContainers(socketPath string, hideByDefault bool) (dockerContainerList, error) {
|
||||
containers, err := fetchAllDockerContainersFromSock(socketPath)
|
||||
func fetchDockerContainers(socketPath string, hideByDefault bool, category string, runningOnly bool) (dockerContainerList, error) {
|
||||
containers, err := fetchDockerContainersFromSource(socketPath, category, runningOnly)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching containers: %w", err)
|
||||
}
|
||||
@ -239,17 +243,48 @@ func isDockerContainerHidden(container *dockerContainerJsonResponse, hideByDefau
|
||||
return hideByDefault
|
||||
}
|
||||
|
||||
func fetchAllDockerContainersFromSock(socketPath string) ([]dockerContainerJsonResponse, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", socketPath)
|
||||
func fetchDockerContainersFromSource(source string, category string, runningOnly bool) ([]dockerContainerJsonResponse, error) {
|
||||
var hostname string
|
||||
|
||||
var client *http.Client
|
||||
if strings.HasPrefix(source, "tcp://") || strings.HasPrefix(source, "http://") {
|
||||
client = &http.Client{}
|
||||
parsed, err := url.Parse(source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing URL: %w", err)
|
||||
}
|
||||
|
||||
port := parsed.Port()
|
||||
if port == "" {
|
||||
port = "80"
|
||||
}
|
||||
|
||||
hostname = parsed.Hostname() + ":" + port
|
||||
} else {
|
||||
hostname = "docker"
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", source)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("GET", "http://docker/containers/json?all=true", nil)
|
||||
query := url.Values{}
|
||||
query.Set("all", ternary(runningOnly, "false", "true"))
|
||||
|
||||
if category != "" {
|
||||
query.Set(
|
||||
"filters",
|
||||
fmt.Sprintf(`{"label": ["%s=%s"]}`, dockerContainerLabelCategory, category),
|
||||
)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, "GET", "http://"+hostname+"/containers/json?"+query.Encode(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating request: %w", err)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user