@fnndsc/stratus 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +6 -1
  2. package/dist/args.d.ts +20 -6
  3. package/dist/args.js +45 -2
  4. package/dist/args.js.map +1 -1
  5. package/dist/backend.d.ts +35 -4
  6. package/dist/backend.js +77 -12
  7. package/dist/backend.js.map +1 -1
  8. package/dist/cloud/builder.d.ts +172 -0
  9. package/dist/cloud/builder.js +41 -0
  10. package/dist/cloud/builder.js.map +1 -0
  11. package/dist/cloud/driver.d.ts +149 -0
  12. package/dist/cloud/fake/builder.d.ts +147 -0
  13. package/dist/cloud/fake/builder.js +213 -0
  14. package/dist/cloud/fake/builder.js.map +1 -0
  15. package/dist/cloud/fake/driver.d.ts +73 -1
  16. package/dist/cloud/fake/driver.js +122 -0
  17. package/dist/cloud/fake/driver.js.map +1 -1
  18. package/dist/cloud/oci/api.d.ts +3 -2
  19. package/dist/cloud/oci/api.js +2 -0
  20. package/dist/cloud/oci/api.js.map +1 -1
  21. package/dist/cloud/oci/buildApi.d.ts +61 -0
  22. package/dist/cloud/oci/buildApi.js +132 -0
  23. package/dist/cloud/oci/buildApi.js.map +1 -0
  24. package/dist/cloud/oci/builder.d.ts +172 -0
  25. package/dist/cloud/oci/builder.js +370 -0
  26. package/dist/cloud/oci/builder.js.map +1 -0
  27. package/dist/cloud/oci/driver.d.ts +23 -2
  28. package/dist/cloud/oci/driver.js +107 -1
  29. package/dist/cloud/oci/driver.js.map +1 -1
  30. package/dist/cloud/oci/planRead.d.ts +38 -0
  31. package/dist/cloud/oci/planRead.js +67 -0
  32. package/dist/cloud/oci/planRead.js.map +1 -0
  33. package/dist/cloud/oci/prices.d.ts +22 -1
  34. package/dist/cloud/oci/prices.js +35 -0
  35. package/dist/cloud/oci/prices.js.map +1 -1
  36. package/dist/cloud/oci/resourceApi.d.ts +114 -0
  37. package/dist/cloud/oci/resourceApi.js +261 -0
  38. package/dist/cloud/oci/resourceApi.js.map +1 -0
  39. package/dist/cloud/oci/resourceMap.d.ts +44 -0
  40. package/dist/cloud/oci/resourceMap.js +70 -0
  41. package/dist/cloud/oci/resourceMap.js.map +1 -0
  42. package/dist/cloud/oci/rmApi.d.ts +74 -0
  43. package/dist/cloud/oci/rmApi.js +141 -0
  44. package/dist/cloud/oci/rmApi.js.map +1 -0
  45. package/dist/cloud/oci/stackVars.d.ts +49 -0
  46. package/dist/cloud/oci/stackVars.js +70 -0
  47. package/dist/cloud/oci/stackVars.js.map +1 -0
  48. package/dist/cluster/fakeKube.d.ts +43 -0
  49. package/dist/cluster/fakeKube.js +86 -0
  50. package/dist/cluster/fakeKube.js.map +1 -0
  51. package/dist/cluster/kube.d.ts +40 -0
  52. package/dist/cluster/kube.js +46 -0
  53. package/dist/cluster/kube.js.map +1 -0
  54. package/dist/cluster/kubeHttp.d.ts +16 -0
  55. package/dist/cluster/kubeHttp.js +86 -0
  56. package/dist/cluster/kubeHttp.js.map +1 -0
  57. package/dist/commands/build.d.ts +90 -0
  58. package/dist/commands/build.js +358 -0
  59. package/dist/commands/build.js.map +1 -0
  60. package/dist/commands/capacity.d.ts +37 -0
  61. package/dist/commands/capacity.js +93 -0
  62. package/dist/commands/capacity.js.map +1 -0
  63. package/dist/commands/domain.d.ts +45 -0
  64. package/dist/commands/domain.js +150 -0
  65. package/dist/commands/domain.js.map +1 -0
  66. package/dist/commands/spend.d.ts +22 -0
  67. package/dist/commands/spend.js +65 -0
  68. package/dist/commands/spend.js.map +1 -0
  69. package/dist/commands/teardown.d.ts +10 -0
  70. package/dist/commands/teardown.js +72 -0
  71. package/dist/commands/teardown.js.map +1 -0
  72. package/dist/commands/verify.d.ts +28 -0
  73. package/dist/commands/verify.js +98 -0
  74. package/dist/commands/verify.js.map +1 -0
  75. package/dist/domain/adopt.d.ts +60 -0
  76. package/dist/domain/adopt.js +143 -0
  77. package/dist/domain/adopt.js.map +1 -0
  78. package/dist/domain/sizing.d.ts +55 -0
  79. package/dist/domain/sizing.js +66 -0
  80. package/dist/domain/sizing.js.map +1 -0
  81. package/dist/domain/spec.d.ts +101 -0
  82. package/dist/domain/spec.js +191 -0
  83. package/dist/domain/spec.js.map +1 -0
  84. package/dist/domain/spend.d.ts +84 -0
  85. package/dist/domain/spend.js +109 -0
  86. package/dist/domain/spend.js.map +1 -0
  87. package/dist/domain/state.d.ts +149 -0
  88. package/dist/domain/state.js +182 -0
  89. package/dist/domain/state.js.map +1 -0
  90. package/dist/domain/steps.d.ts +82 -0
  91. package/dist/domain/steps.js +311 -0
  92. package/dist/domain/steps.js.map +1 -0
  93. package/dist/domain/teardown.d.ts +38 -0
  94. package/dist/domain/teardown.js +48 -0
  95. package/dist/domain/teardown.js.map +1 -0
  96. package/dist/domain/verify.d.ts +68 -0
  97. package/dist/domain/verify.js +216 -0
  98. package/dist/domain/verify.js.map +1 -0
  99. package/dist/domain/view.d.ts +24 -0
  100. package/dist/domain/view.js +38 -0
  101. package/dist/domain/view.js.map +1 -0
  102. package/dist/domains/harborOci.d.ts +75 -0
  103. package/dist/domains/harborOci.js +165 -0
  104. package/dist/domains/harborOci.js.map +1 -0
  105. package/dist/index.d.ts +7 -0
  106. package/dist/index.js +6 -0
  107. package/dist/index.js.map +1 -1
  108. package/dist/installer/assisted.d.ts +97 -0
  109. package/dist/installer/assisted.js +171 -0
  110. package/dist/installer/assisted.js.map +1 -0
  111. package/dist/installer/installer.d.ts +86 -0
  112. package/dist/installer/installer.js +15 -0
  113. package/dist/installer/installer.js.map +1 -0
  114. package/dist/prompt.d.ts +33 -0
  115. package/dist/prompt.js +46 -0
  116. package/dist/prompt.js.map +1 -0
  117. package/dist/session.d.ts +2 -0
  118. package/dist/session.js +4 -0
  119. package/dist/session.js.map +1 -1
  120. package/dist/stratus.js +75 -3
  121. package/dist/stratus.js.map +1 -1
  122. package/dist/vfs/domains.d.ts +39 -0
  123. package/dist/vfs/domains.js +128 -0
  124. package/dist/vfs/domains.js.map +1 -0
  125. package/dist/vfs/look.d.ts +10 -0
  126. package/dist/vfs/look.js +43 -8
  127. package/dist/vfs/look.js.map +1 -1
  128. package/dist/vfs/resources.d.ts +136 -0
  129. package/dist/vfs/resources.js +325 -0
  130. package/dist/vfs/resources.js.map +1 -0
  131. package/dist/vfs/tenancy.d.ts +15 -2
  132. package/dist/vfs/tenancy.js +53 -17
  133. package/dist/vfs/tenancy.js.map +1 -1
  134. package/package.json +14 -7
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @file OCI resource records as the driver's generic kinds.
3
+ *
4
+ * Every OCI resource answers a display name, an OCID, an upper-case
5
+ * lifecycle state and two tag maps; these become the fields every kind has.
6
+ * What is OCI's own (a VCN's CIDR blocks, an NSG's rules) stays in `raw`,
7
+ * which the tree shows as `info.json`.
8
+ *
9
+ * @module
10
+ */
11
+ import type { CloudResource, ResourceCounts, ResourceKind } from '../driver.js';
12
+ import type { OciResourceRecord, OciSearchRecord } from './resourceApi.js';
13
+ /** Resource Search's type names, as the tree's kinds. */
14
+ export declare const OCI_SEARCH_KINDS: Readonly<Record<string, ResourceKind>>;
15
+ /**
16
+ * The fields every kind has, from an OCI record.
17
+ *
18
+ * @param record - The record.
19
+ * @param region - The region it was asked in.
20
+ * @returns The generic resource.
21
+ */
22
+ export declare function resource_ofRecord(record: OciResourceRecord, region: string): CloudResource;
23
+ /**
24
+ * The Resource Search query that counts a compartment's resources of every
25
+ * kind the tree shows.
26
+ *
27
+ * @param compartmentId - The compartment.
28
+ * @returns The structured query.
29
+ */
30
+ export declare function searchQuery_of(compartmentId: string): string;
31
+ /**
32
+ * A search's hits counted by kind, gone resources left out.
33
+ *
34
+ * @param hits - The hits.
35
+ * @returns The counts.
36
+ */
37
+ export declare function searchCounts_of(hits: ReadonlyArray<OciSearchRecord>): ResourceCounts;
38
+ /**
39
+ * Sorts resources by name, the order every listing keeps.
40
+ *
41
+ * @param resources - The resources.
42
+ * @returns A sorted copy.
43
+ */
44
+ export declare function byName_sort<T extends CloudResource>(resources: ReadonlyArray<T>): T[];
@@ -0,0 +1,70 @@
1
+ import { ociTags_flatten } from './driver.js';
2
+ /** Resource Search's type names, as the tree's kinds. */
3
+ export const OCI_SEARCH_KINDS = {
4
+ Instance: 'instances',
5
+ Vcn: 'networks',
6
+ Subnet: 'subnets',
7
+ NetworkSecurityGroup: 'securitygroups',
8
+ LoadBalancer: 'loadbalancers',
9
+ Volume: 'volumes',
10
+ BootVolume: 'volumes',
11
+ Bucket: 'buckets',
12
+ CustomerDnsZone: 'dns',
13
+ };
14
+ /** The states a search leaves out: what is gone. */
15
+ const GONE_STATES = ['TERMINATED', 'DELETED'];
16
+ /**
17
+ * The fields every kind has, from an OCI record.
18
+ *
19
+ * @param record - The record.
20
+ * @param region - The region it was asked in.
21
+ * @returns The generic resource.
22
+ */
23
+ export function resource_ofRecord(record, region) {
24
+ return {
25
+ name: record.displayName,
26
+ id: record.id,
27
+ state: record.lifecycleState.toLowerCase(),
28
+ region,
29
+ created: record.timeCreated,
30
+ tags: ociTags_flatten(record.freeformTags, record.definedTags),
31
+ raw: record.raw,
32
+ };
33
+ }
34
+ /**
35
+ * The Resource Search query that counts a compartment's resources of every
36
+ * kind the tree shows.
37
+ *
38
+ * @param compartmentId - The compartment.
39
+ * @returns The structured query.
40
+ */
41
+ export function searchQuery_of(compartmentId) {
42
+ const types = Object.keys(OCI_SEARCH_KINDS).map((type) => type.toLowerCase()).join(', ');
43
+ return `query ${types} resources where compartmentId = '${compartmentId}'`;
44
+ }
45
+ /**
46
+ * A search's hits counted by kind, gone resources left out.
47
+ *
48
+ * @param hits - The hits.
49
+ * @returns The counts.
50
+ */
51
+ export function searchCounts_of(hits) {
52
+ const counts = {};
53
+ for (const hit of hits) {
54
+ const kind = OCI_SEARCH_KINDS[hit.resourceType];
55
+ if (kind === undefined || GONE_STATES.includes(hit.lifecycleState.toUpperCase()))
56
+ continue;
57
+ counts[kind] = (counts[kind] ?? 0) + 1;
58
+ }
59
+ return counts;
60
+ }
61
+ /**
62
+ * Sorts resources by name, the order every listing keeps.
63
+ *
64
+ * @param resources - The resources.
65
+ * @returns A sorted copy.
66
+ */
67
+ export function byName_sort(resources) {
68
+ return [...resources].sort((a, b) => a.name.localeCompare(b.name));
69
+ }
70
+ //# sourceMappingURL=resourceMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceMap.js","sourceRoot":"","sources":["../../../src/cloud/oci/resourceMap.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAA2C;IACtE,QAAQ,EAAE,WAAW;IACrB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,SAAS;IACjB,oBAAoB,EAAE,gBAAgB;IACtC,YAAY,EAAE,eAAe;IAC7B,MAAM,EAAE,SAAS;IACjB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IACjB,eAAe,EAAE,KAAK;CACvB,CAAC;AAEF,oDAAoD;AACpD,MAAM,WAAW,GAA0B,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAyB,EAAE,MAAc;IACzE,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,WAAW;QACxB,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE;QAC1C,MAAM;QACN,OAAO,EAAE,MAAM,CAAC,WAAW;QAC3B,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC;QAC9D,GAAG,EAAE,MAAM,CAAC,GAAG;KAChB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,aAAqB;IAClD,MAAM,KAAK,GAAW,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjH,OAAO,SAAS,KAAK,qCAAqC,aAAa,GAAG,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAAoC;IAClE,MAAM,MAAM,GAA0C,EAAE,CAAC;IACzD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAA6B,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC1E,IAAI,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;YAAE,SAAS;QAC3F,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAA0B,SAA2B;IAC9E,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAI,EAAE,CAAI,EAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnF,CAAC"}
@@ -0,0 +1,74 @@
1
+ /** The Terraform the stacks run: the newest Resource Manager offers. */
2
+ export declare const RM_TERRAFORM_VERSION: string;
3
+ /** A job as Resource Manager reports it. */
4
+ export interface RmJobRecord {
5
+ readonly id: string;
6
+ /** `ACCEPTED`, `IN_PROGRESS`, `FAILED`, `SUCCEEDED`, `CANCELING`, `CANCELED`. */
7
+ readonly state: string;
8
+ /** Why it failed, in Resource Manager's words. */
9
+ readonly failure?: string;
10
+ }
11
+ /** A stack as Resource Manager reports it. */
12
+ export interface RmStackRecord {
13
+ readonly id: string;
14
+ readonly displayName: string;
15
+ readonly state: string;
16
+ readonly compartmentId: string;
17
+ }
18
+ /** What a job is asked to do. */
19
+ export type RmOperation = {
20
+ readonly kind: 'plan';
21
+ } | {
22
+ readonly kind: 'apply';
23
+ readonly planJobId: string;
24
+ } | {
25
+ readonly kind: 'import';
26
+ readonly stateBase64: string;
27
+ } | {
28
+ readonly kind: 'destroy';
29
+ };
30
+ /** The Resource Manager calls, in one region. */
31
+ export interface RmApi {
32
+ stack_create(request: {
33
+ compartmentId: string;
34
+ displayName: string;
35
+ description: string;
36
+ zipBase64: string;
37
+ variables: Record<string, string>;
38
+ tags: Record<string, string>;
39
+ }): Promise<RmStackRecord>;
40
+ stack_update(stackId: string, request: {
41
+ zipBase64?: string;
42
+ variables?: Record<string, string>;
43
+ }): Promise<void>;
44
+ stack_get(stackId: string): Promise<RmStackRecord>;
45
+ /** The stacks in a compartment carrying a freeform tag. */
46
+ stacks_tagged(compartmentId: string, tagKey: string): Promise<Array<RmStackRecord & {
47
+ tagValue: string;
48
+ }>>;
49
+ job_create(stackId: string, operation: RmOperation, displayName: string): Promise<RmJobRecord>;
50
+ job_get(jobId: string): Promise<RmJobRecord>;
51
+ /** Asks a job to stop; never forced. */
52
+ job_cancel(jobId: string): Promise<void>;
53
+ /** The job's log lines, oldest first. */
54
+ jobLog_read(jobId: string): Promise<string[]>;
55
+ /** A plan job's plan, as Terraform's JSON. */
56
+ jobPlan_read(jobId: string): Promise<unknown>;
57
+ /** An apply job's outputs, by name. */
58
+ jobOutputs_read(jobId: string): Promise<Record<string, string>>;
59
+ /** How many resources a stack's Terraform state holds. */
60
+ stackResources_count(stackId: string): Promise<number>;
61
+ }
62
+ /** How the calls authenticate: an API-key profile, as the read driver does. */
63
+ export interface RmApiOptions {
64
+ readonly configFile?: string;
65
+ readonly profile?: string;
66
+ readonly region: string;
67
+ }
68
+ /**
69
+ * The Resource Manager calls over the SDK.
70
+ *
71
+ * @param options - The profile and the region.
72
+ * @returns The calls.
73
+ */
74
+ export declare function rmApi_make(options: RmApiOptions): RmApi;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @file The Resource Manager calls the OCI builder makes: stacks made from
3
+ * a zip, plan, apply, import-state and destroy jobs, and what a job leaves
4
+ * (its state, its log, its plan as JSON, its outputs). Terraform runs inside
5
+ * OCI; nothing here runs a host program (docs/stratus.adoc, D3).
6
+ *
7
+ * Every call answers plain records, so the builder maps records and its
8
+ * tests replay recorded answers. One client per region. Only this folder
9
+ * imports an `oci-*` package (`lint:stratus-deps`).
10
+ *
11
+ * @module
12
+ */
13
+ import * as common from 'oci-common';
14
+ import * as resourcemanager from 'oci-resourcemanager';
15
+ /** The Terraform the stacks run: the newest Resource Manager offers. */
16
+ export const RM_TERRAFORM_VERSION = '1.5.x';
17
+ /**
18
+ * A readable stream's whole text.
19
+ *
20
+ * @param value - The stream the SDK answered with.
21
+ * @returns Its text.
22
+ */
23
+ async function stream_text(value) {
24
+ if (typeof value === 'string')
25
+ return value;
26
+ const chunks = [];
27
+ if (value !== null && typeof value === 'object' && Symbol.asyncIterator in value) {
28
+ for await (const chunk of value)
29
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
30
+ return Buffer.concat(chunks).toString('utf-8');
31
+ }
32
+ if (value !== null && typeof value === 'object' && 'getReader' in value) {
33
+ const reader = value.getReader();
34
+ for (;;) {
35
+ const read = await reader.read();
36
+ if (read.done)
37
+ break;
38
+ chunks.push(Buffer.from(read.value));
39
+ }
40
+ return Buffer.concat(chunks).toString('utf-8');
41
+ }
42
+ return String(value);
43
+ }
44
+ /**
45
+ * The Resource Manager calls over the SDK.
46
+ *
47
+ * @param options - The profile and the region.
48
+ * @returns The calls.
49
+ */
50
+ export function rmApi_make(options) {
51
+ const provider = new common.ConfigFileAuthenticationDetailsProvider(options.configFile, options.profile);
52
+ const client = new resourcemanager.ResourceManagerClient({ authenticationDetailsProvider: provider });
53
+ client.regionId = options.region;
54
+ const job_of = (job) => ({
55
+ id: job.id ?? '',
56
+ state: String(job.lifecycleState ?? 'UNKNOWN'),
57
+ ...(job.failureDetails?.message !== undefined ? { failure: job.failureDetails.message } : {}),
58
+ });
59
+ const stack_of = (stack) => ({
60
+ id: stack.id ?? '', displayName: stack.displayName ?? '', state: String(stack.lifecycleState ?? 'UNKNOWN'), compartmentId: stack.compartmentId ?? '',
61
+ });
62
+ return {
63
+ async stack_create(request) {
64
+ const response = await client.createStack({
65
+ createStackDetails: {
66
+ compartmentId: request.compartmentId,
67
+ displayName: request.displayName,
68
+ description: request.description,
69
+ configSource: { configSourceType: 'ZIP_UPLOAD', zipFileBase64Encoded: request.zipBase64 },
70
+ variables: request.variables,
71
+ terraformVersion: RM_TERRAFORM_VERSION,
72
+ freeformTags: request.tags,
73
+ },
74
+ });
75
+ return stack_of(response.stack);
76
+ },
77
+ async stack_update(stackId, request) {
78
+ await client.updateStack({
79
+ stackId,
80
+ updateStackDetails: {
81
+ ...(request.zipBase64 !== undefined ? { configSource: { configSourceType: 'ZIP_UPLOAD', zipFileBase64Encoded: request.zipBase64 } } : {}),
82
+ ...(request.variables !== undefined ? { variables: request.variables } : {}),
83
+ },
84
+ });
85
+ },
86
+ async stack_get(stackId) {
87
+ return stack_of((await client.getStack({ stackId })).stack);
88
+ },
89
+ async stacks_tagged(compartmentId, tagKey) {
90
+ const found = [];
91
+ for await (const stack of client.listAllStacks({ compartmentId })) {
92
+ const value = stack.freeformTags?.[tagKey];
93
+ if (value !== undefined)
94
+ found.push({ ...stack_of(stack), tagValue: value });
95
+ }
96
+ return found;
97
+ },
98
+ async job_create(stackId, operation, displayName) {
99
+ const details = operation.kind === 'plan' ? { operation: 'PLAN' }
100
+ : operation.kind === 'apply' ? { operation: 'APPLY', executionPlanStrategy: 'FROM_PLAN_JOB_ID', executionPlanJobId: operation.planJobId }
101
+ : operation.kind === 'import' ? { operation: 'IMPORT_TF_STATE', tfStateBase64Encoded: operation.stateBase64 }
102
+ : { operation: 'DESTROY', executionPlanStrategy: 'AUTO_APPROVED' };
103
+ const response = await client.createJob({ createJobDetails: { stackId, displayName, jobOperationDetails: details } });
104
+ return job_of(response.job);
105
+ },
106
+ async job_get(jobId) {
107
+ return job_of((await client.getJob({ jobId })).job);
108
+ },
109
+ async job_cancel(jobId) {
110
+ await client.cancelJob({ jobId, isForced: false });
111
+ },
112
+ async jobLog_read(jobId) {
113
+ const lines = [];
114
+ for await (const entry of client.getAllJobLogs({ jobId }))
115
+ lines.push(entry.message ?? '');
116
+ return lines;
117
+ },
118
+ async jobPlan_read(jobId) {
119
+ const response = await client.getJobTfPlan({ jobId, tfPlanFormat: resourcemanager.requests.GetJobTfPlanRequest.TfPlanFormat.Json });
120
+ return JSON.parse(await stream_text(response.value));
121
+ },
122
+ async stackResources_count(stackId) {
123
+ const state = JSON.parse(await stream_text((await client.getStackTfState({ stackId })).value));
124
+ return (state.resources ?? []).filter((resource) => resource.mode !== 'data').reduce((sum, resource) => sum + (resource.instances?.length ?? 1), 0);
125
+ },
126
+ async jobOutputs_read(jobId) {
127
+ const outputs = {};
128
+ let page;
129
+ do {
130
+ const response = await client.listJobOutputs({ jobId, ...(page !== undefined ? { page } : {}) });
131
+ for (const output of response.jobOutputsCollection.items ?? []) {
132
+ if (output.outputName !== undefined)
133
+ outputs[output.outputName] = output.outputValue ?? '';
134
+ }
135
+ page = response.opcNextPage || undefined;
136
+ } while (page !== undefined);
137
+ return outputs;
138
+ },
139
+ };
140
+ }
141
+ //# sourceMappingURL=rmApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rmApi.js","sourceRoot":"","sources":["../../../src/cloud/oci/rmApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @file A new domain's stack variables: the spec in OCI's units, and the
3
+ * choices `harbor-oci` made for every build (its `tfvars_build`). Every value
4
+ * is a string, as Resource Manager takes them.
5
+ *
6
+ * The choices: the stack writes no DNS (the zone is long-lived and the dns
7
+ * step writes the three records), the attribution tag namespace lives in the
8
+ * domain's compartment, the API's load balancer is public, the Assisted
9
+ * Installer installs. With no workers only `compute_count` is set: the stack
10
+ * still reads `compute_shape` for the image, so its other compute variables
11
+ * keep their defaults and a compact cluster plans unchanged.
12
+ *
13
+ * @module
14
+ */
15
+ import type { DomainSpec } from '../../domain/spec.js';
16
+ /** Volume performance units per GB for each tier, as `harbor-oci` sets them. */
17
+ export declare const TIER_VPUS: Readonly<Record<string, number>>;
18
+ /** The OCI cloud controller and CSI driver release the stack installs. */
19
+ export declare const OCI_DRIVER_VERSION: string;
20
+ /**
21
+ * The flexible shape a family runs on, and its vCPU per OCPU.
22
+ *
23
+ * @param family - The family (`E5`).
24
+ * @returns The shape and its ratio.
25
+ * @throws Error - For a family with no flexible shape known.
26
+ */
27
+ export declare function familyShape_of(family: string): {
28
+ shape: string;
29
+ vcpuPerOcpu: number;
30
+ };
31
+ /** What a new stack's variables are made from. */
32
+ export interface StackVarsRequest {
33
+ readonly domain: string;
34
+ readonly spec: DomainSpec;
35
+ readonly tenancyId: string;
36
+ readonly compartmentId: string;
37
+ readonly region: string;
38
+ readonly baseDomain: string;
39
+ /** The discovery image's link; a secret. */
40
+ readonly isoLink: string;
41
+ readonly sshPublicKey: string;
42
+ }
43
+ /**
44
+ * A new domain's stack variables.
45
+ *
46
+ * @param request - The domain, its spec, where it goes, the image and the key.
47
+ * @returns The variables, each a string.
48
+ */
49
+ export declare function stackVariables_build(request: StackVarsRequest): Record<string, string>;
@@ -0,0 +1,70 @@
1
+ import { SHAPE_TERMS } from './prices.js';
2
+ /** Volume performance units per GB for each tier, as `harbor-oci` sets them. */
3
+ export const TIER_VPUS = { balanced: 10, higher: 20, ultra: 100 };
4
+ /** The OCI cloud controller and CSI driver release the stack installs. */
5
+ export const OCI_DRIVER_VERSION = 'v1.34.0';
6
+ /**
7
+ * The flexible shape a family runs on, and its vCPU per OCPU.
8
+ *
9
+ * @param family - The family (`E5`).
10
+ * @returns The shape and its ratio.
11
+ * @throws Error - For a family with no flexible shape known.
12
+ */
13
+ export function familyShape_of(family) {
14
+ const found = Object.entries(SHAPE_TERMS).find(([, terms]) => terms.family === family);
15
+ if (found === undefined)
16
+ throw new Error(`${family}: no flexible shape known for this family`);
17
+ return { shape: found[0], vcpuPerOcpu: found[1].vcpuPerOcpu };
18
+ }
19
+ /**
20
+ * One pool as the stack's `<prefix>_*` variables.
21
+ *
22
+ * @param prefix - `control_plane` or `compute`.
23
+ * @param pool - The pool.
24
+ * @param family - The family.
25
+ * @returns The variables.
26
+ * @throws Error - When the vCPU is not whole OCPUs, or the tier is unknown.
27
+ */
28
+ function pool_variables(prefix, pool, family) {
29
+ const { shape, vcpuPerOcpu } = familyShape_of(family);
30
+ if (pool.vcpu % vcpuPerOcpu !== 0)
31
+ throw new Error(`${prefix}: ${pool.vcpu} vCPU is not whole OCPUs on ${family} (${vcpuPerOcpu} vCPU an OCPU)`);
32
+ const vpus = TIER_VPUS[pool.bootTier];
33
+ if (vpus === undefined)
34
+ throw new Error(`${prefix}: boot tier ${pool.bootTier} is not one of ${Object.keys(TIER_VPUS).join(', ')}`);
35
+ return {
36
+ [`${prefix}_count`]: String(pool.count),
37
+ [`${prefix}_shape`]: shape,
38
+ [`${prefix}_ocpu`]: String(pool.vcpu / vcpuPerOcpu),
39
+ [`${prefix}_memory`]: String(pool.ramGib),
40
+ [`${prefix}_boot_size`]: String(pool.bootGib),
41
+ [`${prefix}_boot_volume_vpus_per_gb`]: String(vpus),
42
+ };
43
+ }
44
+ /**
45
+ * A new domain's stack variables.
46
+ *
47
+ * @param request - The domain, its spec, where it goes, the image and the key.
48
+ * @returns The variables, each a string.
49
+ */
50
+ export function stackVariables_build(request) {
51
+ return {
52
+ tenancy_ocid: request.tenancyId,
53
+ compartment_ocid: request.compartmentId,
54
+ tag_namespace_compartment_ocid_resource_tagging: request.compartmentId,
55
+ region: request.region,
56
+ cluster_name: request.domain,
57
+ zone_dns: request.baseDomain,
58
+ installation_method: 'Assisted',
59
+ openshift_image_source_uri: request.isoLink,
60
+ public_ssh_key: request.sshPublicKey,
61
+ ...pool_variables('control_plane', request.spec.controlPlane, request.spec.family),
62
+ ...(request.spec.workers.count > 0 ? pool_variables('compute', request.spec.workers, request.spec.family) : { compute_count: '0' }),
63
+ create_public_dns: 'false',
64
+ create_private_dns: 'false',
65
+ enable_public_api_lb: 'true',
66
+ enable_public_apps_lb: 'true',
67
+ oci_driver_version: OCI_DRIVER_VERSION,
68
+ };
69
+ }
70
+ //# sourceMappingURL=stackVars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackVars.js","sourceRoot":"","sources":["../../../src/cloud/oci/stackVars.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file A fake cluster answering the Kubernetes API calls `verify` makes, a
3
+ * healthy one unless told otherwise, and the fake world's DNS and HTTPS
4
+ * around it. What `stratus --fake` verifies against, and the tests.
5
+ *
6
+ * @module
7
+ */
8
+ import type { KubeApi } from './kube.js';
9
+ import type { VerifyReach } from '../commands/verify.js';
10
+ /** One fake node. */
11
+ export interface FakeNode {
12
+ readonly name: string;
13
+ readonly zone: string;
14
+ readonly shape: string;
15
+ }
16
+ /** How the fake cluster answers. */
17
+ export interface FakeClusterOptions {
18
+ readonly nodes: ReadonlyArray<FakeNode>;
19
+ /** Operators that are not settled. */
20
+ readonly degraded?: ReadonlyArray<string>;
21
+ /** Whether the volume probe's pod succeeds. */
22
+ readonly probeSucceeds?: boolean;
23
+ }
24
+ /** A fake cluster, keeping what the volume probe makes. */
25
+ export declare class FakeKube implements KubeApi {
26
+ private readonly options;
27
+ readonly made: string[];
28
+ readonly deleted: string[];
29
+ private readonly namespaces;
30
+ constructor(options: FakeClusterOptions);
31
+ json_get(path: string): Promise<unknown>;
32
+ text_get(path: string): Promise<string>;
33
+ json_post(path: string, body: unknown): Promise<unknown>;
34
+ delete(path: string): Promise<void>;
35
+ }
36
+ /**
37
+ * The fake world's reach for `verify`: a healthy cluster of the given nodes,
38
+ * the fake build's load-balancer addresses in DNS, a console that answers.
39
+ *
40
+ * @param nodes_of - The nodes of a domain's cluster, from its kubeconfig's text.
41
+ * @returns The reach.
42
+ */
43
+ export declare function fakeVerifyReach(nodes_of: (kubeconfig: string) => FakeNode[]): VerifyReach;
@@ -0,0 +1,86 @@
1
+ import { KubeError } from './kube.js';
2
+ /** A fake cluster, keeping what the volume probe makes. */
3
+ export class FakeKube {
4
+ options;
5
+ made = [];
6
+ deleted = [];
7
+ namespaces = new Set();
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ async json_get(path) {
12
+ if (path === '/apis/config.openshift.io/v1/clusterversions/version') {
13
+ return { status: { desired: { version: '4.22.3' }, conditions: [{ type: 'Available', status: 'True' }, { type: 'Failing', status: 'False' }] } };
14
+ }
15
+ if (path === '/api/v1/nodes') {
16
+ return {
17
+ items: this.options.nodes.map((node) => ({
18
+ metadata: { name: node.name, labels: { 'node.kubernetes.io/instance-type': node.shape, 'topology.kubernetes.io/zone': node.zone } },
19
+ spec: { providerID: `oci://ocid1.instance.${node.name}` },
20
+ status: { conditions: [{ type: 'Ready', status: 'True' }], allocatable: { cpu: '7500m' } },
21
+ })),
22
+ };
23
+ }
24
+ if (path === '/apis/config.openshift.io/v1/clusteroperators') {
25
+ const names = ['console', 'dns', 'ingress', 'storage', ...(this.options.degraded ?? [])];
26
+ return {
27
+ items: names.map((name) => ({
28
+ metadata: { name },
29
+ status: { conditions: (this.options.degraded ?? []).includes(name)
30
+ ? [{ type: 'Available', status: 'True' }, { type: 'Progressing', status: 'False' }, { type: 'Degraded', status: 'True' }]
31
+ : [{ type: 'Available', status: 'True' }, { type: 'Progressing', status: 'False' }, { type: 'Degraded', status: 'False' }] },
32
+ })),
33
+ };
34
+ }
35
+ if (path === '/apis/storage.k8s.io/v1/storageclasses') {
36
+ return { items: [{ metadata: { name: 'oci-bv', annotations: { 'storageclass.kubernetes.io/is-default-class': 'true' } } }, { metadata: { name: 'oci-bv-encrypted' } }] };
37
+ }
38
+ if (path === '/api/v1/pods') {
39
+ return { items: this.options.nodes.map((node) => ({ spec: { nodeName: node.name, containers: [{ resources: { requests: { cpu: '3' } } }] }, status: { phase: 'Running' } })) };
40
+ }
41
+ if (path === '/api/v1/namespaces/openshift-ingress-operator/secrets/router-ca') {
42
+ return { data: { 'tls.crt': Buffer.from('-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----\n').toString('base64') } };
43
+ }
44
+ const pod = /^\/api\/v1\/namespaces\/([^/]+)\/pods\/probe$/.exec(path);
45
+ if (pod !== null && this.namespaces.has(pod[1]))
46
+ return { status: { phase: this.options.probeSucceeds === false ? 'Failed' : 'Succeeded' } };
47
+ throw new KubeError(404, `GET ${path}: HTTP 404 not found`);
48
+ }
49
+ async text_get(path) {
50
+ if (path === '/readyz')
51
+ return 'ok';
52
+ if (/\/pods\/probe\/log$/.test(path))
53
+ return 'stratus\n';
54
+ throw new KubeError(404, `GET ${path}: HTTP 404 not found`);
55
+ }
56
+ async json_post(path, body) {
57
+ this.made.push(path);
58
+ if (path === '/api/v1/namespaces')
59
+ this.namespaces.add(body.metadata.name);
60
+ return body;
61
+ }
62
+ async delete(path) {
63
+ const ns = /^\/api\/v1\/namespaces\/([^/]+)$/.exec(path);
64
+ if (ns === null || !this.namespaces.has(ns[1]))
65
+ throw new KubeError(404, `DELETE ${path}: HTTP 404 not found`);
66
+ this.namespaces.delete(ns[1]);
67
+ this.deleted.push(path);
68
+ }
69
+ }
70
+ /**
71
+ * The fake world's reach for `verify`: a healthy cluster of the given nodes,
72
+ * the fake build's load-balancer addresses in DNS, a console that answers.
73
+ *
74
+ * @param nodes_of - The nodes of a domain's cluster, from its kubeconfig's text.
75
+ * @returns The reach.
76
+ */
77
+ export function fakeVerifyReach(nodes_of) {
78
+ return {
79
+ kube_make: (kubeconfig) => new FakeKube({ nodes: nodes_of(kubeconfig) }),
80
+ resolve: async (name) => [name.startsWith('api-int.') ? '10.0.0.11' : name.startsWith('api.') ? '10.0.0.10' : '10.0.0.12'],
81
+ https_status: async () => 200,
82
+ probeTimeoutMs: 1000,
83
+ pollMs: 0,
84
+ };
85
+ }
86
+ //# sourceMappingURL=fakeKube.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fakeKube.js","sourceRoot":"","sources":["../../src/cluster/fakeKube.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /** How a kubeconfig reaches its cluster: the server, its CA, and who we are. */
2
+ export interface KubeAccess {
3
+ /** The API server's address. */
4
+ readonly server: string;
5
+ /** The CA that signs the server's certificate, PEM, or null to trust the system's. */
6
+ readonly ca: string | null;
7
+ /** A client certificate and key, PEM. */
8
+ readonly cert: string | null;
9
+ readonly key: string | null;
10
+ /** A bearer token. */
11
+ readonly token: string | null;
12
+ }
13
+ /** A Kubernetes API answer that was not a success. */
14
+ export declare class KubeError extends Error {
15
+ readonly status: number;
16
+ /**
17
+ * @param status - The HTTP status.
18
+ * @param message - What the server said.
19
+ */
20
+ constructor(status: number, message: string);
21
+ }
22
+ /** The Kubernetes API, as `verify` calls it. */
23
+ export interface KubeApi {
24
+ /** A path's JSON (`/api/v1/nodes`). */
25
+ json_get(path: string): Promise<unknown>;
26
+ /** A path's text (`/readyz`, a pod's log). */
27
+ text_get(path: string): Promise<string>;
28
+ /** Creates an object under a path. */
29
+ json_post(path: string, body: unknown): Promise<unknown>;
30
+ /** Deletes the object at a path. */
31
+ delete(path: string): Promise<void>;
32
+ }
33
+ /**
34
+ * Reads a kubeconfig: the current context's cluster and user.
35
+ *
36
+ * @param text - The kubeconfig.
37
+ * @returns How to reach the cluster.
38
+ * @throws Error - When it names no cluster to reach.
39
+ */
40
+ export declare function kubeconfig_read(text: string): KubeAccess;