init
This commit is contained in:
149
s3_api/Jenkinsfile
vendored
Normal file
149
s3_api/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
def vaultConfig() {
|
||||
return [
|
||||
vaultUrl: '172.17.0.3:8200',
|
||||
credentialsId: 'vault-approle',
|
||||
engineVersion: 2
|
||||
]
|
||||
}
|
||||
|
||||
def vaultSecrets() {
|
||||
return [[
|
||||
path: 'secret/data/companyTransferMoneyService',
|
||||
secretValues: [
|
||||
[envVar: 'API_KEY', vaultKey: 'api_key'],
|
||||
[envVar: 'SELENIUM_GRID', vaultKey: 'selenium_grid_url']
|
||||
]
|
||||
]]
|
||||
}
|
||||
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'python:3.12-slim'
|
||||
label 'python3.12'
|
||||
args '-v /tmp:/tmp' // Optional: Mount /tmp for caching, etc.
|
||||
}
|
||||
}
|
||||
|
||||
environment {
|
||||
PYTHON_VERSION = "3.12"
|
||||
AWS_REGION = "eu-central-1"
|
||||
S3_BUCKET = "Company-ci-executions"
|
||||
SERVICE_NAME = "companyTransferMoneyService"
|
||||
}
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
buildDiscarder(logRotator(numToKeepStr: '20'))
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
stage('Checkout') {
|
||||
agent { label 'ubuntu' }
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Environment') {
|
||||
steps {
|
||||
sh '''
|
||||
python3.12 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
mkdir -p reports
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Unit Tests (Parallel)') {
|
||||
parallel {
|
||||
stage('Unit Batch 1') {
|
||||
steps {
|
||||
sh '''
|
||||
. venv/bin/activate
|
||||
pytest tests/unit -n auto \
|
||||
--junitxml=reports/unit1.xml \
|
||||
--cov=app --cov-report=xml:reports/coverage1.xml
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Unit Batch 2') {
|
||||
steps {
|
||||
sh '''
|
||||
. venv/bin/activate
|
||||
pytest tests/unit -n auto \
|
||||
--junitxml=reports/unit2.xml \
|
||||
--cov=app --cov-report=xml:reports/coverage2.xml
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'reports/unit*.xml'
|
||||
publishCoverage adapters: [coberturaAdapter('reports/coverage*.xml')]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Integration Tests') {
|
||||
steps {
|
||||
withVault(configuration: vaultConfig(), vaultSecrets: vaultSecrets()) {
|
||||
sh '''
|
||||
. venv/bin/activate
|
||||
export API_KEY=$API_KEY
|
||||
export ENV=staging
|
||||
pytest tests/integration \
|
||||
--junitxml=reports/integration.xml
|
||||
'''
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'reports/integration.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('E2E Tests (Selenium Grid)') {
|
||||
steps {
|
||||
withVault(configuration: vaultConfig(), vaultSecrets: vaultSecrets()) {
|
||||
sh '''
|
||||
. venv/bin/activate
|
||||
export API_KEY=$API_KEY
|
||||
export SELENIUM_GRID_URL=$SELENIUM_GRID
|
||||
# Start Flask app in background
|
||||
nohup python app.py &
|
||||
FLASK_PID=$!
|
||||
# Give Flask a few seconds to start
|
||||
sleep 5
|
||||
pytest tests/e2e/test_selenium.py \
|
||||
--junitxml=reports/e2e_selenium.xml
|
||||
kill $FLASK_PID
|
||||
'''
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'reports/e2e_selenium.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Upload Reports to S3') {
|
||||
steps {
|
||||
withAWS(region: "${AWS_REGION}", credentials: 'aws-jenkins-credentials') {
|
||||
sh '''
|
||||
aws s3 cp reports/ \
|
||||
s3://${S3_BUCKET}/${SERVICE_NAME}/${BUILD_NUMBER}/ \
|
||||
--recursive
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
s3_api/requirements.txt
Normal file
0
s3_api/requirements.txt
Normal file
62
s3_api/s3api.py
Normal file
62
s3_api/s3api.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import requests, json, os
|
||||
from dotenv import load_dotenv
|
||||
from marshmallow import Schema, fields, ValidationError
|
||||
from flask import Flask, request, Response, jsonify
|
||||
from python_terraform import Terraform
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
API_KEY = os.getenv('API_KEY')
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
class BucketSchema(Schema):
|
||||
environment = fields.Str(required=True)
|
||||
bucket_name = fields.Str(required=True)
|
||||
versioning = fields.Str(required=True)
|
||||
encryption = fields.Str(required=True)
|
||||
api_key = fields.Str(required=True)
|
||||
|
||||
def create_bucket(ENVIRONMENT, ENCRYPTED, BUCKET_NAME, VERSIONING):
|
||||
tfstate_bucket = os.getenv("TFSTATE_BUCKET", "company-s3-tfstate-bucket-eu-central-1")
|
||||
tfstate_region = os.getenv("AWS_REGION", "eu-central-1")
|
||||
with open("terraform/backend.tf", "w") as f:
|
||||
f.write('terraform {\n')
|
||||
f.write('backend "s3" {\n')
|
||||
f.write(f'bucket = "{tfstate_bucket}"\n')
|
||||
f.write(f'region = "{tfstate_region}"\n')
|
||||
f.write(f'key = "s3-{ENVIRONMENT}-{BUCKET_NAME}"\n')
|
||||
f.write('}\n}')
|
||||
tf = Terraform(working_dir='terraform',
|
||||
variables={'ENCRYPTED': ENCRYPTED, 'VERSIONING': VERSIONING, 'BUCKET_NAME': BUCKET_NAME, 'ENVIRONMENT': ENVIRONMENT}
|
||||
)
|
||||
return tf.apply(capture_output=True, skip_plan=True, auto_approve=True, var={'ENCRYPTED': ENCRYPTED, 'VERSIONING': VERSIONING, 'BUCKET_NAME': BUCKET_NAME, 'ENVIRONMENT': ENVIRONMENT})
|
||||
|
||||
@app.route('/', methods = ['GET'])
|
||||
def ping():
|
||||
return ["Pong"]
|
||||
|
||||
@app.route('/create_bucket', methods = ['POST'])
|
||||
def bucket_data():
|
||||
request_data = BucketSchema().load(request.json)
|
||||
if request_data["api_key"] == API_KEY:
|
||||
try:
|
||||
ENVIRONMENT = request_data["environment"]
|
||||
BUCKET_NAME = request_data["bucket_name"]
|
||||
ENCRYPTED = request_data["encryption"]
|
||||
VERSIONING = request_data["versioning"]
|
||||
if create_bucket(ENVIRONMENT, ENCRYPTED, BUCKET_NAME, VERSIONING)[0] == 1:
|
||||
return "Something went wrong trying to create the bucket"
|
||||
return f"Creating bucket {BUCKET_NAME} in {ENVIRONMENT} with encryption={ENCRYPTED} and versioning={VERSIONING}"
|
||||
except ValidationError as err:
|
||||
return jsonify(err.messages), 400
|
||||
else:
|
||||
return "Authentication error", 403
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(port = 8080, host="0.0.0.0")
|
||||
3
s3_api/terraform/aws.tf
Normal file
3
s3_api/terraform/aws.tf
Normal file
@@ -0,0 +1,3 @@
|
||||
provider "aws" {
|
||||
region = "eu-central-1"
|
||||
}
|
||||
7
s3_api/terraform/backend.tf
Normal file
7
s3_api/terraform/backend.tf
Normal file
@@ -0,0 +1,7 @@
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "company-s3-tfstate-bucket-eu-central-1"
|
||||
region = "eu-central-1"
|
||||
key = "s3-prod-mybucket-python-testing-1234999"
|
||||
}
|
||||
}
|
||||
50
s3_api/terraform/main.tf
Normal file
50
s3_api/terraform/main.tf
Normal file
@@ -0,0 +1,50 @@
|
||||
resource "aws_s3_bucket" "bucket" {
|
||||
bucket = var.BUCKET_NAME
|
||||
|
||||
tags = {
|
||||
Name = var.BUCKET_NAME
|
||||
Environment = var.ENVIRONMENT
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "versioning" {
|
||||
bucket = aws_s3_bucket.bucket.id
|
||||
|
||||
versioning_configuration {
|
||||
status = var.ENCRYPTED
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "block_public" {
|
||||
bucket = aws_s3_bucket.bucket.id
|
||||
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
|
||||
data "aws_iam_policy_document" "bucket_policy" {
|
||||
statement {
|
||||
sid = "AllowUserReadAccess"
|
||||
effect = "Allow"
|
||||
|
||||
principals {
|
||||
type = "AWS"
|
||||
identifiers = ["arn:aws:iam::848173547540:user/dummy_user"]
|
||||
}
|
||||
|
||||
actions = [
|
||||
"s3:GetObject"
|
||||
]
|
||||
|
||||
resources = [
|
||||
"${aws_s3_bucket.bucket.arn}/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_policy" "bucket_policy" {
|
||||
bucket = aws_s3_bucket.bucket.id
|
||||
policy = data.aws_iam_policy_document.bucket_policy.json
|
||||
}
|
||||
19
s3_api/terraform/vars.tf
Normal file
19
s3_api/terraform/vars.tf
Normal file
@@ -0,0 +1,19 @@
|
||||
variable "BUCKET_NAME" {
|
||||
description = "Name of the bucket to create"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "ENCRYPTED" {
|
||||
description = "S3 encryption enabled?"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "VERSIONING" {
|
||||
description = "S3 versioning enabled?"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "ENVIRONMENT" {
|
||||
description = "Staging or production env?"
|
||||
type = string
|
||||
}
|
||||
19
s3_api/tests/e2e/test_e2e.py
Normal file
19
s3_api/tests/e2e/test_e2e.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
import pytest
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||
|
||||
SELENIUM_GRID_URL = os.getenv('SELENIUM_GRID_URL')
|
||||
|
||||
@pytest.mark.e2e
|
||||
def test_ping_endpoint():
|
||||
if not SELENIUM_GRID_URL:
|
||||
pytest.skip("No Selenium Grid URL set")
|
||||
|
||||
driver = webdriver.Remote(
|
||||
command_executor=SELENIUM_GRID_URL,
|
||||
desired_capabilities=DesiredCapabilities.CHROME
|
||||
)
|
||||
driver.get("http://host.docker.internal:8080/")
|
||||
assert "Pong" in driver.page_source
|
||||
driver.quit()
|
||||
0
s3_api/tests/integration/test_integration.py
Normal file
0
s3_api/tests/integration/test_integration.py
Normal file
0
s3_api/tests/unit/test_app.py
Normal file
0
s3_api/tests/unit/test_app.py
Normal file
Reference in New Issue
Block a user