Compare commits

...

42 Commits
master ... dev

Author SHA1 Message Date
keptn 842112359a Updated resource 2023-11-15 15:55:05 +00:00
keptn 5183cac7fa Updated resource 2023-11-15 15:54:47 +00:00
keptn 9238c74a21 Updated resource 2023-11-15 15:54:21 +00:00
keptn 0e0f644421 Updated resource 2023-11-15 14:35:43 +00:00
keptn ee726fc674 Updated resource 2023-11-15 13:15:41 +00:00
keptn 919f734f3b Updated resource 2023-11-15 11:57:31 +00:00
keptn 8aae6a5153 Updated resource 2023-11-15 11:56:52 +00:00
keptn 4660ea8377 Updated resource 2023-11-15 08:15:08 +00:00
keptn ff8c119779 Updated resource 2023-11-15 07:40:21 +00:00
keptn bdcc64166f Updated resource 2023-11-15 07:32:46 +00:00
keptn 087e594b07 Updated resource 2023-11-15 07:24:29 +00:00
keptn 9ab9604298 Updated resource 2023-11-14 22:20:45 +00:00
keptn 762248fd55 Updated resource 2023-11-14 22:17:15 +00:00
keptn eef4e696af Updated resource 2023-11-14 20:18:28 +00:00
keptn c838c74bce Updated resource 2023-11-14 20:17:57 +00:00
keptn bd7bfc1494 Updated resource 2023-11-14 20:10:09 +00:00
keptn 5aa9529113 Updated resource 2023-11-14 19:29:02 +00:00
keptn 75deb16e43 Updated resource 2023-11-14 19:24:28 +00:00
keptn e944e5b014 Updated resource 2023-11-14 19:23:57 +00:00
keptn 732d126c73 Updated resource 2023-11-14 18:43:34 +00:00
keptn 5c6c1f6ebd Updated resource 2023-11-14 18:32:47 +00:00
keptn 30d2f18396 Updated resource 2023-11-14 16:09:26 +00:00
keptn 6f82fad6e4 Updated resource 2023-11-14 16:07:28 +00:00
keptn 30a423c197 Added service: carts-db 2023-11-14 16:06:46 +00:00
keptn f1447d8d6f Updated resource 2023-11-14 15:59:20 +00:00
keptn 6326a80cca Updated resource 2023-11-14 15:56:54 +00:00
keptn a943fa2274 Updated resource 2023-11-14 13:24:30 +00:00
keptn 933b93cffd Updated resource 2023-11-14 13:17:21 +00:00
keptn 96f34f8e90 Updated resource 2023-11-14 13:08:01 +00:00
keptn 4bd9f78e27 Updated resource 2023-11-14 12:20:20 +00:00
keptn 1b8ce5ee12 Updated resource 2023-11-14 11:58:26 +00:00
keptn 8b148c21da Updated resource 2023-11-14 11:46:28 +00:00
keptn d5a57af78f Updated resource 2023-11-14 10:45:48 +00:00
keptn b57c4f3ff8 Updated resource 2023-11-14 10:41:45 +00:00
keptn 72ac3739b6 Updated resource 2023-11-14 10:33:38 +00:00
ermisw af5e784234 added chart 2023-11-14 10:51:40 +01:00
ermisw 7bd2262ad6 added chart 2023-11-14 10:25:08 +01:00
keptn 559229aede Updated resource 2023-11-13 19:50:01 +00:00
keptn ed7f24d1bd Updated resource 2023-11-13 19:48:41 +00:00
keptn 522d814150 Updated resource 2023-11-13 18:32:41 +00:00
keptn ad6bd6b18e Added service: carts 2023-11-13 18:27:46 +00:00
keptn cf18992b3a created stage 2023-11-13 18:26:45 +00:00
17 changed files with 637 additions and 0 deletions

Binary file not shown.

58
carts-db/job/config.yaml Normal file
View File

