(MANUALLY ADDING PR FROM Thlb 0.6) Add Docker platform and template app

This commit is contained in:
Ross Mountjoy 2020-05-30 08:59:02 -04:00
parent 8358cc4749
commit 322612761d
3 changed files with 401 additions and 0 deletions

View File

@ -0,0 +1,394 @@
"""
##### Docker
Display information from Docker API. Informations can be displayed on a custom card or on an app card (e.g. Portainer App)
```ini
[variable_name]
platform = docker
prefix = http://
host = localhost
port = 2375
value_template = {{ value_template }}
```
> **Returns:** `value_template` as rendered string
| Variable | Required | Description | Options |
|-----------------|----------|-----------------------------------------------------------------|-------------------|
| [variable_name] | Yes | Name for the data source. | [variable_name] |
| platform | Yes | Name of the platform. | docker |
| prefix | No | The prefix for the app's url. | web prefix, e.g. http:// or https:// |
| host | Yes | Docker Host | url,ip |
| port | No | Docker Port | port, usually 2375 (Insecure) or 2376 (TLS) |
| api_version | No | Docker API version to use (Default : platform will try to find latest version) | 1.40 |
| tls_mode | No | TLS verification mode, default is None | Server, Client, Both, None |
| tls_ca | No | Requierd for tls_mode=Both or tls_mode=Server, default is None | /path/to/ca, None |
| tls_cert | No | Requierd for tls_mode=Both or tls_mode=Client, default is None | /path/to/cert, None |
| tls_key | No | Requierd for tls_mode=Both or tls_mode=Client, default is None | /path/to/key, None|
| card_type | No | Set to Custom if you want to display informations in a custom card. Default is App | Custom, App|
| value_template | Yes | Jinja template for how the returned data from API is displayed. | jinja template |
<br />
###### **Available fields for value_template**
* version
* max_api_version
* name
* containers
* containers_running
* containers_paused
* containers_stopped
* images
* driver
* cpu
* memory
* warnings
* error (for debug)
> **Working example (using un-encrypted connection, on Portainer card):**
>```ini
> [docker-endpoint-1]
> platform = docker
> prefix = http://
> host = 192.168.0.110
> port = 2375
> value_template = {{error}}<p style="text-align:right;text-transform:uppercase;font-size:14px;font-family: monospace;">{{name}}<br /><i style="position: relative; top: .2rem" class="material-icons md-18 theme-success-text" title="Running">fiber_manual_record</i>{{containers_running}}<i style="position: relative; top: .2rem" class="material-icons md-18 theme-warning-text" title="Paused">fiber_manual_record</i>{{containers_paused}}<i style="position: relative; top: .2rem" class="material-icons md-18 theme-failure-text" title="Stopped">fiber_manual_record</i>{{containers_stopped}}</p>
>
> [Portainer]
> prefix = http://
> url = 192.168.0.110:2375
> icon = static/images/apps/portainer.png
> sidebar_icon = static/images/apps/portainer.png
> description = Making Docker management easy
> open_in = this_tab
> data_sources = docker-endpoint-1
>```
>
>
> **Working example (using encrypted connection, on Portainer card):**
>```ini
> [docker-endpoint-2]
> platform = docker
> prefix = https://
> host = 192.168.0.110
> port = 2376
> tls_mode = Both
> tls_ca = /path/to/ca_file
> tls_cert = /path/to/cert_file
> tls_key = /path/to/key_file
> value_template = {{error}}<p style="text-align:right;text-transform:uppercase;font-size:14px;font-family: monospace;">{{name}}<br /><i style="position: relative; top: .2rem" class="material-icons md-18 theme-success-text" title="Running">fiber_manual_record</i>{{containers_running}}<i style="position: relative; top: .2rem" class="material-icons md-18 theme-warning-text" title="Paused">fiber_manual_record</i>{{containers_paused}}<i style="position: relative; top: .2rem" class="material-icons md-18 theme-failure-text" title="Stopped">fiber_manual_record</i>{{containers_stopped}}</p>
>
> [Portainer]
> prefix = http://
> url = 192.168.0.110:2375
> icon = static/images/apps/portainer.png
> sidebar_icon = static/images/apps/portainer.png
> description = Making Docker management easy
> open_in = this_tab
> data_sources = docker-endpoint-2
>```
>
>
> **Working example (using un-encrypted connection, on custom Docker card):**
>```ini
> [docker-endpoint-3]
> platform = docker
> prefix = http://
> host = 192.168.0.110
> port = 2375
> card_type = Custom
>
> [Docker]
> type = custom
> data_sources = docker-endpoint-3
>```
"""
import json
from flask import render_template_string
import requests
import re
class Docker(object):
def __init__(
self,
method,
prefix,
host,
port,
api_version,
card_type,
tls_mode,
tls_ca,
tls_cert,
tls_key,
):
self.endpoint = None
self.method = method
self.prefix = prefix
self.host = host
self.port = port
self.api_version = api_version
self.card_type = card_type
self.tls_mode = tls_mode
self.tls_ca = tls_ca
self.tls_key = tls_key
self.tls_cert = tls_cert
# Initialize results
self.error = None
self.version = "?"
self.max_api_version = "?"
self.name = "?"
self.running = 0
self.paused = 0
self.stopped = 0
self.images = 0
self.driver = "?"
self.cpu = "?"
self.memory = "?"
self.html_template = ""
def check(self):
port = "" if self.port == None else ":" + self.port
if self.method.upper() == "GET":
try:
response = ""
request = requests.get(
self.prefix + self.host + port + "/v999/info",
verify=self.tls_ca,
cert=(self.tls_cert, self.tls_key),
timeout=10,
)
response = request.text
if "text/plain" in request.headers["content-type"]:
self.error = request.text
rawdata = None
elif "application/json" in request.headers["content-type"]:
rawdata = request.json()
else:
error = request
rawdata = None
except Exception as e:
rawdata = None
self.error = f"{e}" + " " + response
self.setHtml()
if rawdata != None:
if "message" in rawdata:
regex = r"\bv?[0-9]+\.[0-9]+(?:\.[0-9]+)?\b"
r = re.search(regex, rawdata["message"])
self.max_api_version = r.group(0)
self.api_version = (
self.api_version
if self.api_version != None
else self.max_api_version
)
self.endpoint = "/v" + self.api_version + "/"
def getStatus(self):
port = "" if self.port == None else ":" + self.port
if self.method.upper() == "GET":
try:
rawdata = requests.get(
self.prefix + self.host + port + self.endpoint + "/info",
verify=self.tls_ca,
cert=(self.tls_cert, self.tls_key),
timeout=10,
).json()
except Exception as e:
rawdata = None
self.error = f"{e}"
self.setHtml()
if rawdata != None:
self.name = rawdata["Name"]
self.containers = rawdata["Containers"]
self.containers_running = rawdata["ContainersRunning"]
self.containers_paused = rawdata["ContainersPaused"]
self.containers_stopped = rawdata["ContainersStopped"]
self.images = rawdata["Images"]
self.warnings = rawdata["Warnings"]
self.driver = rawdata["Driver"]
self.cpu = rawdata["NCPU"]
self.memory = self.formatSize(rawdata["MemTotal"])
if self.card_type == "Custom":
self.setHtml()
def formatSize(self, size):
# 2**10 = 1024
power = 2 ** 10
n = 0
power_labels = {0: "", 1: "KB", 2: "MB", 3: "GB", 4: "TB"}
while size > power:
size /= power
n += 1
return str(round(size, 1)) + " " + power_labels[n]
def refresh(self):
self.check()
if self.error == None:
self.error = ""
self.getStatus()
def setHtml(self):
if self.error != None and self.error != "":
self.html_template = """
<div class="row">
<div class="col s6">
<span class="mt-0 mb-0 theme-primary-text font-weight-700" style="font-size: 36px"><i class="material-icons md-18 theme-failure-text" title="Error">error</i></h3>
</div>
<div class="col s6 right-align">
<img height="48px" src="static/images/apps/docker.png" alt="Docker">
</div>
</div>
<div class="row">
<h6 class="font-weight-900 center theme-muted-text">Error</h6>
</div>
<div class="row center-align">
<i class="material-icons-outlined">keyboard_arrow_down</i>
</div>
<div class="row center-align">
<div class="col s12">
<div class="collection theme-muted-text">
<div class="collection-item">{{ error }}</div>
</div>
</div>
</div>
"""
else:
if self.tls_mode == None:
img_tls = """
<i class="material-icons md-18 theme-warning-text" title="TLS disabled">lock_open</i>
"""
else:
img_tls = """
<i class="material-icons md-18 theme-success-text" title="TLS enabled">lock</i>
"""
if len(self.warnings) > 0:
img_warnings = """
<i class="material-icons md-18 theme-warning-text" title="{{warnings}}">warning</i>
"""
else:
img_warnings = """
<i class="material-icons md-18 theme-muted2-text" title="No warnings">warning</i>
"""
self.html_template = (
"""
<div class="row">
<div class="col s6">
<span class="mt-0 mb-0 theme-primary-text font-weight-700" style="font-size: 36px">"""
+ img_tls
+ img_warnings
+ """</h3>
</div>
<div class="col s6 right-align">
<img height="48px" src="static/images/apps/docker.png" alt="Docker">
</div>
</div>
<div class="row">
<h6 class="font-weight-900 center theme-muted-text">{{name}}</h6>
</div>
<div class="row center-align">
<i class="material-icons-outlined">keyboard_arrow_down</i>
</div>
<div class="row center-align">
<div class="col s12">
<div class="collection theme-muted-text">
<div class="collection-item"><span class="font-weight-900">Containers: </span>{{ containers }}</div>
<div class="collection-item"><span class="font-weight-900">Running: </span>{{ containers_running }}</div>
<div class="collection-item"><span class="font-weight-900">Paused: </span>{{ containers_paused }}</div>
<div class="collection-item"><span class="font-weight-900">Stopped: </span>{{ containers_stopped }}</div>
<div class="collection-item"><span class="font-weight-900">Images: </span>{{ images }}</div>
<div class="collection-item"><span class="font-weight-900">Driver: </span>{{ driver }}</div>
<div class="collection-item"><span class="font-weight-900">CPU: </span>{{ cpu }}</div>
<div class="collection-item"><span class="font-weight-900">Memory: </span>{{ memory }}</div>
</div>
</div>
</div>
"""
)
def getHtml(self):
return self.html_template
class Platform:
def __init__(self, *args, **kwargs):
# parse the user's options from the config entries
for key, value in kwargs.items():
self.__dict__[key] = value
# set defaults for omitted options
if not hasattr(self, "method"):
self.method = "GET"
if not hasattr(self, "prefix"):
self.prefix = "http://"
if not hasattr(self, "host"):
self.host = None
if not hasattr(self, "port"):
self.port = 2375
if not hasattr(self, "api_version"):
self.api_version = None
if not hasattr(self, "card_type"):
self.card_type = "App"
if not hasattr(self, "tls_ca"):
self.tls_ca = None
if not hasattr(self, "tls_cert"):
self.tls_cert = None
if not hasattr(self, "tls_key"):
self.tls_key = None
# Without TLS
if not hasattr(self, "tls_mode"):
self.tls_mode = None
self.tls_ca = None
self.tls_cert = None
self.tls_key = None
else:
if self.tls_mode == "Both":
if self.tls_ca == None or self.tls_cert == None or self.tls_key == None:
return "tls_mode set to Both, and missing tls_ca/tls_cert/tls_key"
elif self.tls_mode == "Client":
self.tls_ca = False
elif self.tls_mode == "Server":
self.tls_cert = ""
self.tls_key = ""
elif self.tls_mode == "None":
self.tls_ca = None
self.tls_cert = None
self.tls_key = None
self.docker = Docker(
self.method,
self.prefix,
self.host,
self.port,
self.api_version,
self.card_type,
self.tls_mode,
self.tls_ca,
self.tls_cert,
self.tls_key,
)
def process(self):
if self.host == None:
return "host missing"
# TLS check
if self.tls_mode == "Both":
if self.tls_ca == None or self.tls_cert == None or self.tls_key == None:
return "tls_mode set to Both, and missing tls_ca/tls_cert/tls_key"
elif self.tls_mode == "Client":
if self.tls_cert == None or self.tls_key == None:
return "tls_mode set to Client, and missing tls_cert/tls_key"
elif self.tls_mode == "Server":
if self.tls_ca == None:
return "tls_mode set to Server, and missing tls_ca"
else:
if self.tls_mode != None:
return "Invalid tls_mode : " + self.tls_mode
self.docker.refresh()
if self.card_type == "Custom":
return render_template_string(self.docker.getHtml(), **self.docker.__dict__)
else:
return render_template_string(self.value_template, **self.docker.__dict__)

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

7
template_apps/Docker.ini Normal file
View File

@ -0,0 +1,7 @@
[Docker]
prefix = http://
url = your-website.com
icon = static/images/apps/docker.png
sidebar_icon = static/images/apps/docker.png
description = Empowering App Development for Developers
open_in = this_tab