Skip to content

Commit

Permalink
Merge pull request #4 from iaizarc/add_e2e-python
Browse files Browse the repository at this point in the history
Add e2e python
  • Loading branch information
cristianhkr authored Jan 24, 2024
2 parents 90f2c2f + 7b2887a commit 16a202b
Show file tree
Hide file tree
Showing 84 changed files with 4,919 additions and 1 deletion.
48 changes: 48 additions & 0 deletions e2e-python/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
def odsNamespace = ''
def odsGitRef = ''
def odsImageTag = ''
def sharedLibraryRef = ''
def agentImageTag = ''

node {
odsNamespace = env.ODS_NAMESPACE ?: 'ods'
odsGitRef = env.ODS_GIT_REF ?: 'master'
odsImageTag = env.ODS_IMAGE_TAG ?: 'latest'
sharedLibraryRef = env.SHARED_LIBRARY_REF ?: odsImageTag
agentImageTag = env.AGENT_IMAGE_TAG ?: odsImageTag
}

library("ods-jenkins-shared-library@${sharedLibraryRef}")

odsQuickstarterPipeline(
imageStreamTag: "${odsNamespace}/jenkins-agent-base:${agentImageTag}",
) { context ->

odsQuickstarterStageCopyFiles(context)

odsQuickstarterStageRenderJenkinsfile(context)

odsQuickstarterStageRenderJenkinsfile(
context,
[source: 'dev.yml.template',
target: 'environments/dev.yml']
)

odsQuickstarterStageRenderJenkinsfile(
context,
[source: 'test.yml.template',
target: 'environments/test.yml']
)

odsQuickstarterStageRenderJenkinsfile(
context,
[source: 'prod.yml.template',
target: 'environments/prod.yml']
)

odsQuickstarterStageRenderJenkinsfile(
context,
[source: 'testing.yml.template',
target: 'environments/testing.yml']
)
}
185 changes: 185 additions & 0 deletions e2e-python/Jenkinsfile.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/* generated jenkins file used for building and deploying AWS-infrastructure in projects */

@Library('ods-jenkins-shared-library@@shared_library_ref@') _

node {
aws_region = env.AWS_REGION
dockerRegistry = env.DOCKER_REGISTRY
}

odsComponentPipeline(
podContainers: [
containerTemplate(
name: 'jnlp',
image: "${dockerRegistry}/ods/jenkins-agent-terraform-2306:@shared_library_ref@",
envVars: [
envVar(key: 'AWS_REGION', value: aws_region)
],
alwaysPullImage: true,
args: '${computer.jnlpmac} ${computer.name}'
)
],
branchToEnvironmentMapping: [
'*': 'dev',
// 'release/': 'test'
]
) { context ->
getEnvironment(context)
addVars2envJsonFile(context)
odsComponentStageInfrastructure(context, [cloudProvider: 'AWS'])

withEnv(["AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}",
"AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}"
])
{
stage ("AWS Testing Preparation"){
generateTerraformOutputsFile()
}

def outputNames = stageGetNamesFromOutputs()
def aws_pipelineName = outputNames.aws_codepipeline_name
def bitbuckets3_name = outputNames.bitbuckets3_name
def results3_name = outputNames.results3_name

stage ("Publish Bitbucket Code To AWS"){
publishBitbucketCodeToAWS(context, bitbuckets3_name)
}

stage ("Run Tests"){
awsCodePipelineTrigger(context, aws_pipelineName)
awsCodePipelineWaitForExecution(context, aws_pipelineName)
}

stage ("Test Results"){
retrieveReportsFromAWS(context, results3_name)
archiveArtifacts artifacts: "build/test-results/test/**", allowEmptyArchive: true
junit(testResults:'build/test-results/test/*.xml', allowEmptyResults: true)
stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: "build/test-results/test/acceptance*junit.xml", allowEmpty: true)
stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: "build/test-results/test/installation*junit.xml", allowEmpty: true)
stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: "build/test-results/test/integration*junit.xml", allowEmpty: true)
}
}

}