@ -0,0 +1,58 @@
apiVersion: v2
actions:
- name: "Deploy using helm"
events:
- name: "sh.keptn.event.deployment.triggered"
tasks:
- name: "Run helm"
files:
- /charts
env:
- name: IMAGE
value: "$.data.configurationChange.values.image"
valueFrom: event
image: "alpine/helm:3.7.2"
serviceAccount: "jes-deploy-using-helm"
cmd: ["helm"]
args: ["upgrade", "--create-namespace", "--install", "-n", "$(KEPTN_PROJECT)-$(KEPTN_STAGE)", "$(KEPTN_SERVICE)", "/keptn/charts/$(KEPTN_SERVICE).tgz", "--set", "image=$(IMAGE)", "--set", "keptn.service=$(KEPTN_SERVICE)", "--set", "keptn.deployment=$(KEPTN_STAGE)", "--wait"]
- name: "Rollback using helm"
events:
- name: "sh.keptn.event.rollback.triggered"
tasks:
- name: "Run helm"
serviceAccount: "jes-deploy-using-helm"
image: "alpine/helm:3.7.2"
cmd: ["helm"]
args: ["rollback", "-n", "$(KEPTN_PROJECT)-$(KEPTN_STAGE)", "$(KEPTN_SERVICE)", "--wait"]
- name: "Scale using kubectl"
events:
- name: "sh.keptn.event.action.triggered"
jsonpath:
property: "$.data.action.action"
match: "scaling"
tasks:
- name: "Run kubectl"
serviceAccount: "jes-deploy-using-helm"
env:
- name: SCALING
value: $.data.action.value
valueFrom: event
image: "alpine/k8s:1.20.15"
cmd: ["sh"]
# Note: Hardcoded kubernetes namespace & KEPTN_SERVICE does most likely not match the deployment name
args: ["-c", "REPLICAS=$(kubectl -n ${KEPTN_PROJECT}-${KEPTN_STAGE} get deployment/${KEPTN_SERVICE} -o go-template='{{.spec.replicas}}');DESIRED=$((${SCALING}+${REPLICAS}));echo Scaling deployment to ${DESIRED} && kubectl -n ${KEPTN_PROJECT}-${KEPTN_STAGE} scale --replicas=${DESIRED} deployment/${KEPTN_SERVICE}"]
- name: "Run tests using locust"
events:
- name: "sh.keptn.event.test.triggered"
tasks:
- name: "Run locust"
files:
- locust/basic.py
- locust/locust.conf
image: "locustio/locust:2.8.6"
cmd: ["locust"]
args: ["--config", "/keptn/locust/locust.conf", "-f", "/keptn/locust/basic.py", "--host", "http://$(KEPTN_SERVICE).$(KEPTN_PROJECT)-$(KEPTN_STAGE)", "--only-summary"]

2
carts-db/metadata.yaml Normal file
View File

@ -0,0 +1,2 @@
servicename: carts-db
creationtimestamp: 2023-11-14 16:06:46.781502681 +0000 UTC

BIN
carts.tgz Normal file

Binary file not shown.

4
carts/Chart.yaml Normal file
View File

@ -0,0 +1,4 @@
apiVersion: v1
description: A Helm chart for service carts
name: carts
version: 0.1.0

BIN
carts/carts.tgz Normal file

Binary file not shown.

BIN
carts/charts/carts.tgz Normal file

Binary file not shown.

