mirror of
https://github.com/peasead/elastic-container
synced 2026-06-08 16:43:23 +00:00
9b48e37035
- No longer a 'port' - this is now the primary implementation - Remove reference to elastic-container.sh bash script
422 lines
14 KiB
Python
Executable File
422 lines
14 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Elastic Container - Python Edition
|
|
|
|
A 100% containerized Elastic Stack with Elasticsearch, Kibana, Fleet,
|
|
and the Detection Engine all pre-configured and ready to use.
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
import click
|
|
|
|
from lib.config import Config
|
|
from lib.docker_manager import DockerManager
|
|
from lib.kibana_manager import KibanaManager
|
|
from lib.utils import get_host_ip, check_prerequisites
|
|
|
|
|
|
# ASCII art banner
|
|
BANNER = """
|
|
╔═══════════════════════════════════════════════════════════════════╗
|
|
║ ║
|
|
║ ELASTIC CONTAINER - Python Edition ║
|
|
║ ║
|
|
║ Containerized Elastic Stack with Detection Engine & Fleet ║
|
|
║ ║
|
|
╚═══════════════════════════════════════════════════════════════════╝
|
|
"""
|
|
|
|
|
|
@click.group(invoke_without_command=True)
|
|
@click.option('-v', '--verbose', is_flag=True, help='Enable verbose output')
|
|
@click.pass_context
|
|
def cli(ctx, verbose):
|
|
"""Elastic Container - Manage your containerized Elastic Stack"""
|
|
# Store verbose flag in context for subcommands
|
|
ctx.ensure_object(dict)
|
|
ctx.obj['verbose'] = verbose
|
|
|
|
# If no command provided, show help
|
|
if ctx.invoked_subcommand is None:
|
|
click.echo(ctx.get_help())
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def stage(ctx):
|
|
"""Download all necessary Docker images to local storage"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
# Initialize components
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
# Check Docker availability
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
# Pull images
|
|
if docker_manager.stage():
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.option('--force-setup', is_flag=True, help='Force full setup even if containers exist')
|
|
@click.pass_context
|
|
def start(ctx, force_setup):
|
|
"""Create container network and start all stack containers"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
if verbose:
|
|
click.echo(BANNER)
|
|
|
|
# Check prerequisites
|
|
click.secho("Checking prerequisites...", fg="cyan")
|
|
if not check_prerequisites(verbose=verbose):
|
|
sys.exit(1)
|
|
|
|
# Load configuration
|
|
config = Config()
|
|
|
|
# Validate passwords have been changed
|
|
config.validate_passwords()
|
|
|
|
# Initialize managers
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
# Check Docker availability
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
# Check if containers already exist
|
|
containers_exist, containers_running = docker_manager.check_containers_exist()
|
|
|
|
if containers_exist and not force_setup:
|
|
if containers_running:
|
|
click.echo()
|
|
click.secho("✓ Containers are already running!", fg="green", bold=True)
|
|
click.echo()
|
|
click.secho(f"Browse to {config.local_kibana_url}", fg="cyan", bold=True)
|
|
click.echo()
|
|
if verbose:
|
|
click.echo("Use 'python elastic-container.py status' to check container status")
|
|
click.echo("Use 'python elastic-container.py --force-setup start' to reconfigure")
|
|
sys.exit(0)
|
|
else:
|
|
click.echo()
|
|
click.secho("🔄 Containers exist but are stopped. Starting them...", fg="cyan", bold=True)
|
|
click.echo()
|
|
|
|
# Just start existing containers (quick)
|
|
if not docker_manager.start():
|
|
sys.exit(1)
|
|
|
|
click.echo()
|
|
click.secho("=" * 70, fg="green", bold=True)
|
|
click.secho("✓ Containers started successfully!", fg="green", bold=True)
|
|
click.secho("=" * 70, fg="green", bold=True)
|
|
click.echo()
|
|
click.secho(f"Browse to {config.local_kibana_url}", fg="cyan", bold=True)
|
|
click.echo()
|
|
|
|
if verbose:
|
|
click.secho("Login Credentials:", fg="yellow", bold=True)
|
|
click.echo(f" Username: {config.elastic_username}")
|
|
click.echo(f" Password: {config.elastic_password}")
|
|
click.echo()
|
|
|
|
click.secho("Note:", fg="yellow")
|
|
click.echo(" • Existing configuration preserved")
|
|
click.echo(" • Use --force-setup flag to reconfigure if needed")
|
|
click.echo()
|
|
|
|
sys.exit(0)
|
|
|
|
# First-time setup or forced setup
|
|
if force_setup:
|
|
click.echo()
|
|
click.secho("🔧 Force setup requested - running full configuration...", fg="yellow")
|
|
|
|
# Get host IP for Fleet configuration
|
|
host_ip = get_host_ip()
|
|
if verbose:
|
|
click.secho(f"Host IP: {host_ip}", fg="cyan")
|
|
|
|
# Start containers
|
|
if not docker_manager.start():
|
|
sys.exit(1)
|
|
|
|
# Initialize Kibana manager
|
|
kibana_manager = KibanaManager(config, docker_manager, host_ip, verbose=verbose)
|
|
|
|
# Configure Detection Engine and rules
|
|
if not kibana_manager.configure_detection_engine():
|
|
click.secho("\n⚠ Warning: Detection Engine configuration had issues", fg="yellow")
|
|
click.echo("The stack is running but some features may not be configured.")
|
|
|
|
# Wait for Fleet Server to be ready
|
|
click.echo()
|
|
click.secho("Waiting 40 seconds for Fleet Server setup...", fg="cyan")
|
|
click.echo()
|
|
time.sleep(40)
|
|
|
|
# Configure Fleet
|
|
click.echo("Populating Fleet Settings...")
|
|
if not kibana_manager.setup_fleet():
|
|
click.secho("\n⚠ Warning: Fleet configuration had issues", fg="yellow")
|
|
click.echo("The stack is running but Fleet may not be fully configured.")
|
|
|
|
# Success message
|
|
click.echo()
|
|
click.secho("=" * 70, fg="green", bold=True)
|
|
click.secho("✓ Elastic Stack started successfully", fg="green", bold=True)
|
|
click.secho("=" * 70, fg="green", bold=True)
|
|
click.echo()
|
|
click.secho(f"Browse to {config.local_kibana_url}", fg="cyan", bold=True)
|
|
click.echo()
|
|
|
|
if verbose:
|
|
click.secho("Login Credentials:", fg="yellow", bold=True)
|
|
click.echo(f" Username: {config.elastic_username}")
|
|
click.echo(f" Password: {config.elastic_password}")
|
|
click.echo()
|
|
|
|
click.secho("Note:", fg="yellow")
|
|
click.echo(" • You may see a browser warning due to self-signed certificates")
|
|
click.echo(" • Type 'thisisnotsafe' or click proceed to continue to login")
|
|
click.echo()
|
|
|
|
sys.exit(0)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def stop(ctx):
|
|
"""Stop running containers without removing them"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
# Check if containers exist
|
|
containers_exist, containers_running = docker_manager.check_containers_exist()
|
|
|
|
if not containers_exist:
|
|
click.echo()
|
|
click.secho("✗ No containers found!", fg="red", bold=True)
|
|
click.echo()
|
|
click.echo("Run 'python elastic-container.py start' to create containers first.")
|
|
click.echo()
|
|
sys.exit(1)
|
|
|
|
if not containers_running:
|
|
click.echo()
|
|
click.secho("✓ Containers are already stopped", fg="green")
|
|
click.echo()
|
|
sys.exit(0)
|
|
|
|
if docker_manager.stop():
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def destroy(ctx):
|
|
"""Stop and remove containers, networks, and volumes"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
if docker_manager.destroy():
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def restart(ctx):
|
|
"""Restart all Elastic Stack containers"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
# Check if containers exist
|
|
containers_exist, containers_running = docker_manager.check_containers_exist()
|
|
|
|
if not containers_exist:
|
|
click.echo()
|
|
click.secho("✗ No containers found!", fg="red", bold=True)
|
|
click.echo()
|
|
click.echo("Run 'python elastic-container.py start' to create and start containers first.")
|
|
click.echo()
|
|
sys.exit(1)
|
|
|
|
if not containers_running:
|
|
click.echo()
|
|
click.secho("⚠ Containers exist but are not running", fg="yellow")
|
|
click.echo("Starting them instead of restarting...")
|
|
click.echo()
|
|
|
|
if docker_manager.start():
|
|
click.secho("✓ Containers started successfully!", fg="green")
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
# Containers exist and are running - restart them
|
|
if docker_manager.restart():
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def status(ctx):
|
|
"""Check the status of all stack containers"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
if docker_manager.status():
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command()
|
|
@click.pass_context
|
|
def clear(ctx):
|
|
"""Clear all documents in logs and metrics data streams"""
|
|
verbose = ctx.obj['verbose']
|
|
|
|
try:
|
|
config = Config()
|
|
docker_manager = DockerManager(config, verbose=verbose)
|
|
|
|
if not docker_manager.check_docker_available():
|
|
sys.exit(1)
|
|
|
|
# Get host IP
|
|
host_ip = get_host_ip()
|
|
|
|
if docker_manager.clear_documents(host_ip):
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1)
|
|
|
|
except KeyboardInterrupt:
|
|
click.echo("\n\nOperation cancelled by user.")
|
|
sys.exit(130)
|
|
except Exception as e:
|
|
click.secho(f"\n✗ Error: {e}", fg="red", bold=True)
|
|
if verbose:
|
|
import traceback
|
|
click.echo(traceback.format_exc())
|
|
sys.exit(1)
|
|
|
|
|
|
@cli.command('help')
|
|
@click.pass_context
|
|
def help_command(ctx):
|
|
"""Show this help message"""
|
|
# Get the parent context (the group) to show its help
|
|
click.echo(ctx.parent.get_help())
|
|
|
|
|
|
def main():
|
|
"""Main entry point"""
|
|
cli(obj={})
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|