Merge "Add pipeline to test cookiecutter generated models"
diff --git a/test-cookiecutter-reclass.groovy b/test-cookiecutter-reclass.groovy
new file mode 100644
index 0000000..0d8d319
--- /dev/null
+++ b/test-cookiecutter-reclass.groovy
@@ -0,0 +1,120 @@
+common = new com.mirantis.mk.Common()
+git = new com.mirantis.mk.Git()
+python = new com.mirantis.mk.Python()
+saltModelTesting = new com.mirantis.mk.SaltModelTesting()
+
+def generateSaltMaster(modelEnv) {
+    def nodeFile = "${modelEnv}/nodes/cfg01.${clusterDomain}.yml"
+    def nodeString = """classes:
+- cluster.${clusterName}.infra.config
+parameters:
+    _param:
+        linux_system_codename: xenial
+        reclass_data_revision: master
+    linux:
+        system:
+            name: cfg01
+            domain: ${clusterDomain}
+"""
+    sh "mkdir -p ${modelEnv}/nodes/"
+    writeFile(file: nodeFile, text: nodeString)
+}
+
+def generate(contextFile) {
+    def templateEnv = "${env.WORKSPACE}/template"
+    def baseName = sh(script: "basename ${contextFile} .yml", returnStdout: true)
+    def modelEnv = "${env.WORKSPACE}/model-${baseName}"
+    def cookiecutterTemplateContext = readFile(file: "${env.WORKSPACE}/contexts/contextFile")
+    def templateContext = readYaml text: cookiecutterTemplateContext
+    def clusterDomain = templateContext.default_context.cluster_domain
+    def clusterName = templateContext.default_context.cluster_name
+    def cutterEnv = "${env.WORKSPACE}/cutter"
+    def jinjaEnv = "${env.WORKSPACE}/jinja"
+    def outputDestination = "${modelEnv}/classes/cluster/${clusterName}"
+    def targetBranch = "feature/${clusterName}"
+    def templateBaseDir = "${env.WORKSPACE}/template"
+    def templateDir = "${templateEnv}/template/dir"
+    def templateOutputDir = templateBaseDir
+    sh("rm -rf ${templateBaseDir} || true")
+
+    def productList = ["infra", "cicd", "opencontrail", "kubernetes", "openstack", "stacklight"]
+    for (product in productList) {
+        def stagename = (product == "infra") ? "Generate base infrastructure" : "Generate product ${product}"
+        println stagename
+        if (product == "infra" || (templateContext.default_context["${product}_enabled"]
+            && templateContext.default_context["${product}_enabled"].toBoolean())) {
+            templateDir = "${templateEnv}/cluster_product/${product}"
+            templateOutputDir = "${env.WORKSPACE}/template/output/${product}"
+            sh "mkdir -p ${templateOutputDir}"
+            sh "mkdir -p ${outputDestination}"
+            python.setupCookiecutterVirtualenv(cutterEnv)
+            python.buildCookiecutterTemplate(templateDir, cookiecutterTemplateContext, templateOutputDir, cutterEnv, templateBaseDir)
+            sh "mv -v ${templateOutputDir}/${clusterName}/* ${outputDestination}"
+        }
+    }
+    generateSaltMaster(modelEnv)
+}
+
+def testModel(contextFile) {
+    def baseName = sh(script: "basename ${contextFile} .yml", returnStdout: true)
+    def modelEnv = "${env.WORKSPACE}/model-${baseName}"
+    git.checkoutGitRepository("${modelEnv}/classes/system", RECLASS_MODEL_URL, RECLASS_MODEL_BRANCH, RECLASS_MODEL_CREDENTIALS)
+    saltModelTesting.setupAndTestNode("cfg01.${clusterDomain}", "", modelEnv)
+}
+
+timestamps {
+    node("python&&docker") {
+        def templateEnv = "${env.WORKSPACE}/template"
+
+        try {
+            stage ('Download Cookiecutter template') {
+                if (gerritRef) {
+                    def gerritChange = gerrit.getGerritChange(GERRIT_NAME, GERRIT_HOST, GERRIT_CHANGE_NUMBER, CREDENTIALS_ID)
+                    merged = gerritChange.status == "MERGED"
+                    if(!merged){
+                        checkouted = gerrit.gerritPatchsetCheckout ([
+                            credentialsId : CREDENTIALS_ID
+                        ])
+                    } else{
+                        common.successMsg("Change ${GERRIT_CHANGE_NUMBER} is already merged, no need to gate them")
+                    }
+                } else {
+                    gerrit.gerritPatchsetCheckout(COOKIECUTTER_TEMPLATE_URL, COOKIECUTTER_TEMPLATE_BRANCH, "HEAD", CREDENTIALS_ID)
+                }
+            }
+
+            def contextFiles
+            dir("contexts") {
+                contextFiles = findFiles(glob: "*.yml")
+            }
+
+            for (contextFile in contextFiles) {
+                generate(contextFile)
+            }
+
+            stage("test-nodes") {
+                def partitions = common.partitionList(contextFiles, 3)
+                def buildSteps = [:]
+                for (int i = 0; i < partitions.size(); i++) {
+                    def partition = partitions[i]
+                    buildSteps.put("partition-${i}", new HashMap<String,org.jenkinsci.plugins.workflow.cps.CpsClosure2>())
+                    for(int k = 0; k < partition.size; k++){
+                        def basename = sh(script: "basename ${partition[k]} .yml", returnStdout: true).trim()
+                        def modelEnv = "${env.WORKSPACE}/model-${baseName}"
+                        buildSteps.get("partition-${i}").put(basename, { saltModelTesting.setupAndTestNode(basename, "", modelEnv) })
+                    }
+                }
+                common.serial(buildSteps)
+            }
+
+        } catch (Throwable e) {
+             currentBuild.result = "FAILURE"
+             throw e
+        } finally {
+            stage ('Clean workspace directories') {
+                sh(returnStatus: true, script: "rm -rfv *")
+            }
+            common.sendNotification(currentBuild.result,"",["slack"])
+        }
+    }
+}