177
carts/jmeter/basiccheck.jmx Normal file
View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1.1 r1855137">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Testing Sample NodeJs" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="SERVER_URL" elementType="Argument">
<stringProp name="Argument.name">SERVER_URL</stringProp>
<stringProp name="Argument.value">carts-dev.nttdata-xlabs.com</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="CHECK_PATH" elementType="Argument">
<stringProp name="Argument.name">CHECK_PATH</stringProp>
<stringProp name="Argument.value">/</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DT_LTN" elementType="Argument">
<stringProp name="Argument.name">DT_LTN</stringProp>
<stringProp name="Argument.value">Default</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DefaultThinkTime" elementType="Argument">
<stringProp name="Argument.name">DefaultThinkTime</stringProp>
<stringProp name="Argument.value">250</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="SERVER_PORT" elementType="Argument">
<stringProp name="Argument.name">SERVER_PORT</stringProp>
<stringProp name="Argument.value">443</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PROTOCOL" elementType="Argument">
<stringProp name="Argument.name">PROTOCOL</stringProp>
<stringProp name="Argument.value">https</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="VUCount" elementType="Argument">
<stringProp name="Argument.name">VUCount</stringProp>
<stringProp name="Argument.value">1</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="LoopCount" elementType="Argument">
<stringProp name="Argument.name">LoopCount</stringProp>
<stringProp name="Argument.value">1</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="BasicThreadGroup" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">${__P(LoopCount,${VUCount})}</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${__P(VUCount,${VUCount})}</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<longProp name="ThreadGroup.start_time">1444323045000</longProp>
<longProp name="ThreadGroup.end_time">1444323045000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
<collectionProp name="CookieManager.cookies"/>
<boolProp name="CookieManager.clearEachIteration">false</boolProp>
</CookieManager>
<hashTree/>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
<collectionProp name="HeaderManager.headers"/>
</HeaderManager>
<hashTree/>
<BeanShellPreProcessor guiclass="TestBeanGUI" testclass="BeanShellPreProcessor" testname="Set Dynatrace Headers" enabled="true">
<boolProp name="resetInterpreter">true</boolProp>
<stringProp name="parameters"></stringProp>
<stringProp name="filename"></stringProp>
<stringProp name="script">import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import java.io;
import java.util;
// -------------------------------------------------------------------------------------
// Generate the x-dynatrace-test header based on this best practic
// -&gt; https://www.dynatrace.com/support/help/integrations/test-automation-frameworks/how-do-i-integrate-dynatrace-into-my-load-testing-process/
// -------------------------------------------------------------------------------------
String LTN=JMeterUtils.getProperty(&quot;DT_LTN&quot;);
if((LTN == null) || (LTN.length() == 0)) {
if(vars != null) {
LTN = vars.get(&quot;DT_LTN&quot;);
}
}
if(LTN == null) LTN = &quot;NoTestName&quot;;
String LSN = (bsh.args.length &gt; 0) ? bsh.args[0] : &quot;Test Scenario&quot;;
String TSN = sampler.getName();
String VU = ctx.getThreadGroup().getName() + ctx.getThreadNum();
String headerValue = &quot;LSN=&quot;+ LSN + &quot;;TSN=&quot; + TSN + &quot;;LTN=&quot; + LTN + &quot;;VU=&quot; + VU + &quot;;&quot;;
// -------------------------------------------
// Set header
// -------------------------------------------
HeaderManager hm = sampler.getHeaderManager();
hm.removeHeaderNamed(&quot;x-dynatrace-test&quot;);
hm.add(new org.apache.jmeter.protocol.http.control.Header(&quot;x-dynatrace-test&quot;, headerValue));</stringProp>
</BeanShellPreProcessor>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Basic Check" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${__P(SERVER_URL,${SERVER_URL})}</stringProp>
<stringProp name="HTTPSampler.port">${__P(SERVER_PORT,${SERVER_PORT})}</stringProp>
<stringProp name="HTTPSampler.protocol">${__P(PROTOCOL,${PROTOCOL})}</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${__P(CHECK_PATH,${CHECK_PATH})}</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
<collectionProp name="HeaderManager.headers"/>
</HeaderManager>
<hashTree/>
</hashTree>
<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Default Think Time" enabled="true">
<stringProp name="ConstantTimer.delay">{__P(ThinkTime,${DefaultThinkTime})}</stringProp>
</ConstantTimer>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>

