1import * as oracle from "@distilled.cloud/gcp/oracledatabase_v1";
2import * as Effect from "effect/Effect";
3import { Unowned } from "../../AdoptPolicy.ts";
4import { isResolved } from "../../Diff.ts";
5import * as Provider from "../../Provider.ts";
6import { Resource } from "../../Resource.ts";
7import { tagRecord } from "../../Tags.ts";
8import { GcpEnvironment } from "../Environment.ts";
9import {
10 createInternalLabels,
11 diffLabels,
12 hasAlchemyLabels,
13 toLabels,
14} from "../Labels.ts";
15import type { Providers } from "../Providers.ts";
16import {
17 OracleDatabaseNotResolved,
18 collectPages,
19 type CustomerContact,
20 expandNetwork,
21 hasAlchemyLabelMap,
22 listAtLocation,
23 normalizeLocation,
24 parentOf,
25 parseName,
26 replaceOnIdentity,
27 resourceNameOf,
28 retryQuota,
29 specifiedEquals,
30 toPhysicalId,
31 userLabels,
32 waitUntilExists,
33 waitUntilGone,
34 retryConflict,
35 waitUntilReady,
36} from "./internal.ts";
37import { waitForOperation } from "./operations.ts";
38
39const COLLECTION = "autonomousDatabases";
40const FALLBACK_ID = "adb";
41const DEFAULT_LICENSE: oracle.AutonomousDatabasePropertiesLicenseTypeEnum =
42 "LICENSE_INCLUDED";
43const DEFAULT_WORKLOAD: oracle.AutonomousDatabasePropertiesDbWorkloadEnum =
44 "OLTP";
45
46export type EncryptionKey = {
47 /** Key provider (`GOOGLE_MANAGED` or `ORACLE_MANAGED`). */
48 provider?: oracle.EncryptionKeyProviderEnum | (string & {});
49 /**
50 * KMS key
51 * (`projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{cryptoKey}`).
52 */
53 kmsKeyId?: string;
54};
55
56export type SourceConfig = {
57 /** Primary Autonomous Database used to create a peer. */
58 autonomousDatabase?: string;
59 /** Replicate automatic backups when creating Data Guard. */
60 automaticBackupsReplicationEnabled?: boolean;
61};
62
63export type AutonomousDatabasePropertiesInput = {
64 /** License type. Immutable. */
65 licenseType?:
66 | oracle.AutonomousDatabasePropertiesLicenseTypeEnum
67 | (string & {});
68 /** Workload type (`OLTP`, `DW`, `AJD`, `APEX`). Immutable. */
69 dbWorkload?:
70 | oracle.AutonomousDatabasePropertiesDbWorkloadEnum
71 | (string & {});
72 /** Database edition. Immutable. */
73 dbEdition?: oracle.AutonomousDatabasePropertiesDbEditionEnum | (string & {});
74 /** Oracle Database version. Immutable. */
75 dbVersion?: string;
76 /** CPU cores. */
77 cpuCoreCount?: number;
78 /** Compute count (ECPU). */
79 computeCount?: number;
80 /** Data storage in GB. */
81 dataStorageSizeGb?: number;
82 /** Data storage in TB. */
83 dataStorageSizeTb?: number;
84 /** Enable compute auto scaling. */
85 isAutoScalingEnabled?: boolean;
86 /** Enable storage auto scaling. */
87 isStorageAutoScalingEnabled?: boolean;
88 /** Require mTLS. Immutable. */
89 mtlsConnectionRequired?: boolean;
90 /** Backup retention in days (1-60). Immutable. */
91 backupRetentionPeriodDays?: number;
92 /** Character set. Immutable. */
93 characterSet?: string;
94 /** National character set. Immutable. */
95 nCharacterSet?: string;
96 /** Maintenance schedule (`EARLY`, `REGULAR`). Immutable. */
97 maintenanceScheduleType?:
98 | oracle.AutonomousDatabasePropertiesMaintenanceScheduleTypeEnum
99 | (string & {});
100 /** Allowlisted IP addresses. Immutable. */
101 allowlistedIps?: string[];
102 /** Customer contacts. Immutable. */
103 customerContacts?: CustomerContact[];
104 /** Encryption key. Updating appends a history entry. */
105 encryptionKey?: EncryptionKey;
106 /** Enable in-region Data Guard. */
107 localDataGuardEnabled?: boolean;
108 /** Private endpoint label. Immutable. */
109 privateEndpointLabel?: string;
110 /** Private endpoint IP. Immutable. */
111 privateEndpointIp?: string;
112 /** Maximum Data Guard failover data-loss limit, in seconds. */
113 localAdgAutoFailoverMaxDataLossLimitDuration?: number;
114};
115
116export type AutonomousDatabaseProps = {
117 /**
118 * Autonomous Database id (the `{autonomous_database}` segment of
119 * `projects/{project}/locations/{location}/autonomousDatabases/{autonomous_database}`).
120 * If omitted, a unique RFC1035 name is generated from the stack, stage,
121 * and logical id. Immutable — changing it replaces the database.
122 */
123 autonomousDatabaseId?: string;
124 /**
125 * Region (`us-central1`, `us-east4`, …). Immutable — changing it
126 * replaces the database. `US-CENTRAL1` is accepted and normalized to
127 * `us-central1`.
128 * @default the stack's GCP region (`GCP.Region`, else the profile region, else `us-central1`)
129 */
130 location?: string;
131 /**
132 * Oracle database name (1-30 alphanumeric, unique in the project).
133 * Immutable.
134 */
135 database?: string;
136 /**
137 * Display name. Immutable.
138 */
139 displayName?: string;
140 /**
141 * VPC network (`projects/{project}/global/networks/{network}` or a
142 * bare network id). Immutable. Required unless `odbSubnet` is set.
143 */
144 network?: string;
145 /**
146 * Subnet CIDR for the database. Immutable. Required unless
147 * `odbSubnet` is set.
148 */
149 cidr?: string;
150 /**
151 * ODB Network
152 * (`projects/{project}/locations/{location}/odbNetworks/{odb_network}`).
153 * Immutable.
154 */
155 odbNetwork?: string;
156 /**
157 * ODB Subnet
158 * (`projects/{project}/locations/{location}/odbNetworks/{odb_network}/odbSubnets/{odb_subnet}`).
159 * Immutable.
160 */
161 odbSubnet?: string;
162 /**
163 * ADMIN user password. Create-only. Mutually exclusive with
164 * `adminPasswordSecretVersion`.
165 */
166 adminPassword?: string;
167 /**
168 * Secret Manager version holding the ADMIN password
169 * (`projects/{project}/secrets/{secret}/versions/{version}`).
170 * Create-only.
171 */
172 adminPasswordSecretVersion?: string;
173 /**
174 * Source Autonomous Database when creating a Data Guard peer.
175 * Immutable.
176 */
177 sourceConfig?: SourceConfig;
178 /**
179 * User labels. Alchemy ownership labels are merged in automatically.
180 */
181 labels?: Record<string, string>;
182 /**
183 * Database properties. Flattened aliases (`licenseType`,
184 * `dbWorkload`, …) are also accepted on the resource and win over
185 * this nested object when both are set.
186 */
187 properties?: AutonomousDatabasePropertiesInput;
188 /** License type. Immutable. Convenience alias for `properties.licenseType`. */
189 licenseType?:
190 | oracle.AutonomousDatabasePropertiesLicenseTypeEnum
191 | (string & {});
192 /** Workload type. Immutable. Convenience alias for `properties.dbWorkload`. */
193 dbWorkload?:
194 | oracle.AutonomousDatabasePropertiesDbWorkloadEnum
195 | (string & {});
196 /** CPU cores. Convenience alias for `properties.cpuCoreCount`. */
197 cpuCoreCount?: number;
198 /** Compute count. Convenience alias for `properties.computeCount`. */
199 computeCount?: number;
200 /** Data storage in GB. Convenience alias for `properties.dataStorageSizeGb`. */
201 dataStorageSizeGb?: number;
202 /** Data storage in TB. Convenience alias for `properties.dataStorageSizeTb`. */
203 dataStorageSizeTb?: number;
204 /** Compute auto scaling. Convenience alias for `properties.isAutoScalingEnabled`. */
205 isAutoScalingEnabled?: boolean;
206 /** Storage auto scaling. Convenience alias for `properties.isStorageAutoScalingEnabled`. */
207 isStorageAutoScalingEnabled?: boolean;
208 /** Oracle Database version. Immutable. */
209 dbVersion?: string;
210 /** Database edition. Immutable. */
211 dbEdition?: oracle.AutonomousDatabasePropertiesDbEditionEnum | (string & {});
212};
213
214export type AutonomousDatabase = Resource<
215 "GCP.OracleDatabase.AutonomousDatabase",
216 AutonomousDatabaseProps,
217 {
218 /** Full resource name. */
219 name: string;
220 /** Autonomous Database id (last path segment). */
221 autonomousDatabaseId: string;
222 /** Project id. */
223 project: string;
224 /** Location id. */
225 location: string;
226 /** Oracle database name. */
227 database: string | undefined;
228 /** Display name. */
229 displayName: string | undefined;
230 /** VPC network. */
231 network: string | undefined;
232 /** Subnet CIDR. */
233 cidr: string | undefined;
234 /** ODB Network. */
235 odbNetwork: string | undefined;
236 /** ODB Subnet. */
237 odbSubnet: string | undefined;
238 /** User labels (Alchemy ownership labels stripped). */
239 labels: Record<string, string>;
240 /** Entitlement id. */
241 entitlementId: string | undefined;
242 /** Lifecycle state. */
243 state: string | undefined;
244 /** License type. */
245 licenseType: string | undefined;
246 /** Workload type. */
247 dbWorkload: string | undefined;
248 /** Database edition. */
249 dbEdition: string | undefined;
250 /** Oracle Database version. */
251 dbVersion: string | undefined;
252 /** CPU cores. */
253 cpuCoreCount: number | undefined;
254 /** Compute count. */
255 computeCount: number | undefined;
256 /** Data storage in GB. */
257 dataStorageSizeGb: number | undefined;
258 /** Data storage in TB. */
259 dataStorageSizeTb: number | undefined;
260 /** Compute auto scaling. */
261 isAutoScalingEnabled: boolean | undefined;
262 /** Storage auto scaling. */
263 isStorageAutoScalingEnabled: boolean | undefined;
264 /** OCID. */
265 ocid: string | undefined;
266 /** Connection strings currently reported. */
267 connectionStrings: oracle.AutonomousDatabaseConnectionStrings | undefined;
268 /** RFC3339 creation timestamp. */
269 createTime: string | undefined;
270 },
271 never,
272 Providers
273>;
274
275/**
276 * An Oracle Autonomous Database on Google Cloud.
277 *
278 * Changing `autonomousDatabaseId`, `location`, `database`, `network`,
279 * `cidr`, `odbNetwork`, `odbSubnet`, `sourceConfig`, `licenseType`,
280 * `dbWorkload`, `dbEdition`, or `dbVersion` replaces the database.
281 * Labels, compute, storage, and auto-scaling patch in place.
282 *
283 * Provisioning typically takes tens of minutes and requires an Oracle
284 * Database@Google Cloud entitlement.
285 *
286 * ### Creating an Autonomous Database
287 * **Example:** Generated name on a VPC
288 * ```typescript
289 * const db = yield* GCP.OracleDatabase.AutonomousDatabase("AppDb", {
290 * network: "default",
291 * cidr: "10.10.0.0/24",
292 * adminPassword: "AlchemyTest1!",
293 * licenseType: "LICENSE_INCLUDED",
294 * dbWorkload: "OLTP",
295 * cpuCoreCount: 2,
296 * dataStorageSizeGb: 20,
297 * });
298 * ```
299 *
300 * **Example:** Explicit id, ODB subnet, and labels
301 * ```typescript
302 * const db = yield* GCP.OracleDatabase.AutonomousDatabase("AppDb", {
303 * autonomousDatabaseId: "app-db",
304 * odbSubnet: subnet.name,
305 * adminPassword: "AlchemyTest1!",
306 * displayName: "app-db",
307 * labels: { env: "prod" },
308 * properties: {
309 * licenseType: "LICENSE_INCLUDED",
310 * dbWorkload: "OLTP",
311 * computeCount: 2,
312 * dataStorageSizeGb: 20,
313 * },
314 * });
315 * ```
316 *
317 * @resource
318 * @category OracleDatabase
319 */
320export const AutonomousDatabase = Resource<AutonomousDatabase>(
321 "GCP.OracleDatabase.AutonomousDatabase",
322);
323
324const mergedProperties = (
325 news: AutonomousDatabaseProps,
326): AutonomousDatabasePropertiesInput => ({
327 ...(news.properties ?? {}),
328 licenseType: news.licenseType ?? news.properties?.licenseType,
329 dbWorkload: news.dbWorkload ?? news.properties?.dbWorkload,
330 cpuCoreCount: news.cpuCoreCount ?? news.properties?.cpuCoreCount,
331 computeCount: news.computeCount ?? news.properties?.computeCount,
332 dataStorageSizeGb:
333 news.dataStorageSizeGb ?? news.properties?.dataStorageSizeGb,
334 dataStorageSizeTb:
335 news.dataStorageSizeTb ?? news.properties?.dataStorageSizeTb,
336 isAutoScalingEnabled:
337 news.isAutoScalingEnabled ?? news.properties?.isAutoScalingEnabled,
338 isStorageAutoScalingEnabled:
339 news.isStorageAutoScalingEnabled ??
340 news.properties?.isStorageAutoScalingEnabled,
341 dbVersion: news.dbVersion ?? news.properties?.dbVersion,
342 dbEdition: news.dbEdition ?? news.properties?.dbEdition,
343});
344
345const toCreateProperties = (
346 news: AutonomousDatabaseProps,
347): oracle.AutonomousDatabaseProperties => {
348 const props = mergedProperties(news);
349 const body: oracle.AutonomousDatabaseProperties = {
350 licenseType: props.licenseType ?? DEFAULT_LICENSE,
351 dbWorkload: props.dbWorkload ?? DEFAULT_WORKLOAD,
352 };
353 if (props.dbEdition !== undefined) body.dbEdition = props.dbEdition;
354 if (props.dbVersion !== undefined) body.dbVersion = props.dbVersion;
355 if (props.cpuCoreCount !== undefined) body.cpuCoreCount = props.cpuCoreCount;
356 if (props.computeCount !== undefined) body.computeCount = props.computeCount;
357 if (props.dataStorageSizeGb !== undefined) {
358 body.dataStorageSizeGb = props.dataStorageSizeGb;
359 }
360 if (props.dataStorageSizeTb !== undefined) {
361 body.dataStorageSizeTb = props.dataStorageSizeTb;
362 }
363 if (props.isAutoScalingEnabled !== undefined) {
364 body.isAutoScalingEnabled = props.isAutoScalingEnabled;
365 }
366 if (props.isStorageAutoScalingEnabled !== undefined) {
367 body.isStorageAutoScalingEnabled = props.isStorageAutoScalingEnabled;
368 }
369 if (props.mtlsConnectionRequired !== undefined) {
370 body.mtlsConnectionRequired = props.mtlsConnectionRequired;
371 }
372 if (props.backupRetentionPeriodDays !== undefined) {
373 body.backupRetentionPeriodDays = props.backupRetentionPeriodDays;
374 }
375 if (props.characterSet !== undefined) body.characterSet = props.characterSet;
376 if (props.nCharacterSet !== undefined) {
377 body.nCharacterSet = props.nCharacterSet;
378 }
379 if (props.maintenanceScheduleType !== undefined) {
380 body.maintenanceScheduleType = props.maintenanceScheduleType;
381 }
382 if (props.allowlistedIps !== undefined) {
383 body.allowlistedIps = props.allowlistedIps;
384 }
385 if (props.customerContacts !== undefined) {
386 body.customerContacts = props.customerContacts;
387 }
388 if (props.encryptionKey !== undefined) {
389 body.encryptionKey = props.encryptionKey;
390 }
391 if (props.localDataGuardEnabled !== undefined) {
392 body.localDataGuardEnabled = props.localDataGuardEnabled;
393 }
394 if (props.privateEndpointLabel !== undefined) {
395 body.privateEndpointLabel = props.privateEndpointLabel;
396 }
397 if (props.privateEndpointIp !== undefined) {
398 body.privateEndpointIp = props.privateEndpointIp;
399 }
400 if (props.localAdgAutoFailoverMaxDataLossLimitDuration !== undefined) {
401 body.localAdgAutoFailoverMaxDataLossLimitDuration =
402 props.localAdgAutoFailoverMaxDataLossLimitDuration;
403 }
404 return body;
405};
406
407const toCreateBody = (
408 news: AutonomousDatabaseProps,
409 desiredLabels: Record<string, string>,
410 project: string,
411): oracle.AutonomousDatabase => {
412 const body: oracle.AutonomousDatabase = {
413 labels: desiredLabels,
414 properties: toCreateProperties(news),
415 };
416 if (news.database !== undefined) body.database = news.database;
417 if (news.displayName !== undefined) body.displayName = news.displayName;
418 const network = expandNetwork(project, news.network);
419 if (network !== undefined) body.network = network;
420 if (news.cidr !== undefined) body.cidr = news.cidr;
421 if (news.odbNetwork !== undefined) body.odbNetwork = news.odbNetwork;
422 if (news.odbSubnet !== undefined) body.odbSubnet = news.odbSubnet;
423 if (news.adminPassword !== undefined) body.adminPassword = news.adminPassword;
424 if (news.adminPasswordSecretVersion !== undefined) {
425 body.adminPasswordSecretVersion = news.adminPasswordSecretVersion;
426 }
427 if (news.sourceConfig !== undefined) body.sourceConfig = news.sourceConfig;
428 return body;
429};
430
431const toAttrs = (database: oracle.AutonomousDatabase, project: string) => {
432 const name = database.name ?? "";
433 const parsed = parseName(name, COLLECTION);
434 const properties = database.properties;
435 return {
436 name,
437 autonomousDatabaseId: parsed.id,
438 project: parsed.project || project,
439 location: parsed.location,
440 database: database.database,
441 displayName: database.displayName,
442 network: database.network,
443 cidr: database.cidr,
444 odbNetwork: database.odbNetwork,
445 odbSubnet: database.odbSubnet,
446 labels: userLabels(database.labels),
447 entitlementId: database.entitlementId,
448 state: properties?.state,
449 licenseType: properties?.licenseType,
450 dbWorkload: properties?.dbWorkload,
451 dbEdition: properties?.dbEdition,
452 dbVersion: properties?.dbVersion,
453 cpuCoreCount: properties?.cpuCoreCount,
454 computeCount: properties?.computeCount,
455 dataStorageSizeGb: properties?.dataStorageSizeGb,
456 dataStorageSizeTb: properties?.dataStorageSizeTb,
457 isAutoScalingEnabled: properties?.isAutoScalingEnabled,
458 isStorageAutoScalingEnabled: properties?.isStorageAutoScalingEnabled,
459 ocid: properties?.ocid,
460 connectionStrings: properties?.connectionStrings,
461 createTime: database.createTime,
462 };
463};
464
465const getByName = (name: string) =>
466 retryQuota(oracle.getProjectsLocationsAutonomousDatabases({ name })).pipe(
467 Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
468 );
469
470const listDatabases = (project: string, region: string) => {
471 const collect = (parent: string) =>
472 collectPages(
473 oracle.listProjectsLocationsAutonomousDatabases.pages({
474 parent,
475 pageSize: 1000,
476 }),
477 (page) => page.autonomousDatabases,
478 ).pipe(
479 Effect.map((items) =>
480 items.filter((item) => hasAlchemyLabelMap(item.labels)),
481 ),
482 );
483 return listAtLocation(project, region, collect).pipe(
484 Effect.catchTag("NotFound", () => Effect.succeed([])),
485 );
486};
487
488const identityChanged = (
489 news: AutonomousDatabaseProps,
490 olds: AutonomousDatabaseProps | undefined,
491 output: AutonomousDatabase["Attributes"] | undefined,
492) => {
493 const props = mergedProperties(news);
494 const previousNetwork = olds?.network ?? output?.network ?? "";
495 const nextNetwork = news.network ?? previousNetwork;
496 const previousCidr = olds?.cidr ?? output?.cidr ?? "";
497 const nextCidr = news.cidr ?? previousCidr;
498 const previousOdb = olds?.odbSubnet ?? output?.odbSubnet ?? "";
499 const nextOdb = news.odbSubnet ?? previousOdb;
500 const previousOdbNet = olds?.odbNetwork ?? output?.odbNetwork ?? "";
501 const nextOdbNet = news.odbNetwork ?? previousOdbNet;
502 const previousDatabase = olds?.database ?? output?.database ?? "";
503 const nextDatabase = news.database ?? previousDatabase;
504 const previousLicense =
505 olds?.licenseType ??
506 olds?.properties?.licenseType ??
507 output?.licenseType ??
508 "";
509 const nextLicense = props.licenseType ?? previousLicense;
510 const previousWorkload =
511 olds?.dbWorkload ??
512 olds?.properties?.dbWorkload ??
513 output?.dbWorkload ??
514 "";
515 const nextWorkload = props.dbWorkload ?? previousWorkload;
516 const previousEdition =
517 olds?.dbEdition ?? olds?.properties?.dbEdition ?? output?.dbEdition ?? "";
518 const nextEdition = props.dbEdition ?? previousEdition;
519 const previousVersion =
520 olds?.dbVersion ?? olds?.properties?.dbVersion ?? output?.dbVersion ?? "";
521 const nextVersion = props.dbVersion ?? previousVersion;
522 return (
523 nextNetwork !== previousNetwork ||
524 nextCidr !== previousCidr ||
525 nextOdb !== previousOdb ||
526 nextOdbNet !== previousOdbNet ||
527 nextDatabase !== previousDatabase ||
528 nextLicense !== previousLicense ||
529 nextWorkload !== previousWorkload ||
530 nextEdition !== previousEdition ||
531 nextVersion !== previousVersion
532 );
533};
534
535export const AutonomousDatabaseProvider = () =>
536 Provider.succeed(AutonomousDatabase, {
537 stables: [
538 "name",
539 "autonomousDatabaseId",
540 "project",
541 "location",
542 "createTime",
543 "ocid",
544 ],
545
546 diff: Effect.fn(function* ({ news, olds, output }) {
547 if (!isResolved(news)) return undefined;
548 const env = yield* GcpEnvironment.current;
549 return replaceOnIdentity({
550 previousId: olds?.autonomousDatabaseId ?? output?.autonomousDatabaseId,
551 nextId:
552 news.autonomousDatabaseId ??
553 olds?.autonomousDatabaseId ??
554 output?.autonomousDatabaseId,
555 previousLocation: normalizeLocation(
556 olds?.location ?? output?.location ?? env.region,
557 ),
558 nextLocation: normalizeLocation(
559 news.location ?? olds?.location ?? output?.location ?? env.region,
560 ),
561 extra: identityChanged(news, olds, output),
562 });
563 }),
564
565 read: Effect.fn(function* ({ id, olds, output }) {
566 const env = yield* GcpEnvironment.current;
567 const autonomousDatabaseId = yield* toPhysicalId(
568 id,
569 olds?.autonomousDatabaseId,
570 output?.autonomousDatabaseId,
571 FALLBACK_ID,
572 );
573 const location = normalizeLocation(
574 olds?.location ?? output?.location ?? env.region,
575 );
576 const name =
577 output?.name ??
578 resourceNameOf(env.project, location, COLLECTION, autonomousDatabaseId);
579 const existing = yield* getByName(name);
580 if (existing === undefined) return undefined;
581 const attrs = toAttrs(existing, env.project);
582 return (yield* hasAlchemyLabels(id, tagRecord(existing.labels)))
583 ? attrs
584 : Unowned(attrs);
585 }),
586
587 list: () =>
588 Effect.gen(function* () {
589 const env = yield* GcpEnvironment.current;
590 const items = yield* listDatabases(env.project, env.region);
591 return items.map((item) => toAttrs(item, env.project));
592 }),
593
594 reconcile: Effect.fn(function* ({ id, news, output }) {
595 const env = yield* GcpEnvironment.current;
596 const autonomousDatabaseId = yield* toPhysicalId(
597 id,
598 news.autonomousDatabaseId,
599 output?.autonomousDatabaseId,
600 FALLBACK_ID,
601 );
602 const location = normalizeLocation(
603 news.location ?? output?.location ?? env.region,
604 );
605 const name = resourceNameOf(
606 env.project,
607 location,
608 COLLECTION,
609 autonomousDatabaseId,
610 );
611 const desiredLabels = {
612 ...toLabels(news.labels),
613 ...(yield* createInternalLabels(id)),
614 };
615
616 let current = yield* getByName(output?.name ?? name);
617
618 if (current === undefined) {
619 const created = yield* oracle
620 .createProjectsLocationsAutonomousDatabases({
621 parent: parentOf(env.project, location),
622 autonomousDatabaseId,
623 body: toCreateBody(news, desiredLabels, env.project),
624 })
625 .pipe(
626 retryQuota,
627 Effect.catchTag("Conflict", () => Effect.succeed(undefined)),
628 );
629 if (created !== undefined) {
630 yield* waitForOperation(created);
631 }
632 current = yield* waitUntilExists(getByName(name), name);
633 }
634
635 if (current === undefined) {
636 return yield* new OracleDatabaseNotResolved({ name });
637 }
638
639 const ready = yield* waitUntilReady(
640 getByName(current.name ?? name),
641 current.name ?? name,
642 (value) => value.properties?.state,
643 );
644
645 const props = mergedProperties(news);
646 const observedLabels = tagRecord(ready.labels);
647 const { upsert, removed } = diffLabels(observedLabels, desiredLabels);
648 const labelsChanged = upsert.length > 0 || removed.length > 0;
649 const computeChanged =
650 (props.cpuCoreCount !== undefined &&
651 !specifiedEquals(
652 props.cpuCoreCount,
653 ready.properties?.cpuCoreCount,
654 )) ||
655 (props.computeCount !== undefined &&
656 !specifiedEquals(props.computeCount, ready.properties?.computeCount));
657 const storageChanged =
658 (props.dataStorageSizeGb !== undefined &&
659 !specifiedEquals(
660 props.dataStorageSizeGb,
661 ready.properties?.dataStorageSizeGb,
662 )) ||
663 (props.dataStorageSizeTb !== undefined &&
664 !specifiedEquals(
665 props.dataStorageSizeTb,
666 ready.properties?.dataStorageSizeTb,
667 ));
668 const scalingChanged =
669 (props.isAutoScalingEnabled !== undefined &&
670 props.isAutoScalingEnabled !==
671 ready.properties?.isAutoScalingEnabled) ||
672 (props.isStorageAutoScalingEnabled !== undefined &&
673 props.isStorageAutoScalingEnabled !==
674 ready.properties?.isStorageAutoScalingEnabled);
675 const encryptionChanged =
676 props.encryptionKey !== undefined &&
677 !specifiedEquals(props.encryptionKey, ready.properties?.encryptionKey);
678 const dataGuardChanged =
679 props.localDataGuardEnabled !== undefined &&
680 props.localDataGuardEnabled !== ready.properties?.localDataGuardEnabled;
681 const failoverLimitChanged =
682 props.localAdgAutoFailoverMaxDataLossLimitDuration !== undefined &&
683 !specifiedEquals(
684 props.localAdgAutoFailoverMaxDataLossLimitDuration,
685 ready.properties?.localAdgAutoFailoverMaxDataLossLimitDuration,
686 );
687
688 if (
689 labelsChanged ||
690 computeChanged ||
691 storageChanged ||
692 scalingChanged ||
693 encryptionChanged ||
694 dataGuardChanged ||
695 failoverLimitChanged
696 ) {
697 const mask = [
698 labelsChanged ? "labels" : undefined,
699 computeChanged ? "properties.cpu_core_count" : undefined,
700 computeChanged ? "properties.compute_count" : undefined,
701 storageChanged ? "properties.data_storage_size_gb" : undefined,
702 storageChanged ? "properties.data_storage_size_tb" : undefined,
703 scalingChanged ? "properties.is_auto_scaling_enabled" : undefined,
704 scalingChanged
705 ? "properties.is_storage_auto_scaling_enabled"
706 : undefined,
707 encryptionChanged ? "properties.encryption_key" : undefined,
708 dataGuardChanged ? "properties.local_data_guard_enabled" : undefined,
709 failoverLimitChanged
710 ? "properties.local_adg_auto_failover_max_data_loss_limit_duration"
711 : undefined,
712 ].filter((field): field is string => field !== undefined);
713
714 const operation = yield* retryQuota(
715 oracle.patchProjectsLocationsAutonomousDatabases({
716 name: ready.name ?? name,
717 updateMask: mask.join(","),
718 body: {
719 name: ready.name ?? name,
720 labels: desiredLabels,
721 properties: {
722 cpuCoreCount: props.cpuCoreCount,
723 computeCount: props.computeCount,
724 dataStorageSizeGb: props.dataStorageSizeGb,
725 dataStorageSizeTb: props.dataStorageSizeTb,
726 isAutoScalingEnabled: props.isAutoScalingEnabled,
727 isStorageAutoScalingEnabled: props.isStorageAutoScalingEnabled,
728 encryptionKey: props.encryptionKey,
729 localDataGuardEnabled: props.localDataGuardEnabled,
730 localAdgAutoFailoverMaxDataLossLimitDuration:
731 props.localAdgAutoFailoverMaxDataLossLimitDuration,
732 },
733 },
734 }),
735 );
736 yield* waitForOperation(operation);
737 return toAttrs(
738 yield* waitUntilExists(
739 getByName(ready.name ?? name),
740 ready.name ?? name,
741 ),
742 env.project,
743 );
744 }
745
746 return toAttrs(ready, env.project);
747 }),
748
749 delete: Effect.fn(function* ({ output }) {
750 const operation = yield* oracle
751 .deleteProjectsLocationsAutonomousDatabases({
752 name: output.name,
753 })
754 .pipe(
755 retryConflict,
756 Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
757 );
758 if (operation !== undefined) {
759 yield* waitForOperation(operation, { notFoundOk: true });
760 }
761 yield* waitUntilGone(getByName(output.name), output.name);
762 }),
763 });