mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-06 09:12:45 +01:00
ensure local hypervisor dir when new hypervisor key accepted. apply soc.dyanno.hypervisor when hypervisor key accepted
This commit is contained in:
@@ -163,6 +163,7 @@ def _validate_image_checksum(path, expected_sha256):
|
||||
IMAGE_URL = "https://yum.oracle.com/templates/OracleLinux/OL9/u5/x86_64/OL9U5_x86_64-kvm-b253.qcow2"
|
||||
IMAGE_SHA256 = "3b00bbbefc8e78dd28d9f538834fb9e2a03d5ccdc2cadf2ffd0036c0a8f02021"
|
||||
IMAGE_PATH = "/nsm/libvirt/boot/OL9U5_x86_64-kvm-b253.qcow2"
|
||||
MANAGER_HOSTNAME = socket.gethostname()
|
||||
|
||||
def _download_image():
|
||||
"""
|
||||
@@ -332,6 +333,135 @@ def _check_vm_exists(vm_name: str) -> bool:
|
||||
log.info("MAIN: VM %s already exists", vm_name)
|
||||
return exists
|
||||
|
||||
def _ensure_hypervisor_host_dir(minion_id: str = None):
|
||||
"""
|
||||
Ensure the hypervisor host directory exists.
|
||||
|
||||
This function creates the directory structure for a hypervisor host if it doesn't exist.
|
||||
The path is: /opt/so/saltstack/local/salt/hypervisor/hosts/<hypervisorHostname>
|
||||
|
||||
Args:
|
||||
minion_id (str, optional): Salt minion ID of the hypervisor.
|
||||
|
||||
Returns:
|
||||
bool: True if directory exists or was created successfully, False otherwise
|
||||
"""
|
||||
if not minion_id:
|
||||
log.warning("HOSTDIR: No minion_id provided, skipping host directory creation")
|
||||
return True
|
||||
|
||||
try:
|
||||
# Extract hostname from minion_id by removing role suffix (anything after first underscore)
|
||||
hostname = minion_id.split('_', 1)[0] if '_' in minion_id else minion_id
|
||||
|
||||
# Define the directory path
|
||||
host_dir = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}'
|
||||
|
||||
# Check if directory exists and create it if it doesn't
|
||||
if os.path.exists(host_dir):
|
||||
log.info(f"HOSTDIR: Hypervisor host directory already exists: {host_dir}")
|
||||
# Create the VMs file if it doesn't exist
|
||||
vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs'
|
||||
if not os.path.exists(vms_file):
|
||||
with salt.utils.files.fopen(vms_file, 'w') as f:
|
||||
f.write('[]')
|
||||
log.info(f"HOSTDIR: Created empty VMs file: {vms_file}")
|
||||
|
||||
# Set proper ownership for the VMs file
|
||||
try:
|
||||
socore_uid = pwd.getpwnam('socore').pw_uid
|
||||
socore_gid = pwd.getpwnam('socore').pw_gid
|
||||
os.chown(vms_file, socore_uid, socore_gid)
|
||||
log.info(f"HOSTDIR: Set ownership to socore:socore for {vms_file}")
|
||||
except (KeyError, Exception) as e:
|
||||
log.warning(f"HOSTDIR: Failed to set ownership for VMs file: {str(e)}")
|
||||
return True
|
||||
|
||||
# Create all necessary parent directories
|
||||
os.makedirs(host_dir, exist_ok=True)
|
||||
log.info(f"HOSTDIR: Created hypervisor host directory: {host_dir}")
|
||||
|
||||
# Create the VMs file with an empty JSON array
|
||||
vms_file = f'/opt/so/saltstack/local/salt/hypervisor/hosts/{hostname}VMs'
|
||||
with salt.utils.files.fopen(vms_file, 'w') as f:
|
||||
f.write('[]')
|
||||
log.info(f"HOSTDIR: Created empty VMs file: {vms_file}")
|
||||
|
||||
# Set proper ownership (socore:socore)
|
||||
try:
|
||||
socore_uid = pwd.getpwnam('socore').pw_uid
|
||||
socore_gid = pwd.getpwnam('socore').pw_gid
|
||||
os.chown(host_dir, socore_uid, socore_gid)
|
||||
os.chown(vms_file, socore_uid, socore_gid)
|
||||
|
||||
# Also set ownership for parent directories if they were just created
|
||||
parent_dir = os.path.dirname(host_dir) # /opt/so/saltstack/local/salt/hypervisor/hosts
|
||||
if os.path.exists(parent_dir):
|
||||
os.chown(parent_dir, socore_uid, socore_gid)
|
||||
|
||||
parent_dir = os.path.dirname(parent_dir) # /opt/so/saltstack/local/salt/hypervisor
|
||||
if os.path.exists(parent_dir):
|
||||
os.chown(parent_dir, socore_uid, socore_gid)
|
||||
|
||||
log.info(f"HOSTDIR: Set ownership to socore:socore for {host_dir} and {vms_file}")
|
||||
except KeyError:
|
||||
log.warning("HOSTDIR: socore user not found, skipping ownership change")
|
||||
except Exception as e:
|
||||
log.warning(f"HOSTDIR: Failed to set ownership: {str(e)}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
log.error(f"HOSTDIR: Error creating hypervisor host directory: {str(e)}")
|
||||
return False
|
||||
|
||||
def _apply_dyanno_hypervisor_state():
|
||||
"""
|
||||
Apply the soc.dyanno.hypervisor state on the salt master.
|
||||
|
||||
This function applies the soc.dyanno.hypervisor state on the salt master
|
||||
to update the hypervisor annotation and ensure all hypervisor host directories exist.
|
||||
|
||||
Returns:
|
||||
bool: True if state was applied successfully, False otherwise
|
||||
"""
|
||||
try:
|
||||
log.info("DYANNO: Applying soc.dyanno.hypervisor state on salt master")
|
||||
|
||||
# Initialize the LocalClient
|
||||
local = salt.client.LocalClient()
|
||||
|
||||
# Target the salt master (localhost) to apply the soc.dyanno.hypervisor state
|
||||
target = MANAGER_HOSTNAME + '_*'
|
||||
state_result = local.cmd(target, 'state.apply', ['soc.dyanno.hypervisor'], tgt_type='glob', concurrent=True)
|
||||
log.debug(f"DYANNO: state_result: {state_result}")
|
||||
# Check if state was applied successfully
|
||||
if state_result:
|
||||
success = True
|
||||
for minion, states in state_result.items():
|
||||
if not isinstance(states, dict):
|
||||
log.error(f"DYANNO: Unexpected result format from {minion}: {states}")
|
||||
success = False
|
||||
continue
|
||||
|
||||
for state_id, state_data in states.items():
|
||||
if not state_data.get('result', False):
|
||||
log.error(f"DYANNO: State {state_id} failed on {minion}: {state_data.get('comment', 'No comment')}")
|
||||
success = False
|
||||
|
||||
if success:
|
||||
log.info("DYANNO: Successfully applied soc.dyanno.hypervisor state")
|
||||
return True
|
||||
else:
|
||||
log.error("DYANNO: Failed to apply soc.dyanno.hypervisor state")
|
||||
return False
|
||||
else:
|
||||
log.error("DYANNO: No response from salt master when applying soc.dyanno.hypervisor state")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"DYANNO: Error applying soc.dyanno.hypervisor state: {str(e)}")
|
||||
return False
|
||||
|
||||
def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id: str = None):
|
||||
"""
|
||||
Main entry point to set up the hypervisor environment.
|
||||
@@ -380,6 +510,43 @@ def setup_environment(vm_name: str = 'sool9', disk_size: str = '220G', minion_id
|
||||
'vm_result': None
|
||||
}
|
||||
|
||||
# Ensure hypervisor host directory exists
|
||||
if not _ensure_hypervisor_host_dir(minion_id):
|
||||
return {
|
||||
'success': False,
|
||||
'error': 'Failed to create hypervisor host directory',
|
||||
'vm_result': None
|
||||
}
|
||||
|
||||
# Initialize the LocalClient
|
||||
local = salt.client.LocalClient()
|
||||
|
||||
# Add retry logic for mine.update
|
||||
max_retries = 10
|
||||
retry_delay = 3
|
||||
mine_update_success = False
|
||||
|
||||
for attempt in range(1, max_retries + 1):
|
||||
mine_update_result = local.cmd(minion_id, 'mine.update')
|
||||
log.debug(f"DYANNO: mine_update_result: {mine_update_result}")
|
||||
|
||||
# Check if mine.update was successful
|
||||
if mine_update_result and all(mine_update_result.values()):
|
||||
log.info(f"DYANNO: mine.update successful on attempt {attempt}")
|
||||
mine_update_success = True
|
||||
break
|
||||
else:
|
||||
log.warning(f"DYANNO: mine.update failed on attempt {attempt}/{max_retries}, retrying in {retry_delay} seconds...")
|
||||
time.sleep(retry_delay)
|
||||
|
||||
if not mine_update_success:
|
||||
log.error(f"DYANNO: mine.update failed after {max_retries} attempts")
|
||||
|
||||
# Apply the soc.dyanno.hypervisor state on the salt master
|
||||
if not _apply_dyanno_hypervisor_state():
|
||||
log.warning("MAIN: Failed to apply soc.dyanno.hypervisor state, continuing with setup")
|
||||
# We don't return an error here as we want to continue with the setup process
|
||||
|
||||
log.info("MAIN: Starting setup_environment in setup_hypervisor runner")
|
||||
|
||||
# Check if environment is already set up
|
||||
@@ -548,9 +715,6 @@ def create_vm(vm_name: str, disk_size: str = '220G'):
|
||||
log.error("CREATEVM: Failed to read SSH public key: %s", str(e))
|
||||
return {'success': False, 'error': 'Failed to read SSH public key'}
|
||||
|
||||
# Get hostname for repo configuration
|
||||
manager_hostname = socket.gethostname()
|
||||
|
||||
# Read and encode GPG keys
|
||||
keys_dir = '/opt/so/saltstack/default/salt/repo/client/files/oracle/keys'
|
||||
oracle_key = _read_and_encode_key(os.path.join(keys_dir, 'RPM-GPG-KEY-oracle'))
|
||||
@@ -607,7 +771,7 @@ write_files:
|
||||
content: |
|
||||
[securityonion]
|
||||
name=Security Onion Repo
|
||||
baseurl=https://{manager_hostname}/repo
|
||||
baseurl=https://{MANAGER_HOSTNAME}/repo
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
sslverify=0
|
||||
|
||||
Reference in New Issue
Block a user