Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement/4751 dtt1 iteration 2 poc #4841

Merged
merged 74 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
85169b4
Update project's file structure
QU3B1M Dec 6, 2023
25c1807
Update allocation module directory | Create basic classes for providers
QU3B1M Dec 6, 2023
a249d43
Replace interfaces with base classes
QU3B1M Dec 12, 2023
fa4c94b
Update VagrantProvider
QU3B1M Dec 12, 2023
3462f8a
Improve Credential base class & add VagrantCredential
QU3B1M Dec 13, 2023
b7ff11f
Add docstrings
QU3B1M Dec 14, 2023
2f349a5
Add docstrings and order imports
QU3B1M Dec 14, 2023
68a7683
Add Handlers as intermediates with the VMs service
QU3B1M Dec 18, 2023
85a4571
Add first qa-workflow-engine poc
jnasselle Dec 26, 2023
97be679
Add Schema validator
fcaffieri Dec 26, 2023
16a8313
Add cleanup to the schema validator
fcaffieri Dec 26, 2023
73ff004
Add module schemaValidator and requirements
fcaffieri Dec 26, 2023
72ee749
Reorder python imports and add license
jnasselle Dec 27, 2023
6868157
Minor changes
jnasselle Dec 27, 2023
7b626f8
Merge branch 'enhancement/4796-qa-workflow-engine-it2' into enhanceme…
fcaffieri Dec 27, 2023
f252f91
Merge pull request #4798 from wazuh/enhancement/4796-schema-validator…
fcaffieri Dec 27, 2023
48f689c
Add providers and credentials
QU3B1M Dec 27, 2023
c61db1e
Reorganize workflow engine based files
jnasselle Dec 28, 2023
8902b93
Add the two formats for process arguments
jnasselle Dec 28, 2023
fd2b9a2
Add allocator class
QU3B1M Dec 28, 2023
8b716ab
Add cleanup feature
jnasselle Dec 28, 2023
7ce65a8
Fix Path that must be str in models
QU3B1M Dec 28, 2023
a982554
Clean allocator launcher | Minor improvements at values validations
QU3B1M Dec 28, 2023
bd32bfb
Add vm size micro | Remove IP from Vagrant provider and fix Vagrantfile
QU3B1M Dec 28, 2023
6386830
Add debug logs and fix path in vagrantfile for windows
QU3B1M Dec 28, 2023
c3e00f2
Add ip generator and port validator for ConnectionInfo
QU3B1M Dec 29, 2023
4561103
Add validations on track_file for deletion and console logs
QU3B1M Dec 29, 2023
b27820f
Update imports with the new directory structure
QU3B1M Dec 29, 2023
15731c6
Re-order allocator internal directory structure
QU3B1M Dec 29, 2023
47cb868
Add more supported systems for Vagrant provider | Continue dir reorder
QU3B1M Dec 29, 2023
9162863
Add more supported OS for Vagrant provider | fix trailing \r
QU3B1M Dec 29, 2023
f64405b
Fix delete action
QU3B1M Dec 29, 2023
c03a85b
Delete poc-tests/utils/requirements.txt
fcaffieri Dec 29, 2023
390680f
Merge pull request #4800 from wazuh/enhancement/4747-allocator-refactor
fcaffieri Dec 29, 2023
5064aaa
Some fixes on imports, libraries, dependencies and permisions
fcaffieri Dec 29, 2023
2ecd235
Enable delete option for aws provider
QU3B1M Dec 29, 2023
12821e4
Update directory structure and add docstrings to the classes
QU3B1M Dec 30, 2023
10ef41e
Improve docstrings on generic classes
QU3B1M Jan 2, 2024
54d9d25
Fix aws credentials outdated path | Add more docstrings
QU3B1M Jan 2, 2024
2dca94e
Fix AWSCredentials load function
QU3B1M Jan 2, 2024
374b30b
Update credentials errors handling | Fix credentials not being delete…
QU3B1M Jan 2, 2024
4a4f985
Update available sizes | Fix size micro for Vagrant
QU3B1M Jan 2, 2024
1ce47f0
Add Vagrant VMs images
QU3B1M Jan 2, 2024
f2c98e5
Fix yaml template, and modify task.py to support install atribute as …
fcaffieri Jan 2, 2024
3cb1098
Merge with PoC
fcaffieri Jan 2, 2024
327eccc
Merge pull request #4801 from wazuh/enhancement/4747-allocator-refactor
fcaffieri Jan 2, 2024
4040f7b
Clean merge conflicts from the allocation module
QU3B1M Jan 3, 2024
3787f9b
Add playbook and test classes
QU3B1M Jan 3, 2024
4b86d6f
Several changes on workflow engine/processor
jnasselle Jan 3, 2024
bc67bbf
Update Ansible generic class | Add test InputPayload model and create…
QU3B1M Jan 5, 2024
2b4497f
Move test_install to test_agent directory | Add check_files util to h…
QU3B1M Jan 5, 2024
f99cacb
Merge with PoC Iteration 2
fcaffieri Jan 8, 2024
7659215
Merge pull request #4807 from wazuh/enhancement/4796-qa-workflow-engi…
fcaffieri Jan 8, 2024
6596c2c
Fix Task merge problem
fcaffieri Jan 8, 2024
b2ff650
Improvement of provision module, add pydantic, clases, validations, u…
fcaffieri Jan 8, 2024
677ce40
Improvement of provision module, add pydantic, clases, validations, u…
fcaffieri Jan 8, 2024
4dd4e52
Fix task of tasjflow, fix provision launcher, fix shcema validator, f…
fcaffieri Jan 9, 2024
f6987f9
Fix requirements, modes, and task.py
fcaffieri Jan 9, 2024
a46a3b8
Order imports | Update Ansible class usage
QU3B1M Jan 9, 2024
e5ced4d
Merge 4757 into 4750
QU3B1M Jan 9, 2024
a59f7c8
Update Ansible class with new inventory definition
QU3B1M Jan 9, 2024
40a1531
Fix ansible class, add generate inventory, fix task.py to generate ar…
fcaffieri Jan 10, 2024
004a0b3
Uncomment cleanup into yaml example
fcaffieri Jan 10, 2024
19ab4fe
Merge pull request #4822 from wazuh/enhancement/4757-dtt1-provision-m…
fcaffieri Jan 10, 2024
b7f89b0
Rename tests playbooks and clean legacy ones | Update Tester class
QU3B1M Jan 10, 2024
6277774
Merge 4571 into 4570
QU3B1M Jan 10, 2024
0cc6d8e
Add test task to the workflow
QU3B1M Jan 10, 2024
f2601b2
Solve conflixts with enhancement/4751-dtt1-iteration-2-poc
fcaffieri Jan 10, 2024
e730a7a
Solve conflixts with enhancement/4751-dtt1-iteration-2-poc
fcaffieri Jan 10, 2024
57478e3
Merge pull request #4826 from wazuh/enhancement/4750-dtt1-iteration-2…
fcaffieri Jan 10, 2024
b159bca
Add check_files for permissions validations at test_install
QU3B1M Jan 15, 2024
36a8faf
Add assertion to check_files
QU3B1M Jan 15, 2024
9774cc2
Remove the -s tag from the test playbook
QU3B1M Jan 15, 2024
ead7e1e
Merge pull request #4838 from wazuh/enhancement/4750-dtt1-test-module…
fcaffieri Jan 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ __pycache__
venv
wazuh_testing.egg-info
dist
.env

