@fnndsc/stratus 0.1.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.
- package/README.md +6 -1
- package/dist/args.d.ts +20 -6
- package/dist/args.js +45 -2
- package/dist/args.js.map +1 -1
- package/dist/backend.d.ts +35 -4
- package/dist/backend.js +77 -12
- package/dist/backend.js.map +1 -1
- package/dist/cloud/builder.d.ts +172 -0
- package/dist/cloud/builder.js +41 -0
- package/dist/cloud/builder.js.map +1 -0
- package/dist/cloud/driver.d.ts +149 -0
- package/dist/cloud/fake/builder.d.ts +147 -0
- package/dist/cloud/fake/builder.js +213 -0
- package/dist/cloud/fake/builder.js.map +1 -0
- package/dist/cloud/fake/driver.d.ts +73 -1
- package/dist/cloud/fake/driver.js +122 -0
- package/dist/cloud/fake/driver.js.map +1 -1
- package/dist/cloud/oci/api.d.ts +3 -2
- package/dist/cloud/oci/api.js +2 -0
- package/dist/cloud/oci/api.js.map +1 -1
- package/dist/cloud/oci/buildApi.d.ts +61 -0
- package/dist/cloud/oci/buildApi.js +132 -0
- package/dist/cloud/oci/buildApi.js.map +1 -0
- package/dist/cloud/oci/builder.d.ts +172 -0
- package/dist/cloud/oci/builder.js +370 -0
- package/dist/cloud/oci/builder.js.map +1 -0
- package/dist/cloud/oci/driver.d.ts +23 -2
- package/dist/cloud/oci/driver.js +107 -1
- package/dist/cloud/oci/driver.js.map +1 -1
- package/dist/cloud/oci/planRead.d.ts +38 -0
- package/dist/cloud/oci/planRead.js +67 -0
- package/dist/cloud/oci/planRead.js.map +1 -0
- package/dist/cloud/oci/prices.d.ts +22 -1
- package/dist/cloud/oci/prices.js +35 -0
- package/dist/cloud/oci/prices.js.map +1 -1
- package/dist/cloud/oci/resourceApi.d.ts +114 -0
- package/dist/cloud/oci/resourceApi.js +261 -0
- package/dist/cloud/oci/resourceApi.js.map +1 -0
- package/dist/cloud/oci/resourceMap.d.ts +44 -0
- package/dist/cloud/oci/resourceMap.js +70 -0
- package/dist/cloud/oci/resourceMap.js.map +1 -0
- package/dist/cloud/oci/rmApi.d.ts +74 -0
- package/dist/cloud/oci/rmApi.js +141 -0
- package/dist/cloud/oci/rmApi.js.map +1 -0
- package/dist/cloud/oci/stackVars.d.ts +49 -0
- package/dist/cloud/oci/stackVars.js +70 -0
- package/dist/cloud/oci/stackVars.js.map +1 -0
- package/dist/cluster/fakeKube.d.ts +43 -0
- package/dist/cluster/fakeKube.js +86 -0
- package/dist/cluster/fakeKube.js.map +1 -0
- package/dist/cluster/kube.d.ts +40 -0
- package/dist/cluster/kube.js +46 -0
- package/dist/cluster/kube.js.map +1 -0
- package/dist/cluster/kubeHttp.d.ts +16 -0
- package/dist/cluster/kubeHttp.js +86 -0
- package/dist/cluster/kubeHttp.js.map +1 -0
- package/dist/commands/build.d.ts +90 -0
- package/dist/commands/build.js +358 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/capacity.d.ts +37 -0
- package/dist/commands/capacity.js +93 -0
- package/dist/commands/capacity.js.map +1 -0
- package/dist/commands/domain.d.ts +45 -0
- package/dist/commands/domain.js +150 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/spend.d.ts +22 -0
- package/dist/commands/spend.js +65 -0
- package/dist/commands/spend.js.map +1 -0
- package/dist/commands/teardown.d.ts +10 -0
- package/dist/commands/teardown.js +72 -0
- package/dist/commands/teardown.js.map +1 -0
- package/dist/commands/verify.d.ts +28 -0
- package/dist/commands/verify.js +98 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/domain/adopt.d.ts +60 -0
- package/dist/domain/adopt.js +143 -0
- package/dist/domain/adopt.js.map +1 -0
- package/dist/domain/sizing.d.ts +55 -0
- package/dist/domain/sizing.js +66 -0
- package/dist/domain/sizing.js.map +1 -0
- package/dist/domain/spec.d.ts +101 -0
- package/dist/domain/spec.js +191 -0
- package/dist/domain/spec.js.map +1 -0
- package/dist/domain/spend.d.ts +84 -0
- package/dist/domain/spend.js +109 -0
- package/dist/domain/spend.js.map +1 -0
- package/dist/domain/state.d.ts +149 -0
- package/dist/domain/state.js +182 -0
- package/dist/domain/state.js.map +1 -0
- package/dist/domain/steps.d.ts +82 -0
- package/dist/domain/steps.js +311 -0
- package/dist/domain/steps.js.map +1 -0
- package/dist/domain/teardown.d.ts +38 -0
- package/dist/domain/teardown.js +48 -0
- package/dist/domain/teardown.js.map +1 -0
- package/dist/domain/verify.d.ts +68 -0
- package/dist/domain/verify.js +216 -0
- package/dist/domain/verify.js.map +1 -0
- package/dist/domain/view.d.ts +24 -0
- package/dist/domain/view.js +38 -0
- package/dist/domain/view.js.map +1 -0
- package/dist/domains/harborOci.d.ts +75 -0
- package/dist/domains/harborOci.js +165 -0
- package/dist/domains/harborOci.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/installer/assisted.d.ts +97 -0
- package/dist/installer/assisted.js +171 -0
- package/dist/installer/assisted.js.map +1 -0
- package/dist/installer/installer.d.ts +86 -0
- package/dist/installer/installer.js +15 -0
- package/dist/installer/installer.js.map +1 -0
- package/dist/prompt.d.ts +33 -0
- package/dist/prompt.js +46 -0
- package/dist/prompt.js.map +1 -0
- package/dist/session.d.ts +2 -0
- package/dist/session.js +4 -0
- package/dist/session.js.map +1 -1
- package/dist/stratus.js +75 -3
- package/dist/stratus.js.map +1 -1
- package/dist/vfs/domains.d.ts +39 -0
- package/dist/vfs/domains.js +128 -0
- package/dist/vfs/domains.js.map +1 -0
- package/dist/vfs/look.d.ts +10 -0
- package/dist/vfs/look.js +43 -8
- package/dist/vfs/look.js.map +1 -1
- package/dist/vfs/resources.d.ts +136 -0
- package/dist/vfs/resources.js +325 -0
- package/dist/vfs/resources.js.map +1 -0
- package/dist/vfs/tenancy.d.ts +15 -2
- package/dist/vfs/tenancy.js +53 -17
- package/dist/vfs/tenancy.js.map +1 -1
- package/package.json +13 -6
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file A domain's spec: the cluster and the ChRIS on it, in neutral units
|
|
3
|
+
* (vCPU and GiB), as `harbor-oci`'s `spec.yaml` holds them (docs/stratus.adoc,
|
|
4
|
+
* "Three layers, three tools, one spec").
|
|
5
|
+
*
|
|
6
|
+
* The file keeps `harbor-oci`'s shape, so a spec moves between the two: a
|
|
7
|
+
* family, then `controlPlane`, `workers` and `chris` sections of `key: value`
|
|
8
|
+
* lines. It is read and written here without a YAML library, because only
|
|
9
|
+
* that shape is ever read; anything else refuses by line.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** The spec a new domain starts from: `harbor-oci`'s compact cluster. */
|
|
14
|
+
export const SPEC_DEFAULT = {
|
|
15
|
+
family: 'E5',
|
|
16
|
+
controlPlane: { count: 3, vcpu: 8, ramGib: 24, bootGib: 200, bootTier: 'ultra' },
|
|
17
|
+
workers: { count: 0, vcpu: 8, ramGib: 32, bootGib: 120, bootTier: 'balanced' },
|
|
18
|
+
chris: { dataGib: 20, databaseGib: 5, queueGib: 1 },
|
|
19
|
+
};
|
|
20
|
+
/** The sections a spec holds, and the numbers each takes. */
|
|
21
|
+
const SECTIONS = {
|
|
22
|
+
controlPlane: ['count', 'vcpu', 'ramGib', 'bootGib', 'bootTier'],
|
|
23
|
+
workers: ['count', 'vcpu', 'ramGib', 'bootGib', 'bootTier'],
|
|
24
|
+
chris: ['dataGib', 'databaseGib', 'queueGib'],
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* A copy of a spec, nothing shared.
|
|
28
|
+
*
|
|
29
|
+
* @param spec - The spec.
|
|
30
|
+
* @returns The copy.
|
|
31
|
+
*/
|
|
32
|
+
export function spec_copy(spec) {
|
|
33
|
+
return { family: spec.family, controlPlane: { ...spec.controlPlane }, workers: { ...spec.workers }, chris: { ...spec.chris } };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Sets one field of a section, by name: the names were checked against
|
|
37
|
+
* {@link SECTIONS} by the caller.
|
|
38
|
+
*
|
|
39
|
+
* @param spec - The spec.
|
|
40
|
+
* @param section - `controlPlane`, `workers` or `chris`.
|
|
41
|
+
* @param key - The field.
|
|
42
|
+
* @param value - Its value.
|
|
43
|
+
*/
|
|
44
|
+
function specField_set(spec, section, key, value) {
|
|
45
|
+
if (section === 'chris') {
|
|
46
|
+
const chris = spec.chris;
|
|
47
|
+
if (key === 'dataGib' || key === 'databaseGib' || key === 'queueGib')
|
|
48
|
+
chris[key] = Number(value);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const pool = section === 'workers' ? spec.workers : spec.controlPlane;
|
|
52
|
+
if (key === 'bootTier')
|
|
53
|
+
pool.bootTier = String(value);
|
|
54
|
+
else if (key === 'count' || key === 'vcpu' || key === 'ramGib' || key === 'bootGib')
|
|
55
|
+
pool[key] = Number(value);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Writes a spec as `spec.yaml`.
|
|
59
|
+
*
|
|
60
|
+
* @param spec - The spec.
|
|
61
|
+
* @returns The file's text.
|
|
62
|
+
*/
|
|
63
|
+
export function specYaml_render(spec) {
|
|
64
|
+
const pool = (name, p, note) => [
|
|
65
|
+
`${name}:`,
|
|
66
|
+
` count: ${p.count}${note}`,
|
|
67
|
+
` vcpu: ${p.vcpu}`,
|
|
68
|
+
` ramGib: ${p.ramGib}`,
|
|
69
|
+
` bootGib: ${p.bootGib}`,
|
|
70
|
+
` bootTier: ${p.bootTier}`,
|
|
71
|
+
'',
|
|
72
|
+
];
|
|
73
|
+
return [
|
|
74
|
+
'# A Trusted Domain\'s spec: the cluster and the ChRIS on it, in vCPU and GiB.',
|
|
75
|
+
'# Written by `domain new`; harbor-oci reads the same shape.',
|
|
76
|
+
'',
|
|
77
|
+
`family: ${spec.family}`,
|
|
78
|
+
'',
|
|
79
|
+
...pool('controlPlane', spec.controlPlane, spec.controlPlane.count === 3 ? ' # one per availability domain' : ''),
|
|
80
|
+
...pool('workers', spec.workers, spec.workers.count === 0 ? ' # 0: compact cluster, schedulable control plane' : ''),
|
|
81
|
+
'chris:',
|
|
82
|
+
` dataGib: ${spec.chris.dataGib} # grows, never shrinks`,
|
|
83
|
+
` databaseGib: ${spec.chris.databaseGib} # fixed after the first deploy`,
|
|
84
|
+
` queueGib: ${spec.chris.queueGib} # fixed after the first deploy`,
|
|
85
|
+
'',
|
|
86
|
+
].join('\n');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Reads `spec.yaml`.
|
|
90
|
+
*
|
|
91
|
+
* @param text - The file's text.
|
|
92
|
+
* @returns The spec, or the line it could not read.
|
|
93
|
+
*/
|
|
94
|
+
export function specYaml_parse(text) {
|
|
95
|
+
const spec = spec_copy(SPEC_DEFAULT);
|
|
96
|
+
let section = null;
|
|
97
|
+
const lines = text.split('\n');
|
|
98
|
+
for (let index = 0; index < lines.length; index++) {
|
|
99
|
+
const line = (lines[index] ?? '').replace(/\s+#.*$/, '').replace(/^#.*$/, '');
|
|
100
|
+
if (line.trim() === '')
|
|
101
|
+
continue;
|
|
102
|
+
const match = /^(\s*)([A-Za-z]+):\s*(\S*)\s*$/.exec(line);
|
|
103
|
+
if (match === null)
|
|
104
|
+
return { error: `line ${index + 1}: not a key: value line` };
|
|
105
|
+
const indent = match[1] ?? '';
|
|
106
|
+
const key = match[2] ?? '';
|
|
107
|
+
const value = match[3] ?? '';
|
|
108
|
+
if (indent === '') {
|
|
109
|
+
if (key === 'family' && value !== '') {
|
|
110
|
+
spec.family = value;
|
|
111
|
+
section = null;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (SECTIONS[key] !== undefined && value === '') {
|
|
115
|
+
section = key;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
return { error: `line ${index + 1}: ${key}: not a spec field` };
|
|
119
|
+
}
|
|
120
|
+
if (section === null || !(SECTIONS[section] ?? []).includes(key))
|
|
121
|
+
return { error: `line ${index + 1}: ${key}: not a field of ${section ?? 'the spec'}` };
|
|
122
|
+
const number = Number(value);
|
|
123
|
+
if (key !== 'bootTier' && (!Number.isInteger(number) || number < 0))
|
|
124
|
+
return { error: `line ${index + 1}: ${key}: wants a whole number, not '${value}'` };
|
|
125
|
+
specField_set(spec, section, key, key === 'bootTier' ? value : number);
|
|
126
|
+
}
|
|
127
|
+
return { spec };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Reads a pool written as `<count>x<vcpu>/<GiB>` (`3x8/24`).
|
|
131
|
+
*
|
|
132
|
+
* @param text - The words.
|
|
133
|
+
* @returns The count, vCPU and GiB, or null.
|
|
134
|
+
*/
|
|
135
|
+
export function poolArg_parse(text) {
|
|
136
|
+
const match = /^(\d+)x(\d+)\/(\d+)$/.exec(text.trim());
|
|
137
|
+
if (match === null)
|
|
138
|
+
return null;
|
|
139
|
+
return { count: Number(match[1]), vcpu: Number(match[2]), ramGib: Number(match[3]) };
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Applies `domain new`'s sizing options to a spec.
|
|
143
|
+
*
|
|
144
|
+
* @param base - The spec to start from.
|
|
145
|
+
* @param options - `--family`, `--plane`, `--workers`, `--data`, `--database`, `--queue`, by name.
|
|
146
|
+
* @returns The spec, or what could not be read.
|
|
147
|
+
*/
|
|
148
|
+
export function specOptions_apply(base, options) {
|
|
149
|
+
const spec = spec_copy(base);
|
|
150
|
+
for (const [name, value] of options) {
|
|
151
|
+
if (name === '--family') {
|
|
152
|
+
spec.family = value;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (name === '--plane' || name === '--workers') {
|
|
156
|
+
const pool = poolArg_parse(value);
|
|
157
|
+
if (pool === null)
|
|
158
|
+
return { error: `${name} takes <count>x<vCPU>/<GiB>, as 3x8/24, not '${value}'` };
|
|
159
|
+
if (name === '--plane' && pool.count !== 3)
|
|
160
|
+
return { error: '--plane: the control plane is three nodes, one per availability domain' };
|
|
161
|
+
Object.assign(name === '--plane' ? spec.controlPlane : spec.workers, pool);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const field = { '--data': 'dataGib', '--database': 'databaseGib', '--queue': 'queueGib' }[name];
|
|
165
|
+
if (field === undefined)
|
|
166
|
+
return { error: `${name}: unknown option` };
|
|
167
|
+
const number = Number(value);
|
|
168
|
+
if (!Number.isInteger(number) || number <= 0)
|
|
169
|
+
return { error: `${name} wants a whole number of GiB, not '${value}'` };
|
|
170
|
+
spec.chris[field] = number;
|
|
171
|
+
}
|
|
172
|
+
return { spec };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The nodes a spec asks for, placed one per zone in turn.
|
|
176
|
+
*
|
|
177
|
+
* @param domain - The domain's name, for the nodes' names.
|
|
178
|
+
* @param spec - The spec.
|
|
179
|
+
* @param zones - How many zones the region has.
|
|
180
|
+
* @returns The nodes.
|
|
181
|
+
*/
|
|
182
|
+
export function specNodes_of(domain, spec, zones) {
|
|
183
|
+
const nodes = [];
|
|
184
|
+
const count = Math.max(zones, 1);
|
|
185
|
+
for (let i = 0; i < spec.controlPlane.count; i++)
|
|
186
|
+
nodes.push({ name: `${domain}-cp-${i}`, role: 'plane', vcpu: spec.controlPlane.vcpu, ramGib: spec.controlPlane.ramGib, zoneIndex: i % count });
|
|
187
|
+
for (let i = 0; i < spec.workers.count; i++)
|
|
188
|
+
nodes.push({ name: `${domain}-w-${i}`, role: 'worker', vcpu: spec.workers.vcpu, ramGib: spec.workers.ramGib, zoneIndex: i % count });
|
|
189
|
+
return nodes;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/domain/spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file What a domain costs: each live resource in its compartment priced at
|
|
3
|
+
* list price, an hour, and what that has come to since each was made
|
|
4
|
+
* (docs/stratus.adoc, D7). `harbor-oci`'s `burn`, read through the driver.
|
|
5
|
+
*
|
|
6
|
+
* Machines bill by vCPU and memory while running; volumes by size and
|
|
7
|
+
* performance whatever the machine does; load balancers by the hour and their
|
|
8
|
+
* minimum bandwidth. Buckets, networks and DNS zones are free at this scale.
|
|
9
|
+
* The figures are estimates at list price, not the bill: discounts, free
|
|
10
|
+
* tiers and traffic are not in them, and the lines say so.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { CloudDriver, CloudInstance, CloudLoadBalancer, CloudPrice, CloudVolume, ServicePrices } from '../cloud/driver.js';
|
|
15
|
+
/** The hours a month is billed as, as `harbor-oci` reckons. */
|
|
16
|
+
export declare const HOURS_PER_MONTH: number;
|
|
17
|
+
/** One priced resource. */
|
|
18
|
+
export interface SpendItem {
|
|
19
|
+
readonly kind: 'compute' | 'volumes' | 'load balancers';
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly detail: string;
|
|
22
|
+
/** Per hour, or null when it could not be priced. */
|
|
23
|
+
readonly hourly: number | null;
|
|
24
|
+
/** Since it was made, or null when unpriced or its making is not known. */
|
|
25
|
+
readonly soFar: number | null;
|
|
26
|
+
}
|
|
27
|
+
/** A compartment's spend. */
|
|
28
|
+
export interface Spend {
|
|
29
|
+
readonly items: ReadonlyArray<SpendItem>;
|
|
30
|
+
readonly hourly: number;
|
|
31
|
+
readonly soFar: number;
|
|
32
|
+
readonly currency: string;
|
|
33
|
+
/** How many items could not be priced. */
|
|
34
|
+
readonly unpriced: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A machine's hour.
|
|
38
|
+
*
|
|
39
|
+
* @param instance - The machine.
|
|
40
|
+
* @param prices - The shapes' prices.
|
|
41
|
+
* @returns Its price an hour, or null.
|
|
42
|
+
*/
|
|
43
|
+
export declare function instance_hourly(instance: CloudInstance, prices: ReadonlyArray<CloudPrice>): number | null;
|
|
44
|
+
/**
|
|
45
|
+
* A volume's hour.
|
|
46
|
+
*
|
|
47
|
+
* @param volume - The volume.
|
|
48
|
+
* @param prices - Storage prices.
|
|
49
|
+
* @returns Its price an hour.
|
|
50
|
+
*/
|
|
51
|
+
export declare function volume_hourly(volume: CloudVolume, prices: ServicePrices): number;
|
|
52
|
+
/**
|
|
53
|
+
* A load balancer's hour.
|
|
54
|
+
*
|
|
55
|
+
* @param balancer - The load balancer.
|
|
56
|
+
* @param prices - Load-balancing prices.
|
|
57
|
+
* @returns Its price an hour.
|
|
58
|
+
*/
|
|
59
|
+
export declare function balancer_hourly(balancer: CloudLoadBalancer, prices: ServicePrices): number;
|
|
60
|
+
/**
|
|
61
|
+
* Prices every live resource in a compartment.
|
|
62
|
+
*
|
|
63
|
+
* @param driver - The cloud.
|
|
64
|
+
* @param compartmentId - The compartment.
|
|
65
|
+
* @param region - The region.
|
|
66
|
+
* @param now - The clock.
|
|
67
|
+
* @returns The spend.
|
|
68
|
+
*/
|
|
69
|
+
export declare function spend_read(driver: CloudDriver, compartmentId: string, region: string, now: Date): Promise<Spend>;
|
|
70
|
+
/**
|
|
71
|
+
* Money as the operator reads it.
|
|
72
|
+
*
|
|
73
|
+
* @param amount - The amount.
|
|
74
|
+
* @param currency - Its currency.
|
|
75
|
+
* @returns `$1.23`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function money_words(amount: number, currency: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* A spend in a line.
|
|
80
|
+
*
|
|
81
|
+
* @param spend - The spend.
|
|
82
|
+
* @returns `$0.89 an hour · $412.30 so far, at list price`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function spend_line(spend: Spend): string;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** The hours a month is billed as, as `harbor-oci` reckons. */
|
|
2
|
+
export const HOURS_PER_MONTH = 730;
|
|
3
|
+
/** The states in which a machine bills. */
|
|
4
|
+
const COMPUTE_STATES = ['running', 'starting', 'provisioning'];
|
|
5
|
+
/** The states in which a resource is gone and bills nothing. */
|
|
6
|
+
const GONE_STATES = ['terminated', 'deleted', 'terminating', 'deleting'];
|
|
7
|
+
/**
|
|
8
|
+
* The hours since a time.
|
|
9
|
+
*
|
|
10
|
+
* @param created - ISO 8601, or empty.
|
|
11
|
+
* @param now - The clock.
|
|
12
|
+
* @returns Hours, or null when not known.
|
|
13
|
+
*/
|
|
14
|
+
function hours_since(created, now) {
|
|
15
|
+
const at = Date.parse(created);
|
|
16
|
+
return Number.isFinite(at) ? Math.max(0, (now.getTime() - at) / 3_600_000) : null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A machine's hour.
|
|
20
|
+
*
|
|
21
|
+
* @param instance - The machine.
|
|
22
|
+
* @param prices - The shapes' prices.
|
|
23
|
+
* @returns Its price an hour, or null.
|
|
24
|
+
*/
|
|
25
|
+
export function instance_hourly(instance, prices) {
|
|
26
|
+
const price = prices.find((entry) => entry.shape === instance.shape);
|
|
27
|
+
if (price === undefined || instance.vcpus === undefined || instance.memoryGib === undefined)
|
|
28
|
+
return null;
|
|
29
|
+
return instance.vcpus * price.vcpuHour + instance.memoryGib * price.gibHour;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A volume's hour.
|
|
33
|
+
*
|
|
34
|
+
* @param volume - The volume.
|
|
35
|
+
* @param prices - Storage prices.
|
|
36
|
+
* @returns Its price an hour.
|
|
37
|
+
*/
|
|
38
|
+
export function volume_hourly(volume, prices) {
|
|
39
|
+
return (volume.sizeGib * (prices.volumeGibMonth + (volume.vpusPerGib ?? 10) * prices.vpuGibMonth)) / HOURS_PER_MONTH;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A load balancer's hour.
|
|
43
|
+
*
|
|
44
|
+
* @param balancer - The load balancer.
|
|
45
|
+
* @param prices - Load-balancing prices.
|
|
46
|
+
* @returns Its price an hour.
|
|
47
|
+
*/
|
|
48
|
+
export function balancer_hourly(balancer, prices) {
|
|
49
|
+
return prices.balancerHour + (balancer.minimumMbps ?? 10) * prices.balancerMbpsHour;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Prices every live resource in a compartment.
|
|
53
|
+
*
|
|
54
|
+
* @param driver - The cloud.
|
|
55
|
+
* @param compartmentId - The compartment.
|
|
56
|
+
* @param region - The region.
|
|
57
|
+
* @param now - The clock.
|
|
58
|
+
* @returns The spend.
|
|
59
|
+
*/
|
|
60
|
+
export async function spend_read(driver, compartmentId, region, now) {
|
|
61
|
+
const [instances, volumes, balancers, prices, service] = await Promise.all([
|
|
62
|
+
driver.instances_list(compartmentId, region),
|
|
63
|
+
driver.volumes_list(compartmentId, region),
|
|
64
|
+
driver.loadbalancers_list(compartmentId, region),
|
|
65
|
+
driver.prices_list(),
|
|
66
|
+
driver.servicePrices_get(),
|
|
67
|
+
]);
|
|
68
|
+
const item = (kind, name, detail, hourly, created) => {
|
|
69
|
+
const hours = hours_since(created, now);
|
|
70
|
+
return { kind, name, detail, hourly, soFar: hourly === null || hours === null ? null : hourly * hours };
|
|
71
|
+
};
|
|
72
|
+
const items = [
|
|
73
|
+
...instances.filter((instance) => COMPUTE_STATES.includes(instance.state))
|
|
74
|
+
.map((instance) => item('compute', instance.name, `${instance.shape}, ${instance.vcpus ?? '?'} vCPU, ${instance.memoryGib ?? '?'} GiB`, instance_hourly(instance, prices), instance.created)),
|
|
75
|
+
...volumes.filter((volume) => !GONE_STATES.includes(volume.state))
|
|
76
|
+
.map((volume) => item('volumes', volume.name, `${volume.sizeGib} GiB, ${volume.vpusPerGib ?? 10} VPU/GiB`, service === null ? null : volume_hourly(volume, service), volume.created)),
|
|
77
|
+
...balancers.filter((balancer) => !GONE_STATES.includes(balancer.state))
|
|
78
|
+
.map((balancer) => item('load balancers', balancer.name, `${balancer.shape}, ${balancer.minimumMbps ?? 10} Mbps minimum`, service === null ? null : balancer_hourly(balancer, service), balancer.created)),
|
|
79
|
+
];
|
|
80
|
+
return {
|
|
81
|
+
items,
|
|
82
|
+
hourly: items.reduce((sum, entry) => sum + (entry.hourly ?? 0), 0),
|
|
83
|
+
soFar: items.reduce((sum, entry) => sum + (entry.soFar ?? 0), 0),
|
|
84
|
+
currency: service?.currency ?? prices[0]?.currency ?? 'USD',
|
|
85
|
+
unpriced: items.filter((entry) => entry.hourly === null).length,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Money as the operator reads it.
|
|
90
|
+
*
|
|
91
|
+
* @param amount - The amount.
|
|
92
|
+
* @param currency - Its currency.
|
|
93
|
+
* @returns `$1.23`.
|
|
94
|
+
*/
|
|
95
|
+
export function money_words(amount, currency) {
|
|
96
|
+
// A rate under a cent is shown to the hundredth of a cent, never as nothing.
|
|
97
|
+
const digits = amount !== 0 && Math.abs(amount) < 0.01 ? 4 : 2;
|
|
98
|
+
return `${currency === 'USD' ? '$' : `${currency} `}${amount.toFixed(digits)}`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A spend in a line.
|
|
102
|
+
*
|
|
103
|
+
* @param spend - The spend.
|
|
104
|
+
* @returns `$0.89 an hour · $412.30 so far, at list price`.
|
|
105
|
+
*/
|
|
106
|
+
export function spend_line(spend) {
|
|
107
|
+
return `${money_words(spend.hourly, spend.currency)} an hour · ${money_words(spend.soFar, spend.currency)} so far, at list price${spend.unpriced > 0 ? ` (${spend.unpriced} not priced)` : ''}`;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=spend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend.js","sourceRoot":"","sources":["../../src/domain/spend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { type DomainSpec } from './spec.js';
|
|
2
|
+
/** Where a step stands in a domain this session builds. */
|
|
3
|
+
export type BuiltStepState = 'not done' | 'running' | 'done' | 'failed';
|
|
4
|
+
/** One step's history. */
|
|
5
|
+
export interface StepRecord {
|
|
6
|
+
state: BuiltStepState;
|
|
7
|
+
started?: string;
|
|
8
|
+
ended?: string;
|
|
9
|
+
/** What it rests on, or why it failed, in a line. */
|
|
10
|
+
note?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* What `state.json` holds.
|
|
14
|
+
*
|
|
15
|
+
* @property name - The domain's name, its cluster's name and a DNS label.
|
|
16
|
+
* @property created - When `domain new` wrote it.
|
|
17
|
+
* @property region - The region it is built in.
|
|
18
|
+
* @property baseDomain - The DNS zone its cluster's names live under.
|
|
19
|
+
* @property steps - Each step's history, by name.
|
|
20
|
+
* @property ids - What the build recorded for later steps (the installer's ids, the stack's, the ISO object).
|
|
21
|
+
* @property billingAccepted - When the operator answered yes to the cost of the first billing step.
|
|
22
|
+
* @property compartmentId - The compartment its resources live in, when known.
|
|
23
|
+
* @property adopted - Where it was adopted from, and when: built elsewhere, never built on here.
|
|
24
|
+
* @property gone - When its teardown removed what it built.
|
|
25
|
+
*/
|
|
26
|
+
export interface DomainRecord {
|
|
27
|
+
name: string;
|
|
28
|
+
created: string;
|
|
29
|
+
region: string;
|
|
30
|
+
baseDomain: string;
|
|
31
|
+
steps: Record<string, StepRecord>;
|
|
32
|
+
ids: Record<string, string>;
|
|
33
|
+
billingAccepted?: string;
|
|
34
|
+
compartmentId?: string;
|
|
35
|
+
adopted?: {
|
|
36
|
+
from: string;
|
|
37
|
+
at: string;
|
|
38
|
+
};
|
|
39
|
+
gone?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The folder a daemon keeps its domains in.
|
|
43
|
+
*
|
|
44
|
+
* @param env - The environment.
|
|
45
|
+
* @returns `$XDG_STATE_HOME/stratus/domains`, or `~/.local/state/stratus/domains`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function domainsRoot_of(env?: NodeJS.ProcessEnv): string;
|
|
48
|
+
/** A domain name is a DNS label: lower-case letters, digits and hyphens, at most 54. */
|
|
49
|
+
export declare const DOMAIN_NAME: RegExp;
|
|
50
|
+
/** The domains this daemon builds, on its host. */
|
|
51
|
+
export declare class DomainStore {
|
|
52
|
+
readonly root: string;
|
|
53
|
+
/**
|
|
54
|
+
* @param root - The folder the domains live in.
|
|
55
|
+
*/
|
|
56
|
+
constructor(root: string);
|
|
57
|
+
/**
|
|
58
|
+
* A domain's folder.
|
|
59
|
+
*
|
|
60
|
+
* @param name - The domain.
|
|
61
|
+
* @returns Its folder.
|
|
62
|
+
*/
|
|
63
|
+
folder_of(name: string): string;
|
|
64
|
+
/** The names of the domains kept, sorted. */
|
|
65
|
+
names_list(): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Makes a domain.
|
|
68
|
+
*
|
|
69
|
+
* @param record - Its first state.
|
|
70
|
+
* @param spec - Its spec.
|
|
71
|
+
* @throws Error - When one of that name is already kept.
|
|
72
|
+
*/
|
|
73
|
+
create(record: DomainRecord, spec: DomainSpec): void;
|
|
74
|
+
/**
|
|
75
|
+
* A domain's state.
|
|
76
|
+
*
|
|
77
|
+
* @param name - The domain.
|
|
78
|
+
* @returns Its record, or null when none is kept.
|
|
79
|
+
*/
|
|
80
|
+
record_read(name: string): DomainRecord | null;
|
|
81
|
+
/**
|
|
82
|
+
* Saves a domain's state.
|
|
83
|
+
*
|
|
84
|
+
* @param record - Its record.
|
|
85
|
+
*/
|
|
86
|
+
record_write(record: DomainRecord): void;
|
|
87
|
+
/**
|
|
88
|
+
* Changes a domain's state and saves it.
|
|
89
|
+
*
|
|
90
|
+
* @param name - The domain.
|
|
91
|
+
* @param change - What to change.
|
|
92
|
+
* @returns The record as saved.
|
|
93
|
+
* @throws Error - When none is kept.
|
|
94
|
+
*/
|
|
95
|
+
record_update(name: string, change: (record: DomainRecord) => void): DomainRecord;
|
|
96
|
+
/**
|
|
97
|
+
* A domain's spec, as written and as read.
|
|
98
|
+
*
|
|
99
|
+
* @param name - The domain.
|
|
100
|
+
* @returns The text and the spec (or why it does not read), or null when there is no file.
|
|
101
|
+
*/
|
|
102
|
+
spec_read(name: string): {
|
|
103
|
+
text: string;
|
|
104
|
+
spec: DomainSpec | null;
|
|
105
|
+
error?: string;
|
|
106
|
+
} | null;
|
|
107
|
+
/**
|
|
108
|
+
* Writes one of the domain's own files (`plan.json`), whole.
|
|
109
|
+
*
|
|
110
|
+
* @param name - The domain.
|
|
111
|
+
* @param file - The file's name in the domain's folder.
|
|
112
|
+
* @param text - Its content.
|
|
113
|
+
*/
|
|
114
|
+
file_write(name: string, file: string, text: string): void;
|
|
115
|
+
/**
|
|
116
|
+
* Reads one of the domain's own files.
|
|
117
|
+
*
|
|
118
|
+
* @param name - The domain.
|
|
119
|
+
* @param file - The file's name in the domain's folder.
|
|
120
|
+
* @returns Its content, or null when it is not there.
|
|
121
|
+
*/
|
|
122
|
+
file_read(name: string, file: string): string | null;
|
|
123
|
+
/**
|
|
124
|
+
* Keeps a secret the build fetched.
|
|
125
|
+
*
|
|
126
|
+
* @param name - The domain.
|
|
127
|
+
* @param file - Its file name under `auth/`.
|
|
128
|
+
* @param text - Its content.
|
|
129
|
+
*/
|
|
130
|
+
secret_write(name: string, file: string, text: string): void;
|
|
131
|
+
/**
|
|
132
|
+
* Reads a secret the build kept, for the build's own next step; never served.
|
|
133
|
+
*
|
|
134
|
+
* @param name - The domain.
|
|
135
|
+
* @param file - Its file name under `auth/`.
|
|
136
|
+
* @returns Its content, or null.
|
|
137
|
+
*/
|
|
138
|
+
secret_read(name: string, file: string): string | null;
|
|
139
|
+
/**
|
|
140
|
+
* The secrets kept, by name and host path; their content is never read here.
|
|
141
|
+
*
|
|
142
|
+
* @param name - The domain.
|
|
143
|
+
* @returns The files.
|
|
144
|
+
*/
|
|
145
|
+
secrets_list(name: string): Array<{
|
|
146
|
+
name: string;
|
|
147
|
+
hostPath: string;
|
|
148
|
+
}>;
|
|
149
|
+
}
|