191
carts/jmeter/load.jmx Normal file
View File

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1.1 r1855137">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="SERVER_URL" elementType="Argument">
<stringProp name="Argument.name">SERVER_URL</stringProp>
<stringProp name="Argument.value">carts-dev.nttdata-xlabs.com</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DefaultThinkTime" elementType="Argument">
<stringProp name="Argument.name">DefaultThinkTime</stringProp>
<stringProp name="Argument.value">250</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DT_LTN" elementType="Argument">
<stringProp name="Argument.name">DT_LTN</stringProp>
<stringProp name="Argument.value">Default</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="SERVER_PORT" elementType="Argument">
<stringProp name="Argument.name">SERVER_PORT</stringProp>
<stringProp name="Argument.value">443</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PROTOCOL" elementType="Argument">
<stringProp name="Argument.name">PROTOCOL</stringProp>
<stringProp name="Argument.value">https</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="VUCount" elementType="Argument">
<stringProp name="Argument.name">VUCount</stringProp>
<stringProp name="Argument.value">1</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="LoopCount" elementType="Argument">
<stringProp name="Argument.name">LoopCount</stringProp>
<stringProp name="Argument.value">1</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">${__P(LoopCount,${LoopCount})}</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${__P(VUCount,${VUCount})}</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<longProp name="ThreadGroup.start_time">1536064517000</longProp>
<longProp name="ThreadGroup.end_time">1536064517000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
<collectionProp name="CookieManager.cookies"/>
<boolProp name="CookieManager.clearEachIteration">false</boolProp>
</CookieManager>
<hashTree/>
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Cache-Control</stringProp>
<stringProp name="Header.value">no-cache</stringProp>
</elementProp>
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Content-Type</stringProp>
<stringProp name="Header.value">application/json</stringProp>
</elementProp>
<elementProp name="" elementType="Header">
<stringProp name="Header.name">json</stringProp>
<stringProp name="Header.value">true</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
<BeanShellPreProcessor guiclass="TestBeanGUI" testclass="BeanShellPreProcessor" testname="Set Dynatrace Headers" enabled="true">
<stringProp name="filename"></stringProp>
<stringProp name="parameters"></stringProp>
<boolProp name="resetInterpreter">false</boolProp>
<stringProp name="script">import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import java.io;
import java.util;
// -------------------------------------------------------------------------------------
// Generate the x-dynatrace-test header based on this best practic
// -&gt; https://www.dynatrace.com/support/help/integrations/test-automation-frameworks/how-do-i-integrate-dynatrace-into-my-load-testing-process/
// -------------------------------------------------------------------------------------
String LTN=JMeterUtils.getProperty(&quot;DT_LTN&quot;);
if((LTN == null) || (LTN.length() == 0)) {
if(vars != null) {
LTN = vars.get(&quot;DT_LTN&quot;);
}
}
if(LTN == null) LTN = &quot;NoTestName&quot;;
String LSN = (bsh.args.length &gt; 0) ? bsh.args[0] : &quot;Test Scenario&quot;;
String TSN = sampler.getName();
String VU = ctx.getThreadGroup().getName() + ctx.getThreadNum();
String headerValue = &quot;LSN=&quot;+ LSN + &quot;;TSN=&quot; + TSN + &quot;;LTN=&quot; + LTN + &quot;;VU=&quot; + VU + &quot;;&quot;;
// -------------------------------------------
// Set header
// -------------------------------------------
HeaderManager hm = sampler.getHeaderManager();
hm.removeHeaderNamed(&quot;x-dynatrace-test&quot;);
hm.add(new org.apache.jmeter.protocol.http.control.Header(&quot;x-dynatrace-test&quot;, headerValue));</stringProp>
</BeanShellPreProcessor>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Add Item to Cart" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value"> {&#xd;
&quot;itemId&quot;:&quot;03fef6ac-1896-4ce8-bd69-b798f85c6e0b&quot;,&#xd;
&quot;unitPrice&quot;:&quot;99.99&quot;&#xd;
}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">${__P(SERVER_URL,${SERVER_URL})}</stringProp>
<stringProp name="HTTPSampler.port">${__P(SERVER_PORT,${SERVER_PORT})}</stringProp>
<stringProp name="HTTPSampler.protocol">${__P(PROTOCOL,${PROTOCOL})}</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/carts/1/items</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">true</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Default Think Time" enabled="true">
<stringProp name="ConstantTimer.delay">{__P(ThinkTime,${DefaultThinkTime})}</stringProp>
</ConstantTimer>
<hashTree/>
</hashTree>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>

