mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 09:41:57 +00:00
Renaming prometheus plugin to volume-count
This commit is contained in:
40
examples/plugins/volume-count/1-basic-http-server.py
Executable file
40
examples/plugins/volume-count/1-basic-http-server.py
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
|
||||
PLUGIN_ID="prometheus"
|
||||
PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(b"foo")
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def main():
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
server.serve_forever()
|
||||
|
||||
main()
|
||||
56
examples/plugins/volume-count/2-with-cleanup.py
Executable file
56
examples/plugins/volume-count/2-with-cleanup.py
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
|
||||
PLUGIN_ID="prometheus"
|
||||
PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(b"foo")
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def delete_socket_file():
|
||||
if os.path.exists(PLUGIN_UNIX_SOCK):
|
||||
os.remove(PLUGIN_UNIX_SOCK)
|
||||
|
||||
def sig_handler(b, a):
|
||||
delete_socket_file()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
delete_socket_file()
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except:
|
||||
delete_socket_file()
|
||||
raise
|
||||
|
||||
main()
|
||||
72
examples/plugins/volume-count/3-plugin-info.py
Executable file
72
examples/plugins/volume-count/3-plugin-info.py
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import json
|
||||
|
||||
PLUGIN_ID="prometheus"
|
||||
PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Generate our json body
|
||||
body = json.dumps({
|
||||
'Plugins': [
|
||||
{
|
||||
'id': PLUGIN_ID,
|
||||
'label': 'Prometheus data translator',
|
||||
'description': 'Takes data from prometheus and puts it into scope',
|
||||
'interfaces': ['reporter'],
|
||||
'api_version': '1',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-length', len(body))
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(body)
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def delete_socket_file():
|
||||
if os.path.exists(PLUGIN_UNIX_SOCK):
|
||||
os.remove(PLUGIN_UNIX_SOCK)
|
||||
|
||||
def sig_handler(b, a):
|
||||
delete_socket_file()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
delete_socket_file()
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except:
|
||||
delete_socket_file()
|
||||
raise
|
||||
|
||||
main()
|
||||
99
examples/plugins/volume-count/4-static-container-metrics.py
Executable file
99
examples/plugins/volume-count/4-static-container-metrics.py
Executable file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import json
|
||||
|
||||
PLUGIN_ID="prometheus"
|
||||
PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
METRIC_NAME="http_requests_per_second"
|
||||
METRIC_LABEL="HTTP req/sec"
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Get current timestamp in RFC3339
|
||||
date = datetime.datetime.utcnow()
|
||||
date = date.isoformat('T') + 'Z'
|
||||
|
||||
# Generate our json body
|
||||
body = json.dumps({
|
||||
'Plugins': [
|
||||
{
|
||||
'id': PLUGIN_ID,
|
||||
'label': 'Prometheus data translator',
|
||||
'description': 'Takes data from prometheus and puts it into scope',
|
||||
'interfaces': ['reporter'],
|
||||
'api_version': '1',
|
||||
}
|
||||
],
|
||||
'Container': {
|
||||
'nodes': {
|
||||
'abcd1234;<container>': {
|
||||
'metrics': {
|
||||
METRIC_NAME: {
|
||||
'samples': [{
|
||||
'date': date,
|
||||
'value': float(1.0),
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'metric_templates': {
|
||||
METRIC_NAME: {
|
||||
'id': METRIC_NAME,
|
||||
'label': METRIC_LABEL,
|
||||
'priority': 0.1,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-length', len(body))
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(body)
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def delete_socket_file():
|
||||
if os.path.exists(PLUGIN_UNIX_SOCK):
|
||||
os.remove(PLUGIN_UNIX_SOCK)
|
||||
|
||||
def sig_handler(b, a):
|
||||
delete_socket_file()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
delete_socket_file()
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except:
|
||||
delete_socket_file()
|
||||
raise
|
||||
|
||||
main()
|
||||
109
examples/plugins/volume-count/5-querying-prometheus.py
Executable file
109
examples/plugins/volume-count/5-querying-prometheus.py
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import datetime
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import urllib2
|
||||
|
||||
PLUGIN_ID="prometheus"
|
||||
PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
METRIC_NAME="http_requests_per_second"
|
||||
METRIC_LABEL="HTTP req/sec"
|
||||
METRIC_CONTAINER_ID_KEY="container_id"
|
||||
PROMETHEUS_ADDR="prometheus.monitoring.svc.cluster.local"
|
||||
|
||||
def metrics():
|
||||
r = urllib2.urlopen("http://%s/api/v1/query?query=%s" % (PROMETHEUS_ADDR, METRIC_NAME))
|
||||
return json.loads(r.content).get("data", default={}).get("result", default=[])
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Fetch and convert data from prometheus
|
||||
nodes = {}
|
||||
for metric in metrics():
|
||||
container_id = metric.get("metric", default={}).get(METRIC_CONTAINER_ID_KEY, default=None)
|
||||
if container_id == None:
|
||||
continue
|
||||
nodes["%s;<container>" % (container_id)] = {
|
||||
'metrics': {
|
||||
METRIC_NAME: {
|
||||
'samples': [{
|
||||
'date': datetime.datetime.utcfromtimestamp(metric["value"][0]).isoformat('T') + 'Z',
|
||||
'value': float(metric["value"][1]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Generate our json body
|
||||
body = json.dumps({
|
||||
'Plugins': [
|
||||
{
|
||||
'id': PLUGIN_ID,
|
||||
'label': 'Prometheus data translator',
|
||||
'description': 'Takes data from prometheus and puts it into scope',
|
||||
'interfaces': ['reporter'],
|
||||
'api_version': '1',
|
||||
}
|
||||
],
|
||||
'Container': {
|
||||
'nodes': nodes,
|
||||
'metric_templates': {
|
||||
METRIC_NAME: {
|
||||
'id': METRIC_NAME,
|
||||
'label': METRIC_LABEL,
|
||||
'priority': 0.1,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-length', len(body))
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(body)
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def delete_socket_file():
|
||||
if os.path.exists(PLUGIN_UNIX_SOCK):
|
||||
os.remove(PLUGIN_UNIX_SOCK)
|
||||
|
||||
def sig_handler(b, a):
|
||||
delete_socket_file()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
delete_socket_file()
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except:
|
||||
delete_socket_file()
|
||||
raise
|
||||
|
||||
main()
|
||||
10
examples/plugins/volume-count/Dockerfile
Normal file
10
examples/plugins/volume-count/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
# Start from weaveworks/scope, so that we have a docker client built in.
|
||||
FROM python:2
|
||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
||||
LABEL works.weave.role=system
|
||||
|
||||
RUN pip install docker-py
|
||||
|
||||
# Add our plugin
|
||||
ADD ./volume-count.py /usr/bin/volume-count.py
|
||||
ENTRYPOINT ["/usr/bin/volume-count.py"]
|
||||
20
examples/plugins/volume-count/Makefile
Normal file
20
examples/plugins/volume-count/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
.PHONY: run clean
|
||||
|
||||
SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E")
|
||||
EXE=volume-count.py
|
||||
IMAGE=weavescope-volume-count-plugin
|
||||
UPTODATE=.$(EXE).uptodate
|
||||
|
||||
run: $(UPTODATE)
|
||||
$(SUDO) docker run --rm -it \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/scope/plugins:/var/run/scope/plugins \
|
||||
--name $(IMAGE) $(IMAGE)
|
||||
|
||||
$(UPTODATE): $(EXE) Dockerfile
|
||||
$(SUDO) docker build -t $(IMAGE) .
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
- rm -rf $(UPTODATE)
|
||||
- $(SUDO) docker rmi $(IMAGE)
|
||||
137
examples/plugins/volume-count/volume-count.py
Executable file
137
examples/plugins/volume-count/volume-count.py
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from collections import namedtuple
|
||||
from docker import Client
|
||||
import BaseHTTPServer
|
||||
import SocketServer
|
||||
import datetime
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import urllib2
|
||||
|
||||
PLUGIN_ID="volume-count"
|
||||
PLUGIN_UNIX_SOCK="/var/run/scope/plugins/" + PLUGIN_ID + ".sock"
|
||||
DOCKER_SOCK="unix://var/run/docker.sock"
|
||||
|
||||
nodes = {}
|
||||
|
||||
def update_loop():
|
||||
global nodes
|
||||
next_call = time.time()
|
||||
while True:
|
||||
# Get current timestamp in RFC3339
|
||||
timestamp = datetime.datetime.utcnow()
|
||||
timestamp = timestamp.isoformat('T') + 'Z'
|
||||
|
||||
# Fetch and convert data to scope data model
|
||||
new = {}
|
||||
for container_id, volume_count in container_volume_counts().iteritems():
|
||||
new["%s;<container>" % (container_id)] = {
|
||||
'latest': {
|
||||
'volume_count': {
|
||||
'timestamp': timestamp,
|
||||
'value': str(volume_count),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodes = new
|
||||
next_call += 5
|
||||
time.sleep(next_call - time.time())
|
||||
|
||||
def start_update_loop():
|
||||
updateThread = threading.Thread(target=update_loop)
|
||||
updateThread.daemon = True
|
||||
updateThread.start()
|
||||
|
||||
# List all containers, with the count of their volumes
|
||||
def container_volume_counts():
|
||||
containers = {}
|
||||
cli = Client(base_url=DOCKER_SOCK, version='auto')
|
||||
for c in cli.containers(all=True):
|
||||
containers[c['Id']] = len(c['Mounts'])
|
||||
return containers
|
||||
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# The logger requires a client_address, but unix sockets don't have
|
||||
# one, so we fake it.
|
||||
self.client_address = "-"
|
||||
|
||||
# Generate our json body
|
||||
body = json.dumps({
|
||||
'Plugins': [
|
||||
{
|
||||
'id': PLUGIN_ID,
|
||||
'label': 'Volume Counts',
|
||||
'description': 'Shows how many volumes each container has mounted',
|
||||
'interfaces': ['reporter'],
|
||||
'api_version': '1',
|
||||
}
|
||||
],
|
||||
'Container': {
|
||||
'nodes': nodes,
|
||||
# Templates tell the UI how to render this field.
|
||||
'metadata_templates': {
|
||||
'volume_count': {
|
||||
# Key where this data can be found.
|
||||
'id': "volume_count",
|
||||
# Human-friendly field name
|
||||
'label': "# Volumes",
|
||||
# Look up the 'id' in the latest object.
|
||||
'from': "latest",
|
||||
# Priorities over 10 are hidden, lower is earlier in the list.
|
||||
'priority': 0.1,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
# Send the headers
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Content-Length', len(body))
|
||||
self.end_headers()
|
||||
|
||||
# Send the body
|
||||
self.wfile.write(body)
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def delete_socket_file():
|
||||
if os.path.exists(PLUGIN_UNIX_SOCK):
|
||||
os.remove(PLUGIN_UNIX_SOCK)
|
||||
|
||||
def sig_handler(b, a):
|
||||
delete_socket_file()
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
start_update_loop()
|
||||
|
||||
mkdir_p(os.path.dirname(PLUGIN_UNIX_SOCK))
|
||||
delete_socket_file()
|
||||
server = SocketServer.UnixStreamServer(PLUGIN_UNIX_SOCK, Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except:
|
||||
delete_socket_file()
|
||||
raise
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user