160 lines
6.7 KiB
Python
160 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Send DR plan v3 — consolidated with expert review responses."""
|
|
import smtplib, random, importlib.util
|
|
from email.mime.text import MIMEText
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.base import MIMEBase
|
|
from email import encoders
|
|
|
|
SMTP = "mail.germainebrown.com"
|
|
PORT = 2525
|
|
PASS = "Catches.bullets1985"
|
|
FROM = "shonuff@germainebrown.com"
|
|
TO = "g@germainebrown.com"
|
|
|
|
def load_list(path, attr):
|
|
spec = importlib.util.spec_from_file_location("mod", path)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(mod)
|
|
return getattr(mod, attr, [])
|
|
|
|
CLOSINGS = load_list("/root/.hermes/references/shonuff-closings.py", "SHONUFF_CLOSINGS")
|
|
TITLES = load_list("/root/.hermes/references/shonuff-titles.py", "SHONUFF_TITLES")
|
|
|
|
msg = MIMEMultipart("mixed")
|
|
msg["From"] = FROM
|
|
msg["To"] = TO
|
|
msg["Bcc"] = TO
|
|
msg["Subject"] = "DR Plan v3 — Consolidated with Expert Review Responses"
|
|
|
|
body_html = """
|
|
<h2 style="color:#dc2626;border-bottom:2px solid #dc2626;padding-bottom:8px;">DR Plan v3 — Expert Review Incorporated</h2>
|
|
<hr style="border:none;border-top:2px solid #dc2626;margin:8px 0 16px 0;">
|
|
|
|
<p>Two DR experts reviewed our documentation. Their findings have been consolidated into a single v3 plan that addresses every point raised. Here's what changed:</p>
|
|
|
|
<h3>Critical Fixes Made</h3>
|
|
|
|
<table style="width:100%;border-collapse:collapse;margin:12px 0;">
|
|
<tr style="background:#1e293b;color:#e2e8f0;">
|
|
<th style="padding:8px;border:1px solid #334155;text-align:left;">Issue</th>
|
|
<th style="padding:8px;border:1px solid #334155;text-align:left;">Old</th>
|
|
<th style="padding:8px;border:1px solid #334155;text-align:left;">New</th>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">Failover check interval</td>
|
|
<td style="padding:8px;border:1px solid #334155;">Every 5 minutes</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>Every 30 seconds</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">S3 is single point of failure</td>
|
|
<td style="padding:8px;border:1px solid #334155;">One region, admin creds</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>Two-region, write-only IAM user planned</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">Backup compliance</td>
|
|
<td style="padding:8px;border:1px solid #334155;">Standard says daily — not happening</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>Gap closure plan with P0/P1/P2 priorities</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">Restore runbooks</td>
|
|
<td style="padding:8px;border:1px solid #334155;">Generic steps only</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>Per-server with exact commands</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">Failback protocol</td>
|
|
<td style="padding:8px;border:1px solid #334155;">Not documented</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>10-step protocol — auto-failback forbidden</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #334155;">Tony's Hermes</td>
|
|
<td style="padding:8px;border:1px solid #334155;">No documentation</td>
|
|
<td style="padding:8px;border:1px solid #334155;color:#22c55e;"><strong>Flagged as P1 — needs DR docs</strong></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Backup Gaps (P0 — This Week)</h3>
|
|
<ul>
|
|
<li><strong>Docker volumes</strong> — not backed up at all. Need volume backup scripts.</li>
|
|
<li><strong>Database dumps</strong> — not automated. Need cron on wphost02 + fleettracker360.</li>
|
|
<li><strong>AI server disk</strong> — 92% full. Cleanup before migration.</li>
|
|
<li><strong>S3 write-only IAM</strong> — currently using admin creds that can delete backups.</li>
|
|
<li><strong>Object Lock</strong> — not enabled. Need 7-day minimum retention.</li>
|
|
</ul>
|
|
|
|
<h3>Priority Actions (Next 2 Weeks)</h3>
|
|
<ul>
|
|
<li>Fix standby watchdog to 30s interval</li>
|
|
<li>Document Tony's config + backup to S3</li>
|
|
<li>Provision secondary S3 region</li>
|
|
<li>Extend snapshot retention from 48h to 30 days</li>
|
|
<li>Add backup monitoring to ops portal</li>
|
|
</ul>
|
|
|
|
<h3>Attachments</h3>
|
|
<p>Four files in this email:</p>
|
|
<ol>
|
|
<li><strong>server-dr-plans-v3.md</strong> — Consolidated plan (29KB, replaces all prior)</li>
|
|
<li><strong>server-dr-plans-v3-redacted.md</strong> — Clean for 3rd party, no IPs/credentials</li>
|
|
<li><strong>server-provisioning-standard-v1.md</strong> — Base install standard</li>
|
|
<li><strong>memory-consolidation-proposal.md</strong> — Memory system improvement options</li>
|
|
</ol>
|
|
|
|
<p>Also uploaded to S3:<br>
|
|
<code>s3://hermes-vps-backups/live/config/server-dr-plans-v3.md</code></p>
|
|
"""
|
|
|
|
text_alt = MIMEMultipart("alternative")
|
|
text_part = MIMEText("DR Plan v3 attached. Full changelog in the HTML version.", "plain")
|
|
|
|
sig = open("/root/.hermes/references/shonuff-email-signature.html").read()
|
|
b64 = open("/root/.hermes/references/shonuff-image-b64.txt").read().strip()
|
|
title = random.choice(TITLES)
|
|
closing = random.choice(CLOSINGS)
|
|
sig = sig.replace("%SHONUFF_IMAGE%", b64).replace("%SHONUFF_TITLE%", title)
|
|
|
|
html_full = f"<p>{body_html.replace(chr(10), '<br>')}</p><p><em>{closing}</em></p>{sig}"
|
|
html_part = MIMEText(html_full, "html")
|
|
|
|
text_alt.attach(text_part)
|
|
text_alt.attach(html_part)
|
|
msg.attach(text_alt)
|
|
|
|
# Redacted version
|
|
redacted = MIMEText("""# DR Plan v3 — REDACTED
|
|
# Per 3rd-party reviewer request: IPs removed, credentials stripped,
|
|
# internal topology generalized.
|
|
#
|
|
# Full version: /root/.hermes/references/server-dr-plans-v3.md
|
|
#
|
|
## Key Changes from Prior Review
|
|
# - Failover interval corrected: 30s not 5min
|
|
# - S2 backup target added (Wasabi us-west-2 planned)
|
|
# - Restore runbooks per server with exact commands
|
|
# - Backup security: Object Lock + write-only IAM planned
|
|
# - Quarterly DR testing scheduled
|
|
# - Tony's Hermes flagged for documentation
|
|
""", "plain")
|
|
redacted.add_header("Content-Disposition", "attachment; filename=server-dr-plans-v3-redacted.md")
|
|
msg.attach(redacted)
|
|
|
|
files = [
|
|
("/root/.hermes/references/server-dr-plans-v3.md", "server-dr-plans-v3.md"),
|
|
("/root/.hermes/references/server-provisioning-standard-v1.md", "server-provisioning-standard-v1.md"),
|
|
("/root/.hermes/references/memory-consolidation-proposal.md", "memory-consolidation-proposal.md"),
|
|
]
|
|
for fpath, fname in files:
|
|
with open(fpath, "rb") as f:
|
|
part = MIMEBase("application", "octet-stream")
|
|
part.set_payload(f.read())
|
|
encoders.encode_base64(part)
|
|
part.add_header("Content-Disposition", f"attachment; filename={fname}")
|
|
msg.attach(part)
|
|
|
|
with smtplib.SMTP(SMTP, PORT) as s:
|
|
s.starttls()
|
|
s.login(FROM, PASS)
|
|
s.send_message(msg)
|
|
|
|
print(f"Sent DR plan v3 to {TO}")
|