"""Main entry point for the Netdata Zulip bot.""" import argparse import sys import structlog from .config import load_config, load_zuliprc_config from .server import NetdataWebhookServer def setup_logging(): """Configure structured logging.""" structlog.configure( processors=[ structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.processors.JSONRenderer(), ], context_class=dict, logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) def create_sample_configs(): """Create sample configuration files.""" # Sample .env file env_content = """# Server Configuration (HTTP only, TLS handled by reverse proxy) SERVER_HOST=0.0.0.0 SERVER_PORT=8080 # Netdata webhook challenge secret (required for webhook verification) SERVER_CHALLENGE_SECRET=your-challenge-secret-here # Optional: Override Zulip stream (default: netdata-alerts) # ZULIP_STREAM=custom-alerts-stream """ with open(".env.sample", "w") as f: f.write(env_content) # Sample zuliprc file zuliprc_content = """[api] site=https://yourorg.zulipchat.com email=netdata-bot@yourorg.zulipchat.com key=your-api-key-here stream=netdata-alerts """ with open(".zuliprc.sample", "w") as f: f.write(zuliprc_content) print("Created sample configuration files:") print(" - .env.sample") print(" - .zuliprc.sample") print() print("Copy and customize these files:") print(" cp .env.sample .env") print(" cp .zuliprc.sample ~/.zuliprc") def main(): """Main entry point.""" parser = argparse.ArgumentParser( description=( "Netdata Zulip Bot - Webhook service for Netdata Cloud notifications" ) ) parser.add_argument( "--zuliprc", help="Path to zuliprc configuration file (default: ~/.zuliprc)" ) parser.add_argument( "--create-config", action="store_true", help="Create sample configuration files and exit", ) parser.add_argument( "--env-config", action="store_true", help="Use environment variables for configuration instead of zuliprc", ) args = parser.parse_args() setup_logging() logger = structlog.get_logger() if args.create_config: create_sample_configs() return try: # Load configuration if args.env_config: zulip_config, server_config = load_config() # Validate that required Zulip fields are provided via environment if not all([zulip_config.site, zulip_config.email, zulip_config.api_key]): missing = [] if not zulip_config.site: missing.append("ZULIP_SITE") if not zulip_config.email: missing.append("ZULIP_EMAIL") if not zulip_config.api_key: missing.append("ZULIP_API_KEY") raise ValueError( f"When using --env-config, these environment variables are " f"required: {', '.join(missing)}" ) else: zulip_config = load_zuliprc_config(args.zuliprc) # Still need server config from environment _, server_config = load_config() # Create and start the webhook server server = NetdataWebhookServer(zulip_config, server_config) server.run() except KeyboardInterrupt: logger.info("Shutting down webhook server") except Exception as e: logger.error("Failed to start webhook server", error=str(e)) sys.exit(1) if __name__ == "__main__": main()