58
carts/job/config.yaml Normal file
View File

@ -0,0 +1,58 @@
apiVersion: v2
actions:
- name: "Deploy using helm"
events:
- name: "sh.keptn.event.deployment.triggered"
tasks:
- name: "Run helm"
files:
- /charts
env:
- name: IMAGE
value: "$.data.configurationChange.values.image"
valueFrom: event
image: "alpine/helm:3.7.2"
serviceAccount: "jes-deploy-using-helm"
cmd: ["helm"]
args: ["upgrade", "--force", "--create-namespace", "--install", "-n", "$(KEPTN_PROJECT)-$(KEPTN_STAGE)", "$(KEPTN_SERVICE)", "/keptn/charts/$(KEPTN_SERVICE).tgz", "--set", "image=$(IMAGE)", "--set", "keptn.service=$(KEPTN_SERVICE)", "--set", "keptn.deployment=$(KEPTN_STAGE)", "--set", "keptn.project=$(KEPTN_PROJECT)","--set", "keptn.stage=$(KEPTN_STAGE)", "--wait"]
- name: "Rollback using helm"
events:
- name: "sh.keptn.event.rollback.triggered"
tasks:
- name: "Run helm"
serviceAccount: "jes-deploy-using-helm"
image: "alpine/helm:3.7.2"
cmd: ["helm"]
args: ["rollback", "-n", "$(KEPTN_PROJECT)-$(KEPTN_STAGE)", "$(KEPTN_SERVICE)", "--wait"]
- name: "Scale using kubectl"
events:
- name: "sh.keptn.event.action.triggered"
jsonpath:
property: "$.data.action.action"
match: "scaling"
tasks:
- name: "Run kubectl"
serviceAccount: "jes-deploy-using-helm"
env:
- name: SCALING
value: $.data.action.value
valueFrom: event
image: "alpine/k8s:1.20.15"
cmd: ["sh"]
# Note: Hardcoded kubernetes namespace & KEPTN_SERVICE does most likely not match the deployment name
args: ["-c", "REPLICAS=$(kubectl -n ${KEPTN_PROJECT}-${KEPTN_STAGE} get deployment/${KEPTN_SERVICE} -o go-template='{{.spec.replicas}}');DESIRED=$((${SCALING}+${REPLICAS}));echo Scaling deployment to ${DESIRED} && kubectl -n ${KEPTN_PROJECT}-${KEPTN_STAGE} scale --replicas=${DESIRED} deployment/${KEPTN_SERVICE}"]
- name: "Run tests using locust"
events:
- name: "sh.keptn.event.test.triggered"
tasks:
- name: "Run locust"
files:
- locust/basic.py
- locust/locust.conf
image: "locustio/locust:2.8.6"
cmd: ["locust"]
args: ["--config", "/keptn/locust/locust.conf", "-f", "/keptn/locust/basic.py", "--host", "http://$(KEPTN_SERVICE)-$(KEPTN_STAGE).nttdata-xlabs.com", "--only-summary"]

Binary file not shown.

8
carts/locust/basic.py Normal file
View File

