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()