Netdata.cloud bot for Zulip
1"""Main entry point for the Netdata Zulip bot.""" 2 3import argparse 4import sys 5 6import structlog 7 8from .config import load_config, load_zuliprc_config 9from .server import NetdataWebhookServer 10 11 12def setup_logging(): 13 """Configure structured logging.""" 14 structlog.configure( 15 processors=[ 16 structlog.stdlib.filter_by_level, 17 structlog.stdlib.add_logger_name, 18 structlog.stdlib.add_log_level, 19 structlog.stdlib.PositionalArgumentsFormatter(), 20 structlog.processors.TimeStamper(fmt="iso"), 21 structlog.processors.StackInfoRenderer(), 22 structlog.processors.format_exc_info, 23 structlog.processors.UnicodeDecoder(), 24 structlog.processors.JSONRenderer(), 25 ], 26 context_class=dict, 27 logger_factory=structlog.stdlib.LoggerFactory(), 28 wrapper_class=structlog.stdlib.BoundLogger, 29 cache_logger_on_first_use=True, 30 ) 31 32 33def create_sample_configs(): 34 """Create sample configuration files.""" 35 36 # Sample .env file 37 env_content = """# Server Configuration (HTTP only, TLS handled by reverse proxy) 38SERVER_HOST=0.0.0.0 39SERVER_PORT=8080 40 41# Netdata webhook challenge secret (required for webhook verification) 42SERVER_CHALLENGE_SECRET=your-challenge-secret-here 43 44# Optional: Override Zulip stream (default: netdata-alerts) 45# ZULIP_STREAM=custom-alerts-stream 46""" 47 48 with open(".env.sample", "w") as f: 49 f.write(env_content) 50 51 # Sample zuliprc file 52 zuliprc_content = """[api] 53site=https://yourorg.zulipchat.com 54email=netdata-bot@yourorg.zulipchat.com 55key=your-api-key-here 56stream=netdata-alerts 57""" 58 59 with open(".zuliprc.sample", "w") as f: 60 f.write(zuliprc_content) 61 62 print("Created sample configuration files:") 63 print(" - .env.sample") 64 print(" - .zuliprc.sample") 65 print() 66 print("Copy and customize these files:") 67 print(" cp .env.sample .env") 68 print(" cp .zuliprc.sample ~/.zuliprc") 69 70 71def main(): 72 """Main entry point.""" 73 parser = argparse.ArgumentParser( 74 description=( 75 "Netdata Zulip Bot - Webhook service for Netdata Cloud notifications" 76 ) 77 ) 78 parser.add_argument( 79 "--zuliprc", help="Path to zuliprc configuration file (default: ~/.zuliprc)" 80 ) 81 parser.add_argument( 82 "--create-config", 83 action="store_true", 84 help="Create sample configuration files and exit", 85 ) 86 parser.add_argument( 87 "--env-config", 88 action="store_true", 89 help="Use environment variables for configuration instead of zuliprc", 90 ) 91 92 args = parser.parse_args() 93 94 setup_logging() 95 logger = structlog.get_logger() 96 97 if args.create_config: 98 create_sample_configs() 99 return 100 101 try: 102 # Load configuration 103 if args.env_config: 104 zulip_config, server_config = load_config() 105 # Validate that required Zulip fields are provided via environment 106 if not all([zulip_config.site, zulip_config.email, zulip_config.api_key]): 107 missing = [] 108 if not zulip_config.site: 109 missing.append("ZULIP_SITE") 110 if not zulip_config.email: 111 missing.append("ZULIP_EMAIL") 112 if not zulip_config.api_key: 113 missing.append("ZULIP_API_KEY") 114 raise ValueError( 115 f"When using --env-config, these environment variables are " 116 f"required: {', '.join(missing)}" 117 ) 118 else: 119 zulip_config = load_zuliprc_config(args.zuliprc) 120 # Still need server config from environment 121 _, server_config = load_config() 122 123 # Create and start the webhook server 124 server = NetdataWebhookServer(zulip_config, server_config) 125 server.run() 126 127 except KeyboardInterrupt: 128 logger.info("Shutting down webhook server") 129 except Exception as e: 130 logger.error("Failed to start webhook server", error=str(e)) 131 sys.exit(1) 132 133 134if __name__ == "__main__": 135 main()