Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
116 changes: 116 additions & 0 deletions deps/wazuh_testing/wazuh_testing/qa_ctl/deployment/DockerWrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import docker
from Instance import Instance
from json import dumps


class DockerWrapper(Instance):
"""Class to handle docker operations. This class uses the docker python SDK to read a dockerfile and create
the image and container.

Attributes:
dockerfile_path (str): Path where the Dockerfile is stored.
name (str): Container's name.
remove (bool): Remove the container after it has finished.
detach (bool): Run container in background.
ports (dict): Ports to bind inside the container.
The keys of the dictionary are the ports to bind inside the container and the values of the
dictionary are the corresponding ports to open on the host.
stdout (bool): Return stdout logs when detach is False.
stderr (bool): Return stderr logs when detach is False.

Args:
dockerfile_path (str): Value to set dockerfile_path attribute.
name (str): Value to set name attribute.
remove (bool): Value to set remove attribute.
detach (bool): Value to set detach attribute.
ports (dict): Value to set ports attribute.
stdout (bool): Value to set stdout attribute.
stderr (bool): Value to set stderr attribute.
"""
def __init__(self, dockerfile_path, name, remove, ports=None, detach=True, stdout=False, stderr=False):
self.docker_client = docker.from_env()
self.dockerfile_path = dockerfile_path
self.name = name
self.remove = remove
self.detach = detach
self.ports = ports

if self.detach:
self.stdout = stdout
self.stderr = stderr
else:
self.stdout = True
self.stderr = True

self.image = self.docker_client.images.build(path=self.dockerfile_path)[0]

def get_container(self):
"""Function to get the container using the name attribute:

Returns:
Container: Container object with the container info.

Raises:
docker.errors.NotFound: If the container does not exist.
docker.errors.APIError: If the server returns an error.
"""
return self.docker_client.containers.get(self.name)

def run(self):
self.docker_client.containers.run(image=self.image, name=self.name, ports=self.ports,
remove=self.remove, detach=self.detach, stdout=self.stdout,
stderr=self.stderr)

def restart(self):
"""Restart the container.
Raises:
docker.errors.APIError: If the server returns an error.
"""
self.get_container().restart()

def halt(self):
"""Stops the container.
Raises:
docker.errors.APIError: If the server returns an error.
"""
self.get_container().stop()

def destroy(self, remove_image=False):
"""Removes the container
Args:
remove_image(bool): Remove the docker image too. Defaults to False.
Raises:
docker.errors.APIError: If the server returns an error.
"""
self.get_container().remove()
if remove_image:
self.docker_client.images.remove(image=self.image.id, force=True)

def get_instance_info(self):
"""Get the parameters information.
Returns
str: String in JSON format with the parameters of the class.
"""
return dumps({'name': self.name, 'parameters': {
'dockerfile_path': self.dockerfile_path, 'remove': self.remove,
'detach': self.detach, 'ports': self.ports, 'stderr': self.stderr,
'stdout': self.stdout}
})

def get_name(self):
"""Get the name of the container.
Returns
str: String with the name of the container.
"""
return self.name

def status(self):
"""Get the status of the container.
Returns:
str: String with the status of the container (running, exited, not created, etc).
"""
try:
status = self.get_container().status
except docker.errors.NotFound:
status = 'not_created'
return status
41 changes: 41 additions & 0 deletions deps/wazuh_testing/wazuh_testing/qa_ctl/deployment/Instance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (C) 2015-2021, Wazuh Inc.
# Created by Wazuh, Inc. <info@wazuh.com>.
# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2
from abc import ABC, abstractmethod


class Instance(ABC):
"""Abstract class to hold common methods for instance handling"""
@abstractmethod
def run(self):
"""Method to start the instance."""
pass

@abstractmethod
def restart(self):
"""Method to restart the instance."""
pass

@abstractmethod
def halt(self):
"""Method to stop the instance."""
pass

@abstractmethod
def destroy(self):
"""Method to destroy the instance."""
pass

@abstractmethod
def get_instance_info(self):
"""Method to get the instance information."""
pass

@abstractmethod
def get_name(self):
"""Method to get the instance name."""
pass