def getEnvironment(def context){
sh "echo Get Environment Variables"
AWS_ACCESS_KEY_ID = sh(returnStdout: true, script:"oc get secret aws-access-key-id-${context.environment} --namespace ${context.cdProject} --output jsonpath='{.data.secrettext}' | base64 -d")
AWS_SECRET_ACCESS_KEY = sh(returnStdout: true, script:"oc get secret aws-secret-access-key-${context.environment} --namespace ${context.cdProject} --output jsonpath='{.data.secrettext}' | base64 -d")

}


def generateTerraformOutputsFile() {
sh 'terraform output -json > terraform_outputs.json'
sh 'cat terraform_outputs.json'
}

def stageGetNamesFromOutputs() {
def outputNames = [:]
def terraformOutputJson = readJSON file: 'terraform_outputs.json'
//def environmentVarsJson = readJSON file: env.auto.tfvars.json

outputNames.aws_codepipeline_name = terraformOutputJson.codepipeline_name.value
outputNames.bitbuckets3_name = terraformOutputJson.bitbucket_s3bucket_name.value
outputNames.results3_name = terraformOutputJson.e2e_results_bucket_name.value

return outputNames
}

def awsCodePipelineTrigger(def context, pipelineName) {
sh "aws codepipeline start-pipeline-execution --name ${pipelineName}"
}


def awsCodePipelineWaitForExecution(def context, pipelineName) {
def pipelineExecutionStatus = ''

while (true) {
pipelineExecutionStatus = ''
sleep(time: 40, unit: 'SECONDS')
def pipelineState = sh(
script: "aws codepipeline get-pipeline-state --name ${pipelineName} --query 'stageStates[*]' --output json",
returnStdout: true
).trim()

def pipelineStages = readJSON(text: pipelineState)

pipelineStages.each { stage ->
def stageName = stage.stageName
def stageStatus = stage.latestExecution.status
echo "Stage: ${stageName}, Status: ${stageStatus}"

if (stageStatus == 'InProgress') {
pipelineExecutionStatus = 'InProgress'
return
} else if (stageStatus == 'Failed') {
pipelineExecutionStatus = 'Failed'
echo "Pipeline execution failed at stage ${stageName}"
error("Pipeline execution failed at stage ${stageName}")
return
}
}

if (pipelineExecutionStatus == 'InProgress') {
continue
} else if (pipelineExecutionStatus == 'Failed') {
echo "Pipeline execution failed at stage ${stageName}"
break
} else {
echo 'Pipeline execution completed successfully.'
break
}
}
}



def publishBitbucketCodeToAWS(def context, bitbuckets3_name) {
def branch = context.gitBranch
def repository = context.componentId
zip zipFile: "${repository}-${branch}.zip", archive: false, dir: '.'
sh " aws s3 cp ${repository}-${branch}.zip s3://${bitbuckets3_name}/${repository}-${branch}.zip"
}

def retrieveReportsFromAWS(def context, results3_name) {
sh "aws s3 cp s3://${results3_name}/junit/acceptance_GX_junit.xml ./build/test-results/test/acceptance_GX_junit.xml"
sh "aws s3 cp s3://${results3_name}/junit/acceptance_pytest_junit.xml ./build/test-results/test/acceptance_pytest_junit.xml"
sh "aws s3 cp s3://${results3_name}/junit/installation_pytest_junit.xml ./build/test-results/test/installation_pytest_junit.xml"
sh "aws s3 cp s3://${results3_name}/junit/integration_pytest_junit.xml ./build/test-results/test/integration_pytest_junit.xml"

sh "aws s3 cp s3://${results3_name}/GX_test_results ./build/test-results/test/artifacts/acceptance/acceptance_GX_report --recursive"
sh "aws s3 cp s3://${results3_name}/GX_jsons ./build/test-results/test/artifacts/acceptance/GX_jsons --recursive"
sh "aws s3 cp s3://${results3_name}/pytest_results/acceptance/acceptance_allure_report_complete.html ./build/test-results/test/artifacts/acceptance/acceptance_pytest_report.html"
sh "aws s3 cp s3://${results3_name}/pytest_results/installation/installation_allure_report_complete.html ./build/test-results/test/artifacts/installation/installation_pytest_report.html"
sh "aws s3 cp s3://${results3_name}/pytest_results/integration/integration_allure_report_complete.html ./build/test-results/test/artifacts/integration/integration_pytest_report.html"

sh "ls build/test-results/test"
sh "rm build/test-results/test/default.xml"
}