# Python bytecode files
*.pyc
Expand Down Expand Up @@ -44,6 +45,7 @@ Temporary Items

### VisualStudioCode ###
.vscode/*
.vscode/
.mypy_cache/
.vs/*

Expand All @@ -67,3 +69,6 @@ ansible.log

# Ssh keys
key

#Python
__pycache__/
31 changes: 31 additions & 0 deletions deployability/Jenkinsfiles/Launcher.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

String jenkins_reference = params.getOrDefault('JENKINS_REFERENCE', 'enhancement/4751-dtt1-iteration-2-poc')
String launcher_path = "launchers"
String task_flow_launcher = "provision.py"
String workflow = "modules/workflow_engine/examples/dtt1-managers.yaml"
String schema = "modules/workflow_engine/schema.json"

// Jenkinsfile

node {

try {
stage('Clone Repo') {
print("Clone repository")
git branch: "${JENKINS_REFERENCE}", url: 'https://github.com/wazuh/wazuh-qa.git'
}

stage('Launch Task Flow') {
print("Launch Task Flow dry run")
sh "cd ${env.WORKSPACE}/deployability && python3 ${launcher_path}/${task_flow_launcher} ${workflow} --dry-run"

print("Launch Task Flow")
sh "cd ${env.WORKSPACE}/deployability && python3 ${launcher_path}/${task_flow_launcher} ${workflow} ${schema}"
}
}
finally{
stage('Remove venv') {
sh "rm -rf ${env.WORKSPACE}/deployability/venv"
}
}
}
File renamed without changes.
5 changes: 5 additions & 0 deletions deployability/deps/remote_requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# python3-pip
pytest>=7.4.2,<8.0.0
chardet==5.2.0
chardet==5.2.0
pytest-tinybird==0.2.0
10 changes: 10 additions & 0 deletions deployability/deps/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ansible_runner==2.3.4
boto3==1.29.1
pydantic==2.5.2
ansible
ruamel.yaml==0.18.5
ruamel.yaml.clib==0.2.8
graphlib==0.9.5
jsonschema==3.2.0
PyYAML==6.0.1
colorlog==6.8.0
File renamed without changes.
File renamed without changes.
29 changes: 29 additions & 0 deletions deployability/launchers/allocation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import argparse
import os
import sys

project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(project_root)

from modules.allocation import Allocator
from modules.allocation.generic.models import InputPayload

def parse_arguments():
parser = argparse.ArgumentParser(description="Infrastructure providing tool")
parser.add_argument("--provider", choices=['vagrant', 'aws', None], required=False, default=None)
parser.add_argument("--size", choices=['micro', 'small', 'medium', 'large', None], required=False, default=None)
parser.add_argument("--composite-name", required=False, default=None)
parser.add_argument("--action", choices=['create', 'delete'], required=False, default='create')
parser.add_argument("--custom-credentials", required=False, default=None)
parser.add_argument("--track-output", required=False, default='/tmp/wazuh-qa/track.yml')
parser.add_argument("--inventory-output", required=False, default='/tmp/wazuh-qa/inventory.yml')
parser.add_argument("--working-dir", required=False, default='/tmp/wazuh-qa')
return parser.parse_args()


def main():
Allocator.run(InputPayload(**vars(parse_arguments())))


if __name__ == "__main__":
main()
29 changes: 29 additions & 0 deletions deployability/launchers/provision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import argparse
import os
import sys
import ast
import json

# ---------------- Vars ------------------------

project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(project_root)

from modules.provision import Provision, models

# ---------------- Methods ---------------------


def parse_arguments():
parser = argparse.ArgumentParser(description="Provision infraestructure tool")
parser.add_argument("--inventory-agent", default=None, help="Inventory with agent host information")
parser.add_argument("--inventory-manager", default=None, help="Inventory with manager host information")
parser.add_argument('--install', action='append', default=[], help='List of dictionaries for installation.')
parser.add_argument("--custom-credentials", required=False, default=None)
return parser.parse_args()

if __name__ == "__main__":
provision = Provision(models.InputPayload(**vars(parse_arguments())))
provision.run()

# ----------------------------------------------
35 changes: 35 additions & 0 deletions deployability/launchers/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import argparse
import sys
import os

project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(project_root)

from modules.testing import Tester, InputPayload


def parse_arguments():
parser = argparse.ArgumentParser(description="Wazuh testing tool")
parser.add_argument("--inventory", required=True)
parser.add_argument("--tests", required=True)
parser.add_argument("--component", choices=['manager', 'agent'], required=True)
parser.add_argument("--dependency", required=False)
parser.add_argument("--cleanup", required=False, default=True)
parser.add_argument("--wazuh-version", required=True)
parser.add_argument("--wazuh-revision", required=True)
parser.add_argument("--wazuh-branch", required=False)
return parser.parse_args()


if __name__ == "__main__":
Tester.run(InputPayload(**vars(parse_arguments())))



# linux-ubuntu-20.04-amd64:
# hosts:
# VAGRANT-F6FD6643-B41E-4112-A652-3CFF8CC26F51:
# ansible_host: 127.0.0.1
# ansible_port: 2222
# ansible_ssh_private_key_file: C:\tmp\wazuh-qa\VAGRANT-F6FD6643-B41E-4112-A652-3CFF8CC26F51\instance_key
# ansible_user: vagrant
49 changes: 49 additions & 0 deletions deployability/launchers/workflow_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright (C) 2015, Wazuh Inc.
# Created by Wazuh, Inc. <[email protected]>.
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2

import os
import sys
import argparse
import logging
import colorlog
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(project_root)
from modules.workflow_engine.workflow_processor import WorkflowProcessor
from modules.generic import SchemaValidator



def parse_arguments() -> argparse.Namespace:
"""Parse command line arguments."""
parser = argparse.ArgumentParser(description='Execute tasks in a workflow.')
parser.add_argument('workflow_file', type=str, help='Path to the workflow file (YAML format).')
parser.add_argument('schema_file', type=str, default="./schema.json", help='Path to the schema definition file.')
parser.add_argument('--threads', type=int, default=1, help='Number of threads to use for parallel execution.')
parser.add_argument('--dry-run', action='store_true', help='Display the plan without executing tasks.')
parser.add_argument('--log-level', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='INFO',
help='Log level.')
return parser.parse_args()

def setup_logger(log_level: str) -> None:
"""Setup logger."""
logger = logging.getLogger()
console_handler = colorlog.StreamHandler()
console_handler.setFormatter(colorlog.ColoredFormatter("%(log_color)s[%(asctime)s] [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S"))
logger.addHandler(console_handler)
logger.setLevel(log_level)

def main() -> None:
"""Main entry point."""

args = parse_arguments()
validator = SchemaValidator(args.schema_file, args.workflow_file)
validator.preprocess_data()
validator.validateSchema()
setup_logger(args.log_level)
processor = WorkflowProcessor(args.workflow_file, args.dry_run, args.threads)
processor.run()


if __name__ == "__main__":
main()
5 changes: 5 additions & 0 deletions deployability/modules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .provision import Provision
from .generic import Ansible
from .allocation.vagrant import VagrantProvider
from .allocation.aws import AWSProvider
from .generic import SchemaValidator
1 change: 1 addition & 0 deletions deployability/modules/allocation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .allocation import Allocator
113 changes: 113 additions & 0 deletions deployability/modules/allocation/allocation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import yaml

from pathlib import Path

from .generic import Instance, Provider, models
from .aws.provider import AWSProvider
from .vagrant.provider import VagrantProvider

PROVIDERS = {'vagrant': VagrantProvider, 'aws': AWSProvider}


class Allocator:
"""
Allocator class to manage instances based on the payload action.
"""
@classmethod
def run(cls, payload: models.InputPayload) -> None:
"""
Executes the appropriate method based on the payload action.

Args:
payload (InputPayload): The payload containing the action parameters.
"""
payload = models.InputPayload(**dict(payload))
# Detect the action and call the appropriate method.
if payload.action == 'create':
print(f"Creating instance at {payload.working_dir}")
return cls.__create(payload)
elif payload.action == 'delete':
print(f"Deleting instance from trackfile {payload.track_output}")
return cls.__delete(payload)

# Internal methods

@classmethod
def __create(cls, payload: models.CreationPayload):
"""
Creates an instance and generates the inventory and track files.

Args:
payload (CreationPayload): The payload containing the parameters
for instance creation.
"""
instance_params = models.CreationPayload(**dict(payload))
provider: Provider = PROVIDERS[payload.provider]()
instance = provider.create_instance(
payload.working_dir, instance_params)
print(f"Instance {instance.identifier} created.")
# Start the instance
instance.start()
print(f"Instance {instance.identifier} started.")
# Generate the inventory and track files.
cls.__generate_inventory(instance, payload.inventory_output)
cls.__generate_track_file(instance, payload.provider, payload.track_output)

@classmethod
def __delete(cls, payload: models.DeletionPayload) -> None:
"""
Deletes an instance based on the data from the track file.

Args:
payload (DeletionPayload): The payload containing the parameters
for instance deletion.
"""
payload = models.DeletionPayload(**dict(payload))
# Read the data from the track file.
with open(payload.track_output, 'r') as f:
track = models.TrackOutput(**yaml.safe_load(f))
provider = PROVIDERS[track.provider]()
provider.destroy_instance(track.instance_dir, track.identifier)
print(f"Instance {track.identifier} deleted.")

@staticmethod
def __generate_inventory(instance: Instance, inventory_path: Path) -> None:
"""
Generates an inventory file.

Args:
instance (Instance): The instance for which the inventory file is generated.
inventory_path (Path): The path where the inventory file will be generated.
"""
inventory_path = Path(inventory_path)
if not inventory_path.parent.exists():
inventory_path.parent.mkdir(parents=True, exist_ok=True)
ssh_config = instance.ssh_connection_info()
inventory = models.InventoryOutput(ansible_host=ssh_config.hostname,
ansible_user=ssh_config.user,
ansible_port=ssh_config.port,
ansible_ssh_private_key_file=str(ssh_config.private_key))
with open(inventory_path, 'w') as f:
yaml.dump(inventory.model_dump(), f)
print(f"\nInventory file generated at {inventory_path}")

@staticmethod
def __generate_track_file(instance: Instance, provider_name: str, track_path: Path) -> None:
"""
Generates a track file.

Args:
instance (Instance): The instance for which the track file is to be generated.
provider_name (str): The name of the provider.
track_path (Path): The path where the track file will be generated.
"""
track_path = Path(track_path)
if not track_path.parent.exists():
track_path.parent.mkdir(parents=True, exist_ok=True)
track = models.TrackOutput(identifier=instance.identifier,
provider=provider_name,
instance_dir=str(instance.path),
key_path=str(instance.credentials.key_path))
with open(track_path, 'w') as f:
yaml.dump(track.model_dump(), f)
print(f"\nTrack file generated at {track_path}")
3 changes: 3 additions & 0 deletions deployability/modules/allocation/aws/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .credentials import AWSCredentials
from .instance import AWSInstance
from .provider import AWSProvider
Loading