cmd/pubsubhelper: start of SMTP server pubsub bridge, reading Gerrit email

Design:
- create a Google account with email mybot@X.golang.org.
- sign that bot up for all possible Gerrit spam
- this SMTP server parses the Gerrit emails (they have X- headers)
  and converts them a pubsub system that others can subscribe to
- stop polling gerrit and hitting quota limits

It will also be the Github webhook bridge.

And then this will be used by maintnerd etc to reduce their poll
intervals.

Currently this barely does anything, but it's deployed and on the
Internet, which is the tedious part.

Change-Id: I2fb6679c2253c24ee54dadbb091180deb28bfda0
Reviewed-on: https://go-review.googlesource.com/39353
Reviewed-by: Kevin Burke <kev@inburke.com>
diff --git a/.dockerignore b/.dockerignore
index afc85fd..fcb99cf 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,5 +1,5 @@
 .git
 **/*.tar.gz
+**/*.tgz
 **/*.iso
 **/*.raw
-
diff --git a/cmd/pubsubhelper/Dockerfile b/cmd/pubsubhelper/Dockerfile
new file mode 100644
index 0000000..c073c80
--- /dev/null
+++ b/cmd/pubsubhelper/Dockerfile
@@ -0,0 +1,34 @@
+# Copyright 2017 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Note that OpenSSH 6.5+ is required for the Github SSH private key, which requires
+# at least Debian Jessie (not Wheezy). This uses Jessie:
+FROM golang:1.8
+LABEL maintainer "golang-dev@googlegroups.com"
+
+# TODO(bradfitz): remove duplication between this, gitmirror, and coordinator?
+# Maybe make both derive FROM "golang_org:buildbase" or something. But
+# then I want to make sure that FROM base is rebuilt always when things in
+# x/build change.
+
+RUN go get -d cloud.google.com/go/compute/metadata
+RUN cd /go/src/cloud.google.com/go/compute/metadata && git reset --hard cd0da878c66091060d2e7403abd62192b3e387e0
+
+RUN go get -d golang.org/x/time/rate
+RUN cd /go/src/golang.org/x/time/rate && git reset --hard f51c12702a4d776e4c1fa9b0fabab841babae631
+
+RUN go get -d golang.org/x/oauth2
+RUN cd /go/src/golang.org/x/oauth2 && git reset --hard 314dd2c0bf3ebd592ec0d20847d27e79d0dbe8dd
+
+COPY /cmd/gitmirror/install-apt-deps.sh /scripts/install-apt-deps.sh
+RUN  /scripts/install-apt-deps.sh
+
+RUN go get -d github.com/bradfitz/go-smtpd/smtpd
+RUN cd /go/src/github.com/bradfitz/go-smtpd/smtpd && git reset --hard 8ebf70ba0acf0674302879b9872da16f478c29d5
+
+COPY . /go/src/golang.org/x/build/
+
+RUN go install golang.org/x/build/cmd/pubsubhelper
+
+ENTRYPOINT ["/go/bin/pubsubhelper"]
diff --git a/cmd/pubsubhelper/Makefile b/cmd/pubsubhelper/Makefile
new file mode 100644
index 0000000..c64f47b
--- /dev/null
+++ b/cmd/pubsubhelper/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2017 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+VERSION=v4
+
+docker-prod: Dockerfile
+	docker build -f Dockerfile --tag=gcr.io/symbolic-datum-552/pubsubhelper:$(VERSION)  ../..
+docker-dev: Dockerfile
+	docker build -f Dockerfile --tag=gcr.io/go-dashboard-dev/pubsubhelper:latest  ../..
+
+push-prod: docker-prod
+	gcloud docker -- push gcr.io/symbolic-datum-552/pubsubhelper:$(VERSION)
+push-dev: docker-dev
+	gcloud docker -- push gcr.io/go-dashboard-dev/pubsubhelper:latest
diff --git a/cmd/pubsubhelper/deployment-prod.yaml b/cmd/pubsubhelper/deployment-prod.yaml
new file mode 100644
index 0000000..3b5b61f
--- /dev/null
+++ b/cmd/pubsubhelper/deployment-prod.yaml
@@ -0,0 +1,25 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: pubsubhelper-deployment
+spec:
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: pubsubhelper
+    spec:
+      containers:
+      - name: pubsubhelper
+        image: gcr.io/symbolic-datum-552/pubsubhelper:v4
+        command: ["/go/bin/pubsubhelper"]
+        ports:
+        - containerPort: 25
+        - containerPort: 80
+        - containerPort: 443
+        resources:
+          requests:
+            cpu: "1"
+            memory: "1Gi"
+          limits:
+            memory: "2Gi"
diff --git a/cmd/pubsubhelper/pubsubhelper.go b/cmd/pubsubhelper/pubsubhelper.go
new file mode 100644
index 0000000..356326c
--- /dev/null
+++ b/cmd/pubsubhelper/pubsubhelper.go
@@ -0,0 +1,62 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+// The pubsubhelper is an SMTP server for Gerrit updates and an HTTP
+// server for Github webhook updates. It then lets other clients subscribe
+// to those changes.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"log"
+
+	"github.com/bradfitz/go-smtpd/smtpd"
+)
+
+type env struct {
+	*smtpd.BasicEnvelope
+	from smtpd.MailAddress
+	body bytes.Buffer
+}
+
+func (e *env) AddRecipient(rcpt smtpd.MailAddress) error {
+	return e.BasicEnvelope.AddRecipient(rcpt)
+}
+
+func (e *env) Write(line []byte) error {
+	const maxSize = 5 << 20
+	if e.body.Len() > maxSize {
+		return nil
+	}
+	e.body.Write(line)
+	return nil
+}
+
+func (e *env) Close() error {
+	log.Printf("Got email: %s\n", e.body.Bytes())
+	return nil
+}
+
+func onNewMail(c smtpd.Connection, from smtpd.MailAddress) (smtpd.Envelope, error) {
+	log.Printf("new MAIL FROM %q", from)
+	return &env{
+		from:          from,
+		BasicEnvelope: new(smtpd.BasicEnvelope),
+	}, nil
+}
+
+func main() {
+	flag.Parse()
+
+	log.Printf("running pubsubhelper on port 25")
+	s := &smtpd.Server{
+		Addr:      ":25",
+		OnNewMail: onNewMail,
+	}
+	err := s.ListenAndServe()
+	if err != nil {
+		log.Fatalf("ListenAndServe: %v", err)
+	}
+}
diff --git a/cmd/pubsubhelper/service.yaml b/cmd/pubsubhelper/service.yaml
new file mode 100644
index 0000000..fd04c1e
--- /dev/null
+++ b/cmd/pubsubhelper/service.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: pubsubhelper
+spec:
+  ports:
+    - port: 25
+      targetPort: 25
+      name: smtp
+    - port: 80
+      targetPort: 80
+      name: http
+    - port: 443
+      targetPort: 443
+      name: https
+  selector:
+    app: pubsubhelper
+  type: LoadBalancer
+  loadBalancerIP: 35.184.237.80