Skip to content

Commit

Permalink
enhancement(#5229): Merging macos and windows
Browse files Browse the repository at this point in the history
  • Loading branch information
pro-akim committed Apr 26, 2024
1 parent 9b48f37 commit 0dabce1
Show file tree
Hide file tree
Showing 22 changed files with 1,082 additions and 235 deletions.
2 changes: 1 addition & 1 deletion deployability/deps/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ pytest==7.4.4
paramiko==3.4.0
requests==2.31.0
chardet==5.2.0
pywinrm==0.3.0
pywinrm==0.4.0
4 changes: 0 additions & 4 deletions deployability/modules/allocation/static/specs/os.yml
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,6 @@ aws:
ami: ami-0a747df120215911a
zone: us-east-1
user: wazuh-user
windows-sign-10-amd64:
ami: ami-078255d5475b46db5
zone: us-east-1
user: wazuh-user
windows-server-2012r2-amd64:
ami: ami-05710c71113d5a40e
zone: us-east-1
Expand Down
5 changes: 2 additions & 3 deletions deployability/modules/allocation/vagrant/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import platform, json
import subprocess
import boto3
import random

from jinja2 import Environment, FileSystemLoader
from pathlib import Path
Expand Down Expand Up @@ -245,8 +244,8 @@ def check_ip(ip):
if response != 0:
return ip

for i in range(254):
ip = f"192.168.57.{random.randint(2, 253)}"
for i in range(2, 254):
ip = f"192.168.57.{i}"
if check_ip(ip):
return ip

Expand Down
9 changes: 7 additions & 2 deletions deployability/modules/generic/ansible.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# 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 ansible_runner
import jinja2
import yaml

from pathlib import Path
from pydantic import BaseModel, IPvAnyAddress
from typing import Optional

from modules.generic.utils import Utils
from modules.generic.logger import Logger
Expand All @@ -16,7 +18,8 @@ class Inventory(BaseModel):
ansible_host: str | IPvAnyAddress
ansible_user: str
ansible_port: int
ansible_ssh_private_key_file: str
ansible_ssh_private_key_file: Optional[str] = None
ansible_password: Optional[str] = None


class Ansible:
Expand Down Expand Up @@ -118,7 +121,9 @@ def generate_inventory(self) -> dict:
self.ansible_data.ansible_host: {
'ansible_port': self.ansible_data.ansible_port,
'ansible_user': self.ansible_data.ansible_user,
'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file
**({'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file}
if hasattr(self.ansible_data, 'ansible_ssh_private_key_file')
else {'ansible_password': self.ansible_data.ansible_password})
}
}
}
Expand Down
266 changes: 182 additions & 84 deletions deployability/modules/testing/tests/helpers/agent.py

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions deployability/modules/testing/tests/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@
CONFIGURATIONS_DIR = Path(WAZUH_ROOT, "etc")
WAZUH_CONF = Path(CONFIGURATIONS_DIR, "ossec.conf")
CLIENT_KEYS = Path(CONFIGURATIONS_DIR, "client.keys")

WINDOWS_ROOT_DIR = Path("C:", "Program Files (x86)", "ossec-agent")
WINDOWS_CONFIGURATIONS_DIR = Path(WINDOWS_ROOT_DIR, "etc")
WAZUH_WINDOWS_CONF = Path(WINDOWS_ROOT_DIR, "ossec.conf")
WINDOWS_CLIENT_KEYS = Path(WINDOWS_ROOT_DIR, "client.keys")
WINDOWS_VERSION = Path(WINDOWS_ROOT_DIR, "VERSION")
WINDOWS_REVISION = Path(WINDOWS_ROOT_DIR, "REVISION")


MACOS_ROOT_DIR = Path("/Library", "Ossec")
MACOS_CONFIGURATIONS_DIR = Path(MACOS_ROOT_DIR, "etc")
WAZUH_MACOS_CONF = Path(MACOS_CONFIGURATIONS_DIR, "ossec.conf")
MACOS_CLIENT_KEYS = Path(MACOS_CONFIGURATIONS_DIR, "client.keys")

# Binaries paths
BINARIES_DIR = Path(WAZUH_ROOT, "bin")
WAZUH_CONTROL = Path(BINARIES_DIR, "wazuh-control")
Expand Down
137 changes: 112 additions & 25 deletions deployability/modules/testing/tests/helpers/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,133 @@

import json
import requests
import paramiko
import subprocess
import urllib3
import yaml
import winrm

from base64 import b64encode


class Executor:
class ConectionInventory():
host: str
port: int
password: str | None = None
username: str
private_key_path: str | None = None

@staticmethod
def execute_command(inventory_path, command) -> str:

def _get_inventory_data(inventory_path) -> dict:
with open(inventory_path, 'r') as yaml_file:
inventory_data = yaml.safe_load(yaml_file)

host = inventory_data.get('ansible_host')
port = inventory_data.get('ansible_port')
private_key_path = inventory_data.get('ansible_ssh_private_key_file')
username = inventory_data.get('ansible_user')
return {
'host': inventory_data.get('ansible_host'),
'port': inventory_data.get('ansible_port'),
'password': inventory_data.get('ansible_password', None),
'username': inventory_data.get('ansible_user'),
'private_key_path': inventory_data.get('ansible_ssh_private_key_file', None)
}