def addVars2envJsonFile(def context) {
echo "Starting addVars2envJsonFile"
def environment = context.environment
def projectId = context.projectId
def branch_name = context.gitBranch
def repository = context.componentId
def filePath = "./environments/${environment}.json"

def existingJson = readFile file: filePath
def existingData = readJSON text: existingJson

existingData.environment = environment
existingData.projectId = projectId
existingData.aws_region = aws_region
existingData.repository = repository
existingData.branch_name = branch_name

echo "Environment: ${existingData}"

def updatedJson = groovy.json.JsonOutput.toJson(existingData)
writeFile file: filePath, text: updatedJson

echo "Finishing addVars2envJsonFile"
}

105 changes: 104 additions & 1 deletion e2e-python/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,104 @@
# End-to-end tests with python (e2e-python)
# Python end-to-end tests

This end-to-end testing project was generated from the *e2e-python* ODS quickstarter.

## Stages: installation / integration / acceptance

With the introduction of the release manager concept in OpenDevStack 3, e2e test quickstarters are expected to run tests in three different stages (installation, integration & acceptance) and generate a JUnit XML result file for each of these stages.

Make sure to keep `junit` as reporter and to not change the output path for the JUnit results files as they will be stashed by Jenkins and reused by the release manager.

## Running end-to-end tests

To execute all end-to-end tests:

1. Set up AWS account credentials in environment folder's yml files.
2. Customize json files with the desired identification namings for the AWS resources that will be created with the quickestarters execution.
3. Modify the great_expectations and pytes folder to execute your tests located in the 'tests/acceptance/' directory.

# Pipeline execution options:
- By a commit with a change in the code the pipeline in jenkins will be automatically executed
- From jenkins manually
- Automatic from a test (create a function to automatize the trigger of the pipeline)

## How to use this Stack?

