From e7c05f573d652c326fe080d8b6642f0cad96aeca Mon Sep 17 00:00:00 2001 From: Tejal Desai Date: Mon, 1 Aug 2022 16:08:37 -0700 Subject: [PATCH] feat: Support multiple renderer render in skaffold dev and skaffold run (#7697) * feat: allow multiple mixed in renderers * add integration tests and fix examples * fix example * fix integration tests * fix lint * fix lint --- .../multiple-renderers/backend/Chart.yaml | 4 + .../multiple-renderers/backend/src/Dockerfile | 29 +++ .../backend/src/database.go | 10 + .../multiple-renderers/backend/src/go.mod | 9 + .../multiple-renderers/backend/src/go.sum | 203 ++++++++++++++++++ .../multiple-renderers/backend/src/main.go | 117 ++++++++++ .../multiple-renderers/backend/src/mongodb.go | 53 +++++ .../backend/templates/deployment.yaml | 29 +++ .../guestbook-mongodb.deployment.yaml | 29 +++ .../templates/guestbook-mongodb.service.yaml | 14 ++ .../backend/templates/service.yaml | 13 ++ .../multiple-renderers/backend/val.yaml | 2 + .../multiple-renderers/backend/values.yaml | 3 + .../frontend/k8s/deployment.yaml | 29 +++ .../frontend/k8s/service.yaml | 13 ++ .../frontend/src/Dockerfile | 31 +++ .../multiple-renderers/frontend/src/go.mod | 3 + .../multiple-renderers/frontend/src/go.sum | 0 .../multiple-renderers/frontend/src/main.go | 165 ++++++++++++++ .../frontend/src/static/style.css | 111 ++++++++++ .../frontend/src/templates/home.tpl | 64 ++++++ .../examples/multiple-renderers/skaffold.yaml | 40 ++++ integration/run_test.go | 5 + pkg/skaffold/render/renderer/renderer.go | 16 +- 24 files changed, 985 insertions(+), 7 deletions(-) create mode 100644 integration/examples/multiple-renderers/backend/Chart.yaml create mode 100644 integration/examples/multiple-renderers/backend/src/Dockerfile create mode 100644 integration/examples/multiple-renderers/backend/src/database.go create mode 100644 integration/examples/multiple-renderers/backend/src/go.mod create mode 100644 integration/examples/multiple-renderers/backend/src/go.sum create mode 100644 integration/examples/multiple-renderers/backend/src/main.go create mode 100644 integration/examples/multiple-renderers/backend/src/mongodb.go create mode 100644 integration/examples/multiple-renderers/backend/templates/deployment.yaml create mode 100644 integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml create mode 100644 integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml create mode 100644 integration/examples/multiple-renderers/backend/templates/service.yaml create mode 100644 integration/examples/multiple-renderers/backend/val.yaml create mode 100644 integration/examples/multiple-renderers/backend/values.yaml create mode 100644 integration/examples/multiple-renderers/frontend/k8s/deployment.yaml create mode 100644 integration/examples/multiple-renderers/frontend/k8s/service.yaml create mode 100644 integration/examples/multiple-renderers/frontend/src/Dockerfile create mode 100644 integration/examples/multiple-renderers/frontend/src/go.mod create mode 100644 integration/examples/multiple-renderers/frontend/src/go.sum create mode 100644 integration/examples/multiple-renderers/frontend/src/main.go create mode 100644 integration/examples/multiple-renderers/frontend/src/static/style.css create mode 100644 integration/examples/multiple-renderers/frontend/src/templates/home.tpl create mode 100644 integration/examples/multiple-renderers/skaffold.yaml diff --git a/integration/examples/multiple-renderers/backend/Chart.yaml b/integration/examples/multiple-renderers/backend/Chart.yaml new file mode 100644 index 00000000000..d75d2453ed3 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: back end for guestbook +name: backend +version: 0.1.0 diff --git a/integration/examples/multiple-renderers/backend/src/Dockerfile b/integration/examples/multiple-renderers/backend/src/Dockerfile new file mode 100644 index 00000000000..a81769c5792 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/Dockerfile @@ -0,0 +1,29 @@ +# Use base golang image from Docker Hub +FROM golang:1.17 as build + +WORKDIR /app + +# Copy the go.mod and go.sum, download the dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy rest of the application source code +COPY . ./ + +# Compile the application to /app/backend. +# Skaffold passes in debug-oriented compiler flags +ARG SKAFFOLD_GO_GCFLAGS +RUN echo "Go gcflags: ${SKAFFOLD_GO_GCFLAGS}" +RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -mod=readonly -v -o /app/backend . + +# Now create separate deployment image +FROM gcr.io/distroless/base + +# Definition of this variable is used by 'skaffold debug' to identify a golang binary. +# Default behavior - a failure prints a stack trace for the current goroutine. +# See https://golang.org/pkg/runtime/ +ENV GOTRACEBACK=single + +WORKDIR /app +COPY --from=build /app/backend /app/backend +ENTRYPOINT ["/app/backend"] diff --git a/integration/examples/multiple-renderers/backend/src/database.go b/integration/examples/multiple-renderers/backend/src/database.go new file mode 100644 index 00000000000..663e963e71d --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/database.go @@ -0,0 +1,10 @@ +package main + +import ( + "context" +) + +type database interface { + entries(context.Context) ([]guestbookEntry, error) + addEntry(context.Context, guestbookEntry) error +} diff --git a/integration/examples/multiple-renderers/backend/src/go.mod b/integration/examples/multiple-renderers/backend/src/go.mod new file mode 100644 index 00000000000..d29581e2650 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/go.mod @@ -0,0 +1,9 @@ +module backend + +go 1.12 + +require ( + github.com/DataDog/zstd v1.4.4 // indirect + github.com/xdg/stringprep v1.0.0 // indirect + go.mongodb.org/mongo-driver v1.8.4 +) diff --git a/integration/examples/multiple-renderers/backend/src/go.sum b/integration/examples/multiple-renderers/backend/src/go.sum new file mode 100644 index 00000000000..d818d71793c --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/go.sum @@ -0,0 +1,203 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/zstd v1.4.4 h1:+IawcoXhCBylN7ccwdwf8LOH2jKq7NavGpEPanrlTzE= +github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/aws/aws-sdk-go v1.29.15 h1:0ms/213murpsujhsnxnNKNeVouW60aJqSd992Ks3mxs= +github.com/aws/aws-sdk-go v1.29.15/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c= +go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.3 h1:++7u8r9adKhGR+I79NfEtYrk2ktjenErXM99PSufIoI= +go.mongodb.org/mongo-driver v1.1.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.2.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.2.1 h1:ANAlYXXM5XmOdW/Nc38jOr+wS5nlk7YihT24U1imiWM= +go.mongodb.org/mongo-driver v1.2.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.3.0 h1:ew6uUIeJOo+qdUUv7LxFCUhtWmVv7ZV/Xuy4FAUsw2E= +go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.1 h1:op56IfTQiaY2679w922KVWa3qcHdml2K/Io8ayAOUEQ= +go.mongodb.org/mongo-driver v1.3.1/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.2 h1:IYppNjEV/C+/3VPbhHVxQ4t04eVW0cLp0/pNdW++6Ug= +go.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.3 h1:9kX7WY6sU/5qBuhm5mdnNWdqaDAQKB2qSZOd5wMEPGQ= +go.mongodb.org/mongo-driver v1.3.3/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCdE= +go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.4.0 h1:C8rFn1VF4GVEM/rG+dSoMmlm2pyQ9cs2/oRtUATejRU= +go.mongodb.org/mongo-driver v1.4.0/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs= +go.mongodb.org/mongo-driver v1.4.1 h1:38NSAyDPagwnFpUA/D5SFgbugUYR3NzYRNa4Qk9UxKs= +go.mongodb.org/mongo-driver v1.4.1/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs= +go.mongodb.org/mongo-driver v1.4.2 h1:WlnEglfTg/PfPq4WXs2Vkl/5ICC6hoG8+r+LraPmGk4= +go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.3 h1:moga+uhicpVshTyaqY9L23E6QqwcHRUv1sqyOsoyOO8= +go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.4 h1:bsPHfODES+/yx2PCWzUYMH8xj6PVniPI8DQrsJuSXSs= +go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.6 h1:rh7GdYmDrb8AQSkF8yteAus8qYOgOASWDOv1BWqBXkU= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.5.0 h1:REddm85e1Nl0JPXGGhgZkgJdG/yOe6xvpXUcYK5WLt0= +go.mongodb.org/mongo-driver v1.5.0/go.mod h1:boiGPFqyBs5R0R5qf2ErokGRekMfwn+MqKaUyHs7wy0= +go.mongodb.org/mongo-driver v1.5.2 h1:AsxOLoJTgP6YNM0fXWw4OjdluYmWzQYp+lFJL7xu9fU= +go.mongodb.org/mongo-driver v1.5.2/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= +go.mongodb.org/mongo-driver v1.5.3 h1:wWbFB6zaGHpzguF3f7tW94sVE8sFl3lHx8OZx/4OuFI= +go.mongodb.org/mongo-driver v1.5.3/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= +go.mongodb.org/mongo-driver v1.7.2 h1:pFttQyIiJUHEn50YfZgC9ECjITMT44oiN36uArf/OFg= +go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= +go.mongodb.org/mongo-driver v1.7.3 h1:G4l/eYY9VrQAK/AUgkV0koQKzQnyddnWxrd/Etf0jIs= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.8.2 h1:8ssUXufb90ujcIvR6MyE1SchaNj0SFxsakiZgxIyrMk= +go.mongodb.org/mongo-driver v1.8.2/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4= +go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA= +go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f h1:aZp0e2vLN4MToVqnjNEYEtrEA8RH8U8FN1CU7JgqsPU= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration/examples/multiple-renderers/backend/src/main.go b/integration/examples/multiple-renderers/backend/src/main.go new file mode 100644 index 00000000000..34c81c8af2f --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net/http" + "os" + "time" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readpref" +) + +// guestbookEntry represents the message object returned in the API. +type guestbookEntry struct { + Author string `json:"author" bson:"author"` + Message string `json:"message" bson:"message"` + Date time.Time `json:"date" bson:"date"` +} + +type guestbookServer struct { + db database +} + +// main starts a server listening on $PORT responding to requests "GET +// /messages" and "POST /messages" with a JSON API. +func main() { + ctx := context.Background() + + // PORT environment variable is set in guestbook-backend.deployment.yaml. + port := os.Getenv("PORT") + if port == "" { + log.Fatal("PORT environment variable not specified") + } + // GUESTBOOK_DB_ADDR environment variable is set in guestbook-backend.deployment.yaml. + dbAddr := os.Getenv("GUESTBOOK_DB_ADDR") + if dbAddr == "" { + log.Fatal("GUESTBOOK_DB_ADDR environment variable not specified") + } + + mongoURI := "mongodb://" + dbAddr + connCtx, cancel := context.WithTimeout(ctx, time.Second*30) + defer cancel() + dbConn, err := mongo.Connect(connCtx, options.Client().ApplyURI(mongoURI)) + if err != nil { + log.Fatalf("failed to initialize connection to mongodb: %+v", err) + } + if err := dbConn.Ping(connCtx, readpref.Primary()); err != nil { + log.Fatalf("ping to mongodb failed: %+v", err) + } + + gs := &guestbookServer{ + db: &mongodb{ + conn: dbConn, + }, + } + + log.Printf("backend server listening on port %s", port) + http.Handle("/messages", gs) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatal(err) + } +} + +func (s *guestbookServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log.Printf("received request: method=%s path=%s", r.Method, r.URL.Path) + if r.Method == http.MethodGet { + s.getMessagesHandler(w, r) + } else if r.Method == http.MethodPost { + s.postMessageHandler(w, r) + } else { + http.Error(w, fmt.Sprintf("unsupported method %s", r.Method), http.StatusMethodNotAllowed) + } +} + +func (s *guestbookServer) getMessagesHandler(w http.ResponseWriter, r *http.Request) { + entries, err := s.db.entries(r.Context()) + if err != nil { + http.Error(w, fmt.Sprintf("failed to read entries: %+v", err), http.StatusInternalServerError) + // TODO return JSON error + return + } + if err := json.NewEncoder(w).Encode(entries); err != nil { + log.Printf("WARNING: failed to encode json into response: %+v", err) + } else { + log.Printf("%d entries returned", len(entries)) + } +} + +func (s *guestbookServer) postMessageHandler(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + var v guestbookEntry + if err := json.NewDecoder(r.Body).Decode(&v); err != nil { + http.Error(w, fmt.Sprintf("failed to decode request body into json: %+v", err), http.StatusBadRequest) + return + } + if v.Author == "" { + http.Error(w, "empty 'author' value", http.StatusBadRequest) + return + } + if v.Message == "" { + http.Error(w, "empty 'message' value", http.StatusBadRequest) + return + } + + v.Date = time.Now() + + if err := s.db.addEntry(r.Context(), v); err != nil { + http.Error(w, fmt.Sprintf("failed to save entry: %+v", err), http.StatusInternalServerError) + return + } + log.Printf("entry saved: author=%q message=%q", v.Author, v.Message) +} diff --git a/integration/examples/multiple-renderers/backend/src/mongodb.go b/integration/examples/multiple-renderers/backend/src/mongodb.go new file mode 100644 index 00000000000..5b010f86f8e --- /dev/null +++ b/integration/examples/multiple-renderers/backend/src/mongodb.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "fmt" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type mongodb struct { + conn *mongo.Client +} + +func (m *mongodb) entries(ctx context.Context) ([]guestbookEntry, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + col := m.conn.Database("guestbook").Collection("entries") + cur, err := col.Find(ctx, bson.D{}, &options.FindOptions{ + Sort: map[string]interface{}{"_id": -1}, + }) + if err != nil { + return nil, fmt.Errorf("mongodb.Find failed: %+v", err) + } + defer cur.Close(ctx) + + var out []guestbookEntry + for cur.Next(ctx) { + var v guestbookEntry + if err := cur.Decode(&v); err != nil { + return nil, fmt.Errorf("decoding mongodb record failed: %+v", err) + } + out = append(out, v) + } + if err := cur.Err(); err != nil { + return nil, fmt.Errorf("failed to iterate on mongodb cursor: %+v", err) + } + return out, nil +} + +func (m *mongodb) addEntry(ctx context.Context, e guestbookEntry) error { + ctx, cancel := context.WithTimeout(ctx, time.Second*3) + defer cancel() + + col := m.conn.Database("guestbook").Collection("entries") + if _, err := col.InsertOne(ctx, e); err != nil { + return fmt.Errorf("mongodb.InsertOne failed: %+v", err) + } + return nil +} diff --git a/integration/examples/multiple-renderers/backend/templates/deployment.yaml b/integration/examples/multiple-renderers/backend/templates/deployment.yaml new file mode 100644 index 00000000000..553c19a2aa9 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/templates/deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Chart.Name }} + labels: + app: {{ .Chart.Name }} +spec: + selector: + matchLabels: + app: {{ .Chart.Name }} + replicas: {{ .Values.replicaCount }} + template: + metadata: + labels: + app: {{ .Chart.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: {{ .Values.image }} + ports: + - name: http-server + containerPort: 8081 + - name: debug + containerPort: 3000 + env: + - name: PORT + value: "8081" + - name: GUESTBOOK_DB_ADDR + value: go-guestbook-mongodb:27017 diff --git a/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml new file mode 100644 index 00000000000..1a014522095 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.deployment.yaml @@ -0,0 +1,29 @@ +################################################################################ +# WARNING: This MongoDB deployment is not suitable for production as the data is +# not persistently stored and will go away every time the Pod restarts. Consider +# using a Helm chart that provisions a StatefulSet instead of Deployment. +################################################################################ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: go-guestbook-mongodb + labels: + app: guestbook + tier: db +spec: + replicas: 1 + selector: + matchLabels: + app: guestbook + tier: db + template: + metadata: + labels: + app: guestbook + tier: db + spec: + containers: + - name: mongo + image: mongo:4 + ports: + - containerPort: 27017 diff --git a/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml new file mode 100644 index 00000000000..64970bfe045 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/templates/guestbook-mongodb.service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: go-guestbook-mongodb + labels: + app: guestbook + tier: db +spec: + ports: + - port: 27017 + targetPort: 27017 + selector: + app: guestbook + tier: db diff --git a/integration/examples/multiple-renderers/backend/templates/service.yaml b/integration/examples/multiple-renderers/backend/templates/service.yaml new file mode 100644 index 00000000000..5f7aad5d685 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name }} + labels: + app: {{ .Chart.Name }} +spec: + type: ClusterIP + selector: + app: {{ .Chart.Name }} + ports: + - port: 8081 + targetPort: http-server diff --git a/integration/examples/multiple-renderers/backend/val.yaml b/integration/examples/multiple-renderers/backend/val.yaml new file mode 100644 index 00000000000..a28bfc3f4ff --- /dev/null +++ b/integration/examples/multiple-renderers/backend/val.yaml @@ -0,0 +1,2 @@ +# This is another YAML-formatted file. +image: go-guestbook-backend \ No newline at end of file diff --git a/integration/examples/multiple-renderers/backend/values.yaml b/integration/examples/multiple-renderers/backend/values.yaml new file mode 100644 index 00000000000..d6c6edc4131 --- /dev/null +++ b/integration/examples/multiple-renderers/backend/values.yaml @@ -0,0 +1,3 @@ +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +replicaCount: 1 \ No newline at end of file diff --git a/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml b/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml new file mode 100644 index 00000000000..e256fb30ef8 --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/k8s/deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + labels: + app: frontend +spec: + selector: + matchLabels: + app: frontend + replicas: 1 + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + image: go-guestbook-frontend + ports: + - name: http-server + containerPort: 8080 + - name: debug + containerPort: 3000 + env: + - name: PORT + value: "8080" + - name: GUESTBOOK_API_ADDR + value: localhost:27017 diff --git a/integration/examples/multiple-renderers/frontend/k8s/service.yaml b/integration/examples/multiple-renderers/frontend/k8s/service.yaml new file mode 100644 index 00000000000..fdbe0774201 --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/k8s/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: frontend + labels: + app: frontend +spec: + type: ClusterIP + selector: + app: frontend + ports: + - port: 8080 + targetPort: http-server diff --git a/integration/examples/multiple-renderers/frontend/src/Dockerfile b/integration/examples/multiple-renderers/frontend/src/Dockerfile new file mode 100644 index 00000000000..09ef1305d9a --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/src/Dockerfile @@ -0,0 +1,31 @@ +# Use base golang image from Docker Hub +FROM golang:1.17 as build + +WORKDIR /app + +# Copy the go.mod and go.sum, download the dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy rest of the application source code +COPY . ./ + +# Compile the application to /app/frontend. +# Skaffold passes in debug-oriented compiler flags +ARG SKAFFOLD_GO_GCFLAGS +RUN echo "Go gcflags: ${SKAFFOLD_GO_GCFLAGS}" +RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -mod=readonly -v -o /app/frontend . + +# Now create separate deployment image +FROM gcr.io/distroless/base + +# Definition of this variable is used by 'skaffold debug' to identify a golang binary. +# Default behavior - a failure prints a stack trace for the current goroutine. +# See https://golang.org/pkg/runtime/ +ENV GOTRACEBACK=single + +WORKDIR /app +COPY static /app/static +COPY templates /app/templates +COPY --from=build /app/frontend /app/frontend +ENTRYPOINT ["/app/frontend"] diff --git a/integration/examples/multiple-renderers/frontend/src/go.mod b/integration/examples/multiple-renderers/frontend/src/go.mod new file mode 100644 index 00000000000..ffdcef69bb4 --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/src/go.mod @@ -0,0 +1,3 @@ +module frontend + +go 1.12 diff --git a/integration/examples/multiple-renderers/frontend/src/go.sum b/integration/examples/multiple-renderers/frontend/src/go.sum new file mode 100644 index 00000000000..e69de29bb2d diff --git a/integration/examples/multiple-renderers/frontend/src/main.go b/integration/examples/multiple-renderers/frontend/src/main.go new file mode 100644 index 00000000000..c1dfb6f934b --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/src/main.go @@ -0,0 +1,165 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "html/template" + "io/ioutil" + "log" + "net/http" + "os" + "time" +) + +var ( + // tpl stores the parsed frontend html template + tpl *template.Template +) + +// guestbookEntry represents the message object returned from the backend API. +type guestbookEntry struct { + Author string `json:"author"` + Message string `json:"message"` + Date time.Time `json:"date"` +} + +// main starts a frontend server and connects to the backend. +func main() { + // GUESTBOOK_API_ADDR environment variable is provided in guestbook-frontend.deployment.yaml. + backendAddr := os.Getenv("GUESTBOOK_API_ADDR") + if backendAddr == "" { + log.Fatal("GUESTBOOK_API_ADDR environment variable not specified") + } + + // PORT environment variable is provided in guestbook-frontend.deployment.yaml. + port := os.Getenv("PORT") + if port == "" { + log.Fatal("PORT environment variable not specified") + } + + // Parse html templates and save them to global variable. + t, err := template.New("").Funcs(map[string]interface{}{ + "since": sinceDate, + }).ParseGlob("templates/*.tpl") + if err != nil { + log.Fatalf("could not parse templates: %+v", err) + } + tpl = t + + // Register http handlers and start listening on port. + fe := &frontendServer{backendAddr: backendAddr} + fs := http.FileServer(http.Dir("static")) + http.Handle("/static/", http.StripPrefix("/static/", fs)) + http.HandleFunc("/", fe.homeHandler) + http.HandleFunc("/post", fe.postHandler) + log.Printf("frontend server listening on port %s", port) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatalf("server listen error: %+v", err) + } +} + +type frontendServer struct { + backendAddr string +} + +// homeHandler handles GET requests to /. +func (f *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) { + log.Printf("received request: %s %s", r.Method, r.URL.Path) + if r.Method != http.MethodGet { + http.Error(w, fmt.Sprintf("only GET requests are supported (got %s)", r.Method), http.StatusMethodNotAllowed) + return + } + if r.URL.Path != "/" { + http.Error(w, "page not found", http.StatusNotFound) + return + } + + log.Printf("querying backend for entries") + resp, err := http.Get(fmt.Sprintf("http://%s/messages", f.backendAddr)) + if err != nil { + http.Error(w, fmt.Sprintf("querying backend failed: %+v", err), http.StatusInternalServerError) + return + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + http.Error(w, fmt.Sprintf("failed to read response body: %+v", err), http.StatusInternalServerError) + return + } + + if resp.StatusCode != http.StatusOK { + http.Error(w, fmt.Sprintf("got status code %d from the backend: %s", resp.StatusCode, string(body)), http.StatusInternalServerError) + return + } + + log.Printf("parsing backend response into json") + var v []guestbookEntry + if err := json.Unmarshal(body, &v); err != nil { + log.Printf("WARNING: failed to decode json from the api: %+v input=%q", err, string(body)) + http.Error(w, + fmt.Sprintf("could not decode json response from the api: %+v", err), + http.StatusInternalServerError) + return + } + + log.Printf("retrieved %d messages from the backend api", len(v)) + if err := tpl.ExecuteTemplate(w, "home", map[string]interface{}{ + "messages": v, + }); err != nil { + log.Printf("WARNING: failed to render html template: %+v", err) + } +} + +// postHandler handles POST requests to /messages. +func (f *frontendServer) postHandler(w http.ResponseWriter, r *http.Request) { + log.Printf("received request: %s %s", r.Method, r.URL.Path) + if r.Method != http.MethodPost { + http.Error(w, "only POST requests are supported", http.StatusMethodNotAllowed) + return + } + + author := r.FormValue("name") + message := r.FormValue("message") + if author == "" { + http.Error(w, `"name" not specified in the form`, http.StatusBadRequest) + return + } + if message == "" { + http.Error(w, `"message" not specified in the form`, http.StatusBadRequest) + return + } + + if err := f.saveMessage(r.FormValue("name"), r.FormValue("message")); err != nil { + http.Error(w, fmt.Sprintf("failed to save message: %+v", err), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/", http.StatusFound) // redirect to homepage +} + +// saveMessage makes a request to the backend to persist the message. +func (f *frontendServer) saveMessage(author, message string) error { + entry := guestbookEntry{ + Author: author, + Message: message, + } + body, err := json.Marshal(entry) + if err != nil { + return fmt.Errorf("failed to serialize message into json: %+v", err) + } + + resp, err := http.Post(fmt.Sprintf("http://%s/messages", f.backendAddr), "application/json", bytes.NewReader(body)) + if err != nil { + return fmt.Errorf("backend returned failure: %+v", err) + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code from backend: %d %v", resp.StatusCode, resp.Status) + } + defer resp.Body.Close() + return nil +} + +// sinceDate is used in the html template to display human-friendly dates. +func sinceDate(t time.Time) string { return time.Since(t).Truncate(time.Second).String() } diff --git a/integration/examples/multiple-renderers/frontend/src/static/style.css b/integration/examples/multiple-renderers/frontend/src/static/style.css new file mode 100644 index 00000000000..b0ee5b63157 --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/src/static/style.css @@ -0,0 +1,111 @@ +body { + font-family: 'Roboto', sans-serif; + background: #f8f9fa; +} + +.container { + margin-top: 50px; + background: white; + border-radius: 10px; + z-index: 10; + position: relative; + padding: 50px 16px; +} + +.next-logo { + position: absolute; + right: 0; + top: 0; + opacity: 0.5; + z-index: -1; + width: 30% +} + +a:hover { + text-decoration: none; +} + +.header .container { + background: none; +} + +.form-inline { + margin-bottom: 40px; +} + +h1 { + margin-bottom: 2rem; + max-width: 1140px; + margin: auto; + padding-bottom: 16px; + position: relative; +} + +.card-body { + margin: 10px; +} + +.posts:after { + background: linear-gradient(to right, #4285f4 25%,#db4437 25%, #db4437 50%, #f4b400 50%, #f4b400 75%, #0f9d58 75%); + position: absolute; + content: ''; + height: 4px; + right: 0; + left: 0; + top: 0; +} + +.card { + border: none; + box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); + display: inline-block; +} + +.github { + max-width: 80px; + opacity: 0.5; +} + +.github:hover { + opacity: 1; +} + +h5 { + font-size: 24px; + float: left; +} + +h6 { + font-size: 14px; + color: black; + float: right; +} + +p { + font-size: 14px; + color: #646464; + margin-top: 1rem !important; +} + +h1 a { + color: #202124; + font-size: 60px; +} + +.header { + margin: 0; + position: relative; +} + +@media (min-width: 1200px) { + .container { + max-width: 900px; + padding: 50px; + } +} + +@media (max-width: 480px) { + h1 a { + font-size: 40px; + } +} diff --git a/integration/examples/multiple-renderers/frontend/src/templates/home.tpl b/integration/examples/multiple-renderers/frontend/src/templates/home.tpl new file mode 100644 index 00000000000..7ea94314fb1 --- /dev/null +++ b/integration/examples/multiple-renderers/frontend/src/templates/home.tpl @@ -0,0 +1,64 @@ +{{ define "home" }} + + + + + Guestbook + + + + + + + + +
+ +
+ +
+
+ +
+
+
Your Name
+
+ +
+ +
+
+
Message
+
+ +
+ +
+ + {{ range .messages }} +
+
+
{{.Author}}
+
{{ since .Date}} ago
+
+

+ {{ .Message }} +

+
+
+ {{ else }} + + {{ end }} +
+ + +{{ end }} diff --git a/integration/examples/multiple-renderers/skaffold.yaml b/integration/examples/multiple-renderers/skaffold.yaml new file mode 100644 index 00000000000..1717a229fe1 --- /dev/null +++ b/integration/examples/multiple-renderers/skaffold.yaml @@ -0,0 +1,40 @@ +apiVersion: skaffold/v3alpha1 +kind: Config +metadata: + name: go-guestbook +build: + artifacts: + - image: go-guestbook-backend + context: backend/src + docker: + dockerfile: Dockerfile + - image: go-guestbook-frontend + context: frontend/src + docker: + dockerfile: Dockerfile +manifests: + rawYaml: + - frontend/k8s/*.yaml + helm: + releases: + - name: backend + chartPath: backend + valuesFiles: + - backend/val.yaml + - backend/values.yaml + version: 0.1.0 + +profiles: + - name: mix-deploy + patches: + - op: remove + path: /manifests/helm + deploy: + helm: + releases: + - name: backend + chartPath: backend + valuesFiles: + - backend/val.yaml + - backend/values.yaml + version: 0.1.0 diff --git a/integration/run_test.go b/integration/run_test.go index 5e99a8542d7..fd3f7e15643 100644 --- a/integration/run_test.go +++ b/integration/run_test.go @@ -154,6 +154,11 @@ var tests = []struct { deployments: []string{"skaffold-helm"}, targetLog: "Hello world!", }, + { + description: "multiple renderers mixed in", + dir: "examples/multiple-renderers", + deployments: []string{"frontend", "backend", "go-guestbook-mongodb"}, + }, } func TestRun(t *testing.T) { diff --git a/pkg/skaffold/render/renderer/renderer.go b/pkg/skaffold/render/renderer/renderer.go index 43fde13d0a1..720c2b602c7 100644 --- a/pkg/skaffold/render/renderer/renderer.go +++ b/pkg/skaffold/render/renderer/renderer.go @@ -43,25 +43,27 @@ func New(ctx context.Context, cfg render.Config, renderCfg latest.RenderConfig, if usingLegacyHelmDeploy && command != "render" { return GroupRenderer{noop.New(renderCfg, cfg.GetWorkingDir(), hydrationDir, labels)}, nil } - if renderCfg.Validate != nil && renderCfg.Transform != nil { + if renderCfg.Validate != nil || renderCfg.Transform != nil || renderCfg.Kpt != nil { r, err := kpt.New(cfg, renderCfg, hydrationDir, labels, configName) if err != nil { return nil, err } - log.Entry(ctx).Infof("setting up kpt renderer") - return GroupRenderer{r}, nil + log.Entry(context.TODO()).Infof("setting up kpt renderer") + return []Renderer{r}, nil } + var rs GroupRenderer - var r Renderer - var err error + if renderCfg.RawK8s != nil || renderCfg.Kustomize != nil { - if r, err = kubectl.New(cfg, renderCfg, labels, configName); err != nil { + r, err := kubectl.New(cfg, renderCfg, labels, configName) + if err != nil { return nil, err } rs = append(rs, r) } if renderCfg.Helm != nil { - if r, err = helm.New(cfg, renderCfg, labels, configName); err != nil { + r, err := helm.New(cfg, renderCfg, labels, configName) + if err != nil { return nil, err } rs = append(rs, r)