class ConnectionManager:
@staticmethod
def _get_executor(inventory_path) -> type:
from .generic import HostInformation

os_type = HostInformation.get_os_type(inventory_path)
if os_type == "windows":
return WindowsExecutor
elif os_type == "linux":
return UnixExecutor
elif os_type == "macos":
return MacosExecutor

@staticmethod
def execute_commands(inventory_path, commands) -> dict:
executor = ConnectionManager._get_executor(inventory_path)
if isinstance(commands, str):
try:
result = executor._execute_command(ConectionInventory._get_inventory_data(inventory_path), commands)
except Exception as e:
raise Exception(f'Error executing command: {commands} with error: {e}')
return result
else:
results = {}
for command in commands:
result = executor._execute_command(ConectionInventory._get_inventory_data(inventory_path), command)
results[command] = result
return results

class WindowsExecutor():
@staticmethod
def _execute_command(data: ConectionInventory, command) -> dict:
if data.get('port') == 5986:
protocol = 'https'
else:
protocol = 'http'

endpoint_url = f"{protocol}://{data.get('host')}:{data.get('port')}"

try:
session = winrm.Session(endpoint_url, auth=(data.get('username'), data.get('password')),transport='ntlm', server_cert_validation='ignore')
ret = session.run_ps(command)

if ret.status_code == 0:
return {'success': True, 'output': ret.std_out.decode('utf-8').strip()}
else:
return {'success': False, 'output': ret.std_err.decode('utf-8').strip()}
except Exception as e:
raise Exception(f'Error executing command: {command} with error: {e}')

class UnixExecutor():
@staticmethod
def _execute_command(data, command) -> dict:

ssh_command = [
"ssh",
"-i", private_key_path,
"-i", data.get('private_key_path'),
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-p", str(port),
f"{username}@{host}",
"sudo",
"-p", str(data.get('port')),
f"{data.get('username')}@{data.get('host')}",
"sudo",
command
]
result = subprocess.run(ssh_command, stdout=subprocess.PIPE, text=True)

return result.stdout
try:
ret = subprocess.run(ssh_command, stdout=subprocess.PIPE, text=True)
if ret.stdout:
return {'success': True, 'output': ret.stdout.replace('\n', '')}
if ret.stderr:
return {'success': False, 'output': ret.stderr.replace('\n', '')}
return {'success': False, 'output': None}

except Exception as e:
#return {'success': False, 'output': ret.stderr}
raise Exception(f'Error executing command: {command} with error: {e}')


class MacosExecutor():
@staticmethod
def execute_commands(inventory_path, commands=[]) -> dict:
def _execute_command(data, command) -> dict:

try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=data.get('host'), port=data.get('port'), username=data.get('username'), password=data.get('username'))
stdin, stdout, stderr = ssh_client.exec_command(f"sudo {command}")

result = ''.join(stdout.readlines())

results = {}
for command in commands:
results[command] = Executor.execute_command(inventory_path, command)
ssh_client.close()

return results
return result

except Exception as e:
#return {'success': False, 'output': ret.stderr}
raise Exception(f'Error executing command: {command} with error: {e}')

# ------------------------------------------------------


class WazuhAPI:
Expand All @@ -62,14 +146,17 @@ def _authenticate(self):
inventory_data = yaml.safe_load(yaml_file)

user = 'wazuh'

#----Patch issue https://github.com/wazuh/wazuh-packages/issues/2883-------------
file_path = Executor.execute_command(self.inventory_path, 'pwd').replace("\n","") + '/wazuh-install-files/wazuh-passwords.txt'
if not 'true' in Executor.execute_command(self.inventory_path, f'test -f {file_path} && echo "true" || echo "false"'):
Executor.execute_command(self.inventory_path, 'tar -xvf wazuh-install-files.tar')
password = Executor.execute_command(self.inventory_path, "grep api_password wazuh-install-files/wazuh-passwords.txt | head -n 1 | awk '{print $NF}'").replace("'","").replace("\n","")
result = ConnectionManager.execute_commands(self.inventory_path, 'pwd')
file_path = result.get('output') + '/wazuh-install-files/wazuh-passwords.txt'
result = ConnectionManager.execute_commands(self.inventory_path, f'test -f {file_path} && echo "true" || echo "false"')
if not 'true' in result.get('output'):
ConnectionManager.execute_commands(self.inventory_path, 'tar -xvf wazuh-install-files.tar')
result = ConnectionManager.execute_commands(self.inventory_path, "grep api_password wazuh-install-files/wazuh-passwords.txt | head -n 1 | awk '{print $NF}'")
password = result.get('output')[1:-1]
#--------------------------------------------------------------------------------

login_endpoint = 'security/user/authenticate'
host = inventory_data.get('ansible_host')
port = '55000'
Expand Down
Loading

0 comments on commit 0dabce1

Please sign in to comment.