The behavior of a stack is determined by its purpose and the set of input parameters. Here is an overview of the *inputs* and *outputs* available for this stack.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | 4.67.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | 3.5.1 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 4.67.0 |
| <a name="provider_random"></a> [random](#provider\_random) | 3.5.1 |

## Modules

| Name | Description |
|-----------------------------------------------------------------------------------------------------------------|-------------|
| [modules\codebuild]() | resource |
| [modules\codepipeline]() | resource |
| [modules\iam_roles]() | resource |
| [modules\s3-bucket]() | resource |
| [modules\s3-bucket-policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/static) | resource |

## Resources

| Name | Type |
|--------------------------------------------------------------------------------------------------------------------------------------------|------|
| [aws_codebuild_project.build_project](https://registry.terraform.io/providers/hashicorp/...) | resource |
| [aws_codepipeline.codepipeline]() | resource |
| [aws_iam_role.codepipeline_role]() | resource |
| [aws_iam_role.codebuild_role]() | resource |
| [aws_iam_role_policy.codepipeline_policy](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_iam_role_policy.codebuild_policy](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket_policy.allow_access_from_another_account](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket.codepipeline_bucket](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket_versioning.s3versioning-cp](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket.e2e_results_bucket](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket_versioning.s3versioning-artfcs](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket.source_bitbucket_bucket](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [aws_s3_bucket_versioning.s3versioning-bucket](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [random_id.id](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [local_file.terraform-data](https://registry.terraform.io/providers/hashicorp/random/3.5.1/docs/resources/id) | resource |
| [time_static.deployment](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/static) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|------|-----------------------|:--------:|
| <a name="input_codebuild_project_name"></a> [codebuild\_project\_name](#input\_codebuild\_project\_name) | The name of the AWS codebuild project. | `string` | `"codebuild-project"` | no |
| <a name="input_codepipeline_name"></a> [codepipeline\_name](#input\_codepipeline\_name) | The name of the AWS codepipeline. | `string` | `"test-codepipeline"` | no |
| <a name="input_codepipeline_bucket_name"></a> [codepipeline\_bucket\_name](#input\_codepipeline\_bucket\_name) | The name of the codepipeline artifacts S3 bucket. | `string` | `"cpplartifacts"` | no |
| <a name="input_bitbucket_source_bucket_name"></a> [bitbucket\_source\_bucket\_name](#input\_bitbucket\_source\_bucket\_name) | The name of the source S3 bucket. | `string` | `"src-bitbucket"` | no |
| <a name="input_e2e_results_bucket_name"></a> [e2e\_results\_bucket\_name](#input\_e2e\_results\_bucket\_name) | The name of the results S3 bucket. | `string` | `"test-results"` | no |
| <a name="input_pipeline_role_name"></a> [pipeline\_role\_name](#input\_pipeline\_role\_name) | The name of the codepipeline role. | `string` | `"test-codePipelineRole"` | no |
| <a name="input_codebuild_role_name"></a> [codebuild\_role\_name](#input\_codebuild\_role\_name) | The name of the codebuild role. | `string` | `"test-codeBuildRole"` | no |
| <a name="input_codepipeline_policy_name"></a> [codepipeline\_policy\_name](#input\_codepipeline\_policy\_name) | The name of the codepipeline policy. | `string` | `"codepipeline_policy"` | no |
| <a name="input_codebuild_policy_name"></a> [codebuild\_policy\_name](#input\_codebuild\_policy\_name) | The name of the codebuild policy. | `string` | `"codebuild_policy"` | no |
| <a name="input_meta_environment"></a> [meta\_environment](#input\_meta\_environment) | The type of the environment. Can be any of DEVELOPMENT, EVALUATION, PRODUCTIVE, QUALITYASSURANCE, TRAINING, VALIDATION. | `string` | `"DEVELOPMENT"` | no |
| <a name="input_name"></a> [name](#input\_name) | The name of the stack. | `string` | `"stack-aws-quickstarter"` | no |

## Outputs

The output generated by terraform are used for internal quickestarter's purposes.


## Environments
The pipeline supports multiple environments (Testing/DEV/QA/PROD) within OpenDevStack. The behaviour of the pipeline in the environments can be controlled within the **environments** directory.
The *.yml files define the Jenkins secrets to read and are used to deploy into the right environments.
The *.json files can override variables from **variables.tf** in case different environments request different inputs (e.g. deploy a smaller version of the stack in DEV).

## Problems? Questions? Suggestions?

In case of problems, questions or suggestions, feel free to file an issue with the respective project's repository. Thanks!

7 changes: 7 additions & 0 deletions e2e-python/dev.yml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
region: eu-west-1

credentials:
key: @project_id@-cd-aws-access-key-id-dev
secret: @project_id@-cd-aws-secret-access-key-dev

account: "<your_aws_account_id>"
3 changes: 3 additions & 0 deletions e2e-python/files/.devcontainer/devcontainer.json.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"image": "ghcr.io/nichtraunzer/terrarium:latest"
}
19 changes: 19 additions & 0 deletions e2e-python/files/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false ; trimming trailing whitespace may break Markdown

[Makefile]
tab_width = 2
indent_style = tab
20 changes: 20 additions & 0 deletions e2e-python/files/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.bundle
.kitchen
.terraform
.terraform.lock.hcl
.terraform-data.json
.vscode
.devcontainer/devcontainer.json
*.auto.tfvars*
inspec.lock
outputs.json
terraform.tfvars*
terraform.tfstate*
tfplan
vendor
test/integration/*/files/*.json
test/integration/*/files/*.yml
reports/install/*
!reports/install/.gitkeep
Pipfile.lock
.venv
Loading

0 comments on commit 16a202b

Please sign in to comment.