From af901c5dac6fc2214f478506ba6697f4f9f6f267 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Thu, 29 Sep 2016 19:11:55 +0200 Subject: [PATCH 1/5] plugins: remove plugins They now are in the weaveworks-plugins organization. https://github.com/weaveworks-plugins - http-request has been updated and renamed to http-statistics: https://github.com/weaveworks-plugins/scope-http-statistics - iowait: https://github.com/weaveworks-plugins/scope-iowait - traffic-control: https://github.com/weaveworks-plugins/scope-traffic-control --- examples/plugins/http-requests/Dockerfile | 12 - examples/plugins/http-requests/Makefile | 22 - .../plugins/http-requests/http-requests.c | 162 -------- .../plugins/http-requests/http-requests.py | 195 --------- examples/plugins/iowait/.gitignore | 1 - examples/plugins/iowait/Dockerfile | 6 - examples/plugins/iowait/Makefile | 25 -- examples/plugins/iowait/main.go | 384 ------------------ examples/plugins/traffic-control/.gitignore | 1 - examples/plugins/traffic-control/Dockerfile | 7 - examples/plugins/traffic-control/Makefile | 33 -- examples/plugins/traffic-control/README.md | 17 - examples/plugins/traffic-control/docker.go | 144 ------- .../traffic-control/imgs/container_view.png | Bin 148565 -> 0 bytes .../plugins/traffic-control/imgs/controls.png | Bin 49783 -> 0 bytes examples/plugins/traffic-control/main.go | 227 ----------- examples/plugins/traffic-control/report.go | 326 --------------- examples/plugins/traffic-control/store.go | 69 ---- examples/plugins/traffic-control/tc.go | 206 ---------- 19 files changed, 1837 deletions(-) delete mode 100644 examples/plugins/http-requests/Dockerfile delete mode 100644 examples/plugins/http-requests/Makefile delete mode 100644 examples/plugins/http-requests/http-requests.c delete mode 100755 examples/plugins/http-requests/http-requests.py delete mode 100644 examples/plugins/iowait/.gitignore delete mode 100644 examples/plugins/iowait/Dockerfile delete mode 100644 examples/plugins/iowait/Makefile delete mode 100644 examples/plugins/iowait/main.go delete mode 100644 examples/plugins/traffic-control/.gitignore delete mode 100644 examples/plugins/traffic-control/Dockerfile delete mode 100644 examples/plugins/traffic-control/Makefile delete mode 100644 examples/plugins/traffic-control/README.md delete mode 100644 examples/plugins/traffic-control/docker.go delete mode 100644 examples/plugins/traffic-control/imgs/container_view.png delete mode 100644 examples/plugins/traffic-control/imgs/controls.png delete mode 100644 examples/plugins/traffic-control/main.go delete mode 100644 examples/plugins/traffic-control/report.go delete mode 100644 examples/plugins/traffic-control/store.go delete mode 100644 examples/plugins/traffic-control/tc.go diff --git a/examples/plugins/http-requests/Dockerfile b/examples/plugins/http-requests/Dockerfile deleted file mode 100644 index 29e184dd1..000000000 --- a/examples/plugins/http-requests/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM ubuntu:wily -MAINTAINER Weaveworks Inc -LABEL works.weave.role=system - -# Install BCC -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D4284CDD -RUN echo "deb http://52.8.15.63/apt trusty main" | tee /etc/apt/sources.list.d/iovisor.list -RUN apt-get update && apt-get install -y libbcc libbcc-examples python-bcc - -# Add our plugin -ADD ./http-requests.c ./http-requests.py /usr/bin/ -ENTRYPOINT ["/usr/bin/http-requests.py"] diff --git a/examples/plugins/http-requests/Makefile b/examples/plugins/http-requests/Makefile deleted file mode 100644 index fb3913305..000000000 --- a/examples/plugins/http-requests/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -.PHONY: run clean - -IMAGE=weavescope-http-requests-plugin -UPTODATE=.uptodate - -run: $(UPTODATE) - docker run --rm -it \ - --privileged --net=host \ - -v /lib/modules:/lib/modules \ - -v /usr/src:/usr/src \ - -v /sys/kernel/debug/:/sys/kernel/debug/ \ - -v /var/run/scope/plugins:/var/run/scope/plugins \ - --name $(IMAGE) \ - $(IMAGE) - -$(UPTODATE): Dockerfile http-requests.py http-requests.c - docker build -t $(IMAGE) . - touch $@ - -clean: - - rm -rf $(UPTODATE) - - docker rmi $(IMAGE) diff --git a/examples/plugins/http-requests/http-requests.c b/examples/plugins/http-requests/http-requests.c deleted file mode 100644 index 8694967a3..000000000 --- a/examples/plugins/http-requests/http-requests.c +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include - -/* Table from (Task group id|Task id) to (Number of received http requests). - We need to gather requests per task and not only per task group (i.e. userspace pid) - so that entries can be cleared up independently when a task exists. - This implies that userspace needs to do the per-process aggregation. - */ -BPF_HASH(received_http_requests, u64, u64); - - -/* skb_copy_datagram_iter() (Kernels >= 3.19) is in charge of copying socket - buffers from kernel to userspace. - - skb_copy_datagram_iter() has an associated tracepoint - (trace_skb_copy_datagram_iovec), which would be more stable than a kprobe but - it lacks the offset argument. - */ -int kprobe__skb_copy_datagram_iter(struct pt_regs *ctx, const struct sk_buff *skb, int offset, void *unused_iovec, int len) -{ - - /* Inspect the beginning of socket buffers copied to user-space to determine - if they correspond to http requests. - - Caveats: - - Requests may not appear at the beginning of a packet due to: - * Persistent connections. - * Packet fragmentation. - - We could inspect the full packet but: - * It's very inefficient. - * Examining the non-linear (paginated) area of a socket buffer would be - really tricky from ebpf. - */ - - /* Verify it's a TCP socket - TODO: is it worth caching it in a socket table? - */ - struct sock *sk = skb->sk; - unsigned short skc_family = sk->__sk_common.skc_family; - switch (skc_family) { - case PF_INET: - case PF_INET6: - case PF_UNIX: - break; - default: - return 0; - } - /* The socket type and protocol are not directly addressable since they are - bitfields. We access them by assuming sk_write_queue is immediately before - them (admittedly pretty hacky). - */ - unsigned int flags = 0; - size_t flags_offset = offsetof(typeof(struct sock), sk_write_queue) + sizeof(sk->sk_write_queue); - bpf_probe_read(&flags, sizeof(flags), ((u8*)sk) + flags_offset); - u16 sk_type = flags >> 16; - if (sk_type != SOCK_STREAM) { - return 0; - } - u8 sk_protocol = flags >> 8 & 0xFF; - /* The protocol is unset (IPPROTO_IP) in Unix sockets */ - if ( (sk_protocol != IPPROTO_TCP) && ((skc_family == PF_UNIX) && (sk_protocol != IPPROTO_IP)) ) { - return 0; - } - - /* Inline implementation of skb_headlen() */ - unsigned int head_len = skb->len - skb->data_len; - /* http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes - minimum length of http request is always greater than 7 bytes - */ - unsigned int available_data = head_len - offset; - if (available_data < 7) { - return 0; - } - - /* Check if buffer begins with a method name followed by a space. - - To avoid false positives it would be good to do a deeper inspection - (i.e. fully ensure a 'Method SP Request-URI SP HTTP-Version CRLF' - structure) but loops are not allowed in ebpf, making variable-size-data - parsers infeasible. - */ - u8 data[8] = {}; - if (available_data >= 8) { - /* We have confirmed having access to 7 bytes, but need 8 bytes to check the - space after OPTIONS. bpf_probe_read() requires its second argument to be - an immediate, so we obtain the data in this unsexy way. - */ - bpf_probe_read(&data, 8, skb->data + offset); - } else { - bpf_probe_read(&data, 7, skb->data + offset); - } - - switch (data[0]) { - /* DELETE */ - case 'D': - if ((data[1] != 'E') || (data[2] != 'L') || (data[3] != 'E') || (data[4] != 'T') || (data[5] != 'E') || (data[6] != ' ')) { - return 0; - } - break; - - /* GET */ - case 'G': - if ((data[1] != 'E') || (data[2] != 'T') || (data[3] != ' ')) { - return 0; - } - break; - - /* HEAD */ - case 'H': - if ((data[1] != 'E') || (data[2] != 'A') || (data[3] != 'D') || (data[4] != ' ')) { - return 0; - } - break; - - /* OPTIONS */ - case 'O': - if (available_data < 8 || (data[1] != 'P') || (data[2] != 'T') || (data[3] != 'I') || (data[4] != 'O') || (data[5] != 'N') || (data[6] != 'S') || (data[7] != ' ')) { - return 0; - } - break; - - /* PATCH/POST/PUT */ - case 'P': - switch (data[1]) { - case 'A': - if ((data[2] != 'T') || (data[3] != 'C') || (data[4] != 'H') || (data[5] != ' ')) { - return 0; - } - break; - case 'O': - if ((data[2] != 'S') || (data[3] != 'T') || (data[4] != ' ')) { - return 0; - } - break; - case 'U': - if ((data[2] != 'T') || (data[3] != ' ')) { - return 0; - } - break; - } - break; - - default: - return 0; - } - - /* Finally, bump the request counter for current task */ - u64 pid_tgid = bpf_get_current_pid_tgid(); - received_http_requests.increment(pid_tgid); - - return 0; -} - - -/* Clear out request count entries of tasks on exit */ -int kprobe__do_exit(struct pt_regs *ctx) { - u64 pid_tgid = bpf_get_current_pid_tgid(); - received_http_requests.delete(&pid_tgid); - return 0; -} diff --git a/examples/plugins/http-requests/http-requests.py b/examples/plugins/http-requests/http-requests.py deleted file mode 100755 index a914c11fc..000000000 --- a/examples/plugins/http-requests/http-requests.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python -import bcc - -import time -import collections -import datetime -import os -import signal -import errno -import json -import urlparse -import threading -import socket -import BaseHTTPServer -import SocketServer -import sys - -EBPF_FILE = "http-requests.c" -EBPF_TABLE_NAME = "received_http_requests" -PLUGIN_ID="http-requests" -PLUGIN_UNIX_SOCK = "/var/run/scope/plugins/" + PLUGIN_ID + ".sock" - -class KernelInspector(threading.Thread): - def __init__(self): - super(KernelInspector, self).__init__() - self.bpf = bcc.BPF(EBPF_FILE) - self.http_rate_per_pid = dict() - self.lock = threading.Lock() - - def update_http_rate_per_pid(self, last_req_count_snapshot): - # Aggregate the kernel's per-task http request counts into userland's - # per-process counts - req_count_table = self.bpf.get_table(EBPF_TABLE_NAME) - new_req_count_snapshot = collections.defaultdict(int) - for pid_tgid, req_count in req_count_table.iteritems(): - # Note that the kernel's tgid maps into userland's pid - # (not to be confused by the kernel's pid, which is - # the unique identifier of a kernel task) - pid = pid_tgid.value >> 32 - new_req_count_snapshot[pid] += req_count.value - - # Compute request rate - new_http_rate_per_pid = dict() - for pid, req_count in new_req_count_snapshot.iteritems(): - request_delta = req_count - if pid in last_req_count_snapshot: - request_delta -= last_req_count_snapshot[pid] - new_http_rate_per_pid[pid] = request_delta - - self.lock.acquire() - self.http_rate_per_pid = new_http_rate_per_pid - self.lock.release() - - return new_req_count_snapshot - - def on_http_rate_per_pid(self, f): - self.lock.acquire() - r = f(self.http_rate_per_pid) - self.lock.release() - return r - - def run(self): - # Compute request rates based on the requests counts from the last - # second. It would be simpler to clear the table, wait one second but - # clear() is expensive (each entry is individually cleared with a system - # call) and less robust (it contends with the increments done by the - # kernel probe). - req_count_snapshot = collections.defaultdict(int) - while True: - time.sleep(1) - req_count_snapshot = self.update_http_rate_per_pid(req_count_snapshot) - - -class PluginRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - protocol_version = 'HTTP/1.1' - - def __init__(self, *args, **kwargs): - self.request_log = '' - BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs) - - def do_GET(self): - self.log_extra = '' - path = urlparse.urlparse(self.path)[2].lower() - if path == '/report': - self.do_report() - else: - self.send_response(404) - self.send_header('Content-length', 0) - self.end_headers() - - def get_process_nodes(self, http_rate_per_pid): - # Get current timestamp in RFC3339 - date = datetime.datetime.utcnow() - date = date.isoformat('T') + 'Z' - process_nodes = dict() - for pid, http_rate in http_rate_per_pid.iteritems(): - # print "\t%-10s %s" % (pid , http_rate) - node_key = "%s;%d" % (self.server.hostname, pid) - process_nodes[node_key] = { - 'metrics': { - 'http_requests_per_second': { - 'samples': [{ - 'date': date, - 'value': float(http_rate), - }] - } - } - } - return process_nodes - - def do_report(self): - kernel_inspector = self.server.kernel_inspector - process_nodes = kernel_inspector.on_http_rate_per_pid(self.get_process_nodes) - report = { - 'Process': { - 'nodes': process_nodes, - 'metric_templates': { - 'http_requests_per_second': { - 'id': 'http_requests_per_second', - 'label': 'HTTP Req/Second', - 'priority': 0.1, - } - } - }, - 'Plugins': [ - { - 'id': PLUGIN_ID, - 'label': 'HTTP Requests', - 'description': 'Adds http request metrics to processes', - 'interfaces': ['reporter'], - 'api_version': '1', - } - ] - } - body = json.dumps(report) - self.request_log = "resp_size=%d, resp_entry_count=%d" % (len(body), len(process_nodes)) - self.send_response(200) - self.send_header('Content-type', 'application/json') - self.send_header('Content-length', len(body)) - self.end_headers() - self.wfile.write(body) - - def log_request(self, code='-', size='-'): - request_log = '' - if self.request_log: - request_log = ' (%s)' % self.request_log - self.log_message('"%s" %s %s%s', - self.requestline, str(code), str(size), request_log) - - -class PluginServer(SocketServer.ThreadingUnixStreamServer): - daemon_threads = True - - def __init__(self, socket_file, kernel_inspector): - mkdir_p(os.path.dirname(socket_file)) - self.socket_file = socket_file - self.delete_socket_file() - self.kernel_inspector = kernel_inspector - self.hostname = socket.gethostname() - SocketServer.UnixStreamServer.__init__(self, socket_file, PluginRequestHandler) - - def finish_request(self, request, _): - # Make the logger happy by providing a phony client_address - self.RequestHandlerClass(request, '-', self) - - def delete_socket_file(self): - if os.path.exists(self.socket_file): - os.remove(self.socket_file) - - -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 - - -if __name__ == '__main__': - kernel_inspector = KernelInspector() - kernel_inspector.setDaemon(True) - kernel_inspector.start() - plugin_server = PluginServer(PLUGIN_UNIX_SOCK, kernel_inspector) - def sig_handler(b, a): - plugin_server.delete_socket_file() - exit(0) - signal.signal(signal.SIGTERM, sig_handler) - signal.signal(signal.SIGINT, sig_handler) - try: - plugin_server.serve_forever() - except: - plugin_server.delete_socket_file() - raise diff --git a/examples/plugins/iowait/.gitignore b/examples/plugins/iowait/.gitignore deleted file mode 100644 index c01e9b159..000000000 --- a/examples/plugins/iowait/.gitignore +++ /dev/null @@ -1 +0,0 @@ -iowait diff --git a/examples/plugins/iowait/Dockerfile b/examples/plugins/iowait/Dockerfile deleted file mode 100644 index 036342b3e..000000000 --- a/examples/plugins/iowait/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM alpine:3.3 -MAINTAINER Weaveworks Inc -LABEL works.weave.role=system -COPY ./iowait /usr/bin/iowait -RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 -ENTRYPOINT ["/usr/bin/iowait"] diff --git a/examples/plugins/iowait/Makefile b/examples/plugins/iowait/Makefile deleted file mode 100644 index 74f2fce50..000000000 --- a/examples/plugins/iowait/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -.PHONY: run clean - -SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E") -EXE=iowait -IMAGE=weavescope-iowait-plugin -UPTODATE=.$(EXE).uptodate - -run: $(UPTODATE) - # --net=host gives us the remote hostname, in case we're being launched against a non-local docker host. - # We could also pass in the `-hostname=foo` flag, but that doesn't work against a remote docker host. - $(SUDO) docker run --rm -it \ - --net=host \ - -v /var/run/scope/plugins:/var/run/scope/plugins \ - --name $(IMAGE) $(IMAGE) - -$(UPTODATE): $(EXE) Dockerfile - $(SUDO) docker build -t $(IMAGE) . - touch $@ - -$(EXE): main.go - $(SUDO) docker run --rm -v "$$PWD":/usr/src/$(EXE) -w /usr/src/$(EXE) golang:1.6 go build -v - -clean: - - rm -rf $(UPTODATE) $(EXE) - - $(SUDO) docker rmi $(IMAGE) diff --git a/examples/plugins/iowait/main.go b/examples/plugins/iowait/main.go deleted file mode 100644 index 6f1230605..000000000 --- a/examples/plugins/iowait/main.go +++ /dev/null @@ -1,384 +0,0 @@ -package main - -import ( - "encoding/json" - "flag" - "fmt" - "log" - "net" - "net/http" - "os" - "os/exec" - "os/signal" - "strconv" - "strings" - "sync" - "time" -) - -func main() { - hostname, _ := os.Hostname() - var ( - addr = flag.String("addr", "/var/run/scope/plugins/iowait.sock", "unix socket to listen for connections on") - hostID = flag.String("hostname", hostname, "hostname of the host running this plugin") - ) - flag.Parse() - - log.Printf("Starting on %s...\n", *hostID) - - // Check we can get the iowait for the system - _, err := iowait() - if err != nil { - log.Fatal(err) - } - - os.Remove(*addr) - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt) - go func() { - <-interrupt - os.Remove(*addr) - os.Exit(0) - }() - - listener, err := net.Listen("unix", *addr) - if err != nil { - log.Fatal(err) - } - defer func() { - listener.Close() - os.Remove(*addr) - }() - - log.Printf("Listening on: unix://%s", *addr) - - plugin := &Plugin{HostID: *hostID} - http.HandleFunc("/report", plugin.Report) - http.HandleFunc("/control", plugin.Control) - if err := http.Serve(listener, nil); err != nil { - log.Printf("error: %v", err) - } -} - -// Plugin groups the methods a plugin needs -type Plugin struct { - HostID string - - lock sync.Mutex - iowaitMode bool -} - -type request struct { - NodeID string - Control string -} - -type response struct { - ShortcutReport *report `json:"shortcutReport,omitempty"` -} - -type report struct { - Host topology - Plugins []pluginSpec -} - -type topology struct { - Nodes map[string]node `json:"nodes"` - MetricTemplates map[string]metricTemplate `json:"metric_templates"` - Controls map[string]control `json:"controls"` -} - -type node struct { - Metrics map[string]metric `json:"metrics"` - LatestControls map[string]controlEntry `json:"latestControls,omitempty"` -} - -type metric struct { - Samples []sample `json:"samples,omitempty"` - Min float64 `json:"min"` - Max float64 `json:"max"` -} - -type sample struct { - Date time.Time `json:"date"` - Value float64 `json:"value"` -} - -type controlEntry struct { - Timestamp time.Time `json:"timestamp"` - Value controlData `json:"value"` -} - -type controlData struct { - Dead bool `json:"dead"` -} - -type metricTemplate struct { - ID string `json:"id"` - Label string `json:"label,omitempty"` - Format string `json:"format,omitempty"` - Priority float64 `json:"priority,omitempty"` -} - -type control struct { - ID string `json:"id"` - Human string `json:"human"` - Icon string `json:"icon"` - Rank int `json:"rank"` -} - -type pluginSpec struct { - ID string `json:"id"` - Label string `json:"label"` - Description string `json:"description,omitempty"` - Interfaces []string `json:"interfaces"` - APIVersion string `json:"api_version,omitempty"` -} - -func (p *Plugin) makeReport() (*report, error) { - metrics, err := p.metrics() - if err != nil { - return nil, err - } - rpt := &report{ - Host: topology{ - Nodes: map[string]node{ - p.getTopologyHost(): { - Metrics: metrics, - LatestControls: p.latestControls(), - }, - }, - MetricTemplates: p.metricTemplates(), - Controls: p.controls(), - }, - Plugins: []pluginSpec{ - { - ID: "iowait", - Label: "iowait", - Description: "Adds a graph of CPU IO Wait to hosts", - Interfaces: []string{"reporter", "controller"}, - APIVersion: "1", - }, - }, - } - return rpt, nil -} - -func (p *Plugin) metrics() (map[string]metric, error) { - value, err := p.metricValue() - if err != nil { - return nil, err - } - id, _ := p.metricIDAndName() - metrics := map[string]metric{ - id: { - Samples: []sample{ - { - Date: time.Now(), - Value: value, - }, - }, - Min: 0, - Max: 100, - }, - } - return metrics, nil -} - -func (p *Plugin) latestControls() map[string]controlEntry { - ts := time.Now() - ctrls := map[string]controlEntry{} - for _, details := range p.allControlDetails() { - ctrls[details.id] = controlEntry{ - Timestamp: ts, - Value: controlData{ - Dead: details.dead, - }, - } - } - return ctrls -} - -func (p *Plugin) metricTemplates() map[string]metricTemplate { - id, name := p.metricIDAndName() - return map[string]metricTemplate{ - id: { - ID: id, - Label: name, - Format: "percent", - Priority: 0.1, - }, - } -} - -func (p *Plugin) controls() map[string]control { - ctrls := map[string]control{} - for _, details := range p.allControlDetails() { - ctrls[details.id] = control{ - ID: details.id, - Human: details.human, - Icon: details.icon, - Rank: 1, - } - } - return ctrls -} - -// Report is called by scope when a new report is needed. It is part of the -// "reporter" interface, which all plugins must implement. -func (p *Plugin) Report(w http.ResponseWriter, r *http.Request) { - p.lock.Lock() - defer p.lock.Unlock() - log.Println(r.URL.String()) - rpt, err := p.makeReport() - if err != nil { - log.Printf("error: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - raw, err := json.Marshal(*rpt) - if err != nil { - log.Printf("error: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - w.Write(raw) -} - -// Control is called by scope when a control is activated. It is part -// of the "controller" interface. -func (p *Plugin) Control(w http.ResponseWriter, r *http.Request) { - p.lock.Lock() - defer p.lock.Unlock() - log.Println(r.URL.String()) - xreq := request{} - err := json.NewDecoder(r.Body).Decode(&xreq) - if err != nil { - log.Printf("Bad request: %v", err) - w.WriteHeader(http.StatusBadRequest) - return - } - thisNodeID := p.getTopologyHost() - if xreq.NodeID != thisNodeID { - log.Printf("Bad nodeID, expected %q, got %q", thisNodeID, xreq.NodeID) - w.WriteHeader(http.StatusBadRequest) - return - } - expectedControlID, _, _ := p.controlDetails() - if expectedControlID != xreq.Control { - log.Printf("Bad control, expected %q, got %q", expectedControlID, xreq.Control) - w.WriteHeader(http.StatusBadRequest) - return - } - p.iowaitMode = !p.iowaitMode - rpt, err := p.makeReport() - if err != nil { - log.Printf("error: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - res := response{ShortcutReport: rpt} - raw, err := json.Marshal(res) - if err != nil { - log.Printf("error: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - w.Write(raw) -} - -func (p *Plugin) getTopologyHost() string { - return fmt.Sprintf("%s;", p.HostID) -} - -func (p *Plugin) metricIDAndName() (string, string) { - if p.iowaitMode { - return "iowait", "IO Wait" - } - return "idle", "Idle" -} - -func (p *Plugin) metricValue() (float64, error) { - if p.iowaitMode { - return iowait() - } - return idle() -} - -type controlDetails struct { - id string - human string - icon string - dead bool -} - -func (p *Plugin) allControlDetails() []controlDetails { - return []controlDetails{ - { - id: "switchToIdle", - human: "Switch to idle", - icon: "fa-beer", - dead: !p.iowaitMode, - }, - { - id: "switchToIOWait", - human: "Switch to IO wait", - icon: "fa-hourglass", - dead: p.iowaitMode, - }, - } -} - -func (p *Plugin) controlDetails() (string, string, string) { - for _, details := range p.allControlDetails() { - if !details.dead { - return details.id, details.human, details.icon - } - } - return "", "", "" -} - -func iowait() (float64, error) { - return iostatValue(3) -} - -func idle() (float64, error) { - return iostatValue(5) -} - -func iostatValue(idx int) (float64, error) { - values, err := iostat() - if err != nil { - return 0, err - } - if idx >= len(values) { - return 0, fmt.Errorf("invalid iostat field index %d", idx) - } - - return strconv.ParseFloat(values[idx], 64) -} - -// Get the latest iostat values -func iostat() ([]string, error) { - out, err := exec.Command("iostat", "-c").Output() - if err != nil { - return nil, fmt.Errorf("iowait: %v", err) - } - - // Linux 4.2.0-25-generic (a109563eab38) 04/01/16 _x86_64_(4 CPU) - // - // avg-cpu: %user %nice %system %iowait %steal %idle - // 2.37 0.00 1.58 0.01 0.00 96.04 - lines := strings.Split(string(out), "\n") - if len(lines) < 4 { - return nil, fmt.Errorf("iowait: unexpected output: %q", out) - } - - values := strings.Fields(lines[3]) - if len(values) != 6 { - return nil, fmt.Errorf("iowait: unexpected output: %q", out) - } - return values, nil -} diff --git a/examples/plugins/traffic-control/.gitignore b/examples/plugins/traffic-control/.gitignore deleted file mode 100644 index df5531de4..000000000 --- a/examples/plugins/traffic-control/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/traffic-control diff --git a/examples/plugins/traffic-control/Dockerfile b/examples/plugins/traffic-control/Dockerfile deleted file mode 100644 index 3ccf9b633..000000000 --- a/examples/plugins/traffic-control/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM alpine:3.3 -MAINTAINER Weaveworks Inc -LABEL works.weave.role=system -COPY ./traffic-control /usr/bin/traffic-control -RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 -RUN apk add --update iproute2 && rm -rf /var/cache/apk/* -ENTRYPOINT ["/usr/bin/traffic-control"] diff --git a/examples/plugins/traffic-control/Makefile b/examples/plugins/traffic-control/Makefile deleted file mode 100644 index 831a02eb3..000000000 --- a/examples/plugins/traffic-control/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -.PHONY: run clean - -SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E") -EXE=traffic-control -IMAGE=weaveworks/scope-$(EXE)-plugin -NAME=weaveworks-scope-${EXE}-plugin -UPTODATE=.$(EXE).uptodate - -run: $(UPTODATE) - # --net=host gives us the remote hostname, in case we're being launched against a non-local docker host. - # We could also pass in the `-hostname=foo` flag, but that doesn't work against a remote docker host. - $(SUDO) docker run --rm -it \ - --net=host \ - --pid=host \ - --privileged \ - -v /var/run:/var/run \ - --name $(NAME) $(IMAGE) - -$(UPTODATE): $(EXE) Dockerfile - $(SUDO) docker build -t $(IMAGE) . - touch $@ - -$(EXE): $(shell find . -name *.go) - $(SUDO) docker run --rm \ - -v "$$PWD":/go/src/hosting/org/$(EXE) \ - -v $(shell pwd)/../../../vendor:/go/src/hosting/org/$(EXE)/vendor \ - -w /go/src/hosting/org/$(EXE) \ - golang:1.6 go build -v - - -clean: - - rm -rf $(UPTODATE) $(EXE) - - $(SUDO) docker rmi $(IMAGE) diff --git a/examples/plugins/traffic-control/README.md b/examples/plugins/traffic-control/README.md deleted file mode 100644 index ed90cf1f6..000000000 --- a/examples/plugins/traffic-control/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Traffic Control Plugin - -The Traffic Control plugin allows to modify the performance parameters of container's network interfaces. The following images show a simple example of how **status** and **controls** are displayed in scope UI. - -Scope Probe plugin screenshot - -## Visualization - -The parameters are shown in a table named **Traffic Control**. The plugin shows the values of latency and packet loss that are enforced on the network interface. The "-" mean that no value is set for that parameter, latency is displayed in *milliseconds* (ms) and packet loss in *percentage*. - -## Controls - -The Traffic Controls plugin provides a simple interface to change the value of latency (hourglass buttons) and packet loss (scissor button) or remove value that was set (circled cross button). Such buttons are displayed on the top of the container detailed view, just above the STATUS section (See picture below, control are shown inside the red rectangle). - -Scope Probe plugin screenshot - -The *hourglass* buttons control the latency value, from left to right they set: 2000ms, 1000ms, and 500ms. The *scissor* button controls the packet loss value, it set a 10% packet loss. The *circled cross* button clear any previous settings. diff --git a/examples/plugins/traffic-control/docker.go b/examples/plugins/traffic-control/docker.go deleted file mode 100644 index f2c1a78c4..000000000 --- a/examples/plugins/traffic-control/docker.go +++ /dev/null @@ -1,144 +0,0 @@ -package main - -import ( - "fmt" - "time" - - log "github.com/Sirupsen/logrus" - docker "github.com/fsouza/go-dockerclient" -) - -// DockerClient internal data structure -type DockerClient struct { - store *Store - client *docker.Client -} - -// NewDockerClient instantiates a new DockerClient -func NewDockerClient(store *Store) (*DockerClient, error) { - dc, err := docker.NewClient("unix:///var/run/docker.sock") - if err != nil { - return nil, fmt.Errorf("failed to connect to docker daemon: %v", err) - } - return &DockerClient{ - store: store, - client: dc, - }, nil -} - -// Start docker client -func (c *DockerClient) Start() { - for { - func() { - events := make(chan *docker.APIEvents) - if err := c.client.AddEventListener(events); err != nil { - log.Error(err) - return - } - defer func() { - if err := c.client.RemoveEventListener(events); err != nil { - log.Error(err) - } - }() - if err := c.getContainers(); err != nil { - log.Error(err) - return - } - for { - event, ok := <-events - if !ok { - log.Error("event listener unexpectedly disconnected") - return - } - c.handleEvent(event) - } - }() - time.Sleep(time.Second) - } -} - -func (c *DockerClient) getContainers() error { - apiContainers, err := c.client.ListContainers(docker.ListContainersOptions{All: true}) - if err != nil { - return err - } - - for _, apiContainer := range apiContainers { - containerState, err := c.getContainerState(apiContainer.ID) - if err != nil { - log.Error(err) - continue - } - state := Destroyed - switch { - case containerState.Dead || containerState.Paused || containerState.Restarting || containerState.OOMKilled: - state = Stopped - case containerState.Running: - state = Running - } - c.updateContainer(apiContainer.ID, state, containerState.Pid) - } - - return nil -} - -func (c *DockerClient) handleEvent(event *docker.APIEvents) { - var state State - switch event.Status { - case "create": - state = Created - case "destroy": - state = Destroyed - case "start", "unpause": - state = Running - case "die", "pause": - state = Stopped - default: - return - } - pid, err := c.getContainerPID(event.ID) - if err != nil { - log.Error(err) - return - } - c.updateContainer(event.ID, state, pid) -} - -func (c *DockerClient) getContainerPID(containerID string) (int, error) { - containerState, err := c.getContainerState(containerID) - if containerState == nil { - return 0, err - } - return containerState.Pid, nil -} - -func (c *DockerClient) getContainerState(containerID string) (*docker.State, error) { - dockerContainer, err := c.getContainer(containerID) - if dockerContainer == nil { - return nil, err - } - return &dockerContainer.State, nil -} - -func (c *DockerClient) getContainer(containerID string) (*docker.Container, error) { - dockerContainer, err := c.client.InspectContainer(containerID) - if err != nil { - if _, ok := err.(*docker.NoSuchContainer); !ok { - return nil, err - } - return nil, nil - } - return dockerContainer, nil -} - -func (c *DockerClient) updateContainer(containerID string, state State, pid int) { - if state == Destroyed { - c.store.DeleteContainer(containerID) - return - } - cont := Container{ - State: state, - PID: pid, - } - c.store.SetContainer(containerID, cont) -} diff --git a/examples/plugins/traffic-control/imgs/container_view.png b/examples/plugins/traffic-control/imgs/container_view.png deleted file mode 100644 index 7037b44ed2e80809eb36668529e803228b379c3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148565 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 E7f-=w^#A|> diff --git a/examples/plugins/traffic-control/imgs/controls.png b/examples/plugins/traffic-control/imgs/controls.png deleted file mode 100644 index ed3f6f931ad83f8a6c65db5b422cab223005b518..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49783 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 Tdp3hS20q&A26xc6ZJz!g2yFdB diff --git a/examples/plugins/traffic-control/main.go b/examples/plugins/traffic-control/main.go deleted file mode 100644 index f12094e3e..000000000 --- a/examples/plugins/traffic-control/main.go +++ /dev/null @@ -1,227 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net" - "net/http" - "os" - "os/signal" - "path/filepath" - - log "github.com/Sirupsen/logrus" -) - -// TODO: -// -// do not try to install the qdics on the network interface every -// time, skip this step if it is already installed (currently we do -// "replace" instead of "add", but this check may be a way of avoiding -// more one-time installation steps in future). -// -// somehow inform the user about the current traffic control state -// (either add some metadata about latency or maybe add background -// color to buttons to denote whether the button is active); this may -// involve sending shortcut reports as a part of a response to the -// control request -// -// detect if ip and tc binaries are in $PATH -// -// detect if required sch_netem kernel module is loaded; note that in -// some (rare) cases this might be compiled in the kernel instead of -// being a separate module; probably check if tc works, if it does not -// return something like "not implemented". -// -// add traffic control on ingress traffic too (ifb kernel module will -// be required) -// -// currently we can control latency, add controls for packet loss and -// bandwidth -// -// port to eBPF? - -type containerClient interface { - Start() -} - -// Plugin is the internal data structure -type Plugin struct { - reporter *Reporter - - clients []containerClient -} - -// TrafficControlStatus keeps track of parameters status -type TrafficControlStatus struct { - latency string - packetLoss string -} - -// String is useful to easily create a string of the traffic control plugin internal status. -// Useful for debugging -func (tcs *TrafficControlStatus) String() string { - return fmt.Sprintf("%s %s", tcs.latency, tcs.packetLoss) -} - -// SetLatency sets the latency value -// the convention is that empty latency is represented by '-' -func (tcs *TrafficControlStatus) SetLatency(latency string) { - if latency == "" { - tcs.latency = "-" - } - tcs.latency = latency -} - -// SetPacketLoss sets the packet loss value -// the convention is that empty packet loss is represented by '-' -func (tcs *TrafficControlStatus) SetPacketLoss(packetLoss string) { - if packetLoss == "" { - tcs.packetLoss = "-" - } - tcs.packetLoss = packetLoss -} - -// TrafficControlStatusInit initializes with the convention that empty values are '-' -func TrafficControlStatusInit() *TrafficControlStatus { - return &TrafficControlStatus{ - latency: "-", - packetLoss: "-", - } -} - -// TrafficControlStatusCache implements status caching -var trafficControlStatusCache map[string]*TrafficControlStatus - -func main() { - const socket = "/var/run/scope/plugins/traffic-control.sock" - - // Handle the exit signal - setupSignals(socket) - - listener, err := setupSocket(socket) - if err != nil { - log.Fatalf("Failed to setup socket: %v", err) - } - - plugin, err := NewPlugin() - if err != nil { - log.Fatalf("Failed to create a plugin: %v", err) - } - - // Cache - trafficControlStatusCache = make(map[string]*TrafficControlStatus) - - trafficControlServeMux := http.NewServeMux() - - // Report request handler - reportHandler := http.HandlerFunc(plugin.report) - trafficControlServeMux.Handle("/report", reportHandler) - - // Control request handler - controlHandler := http.HandlerFunc(plugin.control) - trafficControlServeMux.Handle("/control", controlHandler) - - log.Println("Listening...") - if err = http.Serve(listener, trafficControlServeMux); err != nil { - log.Fatalf("failed to serve: %v", err) - } -} - -func setupSignals(socket string) { - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt) - go func() { - <-interrupt - os.Remove(socket) - os.Exit(0) - }() -} - -func setupSocket(socket string) (net.Listener, error) { - os.Remove(socket) - if err := os.MkdirAll(filepath.Dir(socket), 0755); err != nil { - return nil, fmt.Errorf("failed to create directory %q: %v", filepath.Dir(socket), err) - } - listener, err := net.Listen("unix", socket) - if err != nil { - return nil, fmt.Errorf("failed to listen on %q: %v", socket, err) - } - - log.Printf("Listening on: unix://%s", socket) - return listener, nil -} - -// NewPlugin instantiates a new plugin -func NewPlugin() (*Plugin, error) { - store := NewStore() - dockerClient, err := NewDockerClient(store) - if err != nil { - return nil, fmt.Errorf("failed to create a docker client: %v", err) - } - reporter := NewReporter(store) - plugin := &Plugin{ - reporter: reporter, - clients: []containerClient{ - dockerClient, - }, - } - for _, client := range plugin.clients { - go client.Start() - } - return plugin, nil -} - -func (p *Plugin) report(w http.ResponseWriter, r *http.Request) { - raw, err := p.reporter.RawReport() - if err != nil { - msg := fmt.Sprintf("error: failed to get raw report: %v", err) - log.Print(msg) - http.Error(w, msg, http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - w.Write(raw) -} - -type request struct { - NodeID string - Control string -} - -type response struct { - Error string `json:"error,omitempty"` -} - -func (p *Plugin) control(w http.ResponseWriter, r *http.Request) { - xreq := request{} - if err := json.NewDecoder(r.Body).Decode(&xreq); err != nil { - log.Printf("Bad request: %v", err) - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - handler, err := p.reporter.GetHandler(xreq.NodeID, xreq.Control) - if err != nil { - sendResponse(w, fmt.Errorf("failed to get handler: %v", err)) - return - } - if err := handler(); err != nil { - sendResponse(w, fmt.Errorf("handler failed: %v", err)) - return - } - sendResponse(w, nil) -} - -func sendResponse(w http.ResponseWriter, err error) { - res := response{} - if err != nil { - res.Error = err.Error() - } - raw, err := json.Marshal(res) - if err != nil { - log.Printf("Internal server error: %v", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - w.Write(raw) -} diff --git a/examples/plugins/traffic-control/report.go b/examples/plugins/traffic-control/report.go deleted file mode 100644 index 4657722a0..000000000 --- a/examples/plugins/traffic-control/report.go +++ /dev/null @@ -1,326 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "strings" - "time" -) - -const ( - trafficControlTablePrefix = "traffic-control-table-" -) - -type report struct { - Container topology - Plugins []pluginSpec -} - -type topology struct { - Nodes map[string]node `json:"nodes"` - Controls map[string]control `json:"controls"` - MetadataTemplates map[string]metadataTemplate `json:"metadata_templates,omitempty"` - TableTemplates map[string]tableTemplate `json:"table_templates,omitempty"` -} - -type tableTemplate struct { - ID string `json:"id"` - Label string `json:"label"` - Prefix string `json:"prefix"` -} - -type metadataTemplate struct { - ID string `json:"id"` - Label string `json:"label,omitempty"` // Human-readable descriptor for this row - Truncate int `json:"truncate,omitempty"` // If > 0, truncate the value to this length. - Datatype string `json:"dataType,omitempty"` - Priority float64 `json:"priority,omitempty"` - From string `json:"from,omitempty"` // Defines how to get the value from a report node -} - -type node struct { - LatestControls map[string]controlEntry `json:"latestControls,omitempty"` - Latest map[string]stringEntry `json:"latest,omitempty"` -} - -type controlEntry struct { - Timestamp time.Time `json:"timestamp"` - Value controlData `json:"value"` -} - -type controlData struct { - Dead bool `json:"dead"` -} - -type control struct { - ID string `json:"id"` - Human string `json:"human"` - Icon string `json:"icon"` - Rank int `json:"rank"` -} - -type stringEntry struct { - Timestamp time.Time `json:"timestamp"` - Value string `json:"value"` -} - -type pluginSpec struct { - ID string `json:"id"` - Label string `json:"label"` - Description string `json:"description,omitempty"` - Interfaces []string `json:"interfaces"` - APIVersion string `json:"api_version,omitempty"` -} - -// Reporter internal data structure -type Reporter struct { - store *Store -} - -// NewReporter instantiates a new Reporter -func NewReporter(store *Store) *Reporter { - return &Reporter{ - store: store, - } -} - -// RawReport returns a report -func (r *Reporter) RawReport() ([]byte, error) { - rpt := &report{ - Container: topology{ - Nodes: r.getContainerNodes(), - Controls: getTrafficControls(), - MetadataTemplates: getMetadataTemplate(), - TableTemplates: getTableTemplate(), - }, - Plugins: []pluginSpec{ - { - ID: "traffic-control", - Label: "Traffic control", - Description: "Adds traffic controls to the running Docker containers", - Interfaces: []string{"reporter", "controller"}, - APIVersion: "1", - }, - }, - } - raw, err := json.Marshal(rpt) - if err != nil { - return nil, fmt.Errorf("failed to marshal the report: %v", err) - } - return raw, nil -} - -// GetHandler returns the function performing the action specified by controlID -func (r *Reporter) GetHandler(nodeID, controlID string) (func() error, error) { - containerID, err := nodeIDToContainerID(nodeID) - if err != nil { - return nil, fmt.Errorf("failed to get container ID from node ID %q: %v", nodeID, err) - } - container, found := r.store.Container(containerID) - if !found { - return nil, fmt.Errorf("container %s not found", containerID) - } - var handler func(pid int) error - for _, c := range getControls() { - if c.control.ID == controlID { - handler = c.handler - break - } - } - if handler == nil { - return nil, fmt.Errorf("unknown control ID %q for node ID %q", controlID, nodeID) - } - return func() error { - return handler(container.PID) - }, nil -} - -// states: -// created, destroyed - don't create any node -// running, not running - create node with controls -func (r *Reporter) getContainerNodes() map[string]node { - nodes := map[string]node{} - timestamp := time.Now() - r.store.ForEach(func(containerID string, container Container) { - dead := false - switch container.State { - case Created, Destroyed: - // do nothing, to prevent adding a stale node - // to a report - case Stopped: - dead = true - fallthrough - case Running: - nodeID := containerIDToNodeID(containerID) - latency, _ := getLatency(container.PID) - packetLoss, _ := getPacketLoss(container.PID) - nodes[nodeID] = node{ - LatestControls: getTrafficNodeControls(timestamp, dead), - Latest: map[string]stringEntry{ - fmt.Sprintf("%s%s", trafficControlTablePrefix, "latency"): { - Timestamp: timestamp, - Value: latency, - }, - fmt.Sprintf("%s%s", trafficControlTablePrefix, "pktloss"): { - Timestamp: timestamp, - Value: packetLoss, - }, - }, - } - } - }) - return nodes -} - -func getMetadataTemplate() map[string]metadataTemplate { - return map[string]metadataTemplate{ - "traffic-control-latency": { - ID: "traffic-control-latency", - Label: "Latency", - Truncate: 0, - Datatype: "", - Priority: 13.5, - From: "latest", - }, - "traffic-control-pktloss": { - ID: "traffic-control-pktloss", - Label: "Packet Loss", - Truncate: 0, - Datatype: "", - Priority: 13.6, - From: "latest", - }, - } -} - -func getTableTemplate() map[string]tableTemplate { - return map[string]tableTemplate{ - "traffic-control-table": { - ID: "traffic-control-table", - Label: "Traffic Control", - Prefix: trafficControlTablePrefix, - }, - } -} - -func getTrafficNodeControls(timestamp time.Time, dead bool) map[string]controlEntry { - controls := map[string]controlEntry{} - entry := controlEntry{ - Timestamp: timestamp, - Value: controlData{ - Dead: dead, - }, - } - for _, c := range getControls() { - controls[c.control.ID] = entry - } - return controls -} - -func getTrafficControls() map[string]control { - controls := map[string]control{} - for _, c := range getControls() { - controls[c.control.ID] = c.control - } - return controls -} - -type extControl struct { - control control - handler func(pid int) error -} - -func getLatencyControls() []extControl { - return []extControl{ - { - control: control{ - ID: fmt.Sprintf("%s%s", trafficControlTablePrefix, "slow"), - Human: "Traffic speed: slow", - Icon: "fa-hourglass-1", - Rank: 20, - }, - handler: func(pid int) error { - return ApplyLatency(pid, "2000ms") - }, - }, - { - control: control{ - ID: fmt.Sprintf("%s%s", trafficControlTablePrefix, "medium"), - Human: "Traffic speed: medium", - Icon: "fa-hourglass-2", - Rank: 21, - }, - handler: func(pid int) error { - return ApplyLatency(pid, "1000ms") - }, - }, - { - control: control{ - ID: fmt.Sprintf("%s%s", trafficControlTablePrefix, "fast"), - Human: "Traffic speed: fast", - Icon: "fa-hourglass-3", - Rank: 22, - }, - handler: func(pid int) error { - return ApplyLatency(pid, "500ms") - }, - }, - } -} - -func getPacketLossControls() []extControl { - return []extControl{ - { - control: control{ - ID: fmt.Sprintf("%s%s", trafficControlTablePrefix, "pkt-drop-low"), - Human: "Packet drop: low", - Icon: "fa-cut", - Rank: 23, - }, - handler: func(pid int) error { - return ApplyPacketLoss(pid, "10%") - }, - }, - } -} - -func getGeneralControls() []extControl { - return []extControl{ - { - control: control{ - ID: fmt.Sprintf("%s%s", trafficControlTablePrefix, "clear"), - Human: "Clear traffic control settings", - Icon: "fa-times-circle", - Rank: 24, - }, - handler: func(pid int) error { - return ClearTrafficControlSettings(pid) - }, - }, - } -} - -func getControls() []extControl { - controls := getLatencyControls() - // TODO alepuccetti why append(controls, getPacketLossControls()) does not work? - for _, ctrl := range getPacketLossControls() { - controls = append(controls, ctrl) - } - for _, ctrl := range getGeneralControls() { - controls = append(controls, ctrl) - } - return controls -} - -const nodeSuffix = ";" - -func containerIDToNodeID(containerID string) string { - return fmt.Sprintf("%s%s", containerID, nodeSuffix) -} - -func nodeIDToContainerID(nodeID string) (string, error) { - if !strings.HasSuffix(nodeID, nodeSuffix) { - return "", fmt.Errorf("no suffix %q in node ID %q", nodeSuffix, nodeID) - } - return strings.TrimSuffix(nodeID, nodeSuffix), nil -} diff --git a/examples/plugins/traffic-control/store.go b/examples/plugins/traffic-control/store.go deleted file mode 100644 index 65c27d0ce..000000000 --- a/examples/plugins/traffic-control/store.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "sync" -) - -// State is the container internal state -type State int - -const ( - // Created state - Created State = iota - // Running state - Running - // Stopped state - Stopped - // Destroyed state - Destroyed -) - -// Container data structure -type Container struct { - State State - PID int -} - -// Store data structure -type Store struct { - lock sync.Mutex - containers map[string]Container -} - -// NewStore instantiates a new Store -func NewStore() *Store { - return &Store{ - containers: map[string]Container{}, - } -} - -// Container returns a container form its ID -func (s *Store) Container(containerID string) (Container, bool) { - s.lock.Lock() - defer s.lock.Unlock() - container, found := s.containers[containerID] - return container, found -} - -// SetContainer sets a container into the store -func (s *Store) SetContainer(containerID string, container Container) { - s.lock.Lock() - defer s.lock.Unlock() - s.containers[containerID] = container -} - -// DeleteContainer deletes a container from the store -func (s *Store) DeleteContainer(containerID string) { - s.lock.Lock() - defer s.lock.Unlock() - delete(s.containers, containerID) -} - -// ForEach execute a function on each container in the store -func (s *Store) ForEach(callback func(ID string, c Container)) { - s.lock.Lock() - defer s.lock.Unlock() - for containerID, container := range s.containers { - callback(containerID, container) - } -} diff --git a/examples/plugins/traffic-control/tc.go b/examples/plugins/traffic-control/tc.go deleted file mode 100644 index 0869a4e89..000000000 --- a/examples/plugins/traffic-control/tc.go +++ /dev/null @@ -1,206 +0,0 @@ -package main - -import ( - "fmt" - "os" - "os/exec" - "strings" - - log "github.com/Sirupsen/logrus" - "github.com/containernetworking/cni/pkg/ns" -) - -// applyTrafficControlRules set the network policies -func applyTrafficControlRules(pid int, rules []string) (netNSID string, err error) { - cmds := [][]string{ - strings.Fields("tc qdisc replace dev eth0 root handle 1: netem"), - } - cmd := strings.Fields("tc qdisc change dev eth0 root handle 1: netem") - cmd = append(cmd, rules...) - cmds = append(cmds, cmd) - - netNS := fmt.Sprintf("/proc/%d/ns/net", pid) - err = ns.WithNetNSPath(netNS, func(hostNS ns.NetNS) error { - for _, cmd := range cmds { - if output, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput(); err != nil { - log.Error(string(output)) - return fmt.Errorf("failed to execute command: %v", err) - } - } - return nil - }) - if err != nil { - return "", fmt.Errorf("failed to perform traffic control: %v", err) - } - netNSID, err = getNSID(netNS) - - if err != nil { - return "", err - } - return netNSID, nil -} - -// ApplyLatency sets the latency -func ApplyLatency(pid int, latency string) error { - if latency == "" { - return nil - } - rules := strings.Fields(fmt.Sprintf("delay %s", latency)) - - // Get cached packet loss - packetLoss, err := getPacketLoss(pid) - if err != nil { - return err - } - if packetLoss != "-" { - rules = append(rules, strings.Fields(fmt.Sprintf("loss %s", packetLoss))...) - } - - netNSID, err := applyTrafficControlRules(pid, rules) - - // Update cached values - if trafficControlStatusCache[netNSID] == nil { - trafficControlStatusCache[netNSID] = TrafficControlStatusInit() - } - trafficControlStatusCache[netNSID].SetLatency(latency) - trafficControlStatusCache[netNSID].SetPacketLoss(packetLoss) - - return nil -} - -// ApplyPacketLoss sets the packet loss -func ApplyPacketLoss(pid int, packetLoss string) error { - if packetLoss == "" { - return nil - } - rules := strings.Fields(fmt.Sprintf("loss %s", packetLoss)) - - // Get cached latency - latency, err := getLatency(pid) - if err != nil { - return err - } - if latency != "-" { - rules = append(rules, strings.Fields(fmt.Sprintf("delay %s", latency))...) - } - - netNSID, err := applyTrafficControlRules(pid, rules) - - // Update cached values - if trafficControlStatusCache[netNSID] == nil { - trafficControlStatusCache[netNSID] = TrafficControlStatusInit() - } - trafficControlStatusCache[netNSID].SetLatency(latency) - trafficControlStatusCache[netNSID].SetPacketLoss(packetLoss) - - return nil -} - -// ClearTrafficControlSettings clear all parameters of the qdisc with tc -func ClearTrafficControlSettings(pid int) error { - cmds := [][]string{ - strings.Fields("tc qdisc replace dev eth0 root handle 1: netem"), - } - netNS := fmt.Sprintf("/proc/%d/ns/net", pid) - err := ns.WithNetNSPath(netNS, func(hostNS ns.NetNS) error { - for _, cmd := range cmds { - if output, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput(); err != nil { - log.Error(string(output)) - return fmt.Errorf("failed to execute command: %v", err) - } - } - return nil - }) - if err != nil { - return fmt.Errorf("failed to perform traffic control: %v", err) - } - // clear cached parameters - netNSID, err := getNSID(netNS) - if err != nil { - log.Error(netNSID) - return fmt.Errorf("failed to get network namespace ID: %v", err) - } - delete(trafficControlStatusCache, netNSID) - return nil -} - -func getLatency(pid int) (string, error) { - var status *TrafficControlStatus - var err error - if status, err = getStatus(pid); err != nil { - return "-", err - } else if status == nil { - return "-", fmt.Errorf("status for PID %d does not exist", pid) - } - return status.latency, nil -} - -func getPacketLoss(pid int) (string, error) { - var status *TrafficControlStatus - var err error - if status, err = getStatus(pid); err != nil { - return "-", err - } else if status == nil { - return "-", fmt.Errorf("status for PID %d does not exist", pid) - } - return status.packetLoss, nil -} - -func getStatus(pid int) (*TrafficControlStatus, error) { - netNS := fmt.Sprintf("/proc/%d/ns/net", pid) - netNSID, err := getNSID(netNS) - if err != nil { - log.Error(netNSID) - return nil, fmt.Errorf("failed to get network namespace ID: %v", err) - } - if status, ok := trafficControlStatusCache[netNSID]; ok { - return status, nil - } - cmd := strings.Fields("tc qdisc show dev eth0") - var output string - err = ns.WithNetNSPath(netNS, func(hostNS ns.NetNS) error { - cmdOut, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput() - if err != nil { - log.Error(string(cmdOut)) - output = "" - return fmt.Errorf("failed to execute command: tc qdisc show dev eth0: %v", err) - } - output = string(cmdOut) - return nil - }) - // cache parameters - trafficControlStatusCache[netNSID] = &TrafficControlStatus{ - latency: parseLatency(output), - packetLoss: parsePacketLoss(output), - } - status, _ := trafficControlStatusCache[netNSID] - return status, err -} - -func parseLatency(statusString string) string { - return parseAttribute(statusString, "delay") -} - -func parsePacketLoss(statusString string) string { - return parseAttribute(statusString, "loss") -} -func parseAttribute(statusString string, attribute string) string { - statusStringSplited := strings.Fields(statusString) - for i, s := range statusStringSplited { - if s == attribute { - if i < len(statusStringSplited)-1 { - return strings.Trim(statusStringSplited[i+1], "\n") - } - return "-" - } - } - return "-" -} - -func getNSID(nsPath string) (string, error) { - nsID, err := os.Readlink(nsPath) - if err != nil { - return "", fmt.Errorf("failed read \"%s\": %v", nsPath, err) - } - return nsID[5 : len(nsID)-1], nil -} From e9e3b5d5c04d2df15e50a7fbdf26be843b3be52c Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Thu, 29 Sep 2016 19:09:50 +0200 Subject: [PATCH 2/5] docs/plugins: Refactoring The plugins README now points to the new repositories in the weaveworks-plugins organization (https://github.com/weaveworks-plugins). --- examples/plugins/README.md | 73 ++++++++++++++------------------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/examples/plugins/README.md b/examples/plugins/README.md index 0dc0e2467..6b3e762cb 100644 --- a/examples/plugins/README.md +++ b/examples/plugins/README.md @@ -1,39 +1,28 @@ # Scope Probe Plugins -Scope probe plugins let you insert your own custom metrics into Scope -and get them displayed in the UI. +Scope probe plugins let you insert your own custom data and controls into Scope and display them in the UI. +The list of the current running plugins is displayed next to the label `PLUGINS` in the bottom right of the UI. Scope Probe plugin screenshot -You can find some examples at the [the example -plugins](https://github.com/weaveworks/scope/tree/master/examples/plugins) -directory. We currently provide two examples: -* A [Python - plugin](https://github.com/weaveworks/scope/tree/master/examples/plugins/http-requests) - using [bcc](http://iovisor.github.io/bcc/) to extract incoming HTTP - request rates per process, without any application-level - instrumentation requirements and negligible performance toll - (metrics are obtained in-kernel without any packet copying to - userspace). **Note:** This plugin needs a [recent kernel version - with ebpf - support](https://github.com/iovisor/bcc/blob/master/INSTALL.md#kernel-configuration). It - will not compile on current [dlite](https://github.com/nlf/dlite) - and boot2docker hosts. -* A [Go - plugin](https://github.com/weaveworks/scope/tree/master/examples/plugins/iowait), - using [iostat](https://en.wikipedia.org/wiki/Iostat) to provide - host-level CPU IO wait or idle metrics. +## Official Plugins -The example plugins can be run by calling `make` in their directory. -This will build the plugin, and immediately run it in the foreground. -To run the plugin in the background, see the `Makefile` for examples -of the `docker run ...` command. +You can find all the official plugins at [Weaveworks Plugins](https://github.com/weaveworks-plugins). -If the running plugin was picked up by Scope, you will see it in the -list of `PLUGINS` in the bottom right of the UI. +* [IOWait](https://github.com/weaveworks-plugins/scope-iowait): a Go plugin using [iostat](https://en.wikipedia.org/wiki/Iostat) to provide host-level CPU IO wait or idle metrics. -## Plugin ID +* [HTTP Statistics](https://github.com/weaveworks-plugins/scope-http-statistics): A Python plugin using [bcc](http://iovisor.github.io/bcc/) to track multiple metrics about HTTP per process, without any application-level instrumentation requirements and negligible performance toll. This plugin is a work in progress, as of now it implements two metrics (for more information read the [plugin documentation](https://github.com/weaveworks-plugins/scope-http-statistics)): + * Number of HTTP requests per seconds. + * Number of HTTP responses code per second (per code). + +* [Traffic Control](https://github.com/weaveworks-plugins/scope-traffic-control): This plugin allows the user to modify latency and packet loss for a specific container via buttons in the UI's container detailed view. + +## Plugins Internals +This section explains the fundamental parts of the plugins structure necessary to understand how a plugin communicates with Scope. +You can find more practical examples in [Weaveworks Plugins](https://github.com/weaveworks-plugins) repositories. + +### Plugin ID Each plugin should have an unique ID. It is forbidden to change it during the plugin's lifetime. The scope probe will get the plugin's ID @@ -42,7 +31,7 @@ from the plugin's socket filename. For example, the socket named `my-plugin`. IDs can only contain alphanumeric sequences, optionally separated with a dash. -## Plugin registration +### Plugin registration All plugins should listen for HTTP connections on a unix socket in the `/var/run/scope/plugins` directory. The scope probe will recursively @@ -51,19 +40,18 @@ scan that directory every 5 seconds, to look for sockets being added sub-directory, in case you want to apply some permissions, or store other information with the socket. -## Protocol +### Protocol There are several interfaces a plugin may (or must) implement. Usually implementing an interface means handling specific requests. These requests are described below. -### Reporter interface +#### Reporter interface -Plugins _must_ implement the reporter interface. Implementing this -interface means listening for HTTP requests at `/report`. +Plugins _must_ implement the reporter interface because Scope uses it to discover which other interfaces the plugin implements. +Implementing this interface means listening for HTTP requests at `/report`. -Add the "reporter" string to the `interfaces` field in the plugin -specification. +**Note**: Plugins must add the "reporter" string to the `interfaces` field in the plugin specification even though this interface is implicitly implemented. #### Report @@ -80,12 +68,12 @@ For example: ```json { - "Processes": {}, + ..., "Plugins": [ { - "id": "iowait", - "label": "IOWait", - "description": "Adds a graph of CPU IO Wait to hosts", + "id": "plugin-id", + "label": "Human Friendly Name", + "description": "Plugin's brief description", "interfaces": ["reporter"], "api_version": "1", } @@ -106,14 +94,7 @@ description. The plugin description fields are: * `api_version` is used to ensure both the plugin and the scope probe can speak to each other. It is required, and must match the probe. -You may notice a small chicken and egg problem - the plugin reports to -the scope probe what interfaces it supports, but the scope probe can -learn that only by doing a `GET /report` request which will be handled -by the plugin if it implements the "reporter" interface. This is -solved (or worked around) by requiring the plugin to always implements -the "reporter" interface. - -### Controller interface +#### Controller interface Plugins _may_ implement the controller interface. Implementing the controller interface means that the plugin can react to HTTP `POST` From 655b532ac3d8655a761f4223daf9b7c97b4a1e21 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Wed, 5 Oct 2016 12:04:58 +0200 Subject: [PATCH 3/5] circleci: update circle.yml Remove traffic-control plugin build and push. --- circle.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/circle.yml b/circle.yml index d5a2c3280..0830268fb 100644 --- a/circle.yml +++ b/circle.yml @@ -51,8 +51,6 @@ test: - test -z "$SECRET_PASSWORD" || (cd $SRCDIR/integration; eval $(./gce.sh hosts); ./run_all.sh): parallel: true timeout: 300 - - cd $SRCDIR/examples/plugins/traffic-control && make .traffic-control.uptodate && docker tag weaveworks/scope-traffic-control-plugin weaveworks/scope-traffic-control-plugin:$(../../../tools/image-tag): - parallel: true post: - test -z "$SECRET_PASSWORD" || (cd $SRCDIR/integration; ./gce.sh destroy): parallel: true @@ -72,14 +70,10 @@ deployment: docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS && (test "${DOCKER_ORGANIZATION:-$DOCKER_USER}" == "weaveworks" || ( docker tag weaveworks/scope:latest ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope:latest && - docker tag weaveworks/scope:$(./tools/image-tag) ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope:$(./tools/image-tag) && - docker tag weaveworks/scope-traffic-control-plugin:latest ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope-traffic-control-plugin:latest && - docker tag weaveworks/scope-traffic-control-plugin:$(./tools/image-tag) ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope-traffic-control-plugin:$(./tools/image-tag) + docker tag weaveworks/scope:$(./tools/image-tag) ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope:$(./tools/image-tag) )) && docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope && docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope:$(./tools/image-tag) && - docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope-traffic-control-plugin && - docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope-traffic-control-plugin:$(./tools/image-tag) && (test -z "${UI_BUCKET_KEY_ID}" || ( make ui-upload )) && From 953548d833e3e3374909070fd9d95ff386f90a51 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 28 Oct 2016 14:28:18 +0200 Subject: [PATCH 4/5] docs/plugins: add volume count plugin A new plugin was added to the weaveworks plugins organization, this patch exposes it into the scope documentation. --- examples/plugins/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/plugins/README.md b/examples/plugins/README.md index 6b3e762cb..06d216d87 100644 --- a/examples/plugins/README.md +++ b/examples/plugins/README.md @@ -18,6 +18,8 @@ You can find all the official plugins at [Weaveworks Plugins](https://github.com * [Traffic Control](https://github.com/weaveworks-plugins/scope-traffic-control): This plugin allows the user to modify latency and packet loss for a specific container via buttons in the UI's container detailed view. +* [Volume Count](https://github.com/weaveworks-plugins/scope-volume-count): This plugin is a Python application that asks docker for the the number of mounted volumes for each container, providing container-level count. + ## Plugins Internals This section explains the fundamental parts of the plugins structure necessary to understand how a plugin communicates with Scope. You can find more practical examples in [Weaveworks Plugins](https://github.com/weaveworks-plugins) repositories. From 655e6677ccd29e0bcaed6afc37410acf54c32e05 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Mon, 14 Nov 2016 15:56:04 +0100 Subject: [PATCH 5/5] docs/plugins: sync docs with changes site changes This patch applies the same changes from the review of https://github.com/weaveworks/scope/pull/2008 --- examples/plugins/README.md | 127 +++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/examples/plugins/README.md b/examples/plugins/README.md index 06d216d87..35ca3c6c3 100644 --- a/examples/plugins/README.md +++ b/examples/plugins/README.md @@ -8,39 +8,40 @@ The list of the current running plugins is displayed next to the label `PLUGINS` ## Official Plugins -You can find all the official plugins at [Weaveworks Plugins](https://github.com/weaveworks-plugins). +Official Weave Scope plugins can be found at [Weaveworks Plugins](https://github.com/weaveworks-plugins). -* [IOWait](https://github.com/weaveworks-plugins/scope-iowait): a Go plugin using [iostat](https://en.wikipedia.org/wiki/Iostat) to provide host-level CPU IO wait or idle metrics. +* [IOWait](https://github.com/weaveworks-plugins/scope-iowait): is a Go plugin that uses [iostat](https://en.wikipedia.org/wiki/Iostat) to provide host-level CPU IO wait or idle metrics. -* [HTTP Statistics](https://github.com/weaveworks-plugins/scope-http-statistics): A Python plugin using [bcc](http://iovisor.github.io/bcc/) to track multiple metrics about HTTP per process, without any application-level instrumentation requirements and negligible performance toll. This plugin is a work in progress, as of now it implements two metrics (for more information read the [plugin documentation](https://github.com/weaveworks-plugins/scope-http-statistics)): +* [HTTP Statistics](https://github.com/weaveworks-plugins/scope-http-statistics): is a Python plugin that uses [bcc](http://iovisor.github.io/bcc/) to track multiple metrics about HTTP per process. It does this without any application-level instrumentation requirements and with a negligible performance toll. This plugin is a work in progress, and implements the following (for more information read the [plugin documentation](https://github.com/weaveworks-plugins/scope-http-statistics)): * Number of HTTP requests per seconds. * Number of HTTP responses code per second (per code). -* [Traffic Control](https://github.com/weaveworks-plugins/scope-traffic-control): This plugin allows the user to modify latency and packet loss for a specific container via buttons in the UI's container detailed view. +* [Traffic Control](https://github.com/weaveworks-plugins/scope-traffic-control): This plugin allows you to modify latency and packet loss for a specific container via controls from the container's detailed view in the Scope user interface. -* [Volume Count](https://github.com/weaveworks-plugins/scope-volume-count): This plugin is a Python application that asks docker for the the number of mounted volumes for each container, providing container-level count. +* [Volume Count](https://github.com/weaveworks-plugins/scope-volume-count): This plugin (written in Python) requests the number of mounted volumes for each container, and provides a container-level count. -## Plugins Internals +## How Plugins Communicate with Scope This section explains the fundamental parts of the plugins structure necessary to understand how a plugin communicates with Scope. You can find more practical examples in [Weaveworks Plugins](https://github.com/weaveworks-plugins) repositories. -### Plugin ID +### Plugin IDs -Each plugin should have an unique ID. It is forbidden to change it -during the plugin's lifetime. The scope probe will get the plugin's ID -from the plugin's socket filename. For example, the socket named -`my-plugin.sock`, the scope probe will deduce the ID as -`my-plugin`. IDs can only contain alphanumeric sequences, optionally -separated with a dash. +Each plugin must have a unique ID and this ID must not change +during the plugin's lifetime. Scope probes retrieve the plugin's ID +from the plugin's socket filename. For example, if a socket is named +`my-plugin.sock`, the scope probe deduces the ID as +`my-plugin`. IDs may contain only alphanumeric sequences that are optionally +separated by a dash. -### Plugin registration +### Registering Plugins -All plugins should listen for HTTP connections on a unix socket in the -`/var/run/scope/plugins` directory. The scope probe will recursively -scan that directory every 5 seconds, to look for sockets being added -(or removed). It is also valid to put the plugin unix socket in a -sub-directory, in case you want to apply some permissions, or store -other information with the socket. +All plugins listen for HTTP connections on a UNIX socket in the `/var/run/scope/plugins` directory. The Scope probe recursively scans that directory every 5 seconds and looks for any added or removed sockets. + +If you want to run permissions or store any other information with the socket, you can also put the plugin UNIX socket into a sub-directory. + +When a new plugin is detected, the Scope probe begins requesting reports from it via GET /report. It is therefore important that **every plugin implements the report interface**. Implementing the report interface also means handling specific requests. + +All plugin endpoints are expected to respond within 500ms, and must respond using the JSON format. ### Protocol @@ -57,9 +58,9 @@ Implementing this interface means listening for HTTP requests at `/report`. #### Report -When the scope probe discovers a new plugin unix socket it will begin +When a scope probe discovers a new plugin UNIX socket it will begin periodically making a `GET` request to the `/report` endpoint. The -report data structure returned from this will be merged into the +report data structure returned from this is merged into the probe's report and sent to the app. An example of the report structure can be viewed at the `/api/report` endpoint of any scope app. @@ -86,22 +87,22 @@ For example: Note that the `Plugins` section includes exactly one plugin description. The plugin description fields are: -* `id` is used to check for duplicate plugins. It is +* `id` - checks for duplicate plugins. It is required. Described in [the Plugin ID section](#plugin-id). -* `label` is a human readable plugin label displayed in the UI. It is +* `label` - a human readable plugin label displayed in the UI. It is required. -* `description` is displayed in the UI. -* `interfaces` is a list of interfaces which this plugin supports. It +* `description` - displayed in the UI. +* `interfaces` - a list of interfaces which this plugin supports. It is required, and must contain at least `["reporter"]`. -* `api_version` is used to ensure both the plugin and the scope probe +* `api_version` - ensure both the plugin and the scope probe can speak to each other. It is required, and must match the probe. #### Controller interface -Plugins _may_ implement the controller interface. Implementing the +Plugins _may_ also implement the controller interface. Implementing the controller interface means that the plugin can react to HTTP `POST` -control requests sent by the app. The plugin will receive them only -for controls it exposed in its reports. The requests will come to the +control requests sent by the app. The plugin receives them only +for the controls it exposed in its reports. All such requests come to the `/control` endpoint. Add the "controller" string to the `interfaces` field in the plugin @@ -109,7 +110,7 @@ specification. #### Control -The `POST` requests will have a JSON-encoded body with the following contents: +The `POST` requests contain a JSON-encoded body with the following contents: ```json { @@ -119,10 +120,10 @@ The `POST` requests will have a JSON-encoded body with the following contents: } ``` -The body of the response should also be a JSON-encoded data. Usually -the body would be an empty JSON object (so, "{}" after -serialization). If some error happens during handling the control, -then the plugin can send a response with an `error` field set, for +The body of the response should also be a JSON-encoded data. In most cases, +the body is an empty JSON object (so, "{}" after +serialization). If an error happens when handling the control, +then the plugin sends a response with an `error` field set, for example: ```json @@ -131,11 +132,11 @@ example: } ``` -Sometimes the control activation can make the control obsolete, so the +Sometimes the control activation can make the control obsolete, and so the plugin may want to hide it (for example, control for stopping the container should be hidden after the container is stopped). For this -to work, the plugin can send a shortcut report by filling the -`ShortcutReport` field in the response, like for example: +to work, the plugin sends a shortcut report by filling the +`ShortcutReport` field in the response, like so: ```json { @@ -145,11 +146,10 @@ to work, the plugin can send a shortcut report by filling the ##### How to expose controls -Each topology in the report (be it host, pod, endpoint and so on) has -a set of available controls a node in the topology may want to +Each topology in the report (be it host, pod, endpoint and so on) contains +a set of available controls that a node in the topology may want to show. The following (rather artificial) example shows a topology with -two controls (`ctrl-one` and `ctrl-two`) and two nodes, each having a -different control from the two: +two controls (`ctrl-one` and `ctrl-two`) and two nodes, each with a different control defined: ```json { @@ -194,8 +194,8 @@ different control from the two: } ``` -When control "ctrl-one" is activated, the plugin will receive a -request like: +When control "ctrl-one" is activated, the plugin receives a +request as follows: ```json { @@ -209,30 +209,31 @@ A short note about the "icon" field of the topology control - the value for it can be taken from [Font Awesome Cheatsheet](http://fontawesome.io/cheatsheet/) -##### Node naming +##### Naming Nodes -Very often the controller plugin wants to add some controls to already -existing nodes (like controls for network traffic management to nodes +Often the controller plugin may want to add some controls to already +existing nodes (for example add controls for network traffic management to nodes representing the running Docker container). To achieve that, it is important to make sure that the node ID in the plugin's report matches the ID of the node created by the probe. The ID is a semicolon-separated list of strings. -For containers, images, hosts and others the ID is usually formatted +For containers, images, hosts and others, the ID is usually formatted as `${name};<${tag}>`. The `${name}` variable is usually a name of a thing the node represents, like an ID of the Docker container or the -hostname. The `${tag}` denotes the type of the node. There is a fixed -set of tags used by the probe: +hostname. The `${tag}` denotes the type of the node. -- host -- container -- container_image -- pod -- service -- deployment -- replica_set +There is a fixed set of tags used by the probe: -The examples of "tagged" node names: +- `host` +- `container` +- `container_image` +- `pod` +- `service` +- `deployment` +- `replica_set` + +These are examples of "tagged" node names: - The Docker container with full ID 2299a2ca59dfd821f367e689d5869c4e568272c2305701761888e1d79d7a6f51: @@ -243,17 +244,19 @@ The examples of "tagged" node names: The fixed set of tags listed above is not a complete set of names a node can have though. For example, nodes representing processes are -have ID formatted as `${host};${pid}`. Probably the easiest ways to +have IDs formatted as `${host};${pid}`. The easiest way to discover how the nodes are named are: -- Read the code in +1. Read the code in [report/id.go](https://github.com/weaveworks/scope/blob/master/report/id.go). -- Browse the Weave Scope GUI, select some node and search for an `id` +2. Browse the Weave Scope GUI, select some node and search for an `id` key in the `nodeDetails` array in the address bar. - For example in the `http://localhost:4040/#!/state/{"controlPipe":null,"nodeDetails":[{"id":"example.com;","label":"example.com","topologyId":"hosts"}],…` URL, you can find the `example.com;` which is an ID of the node representing the host. - - Mentally substitute the `` with `/`. This can appear in +3. Mentally substitute the `` with `/`. This can appear in Docker image names, so `docker.io/alpine` in the address bar will be `docker.ioalpine`. + +For more detailed information visit [https://www.weave.works/documentation/scope-latest-plugins/](https://www.weave.works/documentation/scope-latest-plugins/)