mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-04-10 04:56:49 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21922197b5 | ||
|
|
7ea943525f | ||
|
|
57ff4465cd | ||
|
|
a86ef1fdb6 | ||
|
|
ddf1b80e1b | ||
|
|
896aceb240 | ||
|
|
7996f76e71 | ||
|
|
8b04a8f502 | ||
|
|
8a6a4e8901 | ||
|
|
cf8531c224 | ||
|
|
d1574a6601 | ||
|
|
75d93e0c54 | ||
|
|
7622dfb74f | ||
|
|
85a26ed71e | ||
|
|
81b22f08f8 | ||
|
|
7d9e3afde7 | ||
|
|
3d2028a124 | ||
|
|
1b56648f5b | ||
|
|
3a704215a4 | ||
|
|
25aaeff13c | ||
|
|
3b93a3445e | ||
|
|
a6cc3d2ef9 | ||
|
|
718d8ba4e0 | ||
|
|
24ceb25930 | ||
|
|
fc8dfc7678 | ||
|
|
8e656fdfd0 | ||
|
|
a945842e9b | ||
|
|
09a743f5c2 | ||
|
|
c44a58602e | ||
|
|
2ee11bf6b2 | ||
|
|
70b0e92555 | ||
|
|
7a78c93a49 | ||
|
|
be915d44cc |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -10,8 +10,11 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
.idea/
|
||||
release/
|
||||
build/
|
||||
gcloud/
|
||||
|
||||
@@ -6,7 +6,7 @@ RUN addgroup -S app \
|
||||
curl openssl netcat-openbsd
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY ./ui ./ui
|
||||
ADD podinfo .
|
||||
|
||||
RUN chown -R app:app ./
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
FROM alpine:3.7
|
||||
|
||||
COPY ./ui ./ui
|
||||
ADD podinfo /podinfo
|
||||
|
||||
CMD ["./podinfo"]
|
||||
|
||||
@@ -24,7 +24,7 @@ RUN addgroup -S app \
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY --from=builder /go/src/github.com/stefanprodan/k8s-podinfo/podinfo .
|
||||
|
||||
COPY ./ui ./ui
|
||||
RUN chown -R app:app ./
|
||||
|
||||
USER app
|
||||
|
||||
19
Gopkg.lock
generated
19
Gopkg.lock
generated
@@ -7,6 +7,12 @@
|
||||
packages = ["quantile"]
|
||||
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto"]
|
||||
@@ -65,11 +71,18 @@
|
||||
name = "github.com/rs/zerolog"
|
||||
packages = [
|
||||
".",
|
||||
"internal/cbor",
|
||||
"internal/json",
|
||||
"log"
|
||||
]
|
||||
revision = "56a970de510213e50dbaa39ad73ac07c9ec75606"
|
||||
version = "v1.5.0"
|
||||
revision = "77db4b4f350e31be66a57c332acb7721cf9ff9bb"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "bd9dbc187b6e1dacfdd2722a87e83093c2d7bd6e"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
@@ -80,6 +93,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "4f1e9200a330a22000fc47075b59e68e57c94bcb3d9f444f3ce85cab77e07fde"
|
||||
inputs-digest = "1b88c0a618973c53f6b715dd51ad99f2952baf09c4d752bc8a985d26439a739c"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -9,12 +9,16 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/rs/zerolog"
|
||||
version = "1.5.0"
|
||||
version = "1.8.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
version = "2.1.1"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
version = "1.2.9"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
11
Makefile
11
Makefile
@@ -21,6 +21,7 @@ build:
|
||||
@echo Building: linux/$(LINUX_ARCH) $(VERSION) ;\
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
mkdir -p build/linux/$$arch && CGO_ENABLED=0 GOOS=linux GOARCH=$$arch go build -ldflags="-s -w -X $(GITREPO)/pkg/version.GITCOMMIT=$(GITCOMMIT)" -o build/linux/$$arch/$(NAME) ./cmd/$(NAME) ;\
|
||||
cp -r ui/ build/linux/$$arch/ui;\
|
||||
done
|
||||
|
||||
.PHONY: tar
|
||||
@@ -45,6 +46,7 @@ docker-build: tar
|
||||
@for arch in $(LINUX_ARCH); do \
|
||||
mkdir -p build/docker/linux/$$arch ;\
|
||||
tar -xzf release/$(NAME)_$(VERSION)_linux_$$arch.tgz -C build/docker/linux/$$arch ;\
|
||||
cp -r ui/ build/docker/linux/$$arch/ui;\
|
||||
if [ $$arch == amd64 ]; then \
|
||||
cp Dockerfile build/docker/linux/$$arch ;\
|
||||
cp Dockerfile build/docker/linux/$$arch/Dockerfile.in ;\
|
||||
@@ -103,13 +105,10 @@ dep:
|
||||
.PHONY: charts
|
||||
charts:
|
||||
cd charts/ && helm package podinfo/
|
||||
mv charts/podinfo-0.1.0.tgz docs/
|
||||
cd charts/ && helm package podinfo-istio/
|
||||
cd charts/ && helm package loadtest/
|
||||
cd charts/ && helm package ambassador/
|
||||
mv charts/ambassador-0.1.0.tgz docs/
|
||||
cd charts/ && helm package grafana/
|
||||
mv charts/grafana-0.1.0.tgz docs/
|
||||
cd charts/ && helm package ngrok/
|
||||
mv charts/ngrok-0.1.0.tgz docs/
|
||||
cd charts/ && helm package weave-flux/
|
||||
mv charts/weave-flux-0.2.0.tgz docs/
|
||||
mv charts/*.tgz docs/
|
||||
helm repo index docs --url https://stefanprodan.github.io/k8s-podinfo --merge ./docs/index.yaml
|
||||
|
||||
@@ -9,6 +9,7 @@ Specifications:
|
||||
* Multi-platform Docker image (amd64/arm/arm64/ppc64le/s390x)
|
||||
* Health checks (readiness and liveness)
|
||||
* Graceful shutdown on interrupt signals
|
||||
* Watches for secrets and configmaps changes and updates the in-memory cache
|
||||
* Prometheus instrumentation (RED metrics)
|
||||
* Dependency management with golang/dep
|
||||
* Structured logging with zerolog
|
||||
@@ -29,6 +30,7 @@ Web API:
|
||||
* `POST /echo` echos the posted content, logs the SHA1 hash of the content
|
||||
* `GET /echoheaders` prints the request HTTP headers
|
||||
* `POST /job` long running job, json body: `{"wait":2}`
|
||||
* `GET /configs` prints the configmaps and/or secrets mounted in the `config` volume
|
||||
* `POST /write` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
|
||||
* `POST /read` receives a SHA1 hash and returns the content of the file /data/hash if exists
|
||||
* `POST /backend` forwards the call to the backend service on `http://backend-podinfo:9898/echo`
|
||||
|
||||
@@ -3,7 +3,7 @@ kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "grafana.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "grafana.name" . }}
|
||||
app: {{ template "grafana.fullname" . }}
|
||||
chart: {{ template "grafana.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
@@ -11,12 +11,12 @@ spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "grafana.name" . }}
|
||||
app: {{ template "grafana.fullname" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "grafana.name" . }}
|
||||
app: {{ template "grafana.fullname" . }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
prometheus.io/scrape: 'false'
|
||||
|
||||
@@ -15,5 +15,5 @@ spec:
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "grafana.name" . }}
|
||||
app: {{ template "grafana.fullname" . }}
|
||||
release: {{ .Release.Name }}
|
||||
|
||||
5
charts/loadtest/Chart.yaml
Normal file
5
charts/loadtest/Chart.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: Hey load test Helm chart for Kubernetes
|
||||
name: loadtest
|
||||
version: 0.1.0
|
||||
1
charts/loadtest/templates/NOTES.txt
Normal file
1
charts/loadtest/templates/NOTES.txt
Normal file
@@ -0,0 +1 @@
|
||||
{{ template "loadtest.fullname" . }} has been deployed successfully!
|
||||
@@ -2,7 +2,7 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "weave-cloud.name" -}}
|
||||
{{- define "loadtest.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -11,7 +11,7 @@ Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "weave-cloud.fullname" -}}
|
||||
{{- define "loadtest.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
@@ -27,6 +27,6 @@ If release name contains chart name it will be used as a full name.
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "weave-cloud.chart" -}}
|
||||
{{- define "loadtest.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
31
charts/loadtest/templates/jobs.yaml
Normal file
31
charts/loadtest/templates/jobs.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
{{- $fullname := include "loadtest.fullname" . -}}
|
||||
{{- $name := include "loadtest.name" . -}}
|
||||
{{- $chart := include "loadtest.chart" . -}}
|
||||
{{- $image := .Values.image -}}
|
||||
{{- range $test := .Values.tests }}
|
||||
---
|
||||
apiVersion: batch/v1beta1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{ $fullname }}-{{ .name }}
|
||||
labels:
|
||||
app: {{ $name }}
|
||||
chart: {{ $chart }}
|
||||
spec:
|
||||
schedule: "*/1 * * * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 1
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: loadtest
|
||||
image: {{ $image }}
|
||||
args:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "hey -z 58s {{ $test.cmd }} {{ $test.url }}"
|
||||
restartPolicy: OnFailure
|
||||
{{- end -}}
|
||||
11
charts/loadtest/values.yaml
Normal file
11
charts/loadtest/values.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
# Default values for loadtest.
|
||||
|
||||
image: stefanprodan/loadtest:latest
|
||||
|
||||
tests:
|
||||
- name: "blue"
|
||||
url: "https://canary.istio.weavedx.com/api/echo"
|
||||
cmd: "-h2 -m POST -d '{test: 1}' -H 'X-API-Version: 0.6.0' -c 50 -q 5"
|
||||
- name: "green"
|
||||
url: "https://canary.istio.weavedx.com/api/echo"
|
||||
cmd: "-h2 -m POST -d '{test: 2}' -H 'X-API-Version: 0.6.1' -c 10 -q 5"
|
||||
12
charts/podinfo-istio/Chart.yaml
Normal file
12
charts/podinfo-istio/Chart.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
appVersion: "0.6.0"
|
||||
description: Podinfo Helm chart for Istio
|
||||
name: podinfo-istio
|
||||
version: 0.1.0
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- name: stefanprodan
|
||||
email: stefanprodan@users.noreply.github.com
|
||||
engine: gotpl
|
||||
80
charts/podinfo-istio/README.md
Normal file
80
charts/podinfo-istio/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Podinfo Istio
|
||||
|
||||
Podinfo is a tiny web application made with Go
|
||||
that showcases best practices of running microservices in Kubernetes.
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
Create an Istio enabled namespace:
|
||||
|
||||
```console
|
||||
kubectl create namespace demo
|
||||
kubectl label namespace demo istio-injection=enabled
|
||||
```
|
||||
|
||||
Create an Istio Gateway in the `istio-system` namespace named `public-gateway`:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: public-gateway
|
||||
namespace: istio-system
|
||||
spec:
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- port:
|
||||
number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
httpsRedirect: true
|
||||
- port:
|
||||
number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
mode: SIMPLE
|
||||
privateKey: /etc/istio/ingressgateway-certs/tls.key
|
||||
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
|
||||
```
|
||||
|
||||
Create the `frontend` release by specifying the external domain name:
|
||||
|
||||
```console
|
||||
helm upgrade frontend --install ./charts/podinfo-istio \
|
||||
--namespace=demo \
|
||||
--set host=podinfo.example.com \
|
||||
--set gateway.name=public-gateway \
|
||||
--set gateway.create=false \
|
||||
-f ./charts/podinfo-istio/frontend.yaml
|
||||
```
|
||||
|
||||
Create the `backend` release:
|
||||
|
||||
```console
|
||||
helm upgrade backend --install ./charts/podinfo-istio \
|
||||
--namespace=demo \
|
||||
-f ./charts/podinfo-istio/backend.yaml
|
||||
```
|
||||
|
||||
Create the `store` release:
|
||||
|
||||
```console
|
||||
helm upgrade store --install ./charts/podinfo-istio \
|
||||
--namespace=demo \
|
||||
-f ./charts/podinfo-istio/store.yaml
|
||||
```
|
||||
|
||||
Start load test:
|
||||
|
||||
```console
|
||||
helm upgrade --install loadtest ./charts/loadtest \
|
||||
--namespace=loadtesting
|
||||
```
|
||||
|
||||
34
charts/podinfo-istio/apply.sh
Executable file
34
charts/podinfo-istio/apply.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#Usage: fswatch -o ./podinfo-istio/ | xargs -n1 ./podinfo-istio/apply.sh
|
||||
|
||||
set -e
|
||||
|
||||
MARK='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
log (){
|
||||
echo -e "$(date +%Y-%m-%dT%H:%M:%S%z) ${MARK}${1}${NC}"
|
||||
}
|
||||
|
||||
log "installing frontend"
|
||||
helm upgrade frontend --install ./podinfo-istio \
|
||||
--namespace=demo \
|
||||
--set host=canary.istio.weavedx.com \
|
||||
--set gateway.name=public-gateway \
|
||||
--set gateway.create=false \
|
||||
-f ./podinfo-istio/frontend.yaml
|
||||
|
||||
log "installing backend"
|
||||
helm upgrade backend --install ./podinfo-istio \
|
||||
--namespace=demo \
|
||||
-f ./podinfo-istio/backend.yaml
|
||||
|
||||
log "installing store"
|
||||
helm upgrade store --install ./podinfo-istio \
|
||||
--namespace=demo \
|
||||
-f ./podinfo-istio/store.yaml
|
||||
|
||||
log "finished installing frontend, backend and store"
|
||||
|
||||
|
||||
21
charts/podinfo-istio/backend.yaml
Normal file
21
charts/podinfo-istio/backend.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# Default values for backend demo.
|
||||
|
||||
# expose the blue/green deployments inside the cluster
|
||||
host: backend
|
||||
|
||||
# stable release
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "0.6.0"
|
||||
backend: http://store:9898/api/echo
|
||||
|
||||
# canary release
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "0.6.1"
|
||||
routing:
|
||||
# target green callers
|
||||
- match:
|
||||
- sourceLabels:
|
||||
color: green
|
||||
backend: http://store:9898/api/echo
|
||||
39
charts/podinfo-istio/frontend.yaml
Normal file
39
charts/podinfo-istio/frontend.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
# Default values for frontend demo.
|
||||
|
||||
# external domain
|
||||
host:
|
||||
exposeHost: true
|
||||
|
||||
# no more than one Gateway can be created on a cluster
|
||||
# if TLS is enabled the istio-ingressgateway-certs secret must exist in istio-system ns
|
||||
# if you have a Gateway running you can set the name to your own gateway and turn off create
|
||||
gateway:
|
||||
name: public-gateway
|
||||
create: true
|
||||
tls: true
|
||||
httpsRedirect: true
|
||||
|
||||
# stable release
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "0.6.0"
|
||||
message: "Greetings from the blue frontend"
|
||||
backend: http://backend:9898/api/echo
|
||||
|
||||
# canary release
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "0.6.1"
|
||||
routing:
|
||||
# target Safari
|
||||
- match:
|
||||
- headers:
|
||||
user-agent:
|
||||
regex: "^(?!.*Chrome).*Safari.*"
|
||||
# target API clients by version
|
||||
- match:
|
||||
- headers:
|
||||
x-api-version:
|
||||
regex: "^(v{0,1})0\\.6\\.([1-9]).*"
|
||||
message: "Greetings from the green frontend"
|
||||
backend: http://backend:9898/api/echo
|
||||
1636
charts/podinfo-istio/grafana/istio-bluegreen.json
Normal file
1636
charts/podinfo-istio/grafana/istio-bluegreen.json
Normal file
File diff suppressed because it is too large
Load Diff
19
charts/podinfo-istio/store.yaml
Normal file
19
charts/podinfo-istio/store.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Default values for backend demo.
|
||||
|
||||
# expose the store deployment inside the cluster
|
||||
host: store
|
||||
|
||||
# load balance 80/20 between blue and green
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "0.6.0"
|
||||
backend: https://httpbin.org/anything
|
||||
weight: 80
|
||||
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "0.6.1"
|
||||
backend: https://httpbin.org/anything
|
||||
|
||||
externalServices:
|
||||
- httpbin.org
|
||||
1
charts/podinfo-istio/templates/NOTES.txt
Normal file
1
charts/podinfo-istio/templates/NOTES.txt
Normal file
@@ -0,0 +1 @@
|
||||
{{ template "podinfo-istio.fullname" . }} has been deployed successfully!
|
||||
@@ -2,42 +2,35 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "weave-flux.name" -}}
|
||||
{{- define "podinfo-istio.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
The release name is used as a full name.
|
||||
*/}}
|
||||
{{- define "weave-flux.fullname" -}}
|
||||
{{- define "podinfo-istio.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "podinfo-istio.blue" -}}
|
||||
{{- printf "%s-%s" .Release.Name "blue" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "podinfo-istio.green" -}}
|
||||
{{- printf "%s-%s" .Release.Name "green" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "weave-flux.chart" -}}
|
||||
{{- define "podinfo-istio.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "weave-flux.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{ default (include "weave-flux.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
76
charts/podinfo-istio/templates/blue-deployment.yaml
Normal file
76
charts/podinfo-istio/templates/blue-deployment.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.blue" . }}
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
color: blue
|
||||
version: {{ .Values.blue.tag }}
|
||||
spec:
|
||||
replicas: {{ .Values.blue.replicas }}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
color: blue
|
||||
version: {{ .Values.blue.tag }}
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: "{{ .Values.blue.repository }}:{{ .Values.blue.tag }}"
|
||||
imagePullPolicy: {{ .Values.imagePullPolicy }}
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port={{ .Values.containerPort }}
|
||||
- -logLevel={{ .Values.logLevel }}
|
||||
env:
|
||||
- name: color
|
||||
value: blue
|
||||
{{- if .Values.blue.backend }}
|
||||
- name: backendURL
|
||||
value: {{ .Values.blue.backend }}
|
||||
{{- end }}
|
||||
{{- if .Values.blue.message }}
|
||||
- name: message
|
||||
value: {{ .Values.blue.message }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.containerPort }}
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 2
|
||||
failureThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
failureThreshold: 2
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
20
charts/podinfo-istio/templates/destionation-rule.yaml
Normal file
20
charts/podinfo-istio/templates/destionation-rule.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
host: {{ template "podinfo-istio.fullname" . }}
|
||||
subsets:
|
||||
- name: blue
|
||||
labels:
|
||||
color: blue
|
||||
{{- if gt .Values.green.replicas 0.0 }}
|
||||
- name: green
|
||||
labels:
|
||||
color: green
|
||||
{{- end }}
|
||||
22
charts/podinfo-istio/templates/external-services.yaml
Normal file
22
charts/podinfo-istio/templates/external-services.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
{{- if .Values.externalServices -}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: ServiceEntry
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.fullname" . }}-external-svcs
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
hosts:
|
||||
{{- range .Values.externalServices }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
location: MESH_EXTERNAL
|
||||
ports:
|
||||
- number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
resolution: DNS
|
||||
{{- end }}
|
||||
31
charts/podinfo-istio/templates/gateway.yaml
Normal file
31
charts/podinfo-istio/templates/gateway.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
{{- if .Values.gateway.create -}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: {{ .Values.gateway.name }}
|
||||
namespace: istio-system
|
||||
spec:
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- port:
|
||||
number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
httpsRedirect: {{ .Values.gateway.httpsRedirect }}
|
||||
{{- if .Values.gateway.tls }}
|
||||
- port:
|
||||
number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
mode: SIMPLE
|
||||
privateKey: /etc/istio/ingressgateway-certs/tls.key
|
||||
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
78
charts/podinfo-istio/templates/green-deployment.yaml
Normal file
78
charts/podinfo-istio/templates/green-deployment.yaml
Normal file
@@ -0,0 +1,78 @@
|
||||
{{- if gt .Values.green.replicas 0.0 -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.green" . }}
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
color: green
|
||||
version: {{ .Values.green.tag }}
|
||||
spec:
|
||||
replicas: {{ .Values.green.replicas }}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
color: green
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
color: green
|
||||
version: {{ .Values.green.tag }}
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: "{{ .Values.green.repository }}:{{ .Values.green.tag }}"
|
||||
imagePullPolicy: {{ .Values.imagePullPolicy }}
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port={{ .Values.containerPort }}
|
||||
- -logLevel={{ .Values.logLevel }}
|
||||
env:
|
||||
- name: color
|
||||
value: green
|
||||
{{- if .Values.green.backend }}
|
||||
- name: backendURL
|
||||
value: {{ .Values.green.backend }}
|
||||
{{- end }}
|
||||
{{- if .Values.green.message }}
|
||||
- name: message
|
||||
value: {{ .Values.green.message }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.containerPort }}
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 2
|
||||
failureThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
failureThreshold: 2
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
18
charts/podinfo-istio/templates/service.yaml
Normal file
18
charts/podinfo-istio/templates/service.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ .Values.containerPort }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
43
charts/podinfo-istio/templates/virtual-service.yaml
Normal file
43
charts/podinfo-istio/templates/virtual-service.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
{{- $host := .Release.Name -}}
|
||||
{{- $timeout := .Values.timeout -}}
|
||||
{{- $greenWeight := (sub 100 (.Values.blue.weight|int)) | int -}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: {{ template "podinfo-istio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "podinfo-istio.fullname" . }}
|
||||
chart: {{ template "podinfo-istio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
hosts:
|
||||
- {{ .Values.host }}
|
||||
{{- if .Values.exposeHost }}
|
||||
gateways:
|
||||
- {{ .Values.gateway.name }}.istio-system.svc.cluster.local
|
||||
{{- end }}
|
||||
http:
|
||||
{{- if gt .Values.green.replicas 0.0 }}
|
||||
{{- range .Values.green.routing }}
|
||||
- match:
|
||||
{{ toYaml .match | indent 6 }}
|
||||
route:
|
||||
- destination:
|
||||
host: {{ $host }}
|
||||
subset: green
|
||||
timeout: {{ $timeout }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
- route:
|
||||
- destination:
|
||||
host: {{ template "podinfo-istio.fullname" . }}
|
||||
subset: blue
|
||||
weight: {{ .Values.blue.weight }}
|
||||
{{- if gt .Values.green.replicas 0.0 }}
|
||||
- destination:
|
||||
host: {{ template "podinfo-istio.fullname" . }}
|
||||
subset: green
|
||||
weight: {{ $greenWeight }}
|
||||
{{- end }}
|
||||
timeout: {{ $timeout }}
|
||||
55
charts/podinfo-istio/values.yaml
Normal file
55
charts/podinfo-istio/values.yaml
Normal file
@@ -0,0 +1,55 @@
|
||||
# Default values for podinfo-istio.
|
||||
|
||||
# host can be an extarnal domain or a local one
|
||||
host: podinfo
|
||||
# if the host is an external domain must be exposed via the Gateway
|
||||
exposeHost: false
|
||||
timeout: 30s
|
||||
|
||||
# creates public-gateway.istio-system.svc.cluster.local
|
||||
# no more than one Gateway can be created on a cluster
|
||||
# if TLS is enabled the istio-ingressgateway-certs secret must exist in istio-system ns
|
||||
# if you have a Gateway running you can set the name to your own gateway and turn off create
|
||||
gateway:
|
||||
name: public-gateway
|
||||
create: false
|
||||
tls: false
|
||||
httpsRedirect: false
|
||||
|
||||
# authorise external https services
|
||||
#externalServices:
|
||||
# - api.github.com
|
||||
# - apis.google.com
|
||||
# - googleapis.com
|
||||
|
||||
# stable release
|
||||
# by default all traffic goes to blue
|
||||
blue:
|
||||
replicas: 2
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: "0.6.0"
|
||||
# green must have at at least one replica to set weight under 100
|
||||
weight: 100
|
||||
message:
|
||||
backend:
|
||||
|
||||
|
||||
# canary release
|
||||
# disabled with 0 replicas
|
||||
green:
|
||||
replicas: 0
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: "0.6.1"
|
||||
message:
|
||||
backend:
|
||||
routing:
|
||||
|
||||
# blue/green common settings
|
||||
logLevel: info
|
||||
containerPort: 9898
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
requests:
|
||||
cpu: 1m
|
||||
memory: 16Mi
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: v1
|
||||
appVersion: "0.4.0"
|
||||
appVersion: "0.6.0"
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
name: podinfo
|
||||
version: 0.1.0
|
||||
version: 0.2.2
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
|
||||
@@ -7,20 +7,31 @@ metadata:
|
||||
chart: {{ template "podinfo.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
color: {{ .Values.color }}
|
||||
version: {{ .Values.image.tag }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "podinfo.name" . }}
|
||||
color: {{ .Values.color }}
|
||||
version: {{ .Values.image.tag }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "podinfo.name" . }}
|
||||
color: {{ .Values.color }}
|
||||
version: {{ .Values.image.tag }}
|
||||
release: {{ .Release.Name }}
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
@@ -28,24 +39,32 @@ spec:
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port={{ .Values.service.containerPort }}
|
||||
{{- if .Values.logLevel }}
|
||||
- -debug=true
|
||||
{{- end }}
|
||||
- -logLevel={{ .Values.logLevel }}
|
||||
env:
|
||||
- name: backend_url
|
||||
- name: color
|
||||
value: {{ .Values.color }}
|
||||
{{- if .Values.backend }}
|
||||
- name: backendURL
|
||||
value: {{ .Values.backend }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.containerPort }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: http
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 2
|
||||
failureThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
failureThreshold: 2
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Default values for podinfo.
|
||||
|
||||
replicaCount: 1
|
||||
backend: http://backend-podinfo:9898/echo
|
||||
replicaCount: 2
|
||||
color: blue
|
||||
backend: #http://backend-podinfo:9898/echo
|
||||
|
||||
image:
|
||||
repository: stefanprodan/podinfo
|
||||
tag: 0.4.0
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: 0.6.0
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
@@ -14,7 +15,7 @@ service:
|
||||
containerPort: 9898
|
||||
nodePort: 31198
|
||||
|
||||
# Heapster or metrics-server add-on required
|
||||
# metrics-server add-on required
|
||||
hpa:
|
||||
enabled: false
|
||||
maxReplicas: 10
|
||||
@@ -50,4 +51,4 @@ tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
logLevel: debug
|
||||
logLevel: info
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
description: Weave Cloud is a add-on to Kubernetes which provides Continuous Delivery, along with hosted Prometheus Monitoring and a visual dashboard for exploring & debugging microservices
|
||||
name: weave-cloud
|
||||
version: 0.2.0
|
||||
home: https://weave.works
|
||||
maintainers:
|
||||
- name: Ilya Dmitrichenko
|
||||
email: ilya@weave.works
|
||||
- name: Stefan Prodan
|
||||
email: stefan@weave.works
|
||||
engine: gotpl
|
||||
icon: https://www.weave.works/assets/images/bltd108e8f850ae9e7c/weave-logo-512.png
|
||||
@@ -1,53 +0,0 @@
|
||||
# Weave Cloud Agents
|
||||
|
||||
> ***NOTE: This chart is for Kubernetes version 1.6 and later.***
|
||||
|
||||
Weave Cloud is a add-on to Kubernetes which provides Continuous Delivery, along with hosted Prometheus Monitoring and a visual dashboard for exploring & debugging microservices.
|
||||
|
||||
This package contains the agents which connect your cluster to Weave Cloud.
|
||||
|
||||
_To learn more and sign up please visit [Weaveworks website](https://weave.works)._
|
||||
|
||||
You will need a service token which you can get from [cloud.weave.works](https://cloud.weave.works/).
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart:
|
||||
|
||||
```console
|
||||
$ helm install --name weave-cloud --namespace weave --set token=<YOUR_WEAVE_CLOUD_SERVICE_TOKEN> stable/weave-cloud
|
||||
```
|
||||
|
||||
To view the pods installed:
|
||||
```console
|
||||
$ kubectl get pods -n weave -l weave-cloud-component
|
||||
```
|
||||
|
||||
To upgrade the chart:
|
||||
```console
|
||||
$ helm upgrade --reuse-values weave-cloud stable/weave-cloud
|
||||
```
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `weave-cloud` chart:
|
||||
|
||||
```console
|
||||
$ helm delete --purge weave-cloud
|
||||
```
|
||||
|
||||
Delete the `weave` namespace:
|
||||
|
||||
```console
|
||||
$ kubectl delete namespace weave
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following tables lists the configurable parameters of the Weave Cloud Agents chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| --------- | ----------- | ------- |
|
||||
| `token` | Weave Cloud service token | _none_ _(**must be set**)_ |
|
||||
@@ -1,28 +0,0 @@
|
||||
{{- if .Values.token -}}
|
||||
|
||||
Weave Cloud agents had been installed!
|
||||
|
||||
First, verify all Pods are running:
|
||||
|
||||
kubectl get pods -n {{ .Release.Namespace }}
|
||||
|
||||
Next, login to Weave Cloud (https://cloud.weave.works) and verify the agents are connect to your instance.
|
||||
|
||||
If you need help or have any question, join our Slack to chat to us – https://slack.weave.works.
|
||||
|
||||
Happy hacking!
|
||||
|
||||
{{- else -}}
|
||||
#######################################################
|
||||
#### ERROR: Weave Cloud service token is missing ####
|
||||
#######################################################
|
||||
|
||||
The installation of Weave Cloud agents is incomplete until you set the service token.
|
||||
|
||||
To retrieve your Weave Cloud service token, log in to your instance first: https://cloud.weave.works/instances
|
||||
|
||||
Then run:
|
||||
|
||||
helm upgrade {{ .Release.Name }} --set token=<YOUR_WEAVE_CLOUD_SERVICE_TOKEN> stable/weave-cloud
|
||||
|
||||
{{- end }}
|
||||
@@ -1,40 +0,0 @@
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Values.agent.name }}
|
||||
labels:
|
||||
app: {{ .Values.agent.name }}
|
||||
chart: {{ template "weave-cloud.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ .Values.agent.name }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ .Values.agent.name }}
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
serviceAccount: {{ .Values.agent.name }}
|
||||
serviceAccountName: {{ .Values.agent.name }}
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: {{ .Values.agent.name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
args:
|
||||
- -agent.poll-url=https://get.weave.works/k8s/agent.yaml?instanceID={{"{{.InstanceID}}"}}
|
||||
- -wc.hostname=cloud.weave.works
|
||||
- -wc.token=$(WEAVE_CLOUD_TOKEN)
|
||||
env:
|
||||
- name: WEAVE_CLOUD_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: token
|
||||
name: weave-cloud
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.agent.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ .Values.agent.name }}
|
||||
labels:
|
||||
name: {{ .Values.agent.name }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ .Values.agent.name }}
|
||||
labels:
|
||||
name: {{ .Values.agent.name }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.agent.name }}
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.agent.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
metadata:
|
||||
name: weave-cloud
|
||||
data:
|
||||
token: {{ .Values.token | b64enc }}
|
||||
@@ -1,12 +0,0 @@
|
||||
# Default values for weave-cloud.
|
||||
|
||||
# token: ""
|
||||
|
||||
agent:
|
||||
name: weave-agent
|
||||
|
||||
image:
|
||||
repository: quay.io/weaveworks/launcher-agent
|
||||
tag: master-b60524c
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
apiVersion: v1
|
||||
appVersion: "1.3.0"
|
||||
description: Flux is a tool that automatically ensures that the state of a cluster matches what is specified in version control
|
||||
name: weave-flux
|
||||
version: 0.2.0
|
||||
home: https://weave.works
|
||||
sources:
|
||||
- https://github.com/weaveworks/flux
|
||||
maintainers:
|
||||
- name: stefanprodan
|
||||
email: stefan@weave.works
|
||||
engine: gotpl
|
||||
icon: https://landscape.cncf.io/logos/weave-flux.svg
|
||||
@@ -1,115 +0,0 @@
|
||||
# Weave Flux OSS
|
||||
|
||||
Flux is a tool that automatically ensures that the state of a cluster matches what is specified in version control.
|
||||
It is most useful when used as a deployment tool at the end of a Continuous Delivery pipeline. Flux will make sure that your new container images and config changes are propagated to the cluster.
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart bootstraps a [Weave Flux](https://github.com/weaveworks/flux) deployment on
|
||||
a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.7+
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `cd`:
|
||||
|
||||
```console
|
||||
$ helm install --name cd \
|
||||
--set git.url=git@github.com:weaveworks/flux-example \
|
||||
--namespace flux \
|
||||
./charts/weave-flux
|
||||
```
|
||||
|
||||
To install Flux with the Helm operator:
|
||||
|
||||
```console
|
||||
$ helm install --name cd \
|
||||
--set git.url=git@github.com:stefanprodan/weave-flux-helm-demo \
|
||||
--set git.user="Stefan Prodan" \
|
||||
--set git.email="stefan.prodan@gmail.com" \
|
||||
--set helmOperator.create=true \
|
||||
--namespace flux \
|
||||
./charts/weave-flux
|
||||
```
|
||||
|
||||
Be aware that the Helm operator is alpha quality, DO NOT use it on a production cluster.
|
||||
|
||||
The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
|
||||
### Setup Git deploy
|
||||
|
||||
At startup Flux generates a SSH key and logs the public key.
|
||||
Find the SSH public key with:
|
||||
|
||||
```bash
|
||||
export FLUX_POD=$(kubectl get pods --namespace flux -l "app=weave-flux,release=cd" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl -n flux logs $FLUX_POD | grep identity.pub | cut -d '"' -f2 | sed 's/.\{2\}$//'
|
||||
```
|
||||
|
||||
In order to sync your cluster state with GitHub you need to copy the public key and
|
||||
create a deploy key with write access on your GitHub repository.
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `cd` deployment:
|
||||
|
||||
```console
|
||||
$ helm delete --purge cd
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
You should also remove the deploy key from your GitHub repository.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following tables lists the configurable parameters of the Weave Flux chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| ------------------------------- | ------------------------------------------ | ---------------------------------------------------------- |
|
||||
| `image.repository` | Image repository | `quay.io/weaveworks/flux`
|
||||
| `image.tag` | Image tag | `1.2.5`
|
||||
| `image.pullPoliwell cy` | Image pull policy | `IfNotPresent`
|
||||
| `resources` | CPU/memory resource requests/limits | None
|
||||
| `rbac.create` | If `true`, create and use RBAC resources | `true`
|
||||
| `serviceAccount.create` | If `true`, create a new service account | `true`
|
||||
| `serviceAccount.name` | Service account to be used | `weave-flux`
|
||||
| `service.type` | Service type to be used | `ClusterIP`
|
||||
| `service.port` | Service port to be used | `3030`
|
||||
| `git.url` | URL of git repo with Kubernetes manifests | None
|
||||
| `git.branch` | Branch of git repo to use for Kubernetes manifests | `master`
|
||||
| `git.path` | Path within git repo to locate Kubernetes manifests (relative path) | None
|
||||
| `git.user` | Username to use as git committer | `Weave Flux`
|
||||
| `git.email` | Email to use as git committer | `support@weave.works`
|
||||
| `git.chartsPath` | Path within git repo to locate Helm charts (relative path) | `charts`
|
||||
| `git.pollInterval` | Period at which to poll git repo for new commits | `30s`
|
||||
| `helmOperator.create` | If `true`, install the Helm operator | `false`
|
||||
| `helmOperator.repository` | Helm operator image repository | `quay.io/weaveworks/helm-operator`
|
||||
| `helmOperator.tag` | Helm operator image tag | `master-6f427cb`
|
||||
| `helmOperator.pullPolicy` | Helm operator image pull policy | `IfNotPresent`
|
||||
| `token` | Weave Cloud service token | None
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example:
|
||||
|
||||
```console
|
||||
$ helm upgrade --install --wait cd \
|
||||
--set git.url=git@github.com:stefanprodan/podinfo \
|
||||
--set git.path=deploy/auto-scaling \
|
||||
--namespace flux \
|
||||
./charts/weave-flux
|
||||
```
|
||||
|
||||
## Upgrade
|
||||
|
||||
Update Weave Flux version with:
|
||||
|
||||
```console
|
||||
helm upgrade --reuse-values cd \
|
||||
--set image.tag=1.2.6 \
|
||||
./charts/weave-flux
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "weave-flux.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get svc -w {{ template "weave-flux.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "weave-flux.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "weave-flux.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl -n {{ .Release.Namespace }} port-forward $POD_NAME 8080:3030
|
||||
{{- end }}
|
||||
|
||||
2. Get the Git deploy key by running these commands:
|
||||
export FLUX_POD=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "weave-flux.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl -n {{ .Release.Namespace }} logs $FLUX_POD | grep identity.pub | cut -d '"' -f2 | sed 's/.\{2\}$//'
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
serviceAccountName: {{ template "weave-flux.serviceAccountName" . }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: git-key
|
||||
secret:
|
||||
secretName: {{ template "weave-flux.fullname" . }}-git-deploy
|
||||
defaultMode: 0400
|
||||
- name: git-keygen
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3030
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: git-key
|
||||
mountPath: /etc/fluxd/ssh
|
||||
readOnly: true
|
||||
- name: git-keygen
|
||||
mountPath: /var/fluxd/keygen
|
||||
args:
|
||||
- --ssh-keygen-dir=/var/fluxd/keygen
|
||||
- --k8s-secret-name={{ template "weave-flux.fullname" . }}-git-deploy
|
||||
- --memcached-hostname={{ template "weave-flux.fullname" . }}-memcached
|
||||
- --git-url={{ .Values.git.url }}
|
||||
- --git-branch={{ .Values.git.branch }}
|
||||
- --git-path={{ .Values.git.path }}
|
||||
- --git-user={{ .Values.git.user }}
|
||||
- --git-email={{ .Values.git.email }}
|
||||
- --git-poll-interval={{ .Values.git.pollInterval }}
|
||||
- --sync-interval={{ .Values.git.pollInterval }}
|
||||
{{- if .Values.token }}
|
||||
- --connect=wss://cloud.weave.works/api/flux
|
||||
- --token={{ .Values.token }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,19 +0,0 @@
|
||||
{{- if .Values.helmOperator.create -}}
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: fluxhelmreleases.helm.integrations.flux.weave.works
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
group: helm.integrations.flux.weave.works
|
||||
names:
|
||||
kind: FluxHelmRelease
|
||||
listKind: FluxHelmReleaseList
|
||||
plural: fluxhelmreleases
|
||||
scope: Namespaced
|
||||
version: v1alpha2
|
||||
{{- end -}}
|
||||
@@ -1,43 +0,0 @@
|
||||
{{- if .Values.helmOperator.create -}}
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}-helm-operator
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}-helm-operator
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "weave-flux.name" . }}-helm-operator
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}-helm-operator
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
serviceAccountName: {{ template "weave-flux.serviceAccountName" . }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: git-key
|
||||
secret:
|
||||
secretName: {{ template "weave-flux.fullname" . }}-git-deploy
|
||||
defaultMode: 0400
|
||||
containers:
|
||||
- name: flux-helm-operator
|
||||
image: "{{ .Values.helmOperator.repository }}:{{ .Values.helmOperator.tag }}"
|
||||
imagePullPolicy: {{ .Values.helmOperator.pullPolicy }}
|
||||
volumeMounts:
|
||||
- name: git-key
|
||||
mountPath: /etc/fluxd/ssh
|
||||
readOnly: true
|
||||
args:
|
||||
- --git-url={{ .Values.git.url }}
|
||||
- --git-branch={{ .Values.git.branch }}
|
||||
- --git-charts-path={{ .Values.git.chartsPath }}
|
||||
{{- end -}}
|
||||
@@ -1,54 +0,0 @@
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}-memcached
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}-memcached
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "weave-flux.name" . }}-memcached
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}-memcached
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
containers:
|
||||
- name: memcached
|
||||
image: memcached:1.4.25
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- -m 64 # Maximum memory to use, in megabytes. 64MB is default.
|
||||
- -p 11211 # Default port, but being explicit is nice.
|
||||
- -vv # This gets us to the level of request logs.
|
||||
ports:
|
||||
- name: memcached
|
||||
containerPort: 11211
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}-memcached
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}-memcached
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: 11211
|
||||
targetPort: memcached
|
||||
protocol: TCP
|
||||
name: memcached
|
||||
selector:
|
||||
app: {{ template "weave-flux.name" . }}-memcached
|
||||
release: {{ .Release.Name }}
|
||||
@@ -1,40 +0,0 @@
|
||||
{{- if .Values.rbac.create -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ template "weave-flux.fullname" . }}
|
||||
subjects:
|
||||
- name: {{ template "weave-flux.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
kind: ServiceAccount
|
||||
{{- end -}}
|
||||
@@ -1,5 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}-git-deploy
|
||||
type: Opaque
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "weave-flux.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
@@ -1,11 +0,0 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ template "weave-flux.serviceAccountName" . }}
|
||||
labels:
|
||||
app: {{ template "weave-flux.name" . }}
|
||||
chart: {{ template "weave-flux.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
@@ -1,64 +0,0 @@
|
||||
# Default values for weave-flux.
|
||||
|
||||
# Weave Cloud service token
|
||||
token: ""
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: quay.io/weaveworks/flux
|
||||
tag: 1.3.0
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 3030
|
||||
|
||||
helmOperator:
|
||||
create: false
|
||||
repository: quay.io/weaveworks/helm-operator
|
||||
tag: 0.1.0-alpha
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
rbac:
|
||||
# Specifies whether RBAC resources should be created
|
||||
create: true
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name:
|
||||
|
||||
resources: {}
|
||||
# If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
git:
|
||||
# URL of git repo with Kubernetes manifests; e.g. git@github.com:weaveworks/flux-example
|
||||
url: ""
|
||||
# Branch of git repo to use for Kubernetes manifests
|
||||
branch: "master"
|
||||
# Path within git repo to locate Kubernetes manifests (relative path)
|
||||
path: ""
|
||||
# Username to use as git committer
|
||||
user: "Weave Flux"
|
||||
# Email to use as git committer
|
||||
email: "support@weave.works"
|
||||
# Path within git repo to locate Helm charts (relative path)
|
||||
chartsPath: "charts"
|
||||
# Period at which to poll git repo for new commits
|
||||
pollInterval: "30s"
|
||||
@@ -2,6 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
stdlog "log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@@ -12,26 +15,100 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
port string
|
||||
debug bool
|
||||
port string
|
||||
debug bool
|
||||
logLevel string
|
||||
stressCPU int
|
||||
stressMemory int
|
||||
stressMemoryPayload []byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&port, "port", "9898", "Port to listen on.")
|
||||
flag.BoolVar(&debug, "debug", false, "sets log level to debug")
|
||||
flag.StringVar(&logLevel, "logLevel", "debug", "sets log level as debug, info, warn, error, flat or panic ")
|
||||
flag.IntVar(&stressCPU, "stressCPU", 0, "Number of CPU cores with 100% load")
|
||||
flag.IntVar(&stressMemory, "stressMemory", 0, "MB of data to load into memory")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
if debug {
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
}
|
||||
setLogging()
|
||||
|
||||
log.Info().Msgf("Starting podinfo version %s commit %s", version.VERSION, version.GITCOMMIT)
|
||||
log.Debug().Msgf("Starting HTTP server on port %v", port)
|
||||
|
||||
stopCh := signals.SetupSignalHandler()
|
||||
beginStressTest(stressCPU, stressMemory)
|
||||
server.ListenAndServe(port, 5*time.Second, stopCh)
|
||||
}
|
||||
|
||||
func setLogging() {
|
||||
// set global log level
|
||||
switch logLevel {
|
||||
case "debug":
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
case "info":
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
case "warn":
|
||||
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
||||
case "error":
|
||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
||||
case "fatal":
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
case "panic":
|
||||
zerolog.SetGlobalLevel(zerolog.PanicLevel)
|
||||
default:
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
}
|
||||
|
||||
// keep for backwards compatibility
|
||||
if debug {
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
}
|
||||
|
||||
// set zerolog as standard logger
|
||||
stdlog.SetFlags(0)
|
||||
stdlog.SetOutput(log.Logger)
|
||||
}
|
||||
|
||||
func beginStressTest(cpus int, mem int) {
|
||||
done := make(chan int)
|
||||
if cpus > 0 {
|
||||
log.Info().Msgf("Starting CPU stress, %v core(s)", cpus)
|
||||
for i := 0; i < cpus; i++ {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
if mem > 0 {
|
||||
path := "/tmp/podinfo.data"
|
||||
f, err := os.Create(path)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Memory stress failed")
|
||||
}
|
||||
|
||||
if err := f.Truncate(1000000 * int64(mem)); err != nil {
|
||||
log.Error().Err(err).Msgf("Memory stress failed")
|
||||
}
|
||||
|
||||
stressMemoryPayload, err = ioutil.ReadFile(path)
|
||||
f.Close()
|
||||
os.Remove(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Memory stress failed")
|
||||
}
|
||||
log.Info().Msgf("Starting memory stress, size %v", len(stressMemoryPayload))
|
||||
}
|
||||
}
|
||||
|
||||
28
deploy/istio-system/gateway.yaml
Normal file
28
deploy/istio-system/gateway.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: public-gateway
|
||||
namespace: istio-system
|
||||
spec:
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- port:
|
||||
number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
httpsRedirect: true
|
||||
- port:
|
||||
number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
mode: SIMPLE
|
||||
privateKey: /etc/istio/ingressgateway-certs/tls.key
|
||||
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
|
||||
17
deploy/istio-system/grafana-virtual-service.yaml
Normal file
17
deploy/istio-system/grafana-virtual-service.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: istio-system
|
||||
spec:
|
||||
hosts:
|
||||
- "grafana.istio.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: grafana
|
||||
timeout: 30s
|
||||
|
||||
17
deploy/istio-system/grafanax-virtual-service.yaml
Normal file
17
deploy/istio-system/grafanax-virtual-service.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: grafanax
|
||||
namespace: istio-system
|
||||
spec:
|
||||
hosts:
|
||||
- "grafanax.istio.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: grafanax
|
||||
timeout: 30s
|
||||
|
||||
17
deploy/istio-system/jaeger-virtual-service.yaml
Normal file
17
deploy/istio-system/jaeger-virtual-service.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: jaeger
|
||||
namespace: istio-system
|
||||
spec:
|
||||
hosts:
|
||||
- "jaeger.istio.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: jaeger-query
|
||||
timeout: 30s
|
||||
|
||||
14
deploy/istio/backend-destination-rule.yaml
Normal file
14
deploy/istio/backend-destination-rule.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: podinfo-backend
|
||||
spec:
|
||||
host: podinfo-backend
|
||||
subsets:
|
||||
- name: grey
|
||||
labels:
|
||||
color: grey
|
||||
- name: orange
|
||||
labels:
|
||||
color: orange
|
||||
64
deploy/istio/backend-grey-dep.yaml
Normal file
64
deploy/istio/backend-grey-dep.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo-backend-grey
|
||||
labels:
|
||||
app: podinfo-backend
|
||||
color: grey
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo-backend
|
||||
color: grey
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo-backend
|
||||
color: grey
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 3
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "grey"
|
||||
- name: message
|
||||
value: "Greetings from backend grey"
|
||||
- name: backendURL
|
||||
value: "http://podinfo-store:9898/echo" #"https://httpbin.org/anything"
|
||||
64
deploy/istio/backend-orange-dep.yaml
Normal file
64
deploy/istio/backend-orange-dep.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo-backend-orange
|
||||
labels:
|
||||
app: podinfo-backend
|
||||
color: orange
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo-backend
|
||||
color: orange
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo-backend
|
||||
color: orange
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 3
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "orange"
|
||||
- name: message
|
||||
value: "Greetings from backend orange"
|
||||
- name: backendURL
|
||||
value: "http://podinfo-store:9898/echo" #"https://httpbin.org/anything"
|
||||
15
deploy/istio/backend-svc.yaml
Normal file
15
deploy/istio/backend-svc.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: podinfo-backend
|
||||
labels:
|
||||
app: podinfo-backend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 9898
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: podinfo-backend
|
||||
29
deploy/istio/backend-virtual-service.yaml
Normal file
29
deploy/istio/backend-virtual-service.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: podinfo-backend
|
||||
spec:
|
||||
hosts:
|
||||
- podinfo-backend
|
||||
http:
|
||||
# new version
|
||||
# forward 100% of the traffic to orange
|
||||
- match:
|
||||
# - headers:
|
||||
# x-api-version:
|
||||
# regex: "^(v{0,1})0\\.6\\.([0-9]{1,3}).*"
|
||||
- sourceLabels:
|
||||
color: blue
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo-backend
|
||||
subset: orange
|
||||
timeout: 20s
|
||||
# default route
|
||||
# forward 100% of the traffic to grey
|
||||
- route:
|
||||
- destination:
|
||||
host: podinfo-backend
|
||||
subset: grey
|
||||
timeout: 20s
|
||||
65
deploy/istio/blue-dep.yaml
Normal file
65
deploy/istio/blue-dep.yaml
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo-blue
|
||||
labels:
|
||||
app: podinfo
|
||||
color: blue
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo
|
||||
color: blue
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 3
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
initialDelaySeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "blue"
|
||||
- name: message
|
||||
value: "Greetings from podinfo blue"
|
||||
- name: backendURL
|
||||
value: "http://podinfo-backend:9898/backend"
|
||||
14
deploy/istio/frontend-destination-rule.yaml
Normal file
14
deploy/istio/frontend-destination-rule.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
host: podinfo
|
||||
subsets:
|
||||
- name: blue
|
||||
labels:
|
||||
color: blue
|
||||
- name: green
|
||||
labels:
|
||||
color: green
|
||||
15
deploy/istio/frontend-svc.yaml
Normal file
15
deploy/istio/frontend-svc.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: podinfo
|
||||
labels:
|
||||
app: podinfo
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 9898
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: podinfo
|
||||
82
deploy/istio/frontend-virtual-service.yaml
Normal file
82
deploy/istio/frontend-virtual-service.yaml
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: podinfo
|
||||
spec:
|
||||
hosts:
|
||||
- "podinfo.istio.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
# Opera: forward 100% of the traffic to green
|
||||
- match:
|
||||
- headers:
|
||||
user-agent:
|
||||
regex: ".*OPR.*"
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: green
|
||||
timeout: 30s
|
||||
# Chrome: 50/50 load balancing between blue and green
|
||||
- match:
|
||||
- headers:
|
||||
user-agent:
|
||||
regex: ".*Chrome.*"
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: blue
|
||||
weight: 50
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: green
|
||||
weight: 50
|
||||
timeout: 30s
|
||||
# Safari: 70/30 load balancing between blue and green
|
||||
- match:
|
||||
- headers:
|
||||
user-agent:
|
||||
regex: "^(?!.*Chrome).*Safari.*"
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: blue
|
||||
weight: 100
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: green
|
||||
weight: 0
|
||||
timeout: 30s
|
||||
# Route based on color header
|
||||
- match:
|
||||
- headers:
|
||||
x-color:
|
||||
exact: "blue"
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: blue
|
||||
timeout: 30s
|
||||
retries:
|
||||
attempts: 3
|
||||
perTryTimeout: 3s
|
||||
- match:
|
||||
- headers:
|
||||
x-color:
|
||||
exact: "green"
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: green
|
||||
timeout: 30s
|
||||
retries:
|
||||
attempts: 3
|
||||
perTryTimeout: 3s
|
||||
# Any other browser: forward 100% of the traffic to blue
|
||||
- route:
|
||||
- destination:
|
||||
host: podinfo
|
||||
subset: blue
|
||||
timeout: 35s
|
||||
68
deploy/istio/green-dep.yaml
Normal file
68
deploy/istio/green-dep.yaml
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo-green
|
||||
labels:
|
||||
app: podinfo
|
||||
color: green
|
||||
spec:
|
||||
replicas: 3
|
||||
minReadySeconds: 15
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo
|
||||
color: green
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo
|
||||
color: green
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 4
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 2
|
||||
failureThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "green"
|
||||
- name: message
|
||||
value: "Greetings from podinfo green"
|
||||
- name: backendURL
|
||||
value: "http://podinfo-backend:9898/backend"
|
||||
15
deploy/istio/httpbin-service-entry.yaml
Normal file
15
deploy/istio/httpbin-service-entry.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: ServiceEntry
|
||||
metadata:
|
||||
name: httpbin
|
||||
spec:
|
||||
hosts:
|
||||
- httpbin.org
|
||||
ports:
|
||||
- number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
- number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
resolution: DNS
|
||||
62
deploy/istio/store-dep.yaml
Normal file
62
deploy/istio/store-dep.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo-store
|
||||
labels:
|
||||
app: podinfo-store
|
||||
version: "0.6"
|
||||
spec:
|
||||
replicas: 3
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo-store
|
||||
version: "0.6"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo-store
|
||||
version: "0.6"
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 3
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "yellow"
|
||||
- name: message
|
||||
value: "Greetings from store yellow"
|
||||
15
deploy/istio/store-svc.yaml
Normal file
15
deploy/istio/store-svc.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: podinfo-store
|
||||
labels:
|
||||
app: podinfo-store
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 9898
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: podinfo-store
|
||||
27
deploy/istio/store-virtual-service.yaml
Normal file
27
deploy/istio/store-virtual-service.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: podinfo-store
|
||||
spec:
|
||||
hosts:
|
||||
- podinfo-store
|
||||
http:
|
||||
- match:
|
||||
- sourceLabels:
|
||||
color: orange
|
||||
route:
|
||||
- destination:
|
||||
host: podinfo-store
|
||||
timeout: 15s
|
||||
fault:
|
||||
delay:
|
||||
percent: 50
|
||||
fixedDelay: 500ms
|
||||
abort:
|
||||
percent: 50
|
||||
httpStatus: 500
|
||||
- route:
|
||||
- destination:
|
||||
host: podinfo-store
|
||||
timeout: 15s
|
||||
8
deploy/skaffold/test/basic-auth.yaml
Normal file
8
deploy/skaffold/test/basic-auth.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
basic_auth_password: ODM4NzIwYTUxMjgxNDlkMzJmMTIxYTViMWQ4N2FjMzUwNzAxZThmZQ==
|
||||
basic_auth_test: YWRtaW4=
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: basic-auth
|
||||
type: Opaque
|
||||
79
deploy/skaffold/test/deployment.yaml
Normal file
79
deploy/skaffold/test/deployment.yaml
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: podinfo
|
||||
labels:
|
||||
app: podinfo
|
||||
spec:
|
||||
replicas: 3
|
||||
minReadySeconds: 15
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
maxSurge: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: podinfo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: podinfo
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: quay.io/stefanprodan/podinfo:0.6.0
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- sleep 3
|
||||
command:
|
||||
- ./podinfo
|
||||
- -port=9898
|
||||
- -logLevel=debug
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9898
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 2
|
||||
failureThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 9898
|
||||
initialDelaySeconds: 1
|
||||
periodSeconds: 10
|
||||
failureThreshold: 2
|
||||
resources:
|
||||
requests:
|
||||
memory: "32Mi"
|
||||
cpu: "10m"
|
||||
env:
|
||||
- name: color
|
||||
value: "blue"
|
||||
- name: message
|
||||
value: "Greetings from podinfo blue"
|
||||
- name: backendURL
|
||||
value: "http://podinfo-backend:9898/echo"
|
||||
- name: configPath
|
||||
value: "/var/secrets"
|
||||
volumeMounts:
|
||||
- name: auth
|
||||
readOnly: true
|
||||
mountPath: "/var/secrets"
|
||||
volumes:
|
||||
- name: auth
|
||||
secret:
|
||||
secretName: basic-auth
|
||||
15
deploy/skaffold/test/service.yaml
Normal file
15
deploy/skaffold/test/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: podinfo
|
||||
labels:
|
||||
app: podinfo
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- port: 9898
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: podinfo
|
||||
108
docs/index.yaml
108
docs/index.yaml
@@ -3,7 +3,7 @@ entries:
|
||||
ambassador:
|
||||
- apiVersion: v1
|
||||
appVersion: 0.29.0
|
||||
created: 2018-05-10T11:55:31.454625986+03:00
|
||||
created: 2018-08-17T18:44:47.405027259+03:00
|
||||
description: A Helm chart for Datawire Ambassador
|
||||
digest: a30c8cb38e696b09fda8269ad8465ce6fec6100cfc108ca85ecbc85913ca5c7f
|
||||
engine: gotpl
|
||||
@@ -19,17 +19,27 @@ entries:
|
||||
grafana:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-05-10T11:55:31.455693067+03:00
|
||||
created: 2018-08-17T18:44:47.405800273+03:00
|
||||
description: A Helm chart for Kubernetes
|
||||
digest: abdcadc5cddcb7c015aa5bb64e59bfa246774ad9243b3eb3c2a814abb38f2776
|
||||
name: grafana
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/grafana-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
loadtest:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-08-17T18:44:47.406037468+03:00
|
||||
description: Hey load test Helm chart for Kubernetes
|
||||
digest: fd3c3cd1eafa9d496250356aa52de1430f3467535fc2972eba5c5c392714eb1f
|
||||
name: loadtest
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/loadtest-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
ngrok:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-05-10T11:55:31.456078781+03:00
|
||||
created: 2018-08-17T18:44:47.406355266+03:00
|
||||
description: A Ngrok Helm chart for Kubernetes
|
||||
digest: 7bf5ed2ef63ccd5efb76bcd9a086b04816a162c51d6ab592bccf58c283acd2ea
|
||||
name: ngrok
|
||||
@@ -37,9 +47,57 @@ entries:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/ngrok-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
podinfo:
|
||||
- apiVersion: v1
|
||||
appVersion: 0.6.0
|
||||
created: 2018-08-17T18:44:47.410049875+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: bd25a710eddb3985d3bd921a11022b5c68a04d37cf93a1a4aab17eeda35aa2f8
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-0.2.2.tgz
|
||||
version: 0.2.2
|
||||
- apiVersion: v1
|
||||
appVersion: 0.5.1
|
||||
created: 2018-08-17T18:44:47.409648714+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 631ca3e2db5553541a50b625f538e6a1f2a103c13aa8148fdd38baf2519e5235
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-0.2.1.tgz
|
||||
version: 0.2.1
|
||||
- apiVersion: v1
|
||||
appVersion: 0.5.0
|
||||
created: 2018-08-17T18:44:47.408857715+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: dfe7cf44aef0d170549918b00966422a07e7611f9d0081fb34f5b5beb0641c00
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-0.2.0.tgz
|
||||
version: 0.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 0.3.0
|
||||
created: 2018-05-10T11:55:31.456571425+03:00
|
||||
created: 2018-08-17T18:44:47.407706617+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 4865a2d8b269cf453935cda9661c2efb82c16411471f8c11221a6d03d9bb58b1
|
||||
engine: gotpl
|
||||
@@ -53,41 +111,21 @@ entries:
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
weave-flux:
|
||||
podinfo-istio:
|
||||
- apiVersion: v1
|
||||
appVersion: 1.3.0
|
||||
created: 2018-05-10T11:55:31.457640563+03:00
|
||||
description: Flux is a tool that automatically ensures that the state of a cluster
|
||||
matches what is specified in version control
|
||||
digest: 1f52e427bb1d728641405f5ad9c514e8861905c110c14db95516629d24443b7d
|
||||
appVersion: 0.6.0
|
||||
created: 2018-08-17T18:44:47.410653895+03:00
|
||||
description: Podinfo Helm chart for Istio
|
||||
digest: 79d9cbe4ba8b83ced977d895e56c1223d1fcd88a15f2df1981365c39cf6f4de7
|
||||
engine: gotpl
|
||||
home: https://weave.works
|
||||
icon: https://landscape.cncf.io/logos/weave-flux.svg
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefan@weave.works
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: weave-flux
|
||||
name: podinfo-istio
|
||||
sources:
|
||||
- https://github.com/weaveworks/flux
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/weave-flux-0.2.0.tgz
|
||||
version: 0.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.2.5
|
||||
created: 2018-05-10T11:55:31.457125049+03:00
|
||||
description: Flux is a tool that automatically ensures that the state of a cluster
|
||||
matches what is specified in version control
|
||||
digest: 9e18fb8d175f4fac3b054905c7110d18b6d18f884011df9e9d010c66337da7ec
|
||||
engine: gotpl
|
||||
home: https://weave.works
|
||||
icon: https://www.weave.works/assets/images/bltd108e8f850ae9e7c/weave-logo-512.png
|
||||
maintainers:
|
||||
- email: stefan@weave.works
|
||||
name: Stefan Prodan
|
||||
name: weave-flux
|
||||
sources:
|
||||
- https://github.com/weaveworks/flux
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/weave-flux-0.1.0.tgz
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-istio-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
generated: 2018-05-10T11:55:31.453916675+03:00
|
||||
generated: 2018-08-17T18:44:47.404359545+03:00
|
||||
|
||||
BIN
docs/loadtest-0.1.0.tgz
Normal file
BIN
docs/loadtest-0.1.0.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-0.2.0.tgz
Normal file
BIN
docs/podinfo-0.2.0.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-0.2.1.tgz
Normal file
BIN
docs/podinfo-0.2.1.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-0.2.2.tgz
Normal file
BIN
docs/podinfo-0.2.2.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-istio-0.1.0.tgz
Normal file
BIN
docs/podinfo-istio-0.1.0.tgz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
112
pkg/fscache/fscache.go
Normal file
112
pkg/fscache/fscache.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package fscache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
type Watcher struct {
|
||||
dir string
|
||||
fswatcher *fsnotify.Watcher
|
||||
Cache *sync.Map
|
||||
}
|
||||
|
||||
// NewWatch creates a directory watcher and
|
||||
// updates the cache when any file changes in that dir
|
||||
func NewWatch(dir string) (*Watcher, error) {
|
||||
if len(dir) < 1 {
|
||||
return nil, errors.New("directory is empty")
|
||||
}
|
||||
|
||||
fw, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
dir: dir,
|
||||
fswatcher: fw,
|
||||
Cache: new(sync.Map),
|
||||
}
|
||||
|
||||
log.Printf("fscache start watcher for %s", w.dir)
|
||||
err = w.fswatcher.Add(w.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// initial read
|
||||
err = w.updateCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Watch watches for when kubelet updates the volume mount content
|
||||
func (w *Watcher) Watch() {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
// it can take up to a 2 minutes for kubelet to recreate the ..data symlink
|
||||
case event := <-w.fswatcher.Events:
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
if filepath.Base(event.Name) == "..data" {
|
||||
err := w.updateCache()
|
||||
if err != nil {
|
||||
log.Printf("fscache update error %v", err)
|
||||
} else {
|
||||
log.Printf("fscache reload %s", w.dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
case err := <-w.fswatcher.Errors:
|
||||
log.Printf("fswatcher %s error %v", w.dir, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// updateCache reads files content and loads them into the cache
|
||||
func (w *Watcher) updateCache() error {
|
||||
fileMap := make(map[string]string)
|
||||
files, err := ioutil.ReadDir(w.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// read files ignoring symlinks and sub directories
|
||||
for _, file := range files {
|
||||
name := filepath.Base(file.Name())
|
||||
if !file.IsDir() && !strings.Contains(name, "..") {
|
||||
b, err := ioutil.ReadFile(filepath.Join(w.dir, file.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileMap[name] = string(b)
|
||||
}
|
||||
}
|
||||
|
||||
// remove deleted files from cache
|
||||
w.Cache.Range(func(key interface{}, value interface{}) bool {
|
||||
_, ok := fileMap[key.(string)]
|
||||
if !ok {
|
||||
w.Cache.Delete(key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// sync cache
|
||||
for k, v := range fileMap {
|
||||
w.Cache.Store(k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
178
pkg/server/api.go
Normal file
178
pkg/server/api.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stefanprodan/k8s-podinfo/pkg/version"
|
||||
)
|
||||
|
||||
func (s *Server) apiInfo(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/info" && r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
host, _ := os.Hostname()
|
||||
color := os.Getenv("color")
|
||||
if len(color) < 1 {
|
||||
color = "blue"
|
||||
}
|
||||
|
||||
msg := os.Getenv("message")
|
||||
if len(msg) < 1 {
|
||||
msg = fmt.Sprintf("Greetings from podinfo v%v", version.VERSION)
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Message string `json:"message"`
|
||||
Version string `json:"version"`
|
||||
Revision string `json:"revision"`
|
||||
Hostname string `json:"hostname"`
|
||||
Color string `json:"color"`
|
||||
}{
|
||||
Message: msg,
|
||||
Version: version.VERSION,
|
||||
Revision: version.GITCOMMIT,
|
||||
Hostname: host,
|
||||
Color: color,
|
||||
}
|
||||
|
||||
d, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(d)
|
||||
}
|
||||
|
||||
func (s *Server) apiEcho(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/echo" && r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Reading the request body failed: %v", err)
|
||||
jsonError(w, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
backendURL := os.Getenv("backendURL")
|
||||
if len(backendURL) > 0 {
|
||||
backendReq, err := http.NewRequest("POST", backendURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("%v backend call failed", r.URL.Path)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// forward headers
|
||||
copyTracingHeaders(r, backendReq)
|
||||
setVersionHeaders(backendReq)
|
||||
|
||||
// TODO: make the timeout configurable
|
||||
ctx, cancel := context.WithTimeout(backendReq.Context(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// call backend
|
||||
resp, err := http.DefaultClient.Do(backendReq.WithContext(ctx))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("backend call to %s failed", backendURL)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
// copy error status from backend and exit
|
||||
if resp.StatusCode >= 400 {
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// forward the received body
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("%v reading the backend request body failed", r.URL.Path)
|
||||
jsonError(w, "backend call failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// set logLevel=info when load testing
|
||||
log.Debug().Msgf("Payload received %v from backend: %s", r.URL.Path, string(rbody))
|
||||
|
||||
setResponseHeaders(w)
|
||||
w.Write(rbody)
|
||||
} else {
|
||||
setResponseHeaders(w)
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
||||
|
||||
func copyTracingHeaders(from *http.Request, to *http.Request) {
|
||||
headers := []string{
|
||||
"x-request-id",
|
||||
"x-b3-traceid",
|
||||
"x-b3-spanid",
|
||||
"x-b3-parentspanid",
|
||||
"x-b3-sampled",
|
||||
"x-b3-flags",
|
||||
"x-ot-span-context",
|
||||
}
|
||||
|
||||
for i := range headers {
|
||||
headerValue := from.Header.Get(headers[i])
|
||||
if len(headerValue) > 0 {
|
||||
to.Header.Set(headers[i], headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setVersionHeaders(r *http.Request) {
|
||||
r.Header.Set("X-API-Version", version.VERSION)
|
||||
r.Header.Set("X-API-Revision", version.GITCOMMIT)
|
||||
}
|
||||
|
||||
func setResponseHeaders(w http.ResponseWriter) {
|
||||
color := os.Getenv("color")
|
||||
if len(color) < 1 {
|
||||
color = "blue"
|
||||
}
|
||||
w.Header().Set("X-Color", color)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func jsonError(w http.ResponseWriter, error string, code int) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
|
||||
data := struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}{
|
||||
Code: code,
|
||||
Message: error,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("jsonError marshal failed")
|
||||
} else {
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,12 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -23,23 +25,50 @@ func (s *Server) index(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := makeResponse()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
log.Debug().Msgf("Request %s received from %s on %s", r.Header.Get("x-request-id"), r.RemoteAddr, r.RequestURI)
|
||||
|
||||
if strings.Contains(r.UserAgent(), "Mozilla") {
|
||||
uiPath := os.Getenv("uiPath")
|
||||
if len(uiPath) < 1 {
|
||||
uiPath = "ui"
|
||||
}
|
||||
tmpl, err := template.New("vue.html").ParseFiles(path.Join(uiPath, "vue.html"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(path.Join(uiPath, "vue.html") + err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
host, _ := os.Hostname()
|
||||
data := struct {
|
||||
Title string
|
||||
}{
|
||||
Title: host,
|
||||
}
|
||||
|
||||
if err := tmpl.Execute(w, data); err != nil {
|
||||
http.Error(w, path.Join(uiPath, "vue.html")+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
} else {
|
||||
resp, err := makeResponse()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
d, err := yaml.Marshal(resp)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(d)
|
||||
}
|
||||
|
||||
d, err := yaml.Marshal(resp)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(d)
|
||||
}
|
||||
|
||||
func (s *Server) echo(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -86,9 +115,21 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
backendURL := os.Getenv("backend_url")
|
||||
backendURL := os.Getenv("backendURL")
|
||||
if len(backendURL) > 0 {
|
||||
resp, err := http.Post(backendURL, r.Header.Get("Content-type"), bytes.NewReader(body))
|
||||
backendReq, err := http.NewRequest("POST", backendURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Error().Msgf("Backend call failed: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// forward tracing headers
|
||||
copyTracingHeaders(r, backendReq)
|
||||
setVersionHeaders(backendReq)
|
||||
|
||||
resp, err := http.DefaultClient.Do(backendReq)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Backend call failed: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -96,6 +137,10 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 500 {
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
return
|
||||
}
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Reading the backend request body failed: %v", err)
|
||||
@@ -104,11 +149,12 @@ func (s *Server) backend(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
log.Debug().Msgf("Payload received from backend: %s", string(rbody))
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
|
||||
setResponseHeaders(w)
|
||||
w.Write(rbody)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("Backend not specified, set backend_url env var"))
|
||||
w.Write([]byte("Backend not specified, set backendURL env var"))
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotAcceptable)
|
||||
@@ -205,6 +251,33 @@ func (s *Server) read(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) configs(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
files := make(map[string]string)
|
||||
if watcher != nil {
|
||||
watcher.Cache.Range(func(key interface{}, value interface{}) bool {
|
||||
files[key.(string)] = value.(string)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
d, err := yaml.Marshal(files)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(d)
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotAcceptable)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) version(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/version" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
|
||||
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -99,7 +100,7 @@ func runtimeToMap() map[string]string {
|
||||
"max_procs": strconv.FormatInt(int64(runtime.GOMAXPROCS(0)), 10),
|
||||
"num_goroutine": strconv.FormatInt(int64(runtime.NumGoroutine()), 10),
|
||||
"num_cpu": strconv.FormatInt(int64(runtime.NumCPU()), 10),
|
||||
"external_ip": findIp("http://api.ipify.org"),
|
||||
"external_ip": findIp("http://httpbin.org/ip"),
|
||||
}
|
||||
return info
|
||||
}
|
||||
@@ -117,7 +118,7 @@ func findIp(url string) string {
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(errors.Wrapf(err, "cannot connect to %s", url)).Msg("ipify timeout")
|
||||
log.Error().Err(errors.Wrapf(err, "cannot connect to %s", url)).Msg("timeout")
|
||||
return ip
|
||||
}
|
||||
|
||||
@@ -129,7 +130,12 @@ func findIp(url string) string {
|
||||
if err != nil {
|
||||
return ip
|
||||
}
|
||||
return string(contents)
|
||||
jsonMap := make(map[string]string)
|
||||
err = json.Unmarshal([]byte(contents), &jsonMap)
|
||||
if err != nil {
|
||||
return ip
|
||||
}
|
||||
return jsonMap["origin"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stefanprodan/k8s-podinfo/pkg/fscache"
|
||||
)
|
||||
|
||||
var (
|
||||
healthy int32
|
||||
ready int32
|
||||
dataPath string
|
||||
watcher *fscache.Watcher
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -24,6 +26,7 @@ type Server struct {
|
||||
}
|
||||
|
||||
func NewServer(options ...func(*Server)) *Server {
|
||||
|
||||
s := &Server{mux: http.NewServeMux()}
|
||||
|
||||
for _, f := range options {
|
||||
@@ -43,6 +46,7 @@ func NewServer(options ...func(*Server)) *Server {
|
||||
s.mux.HandleFunc("/write", s.write)
|
||||
s.mux.HandleFunc("/error", s.error)
|
||||
s.mux.HandleFunc("/panic", s.panic)
|
||||
s.mux.HandleFunc("/configs", s.configs)
|
||||
s.mux.HandleFunc("/version", s.version)
|
||||
s.mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
@@ -53,6 +57,10 @@ func NewServer(options ...func(*Server)) *Server {
|
||||
s.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
s.mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
// API
|
||||
s.mux.HandleFunc("/api/info", s.apiInfo)
|
||||
s.mux.HandleFunc("/api/echo", s.apiEcho)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -81,6 +89,18 @@ func ListenAndServe(port string, timeout time.Duration, stopCh <-chan struct{})
|
||||
dataPath = "/data"
|
||||
}
|
||||
|
||||
// config path
|
||||
configPath := os.Getenv("configPath")
|
||||
if len(configPath) > 0 {
|
||||
var err error
|
||||
watcher, err = fscache.NewWatch(configPath)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("%s watch error", configPath)
|
||||
} else {
|
||||
watcher.Watch()
|
||||
}
|
||||
}
|
||||
|
||||
// run server in background
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
@@ -99,6 +119,12 @@ func ListenAndServe(port string, timeout time.Duration, stopCh <-chan struct{})
|
||||
|
||||
log.Info().Msgf("Shutting down HTTP server with timeout: %v", timeout)
|
||||
|
||||
// wait for Kubernetes readiness probe
|
||||
// to remove this instance from the load balancer
|
||||
// the readiness check interval must lower than the timeout
|
||||
time.Sleep(timeout)
|
||||
|
||||
// attempt graceful shutdown
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.Error().Err(err).Msg("HTTP server graceful shutdown failed")
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package version
|
||||
|
||||
var VERSION = "0.4.0"
|
||||
var VERSION = "0.6.1"
|
||||
var GITCOMMIT = "unknown"
|
||||
|
||||
194
ui/vue.html
Normal file
194
ui/vue.html
Normal file
@@ -0,0 +1,194 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.Title}}</title>
|
||||
<meta charset="utf-8">
|
||||
<!-- <meta http-equiv="refresh" content="5"> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link rel="shortcut icon" type="image/png" href="https://kubernetes.io/images/favicon.png">
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
|
||||
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
|
||||
<style>
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" v-cloak>
|
||||
<v-app dark>
|
||||
<v-content>
|
||||
<section>
|
||||
<v-parallax src="#" height="600" :class="info.color">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="white--text"
|
||||
>
|
||||
<img src="https://d33wubrfki0l68.cloudfront.net/33a12d8be0bc50be4738443101616e968c7afb8f/cba76/images/scalable.png" alt="kubernetes" height="200">
|
||||
<h1 class="white--text mb-2 display-1 text-xs-center">${ info.message }</h1>
|
||||
<div class="subheading mb-3 text-xs-center">Served by <b>${ info.hostname }</b></div>
|
||||
<v-btn
|
||||
class="red darken-2 mt-5"
|
||||
dark
|
||||
large
|
||||
@click="postBackend()"
|
||||
>
|
||||
<v-badge left color="red">
|
||||
<span slot="badge">${ pings }</span>
|
||||
<v-icon left dark>touch_app</v-icon>
|
||||
</v-badge>
|
||||
Ping
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</v-parallax>
|
||||
</section>
|
||||
<section>
|
||||
<v-layout
|
||||
column
|
||||
wrap
|
||||
class="my-5"
|
||||
align-center
|
||||
>
|
||||
<v-flex xs12 sm4 class="my-3">
|
||||
<div class="text-xs-center">
|
||||
<h2 class="headline">The best way to start developing</h2>
|
||||
<span class="subheading">
|
||||
stateless microservices with Go for Kubernetes
|
||||
</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<v-container grid-list-xl>
|
||||
<v-layout row wrap align-center>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-0 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large class="blue--text text--lighten-2">cloud</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline text-xs-center">Cloud Native</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Distributed as a Helm chart. Builtin Kubernetes health checks (readiness and liveness).
|
||||
Graceful shutdown on interrupt signals.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-0 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large class="blue--text text--lighten-2">graphic_eq</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline">Observability</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Instrumentation with Prometheus (RED method).
|
||||
Structured logging with zerolog and Fluentd.
|
||||
Tracing with Jaeger and Istio.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
<v-flex xs12 md4>
|
||||
<v-card class="elevation-0 transparent">
|
||||
<v-card-text class="text-xs-center">
|
||||
<v-icon x-large class="blue--text text--lighten-2">flash_on</v-icon>
|
||||
</v-card-text>
|
||||
<v-card-title primary-title class="layout justify-center">
|
||||
<div class="headline text-xs-center">Release automation</div>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
Multi-platform Docker image AMD64 and ARMv7.
|
||||
CI/CD powered by: TravisCI CircleCI Quay.io Google Cloud Container Builder Skaffold Weave Flux.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</section>
|
||||
|
||||
<v-footer class="blue darken-2">
|
||||
<v-layout row wrap align-center>
|
||||
<v-flex xs12>
|
||||
<div class="white--text ml-3">
|
||||
Powered
|
||||
by <a class="white--text" href="https://github.com/stefanprodan/k8s-podinfo" target="_blank">podinfo</a>
|
||||
version ${ info.version } revision ${ info.revision }
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-footer>
|
||||
</v-content>
|
||||
</v-app>
|
||||
</div>
|
||||
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
|
||||
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
|
||||
<script>
|
||||
new Vue({
|
||||
delimiters: ['${', '}'],
|
||||
el: '#app',
|
||||
data: function() {
|
||||
return {
|
||||
info: {},
|
||||
timer: '',
|
||||
color: '',
|
||||
pings: 0
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
this.getInfo();
|
||||
this.timer = setInterval(this.getInfo, 3000)
|
||||
},
|
||||
methods: {
|
||||
getInfo: function() {
|
||||
var xhr = new XMLHttpRequest()
|
||||
var self = this
|
||||
xhr.open('GET', "/api/info")
|
||||
xhr.onload = function () {
|
||||
data = JSON.parse(xhr.responseText)
|
||||
// reload page when the version changes
|
||||
if (self.info.version) {
|
||||
if (self.info.version != data.version) {
|
||||
console.log("New version", data.version)
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
self.info = data
|
||||
document.title = data.hostname
|
||||
}
|
||||
xhr.onerror = function() {
|
||||
console.log(xhr.responseText || 'Network request failed')
|
||||
}
|
||||
xhr.send()
|
||||
},
|
||||
postBackend: function() {
|
||||
var self = this
|
||||
fetch("/api/echo", {
|
||||
method: 'post',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
"X-APP": Math.random(),
|
||||
},
|
||||
body: JSON.stringify({random: Math.random()})
|
||||
})
|
||||
.then(function(response) {
|
||||
self.pings++
|
||||
self.color = response.headers.get('X-Color')
|
||||
return response.json()
|
||||
})
|
||||
.then(function(json) {
|
||||
console.log('Request successful', json);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('Request failed', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
5
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
5
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Setup a Global .gitignore for OS and editor generated files:
|
||||
# https://help.github.com/articles/ignoring-files
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
.vagrant
|
||||
*.sublime-project
|
||||
30
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
30
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
|
||||
before_script:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
|
||||
script:
|
||||
- go test -v --race ./...
|
||||
|
||||
after_script:
|
||||
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
||||
- test -z "$(golint ./... | tee /dev/stderr)"
|
||||
- go vet ./...
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# You can update this list using the following command:
|
||||
#
|
||||
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron L <aaron@bettercoder.net>
|
||||
Adrien Bustany <adrien@bustany.org>
|
||||
Amit Krishnan <amit.krishnan@oracle.com>
|
||||
Anmol Sethi <me@anmol.io>
|
||||
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||
Bruno Bigras <bigras.bruno@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Case Nelson <case@teammating.com>
|
||||
Chris Howey <chris@howey.me> <howeyc@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Daniel Wagner-Hall <dawagner@gmail.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
Evan Phoenix <evan@fallingsnow.net>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
John C Barstow
|
||||
Kelvin Fo <vmirage@gmail.com>
|
||||
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
|
||||
Matt Layher <mdlayher@gmail.com>
|
||||
Nathan Youngman <git@nathany.com>
|
||||
Nickolai Zeldovich <nickolai@csail.mit.edu>
|
||||
Patrick <patrick@dropbox.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pursuit92 <JoshChase@techpursuit.net>
|
||||
Riku Voipio <riku.voipio@linaro.org>
|
||||
Rob Figueiredo <robfig@gmail.com>
|
||||
Rodrigo Chiossi <rodrigochiossi@gmail.com>
|
||||
Slawek Ligus <root@ooz.ie>
|
||||
Soge Zhang <zhssoge@gmail.com>
|
||||
Tiffany Jernigan <tiffany.jernigan@intel.com>
|
||||
Tilak Sharma <tilaks@google.com>
|
||||
Tom Payne <twpayne@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Vahe Khachikyan <vahe@live.ca>
|
||||
Yukang <moorekang@gmail.com>
|
||||
bronze1man <bronze1man@gmail.com>
|
||||
debrando <denis.brandolini@gmail.com>
|
||||
henrikedwards <henrik.edwards@gmail.com>
|
||||
铁哥 <guotie.9@gmail.com>
|
||||
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.7 / 2018-01-09
|
||||
|
||||
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||
* Tests: Fix missing verb on format string (thanks @rchiossi)
|
||||
* Linux: Fix deadlock in Remove (thanks @aarondl)
|
||||
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
|
||||
* Docs: Moved FAQ into the README (thanks @vahe)
|
||||
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
|
||||
* Docs: replace references to OS X with macOS
|
||||
|
||||
## v1.4.2 / 2016-10-10
|
||||
|
||||
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
|
||||
|
||||
## v1.4.1 / 2016-10-04
|
||||
|
||||
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
|
||||
|
||||
## v1.4.0 / 2016-10-01
|
||||
|
||||
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
|
||||
|
||||
## v1.3.1 / 2016-06-28
|
||||
|
||||
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
|
||||
|
||||
## v1.3.0 / 2016-04-19
|
||||
|
||||
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
|
||||
|
||||
## v1.2.10 / 2016-03-02
|
||||
|
||||
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
|
||||
|
||||
## v1.2.9 / 2016-01-13
|
||||
|
||||
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
|
||||
|
||||
## v1.2.8 / 2015-12-17
|
||||
|
||||
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
|
||||
* inotify: fix race in test
|
||||
* enable race detection for continuous integration (Linux, Mac, Windows)
|
||||
|
||||
## v1.2.5 / 2015-10-17
|
||||
|
||||
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
|
||||
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
|
||||
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
|
||||
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
|
||||
|
||||
## v1.2.1 / 2015-10-14
|
||||
|
||||
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
|
||||
|
||||
## v1.2.0 / 2015-02-08
|
||||
|
||||
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
|
||||
|
||||
## v1.1.1 / 2015-02-05
|
||||
|
||||
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||
|
||||
## v1.1.0 / 2014-12-12
|
||||
|
||||
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
|
||||
* add low-level functions
|
||||
* only need to store flags on directories
|
||||
* less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
|
||||
* done can be an unbuffered channel
|
||||
* remove calls to os.NewSyscallError
|
||||
* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v1.0.4 / 2014-09-07
|
||||
|
||||
* kqueue: add dragonfly to the build tags.
|
||||
* Rename source code files, rearrange code so exported APIs are at the top.
|
||||
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
|
||||
|
||||
## v1.0.3 / 2014-08-19
|
||||
|
||||
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
|
||||
|
||||
## v1.0.2 / 2014-08-17
|
||||
|
||||
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
|
||||
|
||||
## v1.0.0 / 2014-08-15
|
||||
|
||||
* [API] Remove AddWatch on Windows, use Add.
|
||||
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
|
||||
* Minor updates based on feedback from golint.
|
||||
|
||||
## dev / 2014-07-09
|
||||
|
||||
* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
|
||||
* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
|
||||
|
||||
## dev / 2014-07-04
|
||||
|
||||
* kqueue: fix incorrect mutex used in Close()
|
||||
* Update example to demonstrate usage of Op.
|
||||
|
||||
## dev / 2014-06-28
|
||||
|
||||
* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
|
||||
* Fix for String() method on Event (thanks Alex Brainman)
|
||||
* Don't build on Plan 9 or Solaris (thanks @4ad)
|
||||
|
||||
## dev / 2014-06-21
|
||||
|
||||
* Events channel of type Event rather than *Event.
|
||||
* [internal] use syscall constants directly for inotify and kqueue.
|
||||
* [internal] kqueue: rename events to kevents and fileEvent to event.
|
||||
|
||||
## dev / 2014-06-19
|
||||
|
||||
* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
|
||||
* [internal] remove cookie from Event struct (unused).
|
||||
* [internal] Event struct has the same definition across every OS.
|
||||
* [internal] remove internal watch and removeWatch methods.
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
|
||||
* [API] Pluralized channel names: Events and Errors.
|
||||
* [API] Renamed FileEvent struct to Event.
|
||||
* [API] Op constants replace methods like IsCreate().
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## dev / 2014-05-23
|
||||
|
||||
* [API] Remove current implementation of WatchFlags.
|
||||
* current implementation doesn't take advantage of OS for efficiency
|
||||
* provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
|
||||
* no tests for the current implementation
|
||||
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||
|
||||
## v0.9.3 / 2014-12-31
|
||||
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v0.9.2 / 2014-08-17
|
||||
|
||||
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
|
||||
## v0.9.1 / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## v0.9.0 / 2014-01-17
|
||||
|
||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||
|
||||
## v0.8.12 / 2013-11-13
|
||||
|
||||
* [API] Remove FD_SET and friends from Linux adapter
|
||||
|
||||
## v0.8.11 / 2013-11-02
|
||||
|
||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
|
||||
|
||||
## v0.8.10 / 2013-10-19
|
||||
|
||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||
|
||||
## v0.8.9 / 2013-09-08
|
||||
|
||||
* [Doc] Contributing (thanks @nathany)
|
||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||
|
||||
## v0.8.8 / 2013-06-17
|
||||
|
||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||
|
||||
## v0.8.7 / 2013-06-03
|
||||
|
||||
* [API] Make syscall flags internal
|
||||
* [Fix] inotify: ignore event changes
|
||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||
* [Fix] tests on Windows
|
||||
* lower case error messages
|
||||
|
||||
## v0.8.6 / 2013-05-23
|
||||
|
||||
* kqueue: Use EVT_ONLY flag on Darwin
|
||||
* [Doc] Update README with full example
|
||||
|
||||
## v0.8.5 / 2013-05-09
|
||||
|
||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||
|
||||
## v0.8.4 / 2013-04-07
|
||||
|
||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||
|
||||
## v0.8.3 / 2013-03-13
|
||||
|
||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||
|
||||
## v0.8.2 / 2013-02-07
|
||||
|
||||
* [Doc] add Authors
|
||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||
|
||||
## v0.8.1 / 2013-01-09
|
||||
|
||||
* [Fix] Windows path separators
|
||||
* [Doc] BSD License
|
||||
|
||||
## v0.8.0 / 2012-11-09
|
||||
|
||||
* kqueue: directory watching improvements (thanks @vmirage)
|
||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||
|
||||
## v0.7.4 / 2012-10-09
|
||||
|
||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||
* [Fix] kqueue: modify after recreation of file
|
||||
|
||||
## v0.7.3 / 2012-09-27
|
||||
|
||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||
|
||||
## v0.7.2 / 2012-09-01
|
||||
|
||||
* kqueue: events for created directories
|
||||
|
||||
## v0.7.1 / 2012-07-14
|
||||
|
||||
* [Fix] for renaming files
|
||||
|
||||
## v0.7.0 / 2012-07-02
|
||||
|
||||
* [Feature] FSNotify flags
|
||||
* [Fix] inotify: Added file name back to event path
|
||||
|
||||
## v0.6.0 / 2012-06-06
|
||||
|
||||
* kqueue: watch files after directory created (thanks @tmc)
|
||||
|
||||
## v0.5.1 / 2012-05-22
|
||||
|
||||
* [Fix] inotify: remove all watches before Close()
|
||||
|
||||
## v0.5.0 / 2012-05-03
|
||||
|
||||
* [API] kqueue: return errors during watch instead of sending over channel
|
||||
* kqueue: match symlink behavior on Linux
|
||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||
|
||||
## v0.4.0 / 2012-03-30
|
||||
|
||||
* Go 1 released: build with go tool
|
||||
* [Feature] Windows support using winfsnotify
|
||||
* Windows does not have attribute change notifications
|
||||
* Roll attribute notifications into IsModify
|
||||
|
||||
## v0.3.0 / 2012-02-19
|
||||
|
||||
* kqueue: add files when watch directory
|
||||
|
||||
## v0.2.0 / 2011-12-30
|
||||
|
||||
* update to latest Go weekly code
|
||||
|
||||
## v0.1.0 / 2011-10-19
|
||||
|
||||
* kqueue: add watch on file creation to match inotify
|
||||
* kqueue: create file event
|
||||
* inotify: ignore `IN_IGNORED` events
|
||||
* event String()
|
||||
* linux: common FileEvent functions
|
||||
* initial commit
|
||||
|
||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
||||
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Contributing
|
||||
|
||||
## Issues
|
||||
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||
* Please indicate the platform you are using fsnotify on.
|
||||
* A code example to reproduce the problem is appreciated.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||
|
||||
Please indicate that you have signed the CLA in your pull request.
|
||||
|
||||
### How fsnotify is Developed
|
||||
|
||||
* Development is done on feature branches.
|
||||
* Tests are run on BSD, Linux, macOS and Windows.
|
||||
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||
* To issue a new release, the maintainers will:
|
||||
* Update the CHANGELOG
|
||||
* Tag a version, which will become available through gopkg.in.
|
||||
|
||||
### How to Fork
|
||||
|
||||
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Ensure everything works and the tests pass (see below)
|
||||
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
|
||||
Contribute upstream:
|
||||
|
||||
1. Fork fsnotify on GitHub
|
||||
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||
3. Push to the branch (`git push fork my-new-feature`)
|
||||
4. Create a new Pull Request on GitHub
|
||||
|
||||
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||
|
||||
### Testing
|
||||
|
||||
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user