diff --git a/gloo-gateway/1-17/enterprise-istio-ambient/default/README.md b/gloo-gateway/1-17/enterprise-istio-ambient/default/README.md index be8a4e5d08..51e5c73815 100644 --- a/gloo-gateway/1-17/enterprise-istio-ambient/default/README.md +++ b/gloo-gateway/1-17/enterprise-istio-ambient/default/README.md @@ -969,6 +969,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 5 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -1042,13 +1043,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1125,13 +1119,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4664,13 +4651,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/enterprise-istio-ambient/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/enterprise-istio-ambient/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/enterprise-istio-ambient/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/enterprise-istio-sidecar/default/README.md b/gloo-gateway/1-17/enterprise-istio-sidecar/default/README.md index 047e9ac9df..78c7e997a1 100644 --- a/gloo-gateway/1-17/enterprise-istio-sidecar/default/README.md +++ b/gloo-gateway/1-17/enterprise-istio-sidecar/default/README.md @@ -920,6 +920,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 5 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -992,13 +993,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1075,13 +1069,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4614,13 +4601,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/enterprise-istio-sidecar/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/enterprise-istio-sidecar/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/enterprise-istio-sidecar/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/enterprise-vm/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/enterprise-vm/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/enterprise-vm/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/enterprise/default/README.md b/gloo-gateway/1-17/enterprise/default/README.md index d69bf3905e..b1316c6907 100644 --- a/gloo-gateway/1-17/enterprise/default/README.md +++ b/gloo-gateway/1-17/enterprise/default/README.md @@ -861,6 +861,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 4 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -932,13 +933,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1015,13 +1009,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4554,13 +4541,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/enterprise/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/enterprise/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/enterprise/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/gloo-edge/default/README.md b/gloo-gateway/1-17/gloo-edge/default/README.md index 1701e6827a..69b03cd59a 100644 --- a/gloo-gateway/1-17/gloo-edge/default/README.md +++ b/gloo-gateway/1-17/gloo-edge/default/README.md @@ -2743,6 +2743,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 12 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -2814,13 +2815,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -2897,13 +2891,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -6436,13 +6423,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/gloo-edge/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/gloo-edge/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/gloo-edge/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/gloo-mesh/default/README.md b/gloo-gateway/1-17/gloo-mesh/default/README.md index dd76680b2b..3a5749b4b1 100644 --- a/gloo-gateway/1-17/gloo-mesh/default/README.md +++ b/gloo-gateway/1-17/gloo-mesh/default/README.md @@ -3557,6 +3557,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 21 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -3630,13 +3631,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -3713,13 +3707,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -7252,13 +7239,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/gloo-mesh/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/gloo-mesh/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/gloo-mesh/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/openshift/README.md b/gloo-gateway/1-17/openshift/README.md index 1f0eea45dd..b9772bf9af 100644 --- a/gloo-gateway/1-17/openshift/README.md +++ b/gloo-gateway/1-17/openshift/README.md @@ -1096,6 +1096,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 6 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -1168,13 +1169,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1251,13 +1245,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4799,13 +4786,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/openshift/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/openshift/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/openshift/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/oss-istio-ambient/README.md b/gloo-gateway/1-17/oss-istio-ambient/README.md index ae580dea55..ea9639c66a 100644 --- a/gloo-gateway/1-17/oss-istio-ambient/README.md +++ b/gloo-gateway/1-17/oss-istio-ambient/README.md @@ -293,6 +293,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 4 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -364,13 +365,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -447,13 +441,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -2834,13 +2821,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/oss-istio-ambient/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/oss-istio-ambient/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/oss-istio-ambient/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-17/oss/default/README.md b/gloo-gateway/1-17/oss/default/README.md index c6a5d69663..388589865d 100644 --- a/gloo-gateway/1-17/oss/default/README.md +++ b/gloo-gateway/1-17/oss/default/README.md @@ -202,6 +202,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || ## Lab 3 - Deploy the httpbin demo app + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -273,13 +274,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -356,13 +350,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -2743,13 +2730,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: diff --git a/gloo-gateway/1-17/oss/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-17/oss/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-17/oss/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-18/enterprise-istio-ambient/default/README.md b/gloo-gateway/1-18/enterprise-istio-ambient/default/README.md index 9186ccb81d..b5d8a7c5b0 100644 --- a/gloo-gateway/1-18/enterprise-istio-ambient/default/README.md +++ b/gloo-gateway/1-18/enterprise-istio-ambient/default/README.md @@ -881,7 +881,7 @@ helm repo update helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context $CLUSTER1 \ --set-string license_key=$LICENSE_KEY \ -f -< + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -1053,13 +1054,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1136,13 +1130,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4932,13 +4919,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -7014,7 +6994,7 @@ We can now configure the Gloo Gateway portal backend to use it: helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context ${CLUSTER1} \ --reuse-values \ -f -< setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-18/enterprise-istio-sidecar/default/README.md b/gloo-gateway/1-18/enterprise-istio-sidecar/default/README.md index 13f7836eab..8dfc516ab2 100644 --- a/gloo-gateway/1-18/enterprise-istio-sidecar/default/README.md +++ b/gloo-gateway/1-18/enterprise-istio-sidecar/default/README.md @@ -826,7 +826,7 @@ helm repo update helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context $CLUSTER1 \ --set-string license_key=$LICENSE_KEY \ -f -< + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -1002,13 +1003,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1085,13 +1079,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4881,13 +4868,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -6963,7 +6943,7 @@ We can now configure the Gloo Gateway portal backend to use it: helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context ${CLUSTER1} \ --reuse-values \ -f -< setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-18/enterprise/ai-gateway/README.md b/gloo-gateway/1-18/enterprise/ai-gateway/README.md index 03befb3cc0..b1edb5be12 100644 --- a/gloo-gateway/1-18/enterprise/ai-gateway/README.md +++ b/gloo-gateway/1-18/enterprise/ai-gateway/README.md @@ -142,7 +142,7 @@ helm repo update helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context $CLUSTER1 \ --set-string license_key=$LICENSE_KEY \ -f -< setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-18/enterprise/default/README.md b/gloo-gateway/1-18/enterprise/default/README.md index 703869c8f6..61da976952 100644 --- a/gloo-gateway/1-18/enterprise/default/README.md +++ b/gloo-gateway/1-18/enterprise/default/README.md @@ -21,27 +21,28 @@ source ./scripts/assert.sh * [Lab 4 - Deploy the httpbin demo app](#lab-4---deploy-the-httpbin-demo-app-) * [Lab 5 - Expose the httpbin application through the gateway](#lab-5---expose-the-httpbin-application-through-the-gateway-) * [Lab 6 - Delegate with control](#lab-6---delegate-with-control-) -* [Lab 7 - Modify the requests and responses](#lab-7---modify-the-requests-and-responses-) -* [Lab 8 - Split traffic between 2 backend services](#lab-8---split-traffic-between-2-backend-services-) -* [Lab 9 - Securing the access with OAuth](#lab-9---securing-the-access-with-oauth-) -* [Lab 10 - Use the transformation filter to manipulate headers](#lab-10---use-the-transformation-filter-to-manipulate-headers-) -* [Lab 11 - Apply rate limiting to the Gateway](#lab-11---apply-rate-limiting-to-the-gateway-) -* [Lab 12 - Use the JWT filter to validate JWT and create headers from claims](#lab-12---use-the-jwt-filter-to-validate-jwt-and-create-headers-from-claims-) -* [Lab 13 - Use the Web Application Firewall filter](#lab-13---use-the-web-application-firewall-filter-) -* [Lab 14 - Validate and authorize client certificates](#lab-14---validate-and-authorize-client-certificates-) -* [Lab 15 - Use the `cache-control` response header to cache responses](#lab-15---use-the-`cache-control`-response-header-to-cache-responses-) -* [Lab 16 - Deploy Argo Rollouts](#lab-16---deploy-argo-rollouts-) -* [Lab 17 - Roll out a new app version using Argo Rollouts](#lab-17---roll-out-a-new-app-version-using-argo-rollouts-) -* [Lab 18 - Expose a service through TCP](#lab-18---expose-a-service-through-tcp-) -* [Lab 19 - Deploy the Bookinfo sample application](#lab-19---deploy-the-bookinfo-sample-application-) -* [Lab 20 - Expose the productpage API securely](#lab-20---expose-the-productpage-api-securely-) -* [Lab 21 - Expose an external API and stitch it with the productpage API](#lab-21---expose-an-external-api-and-stitch-it-with-the-productpage-api-) -* [Lab 22 - Expose the dev portal backend](#lab-22---expose-the-dev-portal-backend-) -* [Lab 23 - Deploy and expose the dev portal frontend](#lab-23---deploy-and-expose-the-dev-portal-frontend-) -* [Lab 24 - Demonstrate the self service capabilities](#lab-24---demonstrate-the-self-service-capabilities-) -* [Lab 25 - Dev portal monetization](#lab-25---dev-portal-monetization-) -* [Lab 26 - Deploy Backstage with the backend plugin](#lab-26---deploy-backstage-with-the-backend-plugin-) -* [Lab 27 - Deploy OpenTelemetry Collector](#lab-27---deploy-opentelemetry-collector-) +* [Lab 7 - Direct response](#lab-7---direct-response-) +* [Lab 8 - Modify the requests and responses](#lab-8---modify-the-requests-and-responses-) +* [Lab 9 - Split traffic between 2 backend services](#lab-9---split-traffic-between-2-backend-services-) +* [Lab 10 - Securing the access with OAuth](#lab-10---securing-the-access-with-oauth-) +* [Lab 11 - Use the transformation filter to manipulate headers](#lab-11---use-the-transformation-filter-to-manipulate-headers-) +* [Lab 12 - Apply rate limiting to the Gateway](#lab-12---apply-rate-limiting-to-the-gateway-) +* [Lab 13 - Use the JWT filter to validate JWT and create headers from claims](#lab-13---use-the-jwt-filter-to-validate-jwt-and-create-headers-from-claims-) +* [Lab 14 - Use the Web Application Firewall filter](#lab-14---use-the-web-application-firewall-filter-) +* [Lab 15 - Validate and authorize client certificates](#lab-15---validate-and-authorize-client-certificates-) +* [Lab 16 - Use the `cache-control` response header to cache responses](#lab-16---use-the-`cache-control`-response-header-to-cache-responses-) +* [Lab 17 - Deploy Argo Rollouts](#lab-17---deploy-argo-rollouts-) +* [Lab 18 - Roll out a new app version using Argo Rollouts](#lab-18---roll-out-a-new-app-version-using-argo-rollouts-) +* [Lab 19 - Expose a service through TCP](#lab-19---expose-a-service-through-tcp-) +* [Lab 20 - Deploy the Bookinfo sample application](#lab-20---deploy-the-bookinfo-sample-application-) +* [Lab 21 - Expose the productpage API securely](#lab-21---expose-the-productpage-api-securely-) +* [Lab 22 - Expose an external API and stitch it with the productpage API](#lab-22---expose-an-external-api-and-stitch-it-with-the-productpage-api-) +* [Lab 23 - Expose the dev portal backend](#lab-23---expose-the-dev-portal-backend-) +* [Lab 24 - Deploy and expose the dev portal frontend](#lab-24---deploy-and-expose-the-dev-portal-frontend-) +* [Lab 25 - Demonstrate the self service capabilities](#lab-25---demonstrate-the-self-service-capabilities-) +* [Lab 26 - Dev portal monetization](#lab-26---dev-portal-monetization-) +* [Lab 27 - Deploy Backstage with the backend plugin](#lab-27---deploy-backstage-with-the-backend-plugin-) +* [Lab 28 - Deploy OpenTelemetry Collector](#lab-28---deploy-opentelemetry-collector-) @@ -774,7 +775,7 @@ helm repo update helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context $CLUSTER1 \ --set-string license_key=$LICENSE_KEY \ -f -< + We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. You can find more information about this application [here](http://httpbin.org/). @@ -944,13 +946,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1027,13 +1022,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -1891,7 +1879,76 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || -## Lab 7 - Modify the requests and responses +## Lab 7 - Direct response + +The Kubernetes Gateway API doesn't provide the ability to configure direct responses (yet), so we've added this capability with a custom filter. + +You need to create a `DirectResponse` object (in this example, to provide a health check endpoint). + +```bash +kubectl apply --context ${CLUSTER1} -f - < ./test.js +const helpersHttp = require('./tests/chai-http'); + +describe("Direct response returns 200", () => { + it('Checking \'200\' status code', () => helpersHttp.checkURL({ host: `https://httpbin.example.com`, path: '/health', retCode: 200 })); +}) +EOF +echo "executing test dist/gloo-gateway-workshop/build/templates/steps/apps/httpbin/direct-response/tests/direct-response.test.js.liquid" +timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || { DEBUG_MODE=true mocha ./test.js --timeout 120000; exit 1; } +--> + + + +## Lab 8 - Modify the requests and responses The Kubernetes Gateway API provides different options to add/update/remove request and response headers. @@ -2369,7 +2426,7 @@ kubectl delete --context ${CLUSTER1} -n httpbin routeoption routeoption -## Lab 8 - Split traffic between 2 backend services +## Lab 9 - Split traffic between 2 backend services You can split traffic between different backends, with different weights. @@ -2442,7 +2499,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || -## Lab 9 - Securing the access with OAuth +## Lab 10 - Securing the access with OAuth In this step, we're going to secure the access to the `httpbin` service using OAuth. @@ -2687,7 +2744,7 @@ If you open the browser in incognito and login using the username `user2` and th -## Lab 10 - Use the transformation filter to manipulate headers +## Lab 11 - Use the transformation filter to manipulate headers In this step, we're going to use a regular expression to extract a part of an existing header and to create a new one: @@ -2741,7 +2798,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || -## Lab 11 - Apply rate limiting to the Gateway +## Lab 12 - Apply rate limiting to the Gateway In this step, we're going to apply rate limiting to the Gateway to only allow 3 requests per minute for the users of the `solo.io` organization. @@ -2852,7 +2909,7 @@ kubectl delete --context ${CLUSTER1} -n httpbin routeoption routeoption -## Lab 12 - Use the JWT filter to validate JWT and create headers from claims +## Lab 13 - Use the JWT filter to validate JWT and create headers from claims In this step, we're going to validate the JWT token and to create a new header from the `email` claim. @@ -3090,7 +3147,7 @@ kubectl --context ${CLUSTER1} -n gloo-system delete virtualhostoption jwt -## Lab 13 - Use the Web Application Firewall filter +## Lab 14 - Use the Web Application Firewall filter A web application firewall (WAF) protects web applications by monitoring, filtering, and blocking potentially harmful traffic and attacks that can overtake or exploit them. @@ -3175,7 +3232,7 @@ kubectl delete --context ${CLUSTER1} -n gloo-system routeoption waf -## Lab 14 - Validate and authorize client certificates +## Lab 15 - Validate and authorize client certificates In this step, we're going to secure the access to the httpbin service using mutual TLS (mTLS), and apply further authorization based on information in the client certificate. @@ -3594,7 +3651,7 @@ kubectl --context ${CLUSTER1} -n httpbin delete RouteOption routeoption -## Lab 15 - Use the `cache-control` response header to cache responses +## Lab 16 - Use the `cache-control` response header to cache responses An HTTP or HTTPS listener on your gateway can be configured to cache responses for upstream services. When the listener routes a request to an upstream service, the response from the upstream is automatically cached by the caching server if it contains a `cache-control` response header. @@ -3851,7 +3908,7 @@ kubectl --context ${CLUSTER1} -n gloo-system delete httplisteneroption cache -## Lab 16 - Deploy Argo Rollouts +## Lab 17 - Deploy Argo Rollouts [Argo Rollouts](https://argoproj.github.io/rollouts/) is a declarative progressive delivery tool for Kubernetes that we can use to update applications gradually, using a blue/green or canary strategy to manage the rollout. @@ -3887,7 +3944,7 @@ Now we're ready to use Argo Rollouts to progressively update applications as par -## Lab 17 - Roll out a new app version using Argo Rollouts +## Lab 18 - Roll out a new app version using Argo Rollouts We're going to use Argo Rollouts to gradually deliver an upgraded version of our httpbin application. To do this, we'll define a resource that lets Argo Rollouts know how we want it to handle updates to our application, @@ -4823,13 +4880,6 @@ spec: httpGet: path: /status/200 port: http - resources: - limits: - cpu: 1 - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi env: - name: K8S_MEM_LIMIT valueFrom: @@ -4863,7 +4913,7 @@ EOF -## Lab 18 - Expose a service through TCP +## Lab 19 - Expose a service through TCP Gloo Gateway allows you to expose TCP services using `TCPRoutes`. @@ -4951,7 +5001,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || -## Lab 19 - Deploy the Bookinfo sample application +## Lab 20 - Deploy the Bookinfo sample application [VIDEO LINK](https://youtu.be/nzYcrjalY5A "Video Link") We're going to deploy the Bookinfo sample application to demonstrate several features of Gloo Gateway. @@ -4994,7 +5044,7 @@ Configure your hosts file to resolve bookinfo.example.com with the IP address of -## Lab 20 - Expose the productpage API securely +## Lab 21 - Expose the productpage API securely Gloo Gateway includes a developer portal, which provides a framework for managing API discovery, API client identity, and API policies. @@ -5542,7 +5592,7 @@ EOF -## Lab 21 - Expose an external API and stitch it with the productpage API +## Lab 22 - Expose an external API and stitch it with the productpage API You can also use Gloo Gateway to expose an API that is outside of the cluster. In this section, we will expose `https://openlibrary.org/search.json` @@ -5809,7 +5859,7 @@ EOF -## Lab 22 - Expose the dev portal backend +## Lab 23 - Expose the dev portal backend Now that your API has been exposed securely and our plans defined, lets advertise this API through a developer portal. @@ -5971,7 +6021,7 @@ We'll create it later. -## Lab 23 - Deploy and expose the dev portal frontend +## Lab 24 - Deploy and expose the dev portal frontend The developer frontend is provided as a fully functional template to allow you to customize it based on your own requirements. @@ -6372,7 +6422,7 @@ kubectl --context ${CLUSTER1} -n gloo-system delete portalgroups.portal.gloo.sol -## Lab 24 - Demonstrate the self service capabilities +## Lab 25 - Demonstrate the self service capabilities We're going to demonstrate how to allow users to create their own teams and applications, subscribe to API Products and get credentials. @@ -6794,7 +6844,7 @@ We can now configure the Gloo Gateway portal backend to use it: helm upgrade -i -n gloo-system \ gloo-gateway gloo-ee-helm/gloo-ee \ --create-namespace \ - --version 1.18.0-rc4 \ + --version 1.18.0-rc6 \ --kube-context ${CLUSTER1} \ --reuse-values \ -f -< +## Lab 26 - Dev portal monetization The `portalMetadata` section of the `ApiProduct` objects we've created previously is used to add some metadata in the access logs. @@ -7133,7 +7183,7 @@ timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=150 --bail || -## Lab 26 - Deploy Backstage with the backend plugin +## Lab 27 - Deploy Backstage with the backend plugin Let's deploy Backstage: @@ -7309,7 +7359,7 @@ timeout --signal=INT 6m mocha ./test.js --timeout 10000 --retries=250 --bail || -## Lab 27 - Deploy OpenTelemetry Collector +## Lab 28 - Deploy OpenTelemetry Collector Having metrics is essential for running applications reliably, and gateways are no exceptions. diff --git a/gloo-gateway/1-18/enterprise/default/tests/proxies-changes.test.js.liquid b/gloo-gateway/1-18/enterprise/default/tests/proxies-changes.test.js.liquid new file mode 100644 index 0000000000..46bbe1422e --- /dev/null +++ b/gloo-gateway/1-18/enterprise/default/tests/proxies-changes.test.js.liquid @@ -0,0 +1,57 @@ +const { execSync } = require('child_process'); +const { expect } = require('chai'); +const { diff } = require('jest-diff'); + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Gloo snapshot stability test', function() { + let contextName = process.env.{{ context | default: "CLUSTER1" }}; + let delaySeconds = {{ delay | default: 5 }}; + + let firstSnapshot; + + it('should retrieve initial snapshot', function() { + const output = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + + try { + firstSnapshot = JSON.parse(output); + } catch (err) { + throw new Error('Failed to parse JSON output from initial snapshot: ' + err.message); + } + expect(firstSnapshot).to.be.an('object'); + }); + + it('should not change after the given delay', async function() { + await delay(delaySeconds * 1000); + + let secondSnapshot; + try { + const output2 = execSync( + `kubectl --context ${contextName} -n gloo-system exec deploy/gloo -- wget -O - localhost:9095/snapshots/proxies -q`, + { encoding: 'utf8' } + ); + secondSnapshot = JSON.parse(output2); + } catch (err) { + throw new Error('Failed to retrieve or parse the second snapshot: ' + err.message); + } + + const firstJson = JSON.stringify(firstSnapshot, null, 2); + const secondJson = JSON.stringify(secondSnapshot, null, 2); + + // Show only 2 lines of context around each change + const diffOutput = diff(firstJson, secondJson, { contextLines: 2, expand: false }); + + if (! diffOutput.includes("Compared values have no visual difference.")) { + console.error('Differences found between snapshots:\n' + diffOutput); + throw new Error('Snapshots differ after the delay.'); + } else { + console.log('No differences found. The snapshots are stable.'); + } + }); +}); + diff --git a/gloo-gateway/1-18/enterprise/lambda/README.md b/gloo-gateway/1-18/enterprise/lambda/README.md new file mode 100644 index 0000000000..8497dadbdd --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/README.md @@ -0,0 +1,1097 @@ + + + + + +
+ +
+ +#
Gloo Gateway Workshop
+ + + +## Table of Contents +* [Introduction](#introduction) +* [Lab 1 - Deploy KinD Cluster(s)](#lab-1---deploy-kind-cluster(s)-) +* [Lab 2 - Deploy the Amazon pod identity webhook](#lab-2---deploy-the-amazon-pod-identity-webhook-) +* [Lab 3 - Deploy Gloo Gateway](#lab-3---deploy-gloo-gateway-) +* [Lab 4 - Deploy the httpbin demo app](#lab-4---deploy-the-httpbin-demo-app-) +* [Lab 5 - Expose the httpbin application through the gateway](#lab-5---expose-the-httpbin-application-through-the-gateway-) +* [Lab 6 - Execute Lambda functions](#lab-6---execute-lambda-functions-) + + + +## Introduction + +Gloo Gateway is a feature-rich, fast, and flexible Kubernetes-native ingress controller and next-generation API gateway that is built on top of Envoy proxy and the Kubernetes Gateway API). + +Gloo Gateway is fully conformant with the Kubernetes Gateway API and extends its functionality with Solo’s custom Gateway APIs, such as `RouteOption`, `VirtualHostOption`, `Upstream`s, `RateLimitConfig`, or `AuthConfig`. +These resources help to centrally configure routing, security, and resiliency rules for a specific component, such as a host, route, or gateway listener. + +These capabilities are grouped into two editions of Gloo Gateway: + +### Open source (OSS) Gloo Gateway + +Use Kubernetes Gateway API-native features and the following Gloo Gateway extensions to configure basic routing, security, and resiliency capabilities: + +* Access logging +* Buffering +* Cross-Origin Resource Sharing (CORS) +* Cross-Site Request Forgery (CSRF) +* Fault injection +* Header control +* Retries +* Timeouts +* Traffic tapping +* Transformations + +### Gloo Gateway Enterprise Edition + +In addition to the features provided by the OSS edition, many more features are available in the Enterprise Edition, including: + +* External authentication and authorization +* External processing +* Data loss prevention +* Developer portal +* JSON web token (JWT) +* Rate limiting +* Response caching +* Web Application Filters + +### Want to learn more about Gloo Gateway? + +In the labs that follow we present some of the common patterns that our customers use and provide a good entry point into the workings of Gloo Gateway. + +You can find more information about Gloo Gateway in the official documentation: . + + + + +## Lab 1 - Deploy KinD Cluster(s) + + +Clone this repository and go to the directory where this `README.md` file is. + +Set the context environment variables: + +```bash +export CLUSTER1=cluster1 +``` + +Deploy the KinD clusters: +```bash +bash ./data/steps/deploy-kind-clusters/deploy-cluster1.sh +``` +Then run the following commands to wait for all the Pods to be ready: + +```bash +./scripts/check.sh cluster1 +``` + +**Note:** If you run the `check.sh` script immediately after the `deploy.sh` script, you may see a jsonpath error. If that happens, simply wait a few seconds and try again. + +Once the `check.sh` script completes, execute the `kubectl get pods -A` command, and verify that all pods are in a running state. + + + + + +## Lab 2 - Deploy the Amazon pod identity webhook + +To use the AWS Lambda integration, we need to deploy the Amazon EKS pod identity webhook. + +A prerequisite is to install [Cert Manager](https://cert-manager.io/): + +```bash +wget https://github.com/cert-manager/cert-manager/releases/download/v1.12.4/cert-manager.yaml + +kubectl --context ${CLUSTER1} apply -f cert-manager.yaml +``` + +Wait for cert-manager to be running: + +```bash +kubectl --context ${CLUSTER1} -n cert-manager rollout status deploy cert-manager +kubectl --context ${CLUSTER1} -n cert-manager rollout status deploy cert-manager-cainjector +kubectl --context ${CLUSTER1} -n cert-manager rollout status deploy cert-manager-webhook +``` + +Now, you can install the Amazon EKS pod identity webhook: + +```bash +kubectl --context ${CLUSTER1} apply -f data/steps/deploy-amazon-pod-identity-webhook +``` + +Wait for the pod identity webhook to be running: + +```bash +kubectl --context ${CLUSTER1} rollout status deploy/pod-identity-webhook +``` + + + + +## Lab 3 - Deploy Gloo Gateway + +You can deploy Gloo Gateway with the `glooctl` CLI or declaratively using Helm. + +We're going to use the Helm option. + +Install the Kubernetes Gateway API CRDs as they do not come installed by default on most Kubernetes clusters. + +```bash +kubectl --context $CLUSTER1 apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml +``` + + + +Next, install Gloo Gateway. This command installs the Gloo Gateway control plane into the namespace `gloo-system`. + +```bash +helm repo add gloo-ee-helm https://storage.googleapis.com/gloo-ee-helm + +helm repo update + +helm upgrade -i -n gloo-system \ + gloo-gateway gloo-ee-helm/gloo-ee \ + --create-namespace \ + --version 1.18.0-rc6 \ + --kube-context $CLUSTER1 \ + --set-string license_key=$LICENSE_KEY \ + -f -< +```bash +kubectl --context $CLUSTER1 -n gloo-system get pods +``` + +Here is the expected output: + +```,nocopy +NAME READY STATUS RESTARTS AGE +caching-service-79cf55ccbb-dcvgp 1/1 Running 0 69s +extauth-58f68c5cd5-gxgxc 1/1 Running 0 69s +gateway-portal-web-server-5c5d58d8d5-7lzwg 1/1 Running 0 69s +gloo-7d8994697-lfg5x 1/1 Running 0 69s +gloo-resource-rollout-check-x8b77 0/1 Completed 0 69s +gloo-resource-rollout-cjtgh 0/1 Completed 0 69s +rate-limit-6db9c67794-vf7h2 1/1 Running 0 69s +redis-6c7c489d8c-g2dhc 1/1 Running 0 69s +``` + + + + + +## Lab 4 - Deploy the httpbin demo app + + +We're going to deploy the httpbin application to demonstrate several features of Gloo Gateway. + +You can find more information about this application [here](http://httpbin.org/). + +Run the following commands to deploy the httpbin app twice (`httpbin1` and `httpbin2`). + +```bash +kubectl --context ${CLUSTER1} create ns httpbin +kubectl apply --context ${CLUSTER1} -f - < +```shell +kubectl --context ${CLUSTER1} -n httpbin get pods +``` + +Here is the expected output when both Pods are ready: + +```,nocopy +NAME READY STATUS RESTARTS AGE +httpbin1-7fdbf6498-ms7qt 1/1 Running 0 94s +httpbin2-655777b846-6nrms 1/1 Running 0 93s +``` + + + + + + +## Lab 5 - Expose the httpbin application through the gateway + + + + +The team in charge of the gateway can create a `Gateway` resource and configure an HTTP listener. + + + +```bash +kubectl apply --context ${CLUSTER1} -f - < + +Configure your hosts file to resolve httpbin.example.com with the IP address of the proxy by executing the following command: + +```bash +./scripts/register-domain.sh httpbin.example.com ${PROXY_IP} +``` + +Try to access the application through HTTP: + +```shell +curl http://httpbin.example.com/get +``` + +Here is the expected output: + +```json,nocopy +{ + "args": {}, + "headers": { + "Accept": [ + "*/*" + ], + "Host": [ + "httpbin.example.com" + ], + "User-Agent": [ + "curl/8.5.0" + ], + "X-Forwarded-Proto": [ + "http" + ], + "X-Request-Id": [ + "d0998a48-7532-4eeb-ab69-23cef22185cf" + ] + }, + "method": "GET", + "origin": "127.0.0.6:38917", + "url": "http://httpbin.example.com/get" +} +``` + + + +Now, let's secure the access through TLS. +Let's first create a private key and a self-signed certificate: + +```bash +openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout tls.key -out tls.crt -subj "/CN=*" +``` + +Then, you have to store it in a Kubernetes secret running the following command: + +```bash +kubectl create --context ${CLUSTER1} -n gloo-system secret tls tls-secret --key tls.key \ + --cert tls.crt +``` + +Update the `Gateway` resource to add HTTPS listeners. + +```bash +kubectl apply --context ${CLUSTER1} -f - < + +```shell +curl -k https://httpbin.example.com/get +``` + +Here is the expected output: + +```json,nocopy +{ + "args": {}, + "headers": { + "Accept": [ + "*/*" + ], + "Host": [ + "httpbin.example.com" + ], + "User-Agent": [ + "curl/8.5.0" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Request-Id": [ + "8e61c480-6373-4c38-824b-2bfe89e79d0c" + ] + }, + "method": "GET", + "origin": "127.0.0.6:52655", + "url": "https://httpbin.example.com/get" +} +``` + + + +The team in charge of the gateway can create an `HTTPRoute` to automatically redirect HTTP to HTTPS: + +```bash +kubectl apply --context ${CLUSTER1} -f - < ./test.js +const helpersHttp = require('./tests/chai-http'); + +describe("location header correctly set", () => { + it('Checking text \'location\'', () => helpersHttp.checkHeaders({ host: `http://httpbin.example.com`, path: '/get', expectedHeaders: [{'key': 'location', 'value': `https://httpbin.example.com/get`}]})); +}) +EOF +echo "executing test dist/gloo-gateway-workshop/build/templates/steps/apps/httpbin/expose-httpbin/tests/redirect-http-to-https.test.js.liquid" +timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || { DEBUG_MODE=true mocha ./test.js --timeout 120000; exit 1; } +--> + + + + +## Lab 6 - Execute Lambda functions +[VIDEO LINK](https://youtu.be/gD6GLMlP-Qc "Video Link") + +First of all, you need to create an `Upstream` object corresponding to the AWS destination: + +```bash +kubectl apply --context ${CLUSTER1} -f - < { + return event; +}; +``` + +You should now be able to invoke the Lambda function using the following command: + +```shell +curl -k "https://httpbin.example.com/lambda" -d '{"foo":"bar"}' +``` + +You should get a response like below: + +```js,nocopy +{ + "headers": { + ":authority": "httpbin.example.com", + ":method": "GET", + ":path": "/lambda", + ":scheme": "https", + "accept": "*/*", + "user-agent": "curl/8.5.0", + "x-forwarded-proto": "https", + "x-request-id": "118e4181-d8d6-4a64-a304-ac247b2a7d84" + }, + "httpMethod": "GET", + "multiValueHeaders": {}, + "multiValueQueryStringParameters": {}, + "path": "/lambda", + "queryString": "", + "queryStringParameters": {} +} + +``` + +It's very similar to what the `httpbin` application provides. It displays information about the request is has received. + +But when a Lambda function is exposed through an AWS API Gateway, the response of the function should be in a specific format (see this [example](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html)). + +The Gloo Gateway integration has the ability to understand this format and to process the response in the same way an AWS API gateway would. + +Here is the Node.js Lambda function we're going to use to demonstrate this capability: + +```js,nocopy +export const handler = async(event) => { + const response = { + "statusCode": 201, + "headers": { + "key": "value" + }, + "isBase64Encoded": false, + "multiValueHeaders": { + "X-Custom-Header": ["My value", "My other value"], + }, + "body": JSON.stringify({TotalCodeSize: 104330022,FunctionCount: 26}) + } + return response; +}; +``` +Let's update the `Upstream`: +```bash +kubectl apply --context ${CLUSTER1} -f - < ./test.js +const helpersHttp = require('./tests/chai-http'); + +describe("Lambda integration is working properly", () => { + it('Checking text \'"TotalCodeSize": 104330022\' in ' + process.env.CLUSTER1, () => helpersHttp.checkBody({ host: `https://httpbin.example.com`, path: '/lambda', body: '"TotalCodeSize": 104330022', match: true })); + it('Checking headers in ' + process.env.CLUSTER1, () => helpersHttp.checkHeaders({ host: `https://httpbin.example.com`, path: '/lambda', expectedHeaders: [{key: "key", value: "value"}, {key: "x-custom-header", value: "My value,My other value"}], match: true })); +}) +EOF +echo "executing test dist/gloo-gateway-workshop/build/templates/steps/gateway-lambda/tests/check-lambda-api-gateway.test.js.liquid" +timeout --signal=INT 3m mocha ./test.js --timeout 10000 --retries=120 --bail || { DEBUG_MODE=true mocha ./test.js --timeout 120000; exit 1; } +--> + +Let's remove the annotation and restart the pods: + +```bash +kubectl --context ${CLUSTER1} -n gloo-system annotate sa -l gloo=kube-gateway "eks.amazonaws.com/role-arn-" +kubectl --context ${CLUSTER1} -n gloo-system rollout restart deploy gloo-proxy-http +``` + +And also delete the different objects we've created: + +```bash +kubectl --context ${CLUSTER1} -n httpbin delete upstream lambda +``` + + + + + + diff --git a/gloo-gateway/1-18/enterprise/lambda/data/.gitkeep b/gloo-gateway/1-18/enterprise/lambda/data/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/auth.yaml b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/auth.yaml new file mode 100644 index 0000000000..369436c244 --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/auth.yaml @@ -0,0 +1,78 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pod-identity-webhook + namespace: default +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pod-identity-webhook + namespace: default +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - update + - patch + resourceNames: + - "pod-identity-webhook" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pod-identity-webhook + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pod-identity-webhook +subjects: +- kind: ServiceAccount + name: pod-identity-webhook + namespace: default +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pod-identity-webhook +rules: +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - watch + - list +- apiGroups: + - certificates.k8s.io + resources: + - certificatesigningrequests + verbs: + - create + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pod-identity-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pod-identity-webhook +subjects: +- kind: ServiceAccount + name: pod-identity-webhook + namespace: default diff --git a/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/deployment-base.yaml b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/deployment-base.yaml new file mode 100644 index 0000000000..d5c8e6c384 --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/deployment-base.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pod-identity-webhook + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: pod-identity-webhook + template: + metadata: + labels: + app: pod-identity-webhook + spec: + serviceAccountName: pod-identity-webhook + containers: + - name: pod-identity-webhook + image: amazon/amazon-eks-pod-identity-webhook:v0.5.0 + imagePullPolicy: Always + command: + - /webhook + - --in-cluster=false + - --namespace=default + - --service-name=pod-identity-webhook + - --annotation-prefix=eks.amazonaws.com + - --token-audience=sts.amazonaws.com + - --logtostderr + volumeMounts: + - name: cert + mountPath: "/etc/webhook/certs" + readOnly: true + volumes: + - name: cert + secret: + secretName: pod-identity-webhook-cert +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: selfsigned +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: pod-identity-webhook + namespace: default +spec: + secretName: pod-identity-webhook-cert + commonName: "pod-identity-webhook.default.svc" + dnsNames: + - "pod-identity-webhook" + - "pod-identity-webhook.default" + - "pod-identity-webhook.default.svc" + - "pod-identity-webhook.default.svc.local" + isCA: true + duration: 2160h # 90d + renewBefore: 360h # 15d + issuerRef: + name: selfsigned + kind: ClusterIssuer diff --git a/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/mutatingwebhook.yaml b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/mutatingwebhook.yaml new file mode 100644 index 0000000000..c8e66e7325 --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/mutatingwebhook.yaml @@ -0,0 +1,22 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: pod-identity-webhook + namespace: default + annotations: + cert-manager.io/inject-ca-from: default/pod-identity-webhook +webhooks: +- name: pod-identity-webhook.amazonaws.com + failurePolicy: Ignore + clientConfig: + service: + name: pod-identity-webhook + namespace: default + path: "/mutate" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + sideEffects: None + admissionReviewVersions: ["v1beta1"] diff --git a/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/service.yaml b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/service.yaml new file mode 100644 index 0000000000..4db1f51448 --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-amazon-pod-identity-webhook/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: pod-identity-webhook + namespace: default + annotations: + prometheus.io/port: "443" + prometheus.io/scheme: "https" + prometheus.io/scrape: "true" +spec: + ports: + - port: 443 + targetPort: 443 + selector: + app: pod-identity-webhook diff --git a/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-kind-clusters/deploy-cluster1.sh b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-kind-clusters/deploy-cluster1.sh new file mode 100644 index 0000000000..4f97e5f1cc --- /dev/null +++ b/gloo-gateway/1-18/enterprise/lambda/data/steps/deploy-kind-clusters/deploy-cluster1.sh @@ -0,0 +1,289 @@ +#!/usr/bin/env bash +set -o errexit + +number="1" +name="cluster1" +region="" +zone="" +twodigits=$(printf "%02d\n" $number) + +kindest_node=${KINDEST_NODE} + +if [ -z "$kindest_node" ]; then + export k8s_version="1.28.0" + + [[ ${k8s_version::1} != 'v' ]] && export k8s_version=v${k8s_version} + kindest_node_ver=$(curl --silent "https://registry.hub.docker.com/v2/repositories/kindest/node/tags?page_size=100" \ + | jq -r '.results | .[] | select(.name==env.k8s_version) | .name+"@"+.digest') + + if [ -z "$kindest_node_ver" ]; then + echo "Incorrect Kubernetes version provided: ${k8s_version}." + exit 1 + fi + kindest_node=kindest/node:${kindest_node_ver} +fi +echo "Using KinD image: ${kindest_node}" + +if [ -z "$3" ]; then + case $name in + cluster1) + region=us-west-1 + ;; + cluster2) + region=us-west-2 + ;; + *) + region=us-east-1 + ;; + esac +fi + +if [ -z "$4" ]; then + case $name in + cluster1) + zone=us-west-1a + ;; + cluster2) + zone=us-west-2a + ;; + *) + zone=us-east-1a + ;; + esac +fi + +if hostname -I 2>/dev/null; then + myip=$(hostname -I | awk '{ print $1 }') +else + myip=$(ipconfig getifaddr en0) +fi + +# Function to determine the next available cluster number +get_next_cluster_number() { + if ! kind get clusters 2>&1 | grep "^kind" > /dev/null; then + echo 1 + else + highest_num=$(kind get clusters | grep "^kind" | tail -1 | cut -c 5-) + echo $((highest_num + 1)) + fi +} + +if [ -f /.dockerenv ]; then +myip=$HOST_IP +container=$(docker inspect $(docker ps -q) | jq -r ".[] | select(.Config.Hostname == \"$HOSTNAME\") | .Name" | cut -d/ -f2) +docker network connect "kind" $container || true +number=$(get_next_cluster_number) +twodigits=$(printf "%02d\n" $number) +fi + +reg_name='kind-registry' +reg_port='5000' +docker start "${reg_name}" 2>/dev/null || \ +docker run -d --restart=always -p "0.0.0.0:${reg_port}:5000" --name "${reg_name}" registry:2 + +cache_port='5000' +cat > registries < ${HOME}/.${cache_name}-config.yml </dev/null || \ +docker run -d --restart=always ${DEPLOY_EXTRA_PARAMS} -v ${HOME}/.${cache_name}-config.yml:/etc/docker/registry/config.yml --name "${cache_name}" registry:2 +done +mkdir -p /tmp/oidc + +cat <<'EOF' >/tmp/oidc/sa-signer-pkcs8.pub +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA53YiBcrn7+ZK0Vb4odeA +1riYdvEb8To4H6/HtF+OKzuCIXFQ+bRy7yMrDGITYpfYPrTZOgfdeTLZqOiAj+cL +395nvxdly83SUrdh7ItfOPRluuuiPHnFn111wpyjBw5nut4Kx+M5MksNfA1hU0Zw +zIM9OviX8iEF8xHWUtz4BAMDG8N6+zpLo0pAzaei5hKuLZ9dZOzHBC8VOW82cQMm +5X5uOKsCHMtNSjqYUNB1DxN6xxM+odGWT/6xthPGk6YCxmO28YHPFZfiS2eAIpD8 +2p/16KQKU6TkZSrldkYxiHIPhu+5f9faZJG7dB9pLN1SfdTBio4PK5Mz9muLUCv9 +ywIDAQAB +-----END PUBLIC KEY----- +EOF + +cat <<'EOF' >/tmp/oidc/sa-signer.key +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA53YiBcrn7+ZK0Vb4odeA1riYdvEb8To4H6/HtF+OKzuCIXFQ ++bRy7yMrDGITYpfYPrTZOgfdeTLZqOiAj+cL395nvxdly83SUrdh7ItfOPRluuui +PHnFn111wpyjBw5nut4Kx+M5MksNfA1hU0ZwzIM9OviX8iEF8xHWUtz4BAMDG8N6 ++zpLo0pAzaei5hKuLZ9dZOzHBC8VOW82cQMm5X5uOKsCHMtNSjqYUNB1DxN6xxM+ +odGWT/6xthPGk6YCxmO28YHPFZfiS2eAIpD82p/16KQKU6TkZSrldkYxiHIPhu+5 +f9faZJG7dB9pLN1SfdTBio4PK5Mz9muLUCv9ywIDAQABAoIBAB8tro+RMYUDRHjG +el9ypAxIeWEsQVNRQFYkW4ZUiNYSAgl3Ni0svX6xAg989peFVL+9pLVIcfDthJxY +FVlNCjBxyQ/YmwHFC9vQkARJEd6eLUXsj8INtS0ubbp1VxCQRDDL0C/0z7OSoJJh +SwboqjEiTJExA2a+RArmEDTBRzdi3t+kT8G23JcqOivrITt17K6bQYyJXw7/vUdc +r/R+hfd5TqVq92VddzDT7RNJAxsbPPXjGnESlq1GALBDs+uBGYsP0fiEJb2nicSv +z9fBnBeERhut1gcE0C0iLRQZb+3r8TitBtxrZv+0BHgXrkKtXDwWTqGEKOwC4dBn +7nxkH2ECgYEA6+/DOTABGYOWOQftFkJMjcugzDrjoGpuXuVOTb65T+3FHAzU93zy +3bt3wQxrlugluyy9Sc/PL3ck2LgUsPHZ+s7zsdGvvGALBD6bOSSKATz9JgjwifO8 +PgqUz1kXRwez2CtKLOOCFFtcIzEdWIzsa1ubNqLzgN7rD+XBkUc2uEcCgYEA+yTy +72EDMQVoIZOygytHsDNdy0iS2RsBbdurT27wkYuFpFUVWdbNSL+8haE+wJHseHcw +BD4WIMpU+hnS4p4OO8+6V7PiXOS5E/se91EJigZAoixgDUiC8ihojWgK9PYEavUo +hULWbayO59SxYWeUI4Ze0GP8Jw8vdB86ib4ulF0CgYEAgyzRuLjk05+iZODwQyDn +WSquov3W0rh51s7cw0LX2wWSQm8r9NGGYhs5kJ5sLwGxAKj2MNSWF4jBdrCZ6Gr+ +y4BGY0X209/+IAUC3jlfdSLIiF4OBlT6AvB1HfclhvtUVUp0OhLfnpvQ1UwYScRI +KcRLvovIoIzP2g3emfwjAz8CgYEAxUHhOhm1mwRHJNBQTuxok0HVMrze8n1eov39 +0RcvBvJSVp+pdHXdqX1HwqHCmxhCZuAeq8ZkNP8WvZYY6HwCbAIdt5MHgbT4lXQR +f2l8F5gPnhFCpExG5ZLNg/urV3oAQE4stHap21zEpdyOMhZb6Yc5424U+EzaFdgN +b3EcPtUCgYAkKvUlSnBbgiJz1iaN6fuTqH0efavuFGMhjNmG7GtpNXdgyl1OWIuc +Yu+tZtHXtKYf3B99GwPrFzw/7yfDwae5YeWmi2/pFTH96wv3brJBqkAWY8G5Rsmd +qF50p34vIFqUBniNRwSArx8t2dq/CuAMgLAtSjh70Q6ZAnCF85PD8Q== +-----END RSA PRIVATE KEY----- +EOF + +echo Contents of kind${number}.yaml +cat << EOF | tee kind${number}.yaml +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + image: ${kindest_node} + extraPortMappings: + - containerPort: 6443 + hostPort: 70${twodigits} + extraMounts: + - containerPath: /etc/kubernetes/oidc + hostPath: /tmp/oidc + labels: + ingress-ready: true + topology.kubernetes.io/region: ${region} + topology.kubernetes.io/zone: ${zone} +networking: + serviceSubnet: "10.$(echo $twodigits | sed 's/^0*//').0.0/16" + podSubnet: "10.1${twodigits}.0.0/16" +kubeadmConfigPatches: +- | + kind: ClusterConfiguration + apiServer: + extraArgs: + service-account-key-file: /etc/kubernetes/pki/sa.pub + service-account-key-file: /etc/kubernetes/oidc/sa-signer-pkcs8.pub + service-account-signing-key-file: /etc/kubernetes/oidc/sa-signer.key + service-account-issuer: https://solo-workshop-oidc.s3.us-east-1.amazonaws.com + api-audiences: sts.amazonaws.com + extraVolumes: + - name: oidc + hostPath: /etc/kubernetes/oidc + mountPath: /etc/kubernetes/oidc + readOnly: true + metadata: + name: config +containerdConfigPatches: +- |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"] + endpoint = ["http://${reg_name}:${reg_port}"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] + endpoint = ["http://docker:${cache_port}"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."us-docker.pkg.dev"] + endpoint = ["http://us-docker:${cache_port}"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."us-central1-docker.pkg.dev"] + endpoint = ["http://us-central1-docker:${cache_port}"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"] + endpoint = ["http://quay:${cache_port}"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"] + endpoint = ["http://gcr:${cache_port}"] +EOF +echo ----------------------------------------------------- + +kind create cluster --name kind${number} --config kind${number}.yaml +ipkind=$(docker inspect kind${number}-control-plane | jq -r '.[0].NetworkSettings.Networks[].IPAddress') +networkkind=$(echo ${ipkind} | awk -F. '{ print $1"."$2 }') +kubectl config set-cluster kind-kind${number} --server=https://${myip}:70${twodigits} --insecure-skip-tls-verify=true + +# Preload images +cat << EOF >> images.txt +quay.io/metallb/controller:v0.13.12 +quay.io/metallb/speaker:v0.13.12 +EOF +cat images.txt | while read image; do + docker pull $image || true + kind load docker-image $image --name kind${number} || true +done + +docker network connect "kind" "${reg_name}" || true +docker network connect "kind" docker || true +docker network connect "kind" us-docker || true +docker network connect "kind" us-central1-docker || true +docker network connect "kind" quay || true +docker network connect "kind" gcr || true + +for i in 1 2 3 4 5; do kubectl --context=kind-kind${number} apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml && break || sleep 15; done +kubectl --context=kind-kind${number} create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" +kubectl --context=kind-kind${number} -n metallb-system rollout status deploy controller || true + +cat << EOF | tee metallb${number}.yaml +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: first-pool + namespace: metallb-system +spec: + addresses: + - ${networkkind}.1${twodigits}.1-${networkkind}.1${twodigits}.254 +--- +apiVersion: metallb.io/v1beta1 +kind: L2Advertisement +metadata: + name: empty + namespace: metallb-system +EOF + +printf "Create IPAddressPool in kind-kind${number}\n" +for i in {1..10}; do +kubectl --context=kind-kind${number} apply -f metallb${number}.yaml && break +sleep 2 +done + +# connect the registry to the cluster network if not already connected +printf "Renaming context kind-kind${number} to ${name}\n" +for i in {1..100}; do + (kubectl config get-contexts -oname | grep ${name}) && break + kubectl config rename-context kind-kind${number} ${name} && break + printf " $i"/100 + sleep 2 + [ $i -lt 100 ] || exit 1 +done + +# Document the local registry +# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry +cat <