diff --git a/README.md b/README.md index 2da500d..7d3a7f8 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ Bagan is a framework that helps to automate the execution, reporting and collection of data with different types of experiments in Gradle projects using Kubernetes. +![alt text](resources/experiment2.png "Bagan image") + # Table of Contents 1. [How to use Bagan](#how-to-use-bagan) 2. [bagan_conf.json](#bagan_conf.json) @@ -21,14 +23,14 @@ Bagan is a framework that helps to automate the execution, reporting and collect ## How to use Bagan -Once you have downloaded this repository you need to set up the `bagan_conf.json`. There you can setup different properties +Once you have downloaded this repository you need to set up the `bagan_conf.json`. You can setup different properties like the type of experiments you want to apply, the target repository or the resources you want to use in the Kubernetes environments. Bagan will be executed with the `./bagan` command following the next format: ` ./bagan MODE COMMAND` -Bagan will execute the experiments in a Kubernetes environment. For each experiment, Bagan will create a Helm Release where it will run the target repository applying the experimentation. +The execution framework and reporting happens in Kubernetes environment. For each experiment, Bagan will create a Helm Release where it will run the target repository applying the experimentation. To report the information of the build Bagan will inject Talaiot in the Gradle configuration of the project using InfluxDb as time-series database and Grafana as dashboard visualization tool. Bagan can deploy a new cluster or will use an existing cluster to execute the experimentation defined @@ -58,8 +60,8 @@ Example: "clusterName": "", "machine": "n1-standard-4", "private": true, - "ssh": "/Users/inaki/.ssh/id_rsa", - "known_hosts": "/Users/inaki/.ssh/known_hosts", + "ssh": "/user/.ssh/id_rsa", + "known_hosts": "/user/.ssh/known_hosts", "iterations": 20, "experiments": { "properties": [ @@ -319,16 +321,88 @@ Simple example of private repository generated by Android Studio | zone |asia-southeast1-b | | repository |git@github.com:cdsap/TestPrivateRepository.git | | private |true | -| experiments |gradle properties :{ "org.gradle.jvmargs": ["-Xmx3g","-Xmx4g"]| +| experiments |gradle properties :{ "org.gradle.jvmargs": ["-Xmx3g","-Xmx4g"]}| | command | ./gradlew clean assembleDebug | | iterations |20 | +2 experiments of Type Gradle Properties will be generated: +* -Xmx3g +* -Xmx4g Result: ![alt text](resources/experiment1.png "experiment1") +### Example 2 + +Experimentation on Google project Plaid, with kapt properties + +| bagan_conf | | +|-----------------|--------------------------------------------------------------| +| machine |n2-standard-8 | +| zone |asia-southeast1-b | +| repository |https://github.com/android/plaid.git | +| private |false | +| experiments |gradle properties:
{ "org.gradle.jvmargs": ["-Xmx2g","-Xmx4g"] }
{ "org.gradle.caching": ["true","false"] }
{ "kapt.incremental.apt": ["true","false"] }
{ "kapt.use.worker.api": ["true","false"] }
| +| command | ./gradlew clean assembleDebug | +| iterations |20 | + + "properties": [ + { + "name": "org.gradle.jvmargs", + "options": ["-Xmx2g","-Xmx4g"] + }, + { + "name": "org.gradle.caching", + "options": ["true","false"] + }, + { + "name": "kapt.incremental.apt", + "options": ["true","false"] + }, + { + "name": "kapt.use.worker.api", + "options": ["true","false"] + } + +16 experiments of Type Gradle Properties will be generated: + +|Experiments | | || +|----------------------|-------------------------------------------|----|--------------------------------| +| org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="true"
kapt.incremental.apt="true"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="true"
kapt.incremental.apt="true"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="true"
kapt.incremental.apt="false"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="true"
kapt.incremental.apt="false"
kapt.use.worker.api="true" | +| org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="false"
kapt.incremental.apt="true"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="false"
kapt.incremental.apt="true"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="false"
kapt.incremental.apt="false"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx2g"
org.gradle.caching="false"
kapt.incremental.apt="false"
kapt.use.worker.api="false" | +| org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="true"
kapt.incremental.apt="true"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="true"
kapt.incremental.apt="true"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="true"
kapt.incremental.apt="false"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="true"
kapt.incremental.apt="false"
kapt.use.worker.api="true" | +| org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="false"
kapt.incremental.apt="true"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="false"
kapt.incremental.apt="true"
kapt.use.worker.api="false" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="false"
kapt.incremental.apt="false"
kapt.use.worker.api="true" | org.gradle.jvmargs="-Xmx4g"
org.gradle.caching="false"
kapt.incremental.apt="false"
kapt.use.worker.api="false" | + + +Result: + +![alt text](resources/experiment2.png "experiment1") + +We don't appreciate on Plaid project significant different using properties like `kapt.incremental.apt` and `kapt.use.worker.api`. However, you can notice the benefits of using caching on the Gradle Builds. + +### Example 3 + +Experimentation on Android Showcase project, with Gradle properties and different Gradle Wrapper versions + +| bagan_conf | | +|-----------------|--------------------------------------------------------------| +| machine |n2-standard-8 | +| zone |asia-southeast1-b | +| repository |https://github.com/igorwojda/android-showcase | +| private |false | +| experiments |gradle properties:
{ "org.gradle.jvmargs": ["-Xmx2g","-Xmx4g"] }
{ "org.gradle.caching": ["true","false"] }
{ "kapt.incremental.apt": ["true","false"] }
{ "kapt.use.worker.api": ["true","false"] }
Gradle Wrapper versions: ["5.6.1","5.5"]| +| command | ./gradlew clean :app:bundleDebug | +| iterations |20 | + +Result: + +![alt text](resources/experiment3.png "experiment3") + + +Best times are using Gradle `5.6.1`. + ## Deploy Bagan is open source and you can update create your requirements. This is the structure of the project: diff --git a/bagan b/bagan index d394423..30e17ba 100755 --- a/bagan +++ b/bagan @@ -66,8 +66,8 @@ fi if [ "$branch" != "null" ]; then log " -branch: $branch" fi -if [ "$gradleWrapper" != "null" ]; then - log " -gradleWrapper: $gradleWrapper" +if [ "$gradleWrapperVersion" != "null" ]; then + log " -gradleWrapperVersion: $gradleWrapperVersion" fi log "" diff --git a/baganGenerator/src/main/java/com/cdsap/bagan/experiments/GradleWrapperVersion.kt b/baganGenerator/src/main/java/com/cdsap/bagan/experiments/GradleWrapperVersion.kt index 00e4b0e..a30e907 100644 --- a/baganGenerator/src/main/java/com/cdsap/bagan/experiments/GradleWrapperVersion.kt +++ b/baganGenerator/src/main/java/com/cdsap/bagan/experiments/GradleWrapperVersion.kt @@ -18,7 +18,7 @@ class GradleWrapperVersion( logger.log(TAG, "Error, not value found for the env variable gradleWrapperVersion") } else { logger.log(TAG, "gradleWrapperVersion version value $value") - val url = "https://services.gradle.org/distributions/gradle-$value-bin.zip" + val url = "https://services.gradle.org/distributions/gradle-${value.replace("'", "")}-bin.zip" try { val inProperties = FileInputStream("$path/gradle/wrapper/gradle-wrapper.properties") val props = Properties() @@ -26,7 +26,7 @@ class GradleWrapperVersion( inProperties.close() val outProperties = FileOutputStream("$path/gradle/wrapper/gradle-wrapper.properties") - logger.log(TAG, "Writing property distributionUrl-$url") + logger.log(TAG, "Writing property distributionUrl-${url.replace("'", "")}") props.setProperty("distributionUrl", url) props.store(outProperties, null) outProperties.close() diff --git a/baganGenerator/src/main/java/com/cdsap/bagan/generator/DashboardProvider.kt b/baganGenerator/src/main/java/com/cdsap/bagan/generator/DashboardProvider.kt index 0d4ffd3..82b70d9 100644 --- a/baganGenerator/src/main/java/com/cdsap/bagan/generator/DashboardProvider.kt +++ b/baganGenerator/src/main/java/com/cdsap/bagan/generator/DashboardProvider.kt @@ -189,7 +189,7 @@ fun getContentLegend(experiments: List): String { } if (it.gradleWrapperVersion.isNotBlank()) { contentExperiment += "#### Gradle Wrapper:\n" - contentExperiment += "${it.gradleWrapperVersion}\n" + contentExperiment += "${it.gradleWrapperVersion.replace("'", "")}\n" } content += contentExperiment } diff --git a/baganGenerator/src/main/java/com/cdsap/bagan/generator/K8Template.kt b/baganGenerator/src/main/java/com/cdsap/bagan/generator/K8Template.kt index 67feee7..d138595 100644 --- a/baganGenerator/src/main/java/com/cdsap/bagan/generator/K8Template.kt +++ b/baganGenerator/src/main/java/com/cdsap/bagan/generator/K8Template.kt @@ -195,7 +195,7 @@ for i in `seq 1 {{ .Values.iterations }}`; do {{ .Values.command }}; done; object ConfigMapExperiments { fun branch(branch: String) = """branch: $branch""" - fun gradleWrapperVersion(version: String) = """gradleWrapperVersion: $version""" + fun gradleWrapperVersion(version: String) = """gradleWrapperVersion: '$version'""" fun properties(properties: String) = """properties: | $properties""".trimIndent() diff --git a/baganGenerator/src/test/java/com/cdsap/bagan/experiments/WrapperVersionTest.kt b/baganGenerator/src/test/java/com/cdsap/bagan/experiments/WrapperVersionTest.kt index a1a29d0..b04f15c 100644 --- a/baganGenerator/src/test/java/com/cdsap/bagan/experiments/WrapperVersionTest.kt +++ b/baganGenerator/src/test/java/com/cdsap/bagan/experiments/WrapperVersionTest.kt @@ -27,7 +27,7 @@ class WrapperVersionTest : BehaviorSpec({ `when`("Environment variable is found but not the file gradle-wrapper.properties") { val testLogger = TestPodLogger() val exception = shouldThrow { - withEnvironment("gradleWrapperVersion" to "5.1") { + withEnvironment("gradleWrapperVersion" to "'5.1'") { val wrapperVersion = GradleWrapperVersion("tmp", testLogger) wrapperVersion.applyExperiments() @@ -47,7 +47,7 @@ class WrapperVersionTest : BehaviorSpec({ val contentFile = File("tmp/gradle/wrapper/gradle-wrapper.properties") contentFile.writeText("distributionUrl=https://services.gradle.org/distributions/gradle-5.4.1-bin.zip") - withEnvironment("gradleWrapperVersion" to "5.5") { + withEnvironment("gradleWrapperVersion" to "'5.5'") { val wrapperVersion = GradleWrapperVersion("tmp", testLogger) wrapperVersion.applyExperiments() } diff --git a/baganGenerator/src/test/java/com/cdsap/bagan/generator/BaganFileGeneratorTest.kt b/baganGenerator/src/test/java/com/cdsap/bagan/generator/BaganFileGeneratorTest.kt index e7bbc08..5ae1f05 100644 --- a/baganGenerator/src/test/java/com/cdsap/bagan/generator/BaganFileGeneratorTest.kt +++ b/baganGenerator/src/test/java/com/cdsap/bagan/generator/BaganFileGeneratorTest.kt @@ -41,7 +41,7 @@ class BaganFileGeneratorTest : BehaviorSpec({ contentValuesFile should haveSubstring("branch: master") contentValuesFile should haveSubstring("properties: |") contentValuesFile should haveSubstring("property1") - contentValuesFile should haveSubstring("gradleWrapperVersion: 4.5") + contentValuesFile should haveSubstring("gradleWrapperVersion: '4.5'") } then("pod is generated with ssh options") { diff --git a/baganGenerator/src/test/java/com/cdsap/bagan/generator/ConfigMapTest.kt b/baganGenerator/src/test/java/com/cdsap/bagan/generator/ConfigMapTest.kt index c886ee8..4330da7 100644 --- a/baganGenerator/src/test/java/com/cdsap/bagan/generator/ConfigMapTest.kt +++ b/baganGenerator/src/test/java/com/cdsap/bagan/generator/ConfigMapTest.kt @@ -44,7 +44,7 @@ metadata: session: {{ .Values.session }} data: id: {{ .Values.name }} - gradleWrapperVersion: 4.3 + gradleWrapperVersion: '4.3' """.trimIndent() ) } @@ -98,7 +98,7 @@ data: properties: | property1=a branch: develop - gradleWrapperVersion: 4.5""".trimIndent() + gradleWrapperVersion: '4.5'""".trimIndent() ) } diff --git a/bagan_conf.json b/bagan_conf.json index 83d6204..0d33180 100644 --- a/bagan_conf.json +++ b/bagan_conf.json @@ -1,22 +1,30 @@ { "bagan": { - "repository": "git@github.com:cdsap/TestPrivateRepository.git", - "gradleCommand": "./gradlew clean assembleDebug", + "repository": "https://github.com/igorwojda/android-showcase.git", + "gradleCommand": "./gradlew clean :app:bundleDebug", "clusterName": "", - "machine": "n1-standard-4", - "zone": null, - "private": true, - "ssh": "/Users/inaki/.ssh/id_rsa", - "known_hosts": "/Users/inaki/.ssh/known_hosts", + "machine": "n2-standard-8", + "zone": "asia-southeast1-b", + "private": false, + "ssh": "", + "known_hosts": "", "iterations": 20, "experiments": { "properties": [ { "name": "org.gradle.jvmargs", - "options": ["-Xmx3g","-Xmx4g"] + "options": ["-Xmx2g","-Xmx4g"] + }, + { + "name": "kapt.incremental.apt", + "options": ["true","false"] + }, + { + "name": "kapt.use.worker.api", + "options": ["true","false"] } ], - "branch": [ "develop3","master"] + "gradleWrapperVersion": ["5.6.1","5.5"] } } } diff --git a/docker/installer/bin/generator/K8Template.kt b/docker/installer/bin/generator/K8Template.kt index 67feee7..d138595 100644 --- a/docker/installer/bin/generator/K8Template.kt +++ b/docker/installer/bin/generator/K8Template.kt @@ -195,7 +195,7 @@ for i in `seq 1 {{ .Values.iterations }}`; do {{ .Values.command }}; done; object ConfigMapExperiments { fun branch(branch: String) = """branch: $branch""" - fun gradleWrapperVersion(version: String) = """gradleWrapperVersion: $version""" + fun gradleWrapperVersion(version: String) = """gradleWrapperVersion: '$version'""" fun properties(properties: String) = """properties: | $properties""".trimIndent() diff --git a/docker/pod/bin/experiments/GradleWrapperVersion.kt b/docker/pod/bin/experiments/GradleWrapperVersion.kt index 3f8f51d..0eca154 100644 --- a/docker/pod/bin/experiments/GradleWrapperVersion.kt +++ b/docker/pod/bin/experiments/GradleWrapperVersion.kt @@ -22,7 +22,7 @@ class GradleWrapperVersion( logger.log(TAG, "Error, not value found for the env variable gradleWrapperVersion") } else { logger.log(TAG, "gradleWrapperVersion version value $value") - val url = "https://services.gradle.org/distributions/gradle-$value-bin.zip" + val url = "https://services.gradle.org/distributions/gradle-${value.replace("'", "")}-bin.zip" try { val inProperties = FileInputStream("$path/gradle/wrapper/gradle-wrapper.properties") val props = Properties() @@ -30,7 +30,7 @@ class GradleWrapperVersion( inProperties.close() val outProperties = FileOutputStream("$path/gradle/wrapper/gradle-wrapper.properties") - logger.log(TAG, "Writing property distributionUrl-$url") + logger.log(TAG, "Writing property distributionUrl-${url.replace("'", "")}") props.setProperty("distributionUrl", url) props.store(outProperties, null) outProperties.close() diff --git a/resources/experiment2.png b/resources/experiment2.png new file mode 100644 index 0000000..f0a1c51 Binary files /dev/null and b/resources/experiment2.png differ diff --git a/resources/experiment3.png b/resources/experiment3.png new file mode 100644 index 0000000..08ed594 Binary files /dev/null and b/resources/experiment3.png differ diff --git a/scripts/mode_gcloud_docker.sh b/scripts/mode_gcloud_docker.sh index 9a57e4c..d2c7884 100644 --- a/scripts/mode_gcloud_docker.sh +++ b/scripts/mode_gcloud_docker.sh @@ -4,10 +4,10 @@ function gcloudDockerExecutor(){ log "Command $command" if [ $command == "cluster" ]; then printf '%s\n' "Mode cluster" - execution="$(gcloudInit) $(gcloudCreateCluster) $(gcloudClusterCredentials) $(helm1) $(infraPods) $(createSecretDockerContainer) $(dockerBagan)" + execution="$(gcloudInit) $(gcloudCreateCluster) $(gcloudClusterCredentials) $(helmInstaller) $(infraPods) $(createSecretDockerContainer) $(dockerBagan)" elif [ $command == "infrastructure" ]; then printf '%s\n' "Mode infrastrucure" - execution="$(gcloudClusterCredentials) $(helm1) $(infraPods) $(createSecretDockerContainer) $(dockerBagan) " + execution="$(gcloudClusterCredentials) $(helmInstaller) $(infraPods) $(createSecretDockerContainer) $(dockerBagan) " elif [ $command == "experiment" ]; then printf '%s\n' "Mode experiment" execution="$(gcloudClusterCredentials) $(dockerBagan)" @@ -18,7 +18,7 @@ function gcloudDockerExecutor(){ elif [[ $command == "secret" ]]; then execution="$(gcloudClusterCredentials) $(createSecretDockerContainer)" elif [[ $command == "helm" ]]; then - execution="$(gcloudClusterCredentials) $(helm1)" + execution="$(gcloudClusterCredentials) $(helmInstaller)" elif [[ $command == "helm_init" ]]; then execution="$(gcloudClusterCredentials) $(helmInit)" elif [[ $command == "helm_clusterrolebinding" ]]; then diff --git a/scripts/validate_json.sh b/scripts/validate_json.sh index 6ea81a6..4fd6f28 100644 --- a/scripts/validate_json.sh +++ b/scripts/validate_json.sh @@ -8,8 +8,8 @@ propertiesJson=$(cat $FILE | jq -c -r '.bagan.experiments.properties' | tr -d '\ propertiesCountJson=$(cat $FILE | jq -c -r '.bagan.experiments.properties | length' | tr -d '\r') branchJson=$(cat $FILE | jq -c -r '.bagan.experiments.branch' | tr -d '\r') branchCountJson=$(cat $FILE | jq -c -r '.bagan.experiments.branch | length' | tr -d '\r') -gradleWrapperJson=$(cat $FILE | jq -c -r '.bagan.experiments.gradleWrapper' | tr -d '\r') -gradleWrapperCountJson=$(cat $FILE | jq -c -r '.bagan.experiments.gradleWrapper | length' | tr -d '\r') +gradleWrapperVersionJson=$(cat $FILE | jq -c -r '.bagan.experiments.gradleWrapperVersion' | tr -d '\r') +gradleWrapperVersionCountJson=$(cat $FILE | jq -c -r '.bagan.experiments.gradleWrapperVersion | length' | tr -d '\r') clusterJson=$(cat $FILE | jq -c -r '.bagan.clusterName' | tr -d '\r') zoneJson=$(cat $FILE | jq -c -r '.bagan.zone' | tr -d '\r') machineJson=$(cat $FILE | jq -c -r '.bagan.machine' | tr -d '\r') @@ -34,7 +34,7 @@ then exit 1 fi -if [ "$propertiesJson" == "null" ] && [ "$branchJson" == "null" ] && [ "$gradleWrapperJson" == "null" ]; then +if [ "$propertiesJson" == "null" ] && [ "$branchJson" == "null" ] && [ "$gradleWrapperVersionJson" == "null" ]; then color '31;1' "Error: you have to include at least one type experiment in the configuration file." log "Example:" log "\"experiments\": { @@ -45,7 +45,7 @@ if [ "$propertiesJson" == "null" ] && [ "$branchJson" == "null" ] && [ "$gradleW } ], \"branch\": [ \"develop\",\"master\"], - \"gradleWrapper\": [ \"5.6\",\"5.5\",\"5.4\"] + \"gradleWrapperVersion\": [ \"5.6\",\"5.5\",\"5.4\"] }" exit 1 fi @@ -103,8 +103,8 @@ properties=$propertiesJson propertiesCount=$propertiesCountJson branch=$branchJson branchCount=$branchCountJson -gradleWrapper=$gradleWrapperJson -gradleWrapperCountJson=$gradleWrapperCountJson +gradleWrapperVersion=$gradleWrapperVersionJson +gradleWrapperVersionCountJson=$gradleWrapperVersionCountJson private=$privateJson ssh=$sshJson known_hosts=$known_hostsJson