@ -0,0 +1,8 @@
from locust import HttpUser, between, task
class WebsiteUser(HttpUser):
#wait_time = between(5, 15)
@task
def index(self):
self.client.post("/carts/1/items", json= {"itemId":"03fef6ac-1896-4ce8-bd69-b798f85c6e0b","unitPrice":"99.99"}, headers={"x-dynatrace-test": "LSN=Test;"})

4
carts/locust/locust.conf Normal file
View File

@ -0,0 +1,4 @@
locustfile = /locust/locust.py
headless = true
users = 5
run-time = 1m

42
carts/slo.yaml Normal file
View File

@ -0,0 +1,42 @@
---
spec_version: "0.1.1"
comparison:
aggregate_function: "avg"
compare_with: "single_result"
include_result_with_score: "pass"
number_of_comparison_results: 1
filter:
objectives:
- sli: "response_time_p95"
key_sli: false
pass: # pass if (relative change <= 10% AND absolute value is < 600ms)
- criteria:
- "<=+25%" # relative values require a prefixed sign (plus or minus)
- "<600000" # absolute values only require a logical operator
warning: # if the response time is below 800ms, the result should be a warning
- criteria:
- "<=800000"
weight: 1
# - sli: "rt_addToCart" # looking at a particular transaction
# weight: 3 # business critical transaction
# pass:
# - criteria:
# - "<=+20%" # Degradation-driven
# - "<300000" # NFR-driven
# warning:
# - criteria:
# - "<=+50%"
# - "<=500000"
- sli: "error_rate"
pass:
- criteria:
- "<=+15%"
- "<2"
warning:
- criteria:
- "<10"
- sli: "pg_heap_suspension"
- sli: "pg_cpu_usage"
total_score:
pass: "90%"
warning: "70%"

View File

@ -0,0 +1,77 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: carts
spec:
replicas: {{ .Values.replicaCount }}
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: carts
template:
metadata:
labels:
app: carts
app.kubernetes.io/name: {{ .Values.keptn.service }}
app.kubernetes.io/instance: "{{ .Values.keptn.service }}-{{ .Values.keptn.deployment }}"
app.kubernetes.io/component: api
app.kubernetes.io/part-of: "{{ .Values.keptn.project }}"
app.kubernetes.io/managed-by: Keptn
app.kubernetes.io/version: {{ (split ":" .Values.image)._1 | default "latest" }}
spec:
containers:
- name: carts
image: "{{ .Values.image }}"
imagePullPolicy: IfNotPresent
ports:
- name: http
protocol: TCP
containerPort: 8080
env:
- name: DT_CUSTOM_PROP
value: "version={{ .Chart.Version }} revision={{ .Release.Revision }} releasename={{ .Release.Name }} keptn_project={{ .Values.keptn.project }} keptn_service={{ .Values.keptn.service }} keptn_stage={{ .Values.keptn.stage }} keptn_deployment={{ .Values.keptn.deployment }}"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: "metadata.name"
- name: DEPLOYMENT_NAME
valueFrom:
fieldRef:
fieldPath: "metadata.labels['deployment']"
- name: CONTAINER_IMAGE
value: "{{ .Values.image }}"
- name: KEPTN_PROJECT
value: "{{ .Chart.Name }}"
- name: KEPTN_STAGE
valueFrom:
fieldRef:
fieldPath: "metadata.namespace"
- name: KEPTN_SERVICE
value: "carts"
- name: UNLEASH_SERVER_URL
value: "http://unleash.unleash-dev/api"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 15
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 15
resources:
limits:
cpu: 1000m
memory: 2048Mi
requests:
cpu: 500m
memory: 1024Mi

View File

@ -0,0 +1,14 @@
---
apiVersion: v1
kind: Service
metadata:
name: carts
spec:
type: ClusterIP
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app: carts

2
carts/values.yaml Normal file
View File

@ -0,0 +1,2 @@
image: docker.io/keptnexamples/carts:0.13.1
replicaCount: 1