mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-06 17:22:49 +01:00
add hypervisor to host keys first connection. cleaner qcow2 logging.
This commit is contained in:
@@ -209,6 +209,7 @@ Logging:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@@ -346,6 +347,47 @@ def delete_vm(profile, vm_name, assume_yes=False):
|
|||||||
logger.error(f"Failed to delete VM {vm_name}: {e}")
|
logger.error(f"Failed to delete VM {vm_name}: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def _add_hypervisor_host_key(hostname):
|
||||||
|
"""Add hypervisor host key to root's known_hosts file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hostname (str): The hostname or IP of the hypervisor
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if key was added or already exists, False on error
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
known_hosts = '/root/.ssh/known_hosts'
|
||||||
|
os.makedirs(os.path.dirname(known_hosts), exist_ok=True)
|
||||||
|
|
||||||
|
# Check if key already exists using ssh-keygen
|
||||||
|
if os.path.exists(known_hosts):
|
||||||
|
check_result = subprocess.run(['ssh-keygen', '-F', hostname],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if check_result.returncode == 0 and check_result.stdout.strip():
|
||||||
|
logger.info("Host key for %s already in known_hosts", hostname)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Get host key using ssh-keyscan
|
||||||
|
logger.info("Scanning host key for %s", hostname)
|
||||||
|
process = subprocess.run(['ssh-keyscan', '-H', hostname],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
|
||||||
|
if process.returncode == 0 and process.stdout:
|
||||||
|
# Append new key
|
||||||
|
with open(known_hosts, 'a') as f:
|
||||||
|
f.write(process.stdout)
|
||||||
|
logger.info("Added host key for %s to known_hosts", hostname)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.error("Failed to get host key for %s: %s",
|
||||||
|
hostname, process.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error adding host key for %s: %s", hostname, str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False):
|
def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False):
|
||||||
"""Call salt-cloud to create or destroy a VM"""
|
"""Call salt-cloud to create or destroy a VM"""
|
||||||
try:
|
try:
|
||||||
@@ -353,6 +395,14 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False):
|
|||||||
delete_vm(profile, vm_name, assume_yes)
|
delete_vm(profile, vm_name, assume_yes)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Extract hypervisor hostname from profile (e.g., sool9-jpphype1 -> jpphype1)
|
||||||
|
hypervisor = profile.split('-', 1)[1] if '-' in profile else None
|
||||||
|
if hypervisor:
|
||||||
|
logger.info("Ensuring host key exists for hypervisor %s", hypervisor)
|
||||||
|
if not _add_hypervisor_host_key(hypervisor):
|
||||||
|
logger.error("Failed to add host key for %s, cannot proceed with VM creation", hypervisor)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Start the salt-cloud command as a subprocess
|
# Start the salt-cloud command as a subprocess
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
['salt-cloud', '-p', profile, vm_name, '-l', 'info'],
|
['salt-cloud', '-p', profile, vm_name, '-l', 'info'],
|
||||||
@@ -394,6 +444,29 @@ def call_salt_cloud(profile, vm_name, destroy=False, assume_yes=False):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"An error occurred while calling salt-cloud: {e}")
|
logger.error(f"An error occurred while calling salt-cloud: {e}")
|
||||||
|
|
||||||
|
def format_qcow2_output(operation, result):
|
||||||
|
"""Format the output from qcow2 module operations for better readability.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
operation (str): The name of the operation (e.g., 'Network configuration', 'Hardware configuration')
|
||||||
|
result (dict): The result dictionary from the qcow2 module
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None - logs the formatted output directly
|
||||||
|
"""
|
||||||
|
for host, host_result in result.items():
|
||||||
|
if isinstance(host_result, dict):
|
||||||
|
# Extract and format stderr which contains the detailed log
|
||||||
|
if 'stderr' in host_result:
|
||||||
|
logger.info(f"{operation} on {host}:")
|
||||||
|
for line in host_result['stderr'].split('\n'):
|
||||||
|
if line.strip():
|
||||||
|
logger.info(f" {line.strip()}")
|
||||||
|
if host_result.get('retcode', 0) != 0:
|
||||||
|
logger.error(f"{operation} failed on {host} with return code {host_result.get('retcode')}")
|
||||||
|
else:
|
||||||
|
logger.info(f"{operation} result from {host}: {host_result}")
|
||||||
|
|
||||||
def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pci_list=None, start=False):
|
def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pci_list=None, start=False):
|
||||||
hv_name = profile.split('-')[1]
|
hv_name = profile.split('-')[1]
|
||||||
target = hv_name + "_*"
|
target = hv_name + "_*"
|
||||||
@@ -411,8 +484,8 @@ def run_qcow2_modify_hardware_config(profile, vm_name, cpu=None, memory=None, pc
|
|||||||
# Pass all PCI devices as a comma-separated list
|
# Pass all PCI devices as a comma-separated list
|
||||||
args_list.append('pci=' + ','.join(pci_list))
|
args_list.append('pci=' + ','.join(pci_list))
|
||||||
|
|
||||||
r = local.cmd(target, 'qcow2.modify_hardware_config', args_list)
|
result = local.cmd(target, 'qcow2.modify_hardware_config', args_list)
|
||||||
logger.info(f'qcow2.modify_hardware_config: {r}')
|
format_qcow2_output('Hardware configuration', result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}")
|
logger.error(f"An error occurred while running qcow2.modify_hardware_config: {e}")
|
||||||
|
|
||||||
@@ -423,7 +496,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No
|
|||||||
interface = 'enp1s0'
|
interface = 'enp1s0'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = local.cmd(target, 'qcow2.modify_network_config', [
|
result = local.cmd(target, 'qcow2.modify_network_config', [
|
||||||
'image=' + image,
|
'image=' + image,
|
||||||
'interface=' + interface,
|
'interface=' + interface,
|
||||||
'mode=' + mode,
|
'mode=' + mode,
|
||||||
@@ -432,7 +505,7 @@ def run_qcow2_modify_network_config(profile, mode, ip=None, gateway=None, dns=No
|
|||||||
'dns4=' + dns if dns else '',
|
'dns4=' + dns if dns else '',
|
||||||
'search4=' + search_domain if search_domain else ''
|
'search4=' + search_domain if search_domain else ''
|
||||||
])
|
])
|
||||||
logger.info(f'qcow2.modify_network_config: {r}')
|
format_qcow2_output('Network configuration', result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"An error occurred while running qcow2.modify_network_config: {e}")
|
logger.error(f"An error occurred while running qcow2.modify_network_config: {e}")
|
||||||
|
|
||||||
@@ -474,6 +547,29 @@ def main():
|
|||||||
try:
|
try:
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
|
|
||||||
|
# Log the initial request
|
||||||
|
if args.destroy:
|
||||||
|
logger.info(f"Received request to destroy VM '{args.vm_name}' using profile '{args.profile}'{' with --assume-yes' if args.assume_yes else ''}")
|
||||||
|
else:
|
||||||
|
# Build network config string
|
||||||
|
network_config = "using DHCP" if args.dhcp4 else f"with static IP {args.ip4}, gateway {args.gw4}"
|
||||||
|
if args.dns4:
|
||||||
|
network_config += f", DNS {args.dns4}"
|
||||||
|
if args.search4:
|
||||||
|
network_config += f", search domain {args.search4}"
|
||||||
|
|
||||||
|
# Build hardware config string
|
||||||
|
hw_config = []
|
||||||
|
if args.cpu:
|
||||||
|
hw_config.append(f"{args.cpu} CPUs")
|
||||||
|
if args.memory:
|
||||||
|
hw_config.append(f"{args.memory}MB RAM")
|
||||||
|
if args.pci:
|
||||||
|
hw_config.append(f"PCI devices: {', '.join(args.pci)}")
|
||||||
|
hw_string = f" and hardware config: {', '.join(hw_config)}" if hw_config else ""
|
||||||
|
|
||||||
|
logger.info(f"Received request to create VM '{args.vm_name}' using profile '{args.profile}' {network_config}{hw_string}")
|
||||||
|
|
||||||
if args.destroy:
|
if args.destroy:
|
||||||
# Handle VM deletion
|
# Handle VM deletion
|
||||||
call_salt_cloud(args.profile, args.vm_name, destroy=True, assume_yes=args.assume_yes)
|
call_salt_cloud(args.profile, args.vm_name, destroy=True, assume_yes=args.assume_yes)
|
||||||
|
|||||||
Reference in New Issue
Block a user