From a49a6c86c172fc834164ddce5be3f0a8f23ac2e4 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Thu, 14 May 2015 15:42:21 +0000 Subject: [PATCH] An example micro-services based application for testing purposes. --- .gitignore | 1 + experimental/example/Makefile | 16 +++ experimental/example/README.md | 2 + experimental/example/client/Dockerfile | 6 + experimental/example/client/client | 3 + experimental/example/docker-compose.yml | 26 +++++ experimental/example/goapp/Dockerfile | 5 + experimental/example/goapp/app.go | 118 ++++++++++++++++++++ experimental/example/goapp/entrypoint.sh | 3 + experimental/example/pyapp/Dockerfile | 6 + experimental/example/pyapp/app.py | 15 +++ experimental/example/pyapp/requirements.txt | 5 + experimental/example/qotd/Dockerfile | 5 + experimental/example/qotd/qotd.c | 99 ++++++++++++++++ 14 files changed, 310 insertions(+) create mode 100644 experimental/example/Makefile create mode 100644 experimental/example/README.md create mode 100644 experimental/example/client/Dockerfile create mode 100755 experimental/example/client/client create mode 100644 experimental/example/docker-compose.yml create mode 100644 experimental/example/goapp/Dockerfile create mode 100644 experimental/example/goapp/app.go create mode 100755 experimental/example/goapp/entrypoint.sh create mode 100644 experimental/example/pyapp/Dockerfile create mode 100644 experimental/example/pyapp/app.py create mode 100644 experimental/example/pyapp/requirements.txt create mode 100644 experimental/example/qotd/Dockerfile create mode 100644 experimental/example/qotd/qotd.c diff --git a/.gitignore b/.gitignore index 6ab8c3543..16d68f005 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ experimental/fixprobe/fixprobe experimental/genreport/genreport experimental/graphviz/graphviz experimental/oneshot/oneshot +experimental/example/qotd/qotd *sublime-project *sublime-workspace *npm-debug.log diff --git a/experimental/example/Makefile b/experimental/example/Makefile new file mode 100644 index 000000000..b68a18a73 --- /dev/null +++ b/experimental/example/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-g -lpthread + +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +all: qotd/qotd goapp/app + +qotd/qotd: qotd/qotd.o + gcc -o $@ $< $(CFLAGS) + +goapp/app: goapp/app.go + go build -o goapp/app ./goapp + +clean: + rm -f qotd/*.o qotd/qotd goapp/app diff --git a/experimental/example/README.md b/experimental/example/README.md new file mode 100644 index 000000000..7efb74667 --- /dev/null +++ b/experimental/example/README.md @@ -0,0 +1,2 @@ +To run: + # make && docker-compose up -d diff --git a/experimental/example/client/Dockerfile b/experimental/example/client/Dockerfile new file mode 100644 index 000000000..14ebf86e8 --- /dev/null +++ b/experimental/example/client/Dockerfile @@ -0,0 +1,6 @@ +FROM gliderlabs/alpine +MAINTAINER Weaveworks Inc +WORKDIR /home/weave +ADD ./client /home/weave/ +RUN chmod u+x /home/weave/client +ENTRYPOINT ["/home/weave/client"] diff --git a/experimental/example/client/client b/experimental/example/client/client new file mode 100755 index 000000000..faf333c72 --- /dev/null +++ b/experimental/example/client/client @@ -0,0 +1,3 @@ +#!/bin/sh + +while true; do echo "foo" | nc qotd 4446; sleep 1; done diff --git a/experimental/example/docker-compose.yml b/experimental/example/docker-compose.yml new file mode 100644 index 000000000..ded399b1b --- /dev/null +++ b/experimental/example/docker-compose.yml @@ -0,0 +1,26 @@ +client: + build: client + links: + - qotd +qotd: + build: qotd + expose: + - "4446" +pyapp: + build: pyapp + ports: + - "5000:5000" + links: + - redis + - qotd +redis: + image: redis +goapp: + build: goapp + links: + - elasticsearch +elasticsearch: + image: elasticsearch + expose: + - "9200" + - "9300" diff --git a/experimental/example/goapp/Dockerfile b/experimental/example/goapp/Dockerfile new file mode 100644 index 000000000..1157068f9 --- /dev/null +++ b/experimental/example/goapp/Dockerfile @@ -0,0 +1,5 @@ +FROM gliderlabs/alpine +MAINTAINER Weaveworks Inc +WORKDIR /home/weave +ADD . /home/weave/ +ENTRYPOINT ["/home/weave/entrypoint.sh"] diff --git a/experimental/example/goapp/app.go b/experimental/example/goapp/app.go new file mode 100644 index 000000000..d86b94c10 --- /dev/null +++ b/experimental/example/goapp/app.go @@ -0,0 +1,118 @@ +package main + +import ( + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "net/http" + "net/url" + "os" + "os/signal" + "strings" + "sync" + "sync/atomic" + "syscall" + "time" +) + +func main() { + var ( + addr = flag.String("addr", ":8080", "HTTP listen address") + rate = flag.Duration("rate", 3*time.Second, "request rate") + ) + flag.Parse() + + var targets []string + for _, s := range os.Args[1:] { + target, err := normalize(s) + if err != nil { + log.Fatal(err) + } + log.Printf("target %s", target) + targets = append(targets, target) + } + if len(targets) <= 0 { + log.Fatal("no targets") + } + + hostname, err := os.Hostname() + if err != nil { + hostname = strings.ToLower(strings.Replace(hostname, " ", "-", -1)) // lol + } + + var reads uint64 + + http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { + fmt.Fprintf(w, "%s %d", hostname, atomic.LoadUint64(&reads)) + }) + + errc := make(chan error) + + go func() { + log.Printf("listening on %s", *addr) + errc <- http.ListenAndServe(*addr, nil) + }() + + go func() { + errc <- read(targets, *rate, &reads) + }() + + go func() { + errc <- interrupt() + }() + + log.Printf("%s", <-errc) +} + +func read(targets []string, rate time.Duration, reads *uint64) error { + for range time.Tick(rate) { + var wg sync.WaitGroup + wg.Add(len(targets)) + for _, target := range targets { + go func(target string) { + get(target) + atomic.AddUint64(reads, 1) + wg.Done() + }(target) + } + wg.Wait() + } + return nil +} + +func get(target string) { + resp, err := http.Get(target) + if err != nil { + log.Printf("%s: %v", target, err) + return + } + log.Printf("%s: %s", target, resp.Status) + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() +} + +func interrupt() error { + c := make(chan os.Signal) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + return fmt.Errorf("%s", <-c) +} + +func normalize(s string) (string, error) { + u, err := url.Parse(s) + if err != nil { + return "", err + } + if u.Scheme == "" { + u.Scheme = "http" + } + if u.Host == "" && u.Path != "" { + u.Host, u.Path = u.Path, u.Host + } + if _, port, err := net.SplitHostPort(u.Host); err != nil || port == "" { + u.Host = u.Host + ":9200" + } + return u.String(), nil +} diff --git a/experimental/example/goapp/entrypoint.sh b/experimental/example/goapp/entrypoint.sh new file mode 100755 index 000000000..764798753 --- /dev/null +++ b/experimental/example/goapp/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/home/weave/app $elasticsearch diff --git a/experimental/example/pyapp/Dockerfile b/experimental/example/pyapp/Dockerfile new file mode 100644 index 000000000..82e3238ea --- /dev/null +++ b/experimental/example/pyapp/Dockerfile @@ -0,0 +1,6 @@ +FROM python:2.7 +MAINTAINER Weaveworks Inc +ADD . /home/weave +WORKDIR /home/weave +RUN pip install -r /home/weave/requirements.txt +ENTRYPOINT ["python", "/home/weave/app.py"] diff --git a/experimental/example/pyapp/app.py b/experimental/example/pyapp/app.py new file mode 100644 index 000000000..3776fd45b --- /dev/null +++ b/experimental/example/pyapp/app.py @@ -0,0 +1,15 @@ +import os + +from flask import Flask +from redis import Redis + +app = Flask(__name__) +redis = Redis(host='redis', port=6379) + +@app.route('/') +def hello(): + redis.incr('hits') + return 'Hello World! I have been seen %s times.' % redis.get('hits') + +if __name__ == "__main__": + app.run(host="0.0.0.0", debug=True) diff --git a/experimental/example/pyapp/requirements.txt b/experimental/example/pyapp/requirements.txt new file mode 100644 index 000000000..4dbe5d710 --- /dev/null +++ b/experimental/example/pyapp/requirements.txt @@ -0,0 +1,5 @@ +flask +redis +requests +futures +requests-futures diff --git a/experimental/example/qotd/Dockerfile b/experimental/example/qotd/Dockerfile new file mode 100644 index 000000000..5bca6fd17 --- /dev/null +++ b/experimental/example/qotd/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu +MAINTAINER Weaveworks Inc +WORKDIR /home/weave +ADD ./qotd /home/weave/ +ENTRYPOINT ["/home/weave/qotd"] diff --git a/experimental/example/qotd/qotd.c b/experimental/example/qotd/qotd.c new file mode 100644 index 000000000..3bcd91ff0 --- /dev/null +++ b/experimental/example/qotd/qotd.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +/* this function is run by the thread */ +void *thread_func(void *sock) { + struct sockaddr_in dest; + char buffer[1024]; + int sockfd = (int)sock; + int clientfd; + + printf("I'm thread %d\n", syscall(SYS_gettid)); + + if (read(sockfd, buffer, sizeof(buffer), 0) < 0) { + perror("ERROR reading from socket"); + return; + } + + clientfd = socket(AF_INET, SOCK_STREAM, 0); + if (clientfd < 0) { + perror("ERROR opening socket"); + return; + } + + dest.sin_family = AF_INET; + dest.sin_port = htons(17); + if (inet_aton("104.230.14.102", &dest.sin_addr.s_addr) == 0) { + perror("cygnus"); + return; + } + + if (connect(clientfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 ) { + perror("Connect "); + return; + } + + int readbytes = recv(clientfd, buffer, sizeof(buffer), 0); + close(clientfd); + + if (write(sockfd, buffer, read) < 0) { + perror("ERROR writing to socket"); + return; + } + + if (close(sockfd)) { + perror("ERROR closing socket"); + return; + } +} + +int main(int argc, char **argv) { + int sockfd, newsockfd, portno, clilen; + struct sockaddr_in serv_addr, cli_addr; + int n; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("ERROR opening socket"); + return 1; + } + + int i = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { + perror("setsockopt"); + } + + // bzero((char *) &serv_addr, sizeof(serv_addr)); + portno = 4446; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(portno); + + if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR on binding"); + return 1; + } + + listen(sockfd, 5); + + while (1) { + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); + if (newsockfd < 0) { + perror("ERROR on accept"); + return 1; + } + + pthread_t thread0; + if(pthread_create(&thread0, NULL, thread_func, (void *)newsockfd)) { + perror("ERROR on pthread_create"); + return 1; + } + } + return 0; +} +