@abstractmethod
def status(self):
"""Method to get the instance status."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright (C) 2015-2021, Wazuh Inc.
# Created by Wazuh, Inc. <info@wazuh.com>.
# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2
from DockerWrapper import DockerWrapper
from VagrantWrapper import VagrantWrapper


class QAInfraestructure:
"""Class to handle multiples instances objects.
Attributes:
instances (list): List with the instances to handle.
Args:
vm_list (dict): Dictionary with the information of the instances. Must follow the format of the yaml template.
"""
instances = []

def __init__(self, vm_list):
for host in vm_list:
for provider in vm_list[host]['provider']:
data = vm_list[host]['provider'][provider]
if not data['enabled']:
continue

if provider == 'vagrant':
quiet_out = True if 'quiet_out' not in data else data['quiet_out']
vagrant_instance = VagrantWrapper(data['vagrantfile_path'], data['vagrant_box'], data['label'],
data['vm_name'], data['vm_cpu'], data['vm_memory'],
data['vm_system'], data['vm_ip'], quiet_out)
self.instances.append(vagrant_instance)

elif provider == 'docker':
_ports = None if 'ports' not in data else data['ports']
_detach = True if 'detach' not in data else data['detach']
_stdout = False if 'stdout' not in data else data['stdout']
_stderr = False if 'stderr' not in data else data['stderr']

docker_instance = DockerWrapper(data['dockerfile_path'], data['name'], data['remove'],
_ports, _detach, _stdout, _stderr)
self.instances.append(docker_instance)

def run(self):
"""Executes the run method on every configured instance."""
for instance in self.instances:
instance.run()

def halt(self):
"""Executes the 'halt' method on every configured instance."""
for instance in self.instances:
instance.halt()

def restart(self):
"""Executes the 'restart' method on every configured instance."""
for instance in self.instances:
instance.restart()

def destroy(self):
"""Executes the 'destroy' method on every configured instance."""
for instance in self.instances:
instance.destroy()

def status(self):
"""Executes the 'status' method on every configured instance.

Returns:
Dictionary: Contains the status for each configured instance.
"""
status = {}
for instance in self.instances:
status[instance.get_name()] = instance.status()

return status

def get_instances_info(self):
"""Get information about the information for all the configured instances.
Returns:
Dictionary: Dictionary with the information for each configured instance.
"""
info = {}
for instance in self.instances:
info[instance.get_name()] = instance.get_instance_info()

return info
102 changes: 102 additions & 0 deletions deps/wazuh_testing/wazuh_testing/qa_ctl/deployment/VagrantWrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Copyright (C) 2015-2021, Wazuh Inc.
# Created by Wazuh, Inc. <info@wazuh.com>.
# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2
import Vagrantfile as vfile
import vagrant
import os
from Instance import Instance


class VagrantWrapper(Instance):
"""Class to handle Vagrant operations. The class will use the Vagrantfile class to create a vagrantfile in
runtime. The vagrantfile will be dumped to disk only if the up method is executed.

Attributes:
vagrantfile (Vagrantfile): Vagrantfile object containing the vagrantfile information.
vagrant (Vagrant): Vagrant object to handle vagrant operations
Args:
vagrant_root_folder (str): Root folder where the vagrant environment will be created.
vm_box (str): Name or link to the Vagrant box
vm_name (str): Name that will be assigned to the VM
vm_label (str): Label used in the vagrantfile.
vm_cpus (int): Number of CPUs assigned to the VM.
vm_memory (int): Number of RAM bytes assigned to the VM.
vm_system (str): System of the VM (Linux, Windows, Solaris, etc)
vm_ip (str): IP assigned to the VM.
quiet_out (Boolean): Flag to ignore the vagrant output. Defaults to True.
"""

def __init__(self, vagrant_root_folder, vm_box, vm_label, vm_name, vm_cpus, vm_memory, vm_system, vm_ip,
quiet_out=True):

box_folder = os.path.join(vagrant_root_folder, vm_name)
os.makedirs(box_folder, exist_ok=True)

self.vagrantfile = vfile.Vagrantfile(box_folder, vm_box, vm_label, vm_name, vm_cpus, vm_memory,
vm_system, vm_ip)

self.vagrant = vagrant.Vagrant(root=box_folder, quiet_stdout=quiet_out, quiet_stderr=False)
self.vagrantfile.write_vagrantfile()

def run(self):
"""Writes the vagrantfile and starts the VM specified in the vagrantfile."""
self.vagrant.up()

def halt(self):
"""Stops the VM specified in the vagrantfile."""
self.vagrant.halt()

def restart(self):
"""Restarts the VM specified in the vagrantfile."""
self.vagrant.restart()

def destroy(self):
"""Destroys the VM specified in the vagrantfile and remove the vagrantfile."""
self.vagrant.destroy()
self.vagrantfile.remove_vagrantfile()

def suspend(self):
"""Suspends the VM specified in the vagrantfile."""
self.vagrant.suspend()

def resume(self):
"""Resumes the VM specified in the vagrantfile."""
self.vagrant.resume()

def get_vagrant_version(self):
"""Gets the vagrant version of the host.
Returns:
String: Vagrant version
"""
return self.vagrant.version()

def status(self):
"""Gets the status of the VM specified in the vagrantfile.
The vagrant module returns a list of namedtuples like the following
`[Status(name='ubuntu', state='not_created', provider='virtualbox')]`
but we are only interested in the `state` field.
Returns:
Dictionary: Status of the VM.
"""
return self.vagrant.status()[0].state

def get_ssh_config(self):
"""Gets the config of the VM specified in the vagrantfile.
Returns:
Dictionary: Dictionary with the configuration of the VM.
"""
return self.vagrant.conf()

def get_instance_info(self):
"""Gets the instance info.
Returns:
Dictionary: Dictionary with the parameters of the VM.
"""
return str(self.vagrantfile)

def get_name(self):
"""Gets the name of the VM.
Returns:
String: Name of the VM.
"""
return self.vagrantfile.vm_name
Loading