-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathdisaster-recovery.zod.ts
More file actions
248 lines (223 loc) · 9.95 KB
/
Copy pathdisaster-recovery.zod.ts
File metadata and controls
248 lines (223 loc) · 9.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
import { CronExpressionInputSchema } from '../shared/expression.zod';
/**
* Backup Strategy Schema
*
* Defines backup methods for disaster recovery.
*
* - **full**: Complete snapshot of all data
* - **incremental**: Only changes since last backup
* - **differential**: All changes since last full backup
*
* @example
* ```typescript
* const backup: BackupConfig = {
* strategy: 'incremental',
* schedule: '0 2 * * *',
* retention: { days: 30, minCopies: 3 },
* encryption: { enabled: true, algorithm: 'AES-256-GCM' },
* };
* ```
*/
import { lazySchema } from '../shared/lazy-schema';
export const BackupStrategySchema = lazySchema(() => z.enum([
'full',
'incremental',
'differential',
]).describe('Backup strategy type'));
export type BackupStrategy = z.infer<typeof BackupStrategySchema>;
/**
* Backup Retention Policy Schema
*/
export const BackupRetentionSchema = lazySchema(() => z.object({
/** Number of days to retain backups */
days: z.number().min(1).describe('Retention period in days'),
/** Minimum number of backup copies to keep regardless of age */
minCopies: z.number().min(1).default(3).describe('Minimum backup copies to retain'),
/** Maximum number of backup copies */
maxCopies: z.number().optional().describe('Maximum backup copies to store'),
}).describe('Backup retention policy'));
export type BackupRetention = z.infer<typeof BackupRetentionSchema>;
/**
* Backup Configuration Schema
*/
export const BackupConfigSchema = lazySchema(() => z.object({
/** Backup strategy */
strategy: BackupStrategySchema.default('incremental').describe('Backup strategy'),
/** Cron schedule for automated backups */
schedule: CronExpressionInputSchema.optional().describe('Cron expression for backup schedule — cron`0 2 * * *`'),
/** Retention policy */
retention: BackupRetentionSchema.describe('Backup retention policy'),
/** Storage destination */
destination: z.object({
type: z.enum(['s3', 'gcs', 'azure_blob', 'local']).describe('Storage backend type'),
bucket: z.string().optional().describe('Cloud storage bucket/container name'),
path: z.string().optional().describe('Storage path prefix'),
region: z.string().optional().describe('Cloud storage region'),
}).describe('Backup storage destination'),
/** Encryption settings */
encryption: z.object({
enabled: z.boolean().default(true).describe('Enable backup encryption'),
algorithm: z.enum(['AES-256-GCM', 'AES-256-CBC', 'ChaCha20-Poly1305']).default('AES-256-GCM')
.describe('Encryption algorithm'),
keyId: z.string().optional().describe('KMS key ID for encryption'),
}).optional().describe('Backup encryption settings'),
/** Compression settings */
compression: z.object({
enabled: z.boolean().default(true).describe('Enable backup compression'),
algorithm: z.enum(['gzip', 'zstd', 'lz4', 'snappy']).default('zstd').describe('Compression algorithm'),
}).optional().describe('Backup compression settings'),
/** Verify backup integrity after creation */
verifyAfterBackup: z.boolean().default(true).describe('Verify backup integrity after creation'),
}).describe('Backup configuration'));
export type BackupConfig = z.infer<typeof BackupConfigSchema>;
export type BackupConfigInput = z.input<typeof BackupConfigSchema>;
/**
* Failover Mode Schema
*
* Defines how traffic is routed between primary and secondary systems.
*
* - **active_passive**: Secondary is standby, activated on primary failure
* - **active_active**: Both primary and secondary handle traffic
* - **pilot_light**: Minimal secondary with quick scale-up capability
* - **warm_standby**: Reduced-capacity secondary, faster failover than pilot light
*/
export const FailoverModeSchema = lazySchema(() => z.enum([
'active_passive',
'active_active',
'pilot_light',
'warm_standby',
]).describe('Failover mode'));
export type FailoverMode = z.infer<typeof FailoverModeSchema>;
/**
* Failover Configuration Schema
*/
export const FailoverConfigSchema = lazySchema(() => z.object({
/** Failover mode */
mode: FailoverModeSchema.default('active_passive').describe('Failover mode'),
/** Automatic failover enabled */
autoFailover: z.boolean().default(true).describe('Enable automatic failover'),
/** Health check interval in seconds */
healthCheckInterval: z.number().default(30).describe('Health check interval in seconds'),
/** Number of consecutive failures before triggering failover */
failureThreshold: z.number().default(3).describe('Consecutive failures before failover'),
/** Regions/zones for disaster recovery */
regions: z.array(z.object({
name: z.string().describe('Region identifier (e.g., "us-east-1", "eu-west-1")'),
role: z.enum(['primary', 'secondary', 'witness']).describe('Region role'),
endpoint: z.string().optional().describe('Region endpoint URL'),
priority: z.number().optional().describe('Failover priority (lower = higher priority)'),
})).min(2).describe('Multi-region configuration (minimum 2 regions)'),
/** DNS failover configuration */
dns: z.object({
ttl: z.number().default(60).describe('DNS TTL in seconds for failover'),
provider: z.enum(['route53', 'cloudflare', 'azure_dns', 'custom']).optional()
.describe('DNS provider for automatic failover'),
}).optional().describe('DNS failover settings'),
}).describe('Failover configuration'));
export type FailoverConfig = z.infer<typeof FailoverConfigSchema>;
export type FailoverConfigInput = z.input<typeof FailoverConfigSchema>;
/**
* Recovery Point Objective (RPO) Schema
*
* Maximum acceptable amount of data loss measured in time.
*/
export const RPOSchema = lazySchema(() => z.object({
/** RPO value */
value: z.number().min(0).describe('RPO value'),
/** RPO time unit */
unit: z.enum(['seconds', 'minutes', 'hours']).default('minutes').describe('RPO time unit'),
}).describe('Recovery Point Objective (maximum acceptable data loss)'));
export type RPO = z.infer<typeof RPOSchema>;
/**
* Recovery Time Objective (RTO) Schema
*
* Maximum acceptable time to restore service after a disaster.
*/
export const RTOSchema = lazySchema(() => z.object({
/** RTO value */
value: z.number().min(0).describe('RTO value'),
/** RTO time unit */
unit: z.enum(['seconds', 'minutes', 'hours']).default('minutes').describe('RTO time unit'),
}).describe('Recovery Time Objective (maximum acceptable downtime)'));
export type RTO = z.infer<typeof RTOSchema>;
/**
* Disaster Recovery Plan Schema
*
* Complete disaster recovery configuration for an ObjectStack deployment.
* Covers backup, failover, replication, and recovery objectives.
*
* Aligned with industry standards:
* - ISO 22301 (Business Continuity Management)
* - AWS Well-Architected Framework (Reliability Pillar)
*
* @example
* ```typescript
* const drPlan: DisasterRecoveryPlan = {
* enabled: true,
* rpo: { value: 15, unit: 'minutes' },
* rto: { value: 1, unit: 'hours' },
* backup: {
* strategy: 'incremental',
* schedule: '0 0/6 * * *',
* retention: { days: 90, minCopies: 5 },
* destination: { type: 's3', bucket: 'backup-bucket', region: 'us-east-1' },
* },
* failover: {
* mode: 'active_passive',
* autoFailover: true,
* healthCheckInterval: 30,
* failureThreshold: 3,
* regions: [
* { name: 'us-east-1', role: 'primary' },
* { name: 'us-west-2', role: 'secondary' },
* ],
* },
* };
* ```
*/
export const DisasterRecoveryPlanSchema = lazySchema(() => z.object({
/** Enable disaster recovery */
enabled: z.boolean().default(false).describe('Enable disaster recovery plan'),
/** Recovery Point Objective */
rpo: RPOSchema.describe('Recovery Point Objective'),
/** Recovery Time Objective */
rto: RTOSchema.describe('Recovery Time Objective'),
/** Backup configuration */
backup: BackupConfigSchema.describe('Backup configuration'),
/** Failover configuration */
failover: FailoverConfigSchema.optional().describe('Multi-region failover configuration'),
/** Data replication settings */
replication: z.object({
/** Replication mode */
mode: z.enum(['synchronous', 'asynchronous', 'semi_synchronous']).default('asynchronous')
.describe('Data replication mode'),
/** Maximum replication lag allowed (seconds) */
maxLagSeconds: z.number().optional().describe('Maximum acceptable replication lag in seconds'),
/** Objects/tables to replicate (empty = all) */
includeObjects: z.array(z.string()).optional().describe('Objects to replicate (empty = all)'),
/** Objects/tables to exclude from replication */
excludeObjects: z.array(z.string()).optional().describe('Objects to exclude from replication'),
}).optional().describe('Data replication settings'),
/** Automated recovery testing */
testing: z.object({
/** Enable periodic DR testing */
enabled: z.boolean().default(false).describe('Enable automated DR testing'),
/** Cron schedule for DR tests */
schedule: CronExpressionInputSchema.optional().describe('Cron expression for DR test schedule'),
/** Notification channel for test results */
notificationChannel: z.string().optional().describe('Notification channel for DR test results'),
}).optional().describe('Automated disaster recovery testing'),
/** Runbook URL for manual procedures */
runbookUrl: z.string().optional().describe('URL to disaster recovery runbook/playbook'),
/** Contact list for DR incidents */
contacts: z.array(z.object({
name: z.string().describe('Contact name'),
role: z.string().describe('Contact role (e.g., "DBA", "SRE Lead")'),
email: z.string().optional().describe('Contact email'),
phone: z.string().optional().describe('Contact phone'),
})).optional().describe('Emergency contact list for DR incidents'),
}).describe('Complete disaster recovery plan configuration'));
export type DisasterRecoveryPlan = z.infer<typeof DisasterRecoveryPlanSchema>;
export type DisasterRecoveryPlanInput = z.input<typeof DisasterRecoveryPlanSchema>;