@varde-flyt/vfac 0.11.0 → 0.12.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 +19 -7
- package/dist/vfac.mjs +70 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,14 +74,21 @@ vfac manifest init --product <productId> --name "My resource" > resource.yaml
|
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
76
|
vfac validate -f resource.yaml
|
|
77
|
-
vfac plan -f resource.yaml
|
|
77
|
+
vfac plan -f resource.yaml --secret SETTING=env:VARIABLE
|
|
78
78
|
vfac apply -f resource.yaml --secret SETTING=env:VARIABLE
|
|
79
79
|
vfac get operation <operationId>
|
|
80
80
|
vfac get product-instance <productInstanceId>
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Secrets are supplied per apply and never belong in the manifest — a manifest is a
|
|
84
|
-
file you commit.
|
|
84
|
+
file you commit. **Plan the run that sets one with the same `--secret` inputs the
|
|
85
|
+
apply will carry**: `plan` takes the flag exactly as `apply` does, and without it
|
|
86
|
+
the plan describes a different request.
|
|
87
|
+
|
|
88
|
+
`requiredSecrets` in a plan is what the Product requires for the configuration in
|
|
89
|
+
your document — not a list of what the platform is missing. It names a credential
|
|
90
|
+
whether or not this resource already holds one, so it is not a shopping list to
|
|
91
|
+
act on. `secretsToWrite` is the field that says what this apply would write.
|
|
85
92
|
|
|
86
93
|
### `metadata.key` is the name you choose
|
|
87
94
|
|
|
@@ -176,7 +183,8 @@ spec:
|
|
|
176
183
|
`vfac manifest init` names the exact property for every dependency you have to
|
|
177
184
|
choose, and `vfac plan` prints the connections an apply would establish before
|
|
178
185
|
you approve it. The dependency key comes from the Product, not from you —
|
|
179
|
-
`vfac product show <productId>` lists
|
|
186
|
+
`vfac product show <productId>` lists every dependency with its key, its
|
|
187
|
+
capability, and whether a setting is what turns it on.
|
|
180
188
|
|
|
181
189
|
This is not the same thing as the section above, and the difference is worth
|
|
182
190
|
holding on to:
|
|
@@ -198,7 +206,8 @@ it.
|
|
|
198
206
|
|
|
199
207
|
Every command takes `--output json`, and it is the same data rather than a
|
|
200
208
|
prettier subset — the human format of `vfac product show` prints a readable
|
|
201
|
-
selection on purpose
|
|
209
|
+
selection on purpose and says so at the foot of its output, and the JSON carries
|
|
210
|
+
the whole Product contract.
|
|
202
211
|
|
|
203
212
|
```sh
|
|
204
213
|
vfac product show <productId> --output json
|
|
@@ -261,12 +270,15 @@ so this answers `UPDATE` and redeploys, even when the value is the value already
|
|
|
261
270
|
stored:
|
|
262
271
|
|
|
263
272
|
```sh
|
|
273
|
+
vfac plan -f resource.yaml --secret SETTING=env:VARIABLE
|
|
264
274
|
vfac apply -f resource.yaml --secret SETTING=env:VARIABLE
|
|
265
275
|
```
|
|
266
276
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
Three runs carry a secret: the apply that creates the resource, the first time a
|
|
278
|
+
setting needs a credential on a resource that already exists, and a rotation. Send
|
|
279
|
+
none on any other run — a pipeline that passes its secrets every run restarts your
|
|
280
|
+
service every time somebody pushes a README. Plan each of those three with the
|
|
281
|
+
same `--secret` inputs: with no secret to write, a rotation plans as `NO_CHANGE`.
|
|
270
282
|
|
|
271
283
|
## Where the Gate Secret goes
|
|
272
284
|
|
package/dist/vfac.mjs
CHANGED
|
@@ -7932,8 +7932,9 @@ function renderOperation(operationId, data) {
|
|
|
7932
7932
|
if (typeof retryable === "boolean") {
|
|
7933
7933
|
const again = data["type"] === "PRODUCT_INSTANCE_UPGRADE" ? "`vfac lifecycle upgrade <pri_\u2026>`" : "`vfac lifecycle reconcile <pri_\u2026>`";
|
|
7934
7934
|
const changeIt = data["type"] === "PRODUCT_INSTANCE_UPGRADE" ? "" : ", or `vfac apply` a corrected manifest";
|
|
7935
|
+
const cause2 = failure["cause"];
|
|
7935
7936
|
lines.push(
|
|
7936
|
-
retryable ? ` Another attempt can succeed: ${again}.` : ` Repeating this unchanged fails again \u2014 fix what the lines above name, then ${again}${changeIt}.`
|
|
7937
|
+
retryable ? ` Another attempt can succeed: ${again}.` : cause2 === "unknown" ? ` The platform could not classify this, so there is nothing here to correct. Read the whole record with \`vfac get operation ${operationId} --output json\`, and quote that id if you ask for help. Repeating it unchanged fails the same way.` : ` Repeating this unchanged fails again \u2014 fix what the lines above name, then ${again}${changeIt}.`
|
|
7937
7938
|
);
|
|
7938
7939
|
}
|
|
7939
7940
|
}
|
|
@@ -13255,6 +13256,7 @@ function conditionHolds(condition, configuration) {
|
|
|
13255
13256
|
// ../product-configuration/dist/customer-configuration-input.js
|
|
13256
13257
|
var ABSOLUTE_MAX_STRING = MAX_DECLARABLE_STRING_LENGTH;
|
|
13257
13258
|
var MAX_REPORTED_UNDECLARED_KEYS = 10;
|
|
13259
|
+
var UNDECLARED_SETTING_MESSAGE = "This Product does not declare a setting with that name.";
|
|
13258
13260
|
function isPlainObject2(value) {
|
|
13259
13261
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13260
13262
|
}
|
|
@@ -13338,7 +13340,7 @@ function validateObject(declaration, input, container, walk, root) {
|
|
|
13338
13340
|
};
|
|
13339
13341
|
const undeclared = Object.keys(input).filter((name) => !Object.hasOwn(declaration.properties, name));
|
|
13340
13342
|
for (const name of undeclared.slice(0, MAX_REPORTED_UNDECLARED_KEYS)) {
|
|
13341
|
-
report(walk, fieldFor(name),
|
|
13343
|
+
report(walk, fieldFor(name), UNDECLARED_SETTING_MESSAGE);
|
|
13342
13344
|
}
|
|
13343
13345
|
if (undeclared.length > MAX_REPORTED_UNDECLARED_KEYS) {
|
|
13344
13346
|
report(walk, container === null ? "" : container, `${undeclared.length - MAX_REPORTED_UNDECLARED_KEYS} further settings are not declared by this Product.`);
|
|
@@ -13604,7 +13606,11 @@ function checkString(field, property, value, issues) {
|
|
|
13604
13606
|
return void 0;
|
|
13605
13607
|
}
|
|
13606
13608
|
if (property.pattern !== void 0 && !matches(property.pattern, value)) {
|
|
13607
|
-
|
|
13609
|
+
const expectation = property.description;
|
|
13610
|
+
issues.push({
|
|
13611
|
+
field,
|
|
13612
|
+
message: expectation === void 0 ? "Value is not in the required format." : `Value is not in the required format. ${expectation.replace(/\s+$/, "")}`
|
|
13613
|
+
});
|
|
13608
13614
|
return void 0;
|
|
13609
13615
|
}
|
|
13610
13616
|
return value;
|
|
@@ -16801,8 +16807,16 @@ var MANIFEST_ACTIONS = [
|
|
|
16801
16807
|
"ADOPT",
|
|
16802
16808
|
/** The key names a resource and something in the document differs. */
|
|
16803
16809
|
"UPDATE",
|
|
16804
|
-
/** The key names a resource and
|
|
16805
|
-
*
|
|
16810
|
+
/** The key names a resource and this REQUEST asks for nothing: no field
|
|
16811
|
+
* differs and no secret would be written.
|
|
16812
|
+
*
|
|
16813
|
+
* NOT "the document matches it", which is how it read and is a stronger claim
|
|
16814
|
+
* than the planner makes. What a document OMITS is left alone rather than
|
|
16815
|
+
* compared — a manifest naming no connections answers this beside a resource
|
|
16816
|
+
* that holds several — so this never means the file mirrors stored state.
|
|
16817
|
+
*
|
|
16818
|
+
* A pipeline that runs on every push and changes nothing reports it, and it
|
|
16819
|
+
* is SUCCESS. */
|
|
16806
16820
|
"NO_CHANGE",
|
|
16807
16821
|
/** `adopt` points at a resource that was DELETED. Its own verb, because both
|
|
16808
16822
|
* alternatives are wrong: `NO_CHANGE` would call a missing resource fine, and
|
|
@@ -17089,7 +17103,9 @@ function secretWriteConsequence(plan) {
|
|
|
17089
17103
|
const lines = ["the value you send REPLACES the stored one, and the resource redeploys."];
|
|
17090
17104
|
if (plan.action === "UPDATE" && (plan.changes ?? []).length === 0) {
|
|
17091
17105
|
lines.push("Nothing else changed \u2014 sending a secret is itself the change.");
|
|
17092
|
-
lines.push(
|
|
17106
|
+
lines.push(
|
|
17107
|
+
"Omit --secret on a run that is not setting or changing one; that is what answers NO_CHANGE."
|
|
17108
|
+
);
|
|
17093
17109
|
}
|
|
17094
17110
|
return lines;
|
|
17095
17111
|
}
|
|
@@ -17893,9 +17909,9 @@ async function runGet(parsed) {
|
|
|
17893
17909
|
lines.push("", " Outputs");
|
|
17894
17910
|
const width = Math.max(...names.map((name) => name.length));
|
|
17895
17911
|
for (const name of names) {
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
);
|
|
17912
|
+
const value = outputs[name];
|
|
17913
|
+
const shown = isSecret2(name) ? "[secret]" : value === void 0 || value === null ? "[not available]" : String(value);
|
|
17914
|
+
lines.push(` ${name.padEnd(width)} ${shown}`);
|
|
17899
17915
|
const meaning = declared.find((entry) => entry["key"] === name);
|
|
17900
17916
|
const description = meaning?.["description"];
|
|
17901
17917
|
if (typeof description === "string") {
|
|
@@ -18085,14 +18101,41 @@ function renderProduct(product) {
|
|
|
18085
18101
|
lines.push(` ${setting.label} ${setting.type ?? ""}`.trimEnd());
|
|
18086
18102
|
}
|
|
18087
18103
|
}
|
|
18088
|
-
const
|
|
18089
|
-
if (
|
|
18090
|
-
lines.push("", "
|
|
18091
|
-
for (const dependency of
|
|
18092
|
-
|
|
18104
|
+
const dependencies = product.dependencies ?? [];
|
|
18105
|
+
if (dependencies.length > 0) {
|
|
18106
|
+
lines.push("", " Connections to another resource");
|
|
18107
|
+
for (const dependency of dependencies) {
|
|
18108
|
+
const when = dependency.requiredWhen?.property;
|
|
18109
|
+
const need = dependency.required ? "required" : when === void 0 ? "optional" : `required when ${when} is ${(dependency.requiredWhen?.anyOf ?? []).join(" or ")}`;
|
|
18110
|
+
lines.push(` ${dependency.key ?? "(no key)"} ${need}`);
|
|
18111
|
+
const capability = dependency.interface?.id;
|
|
18112
|
+
if (capability !== void 0) {
|
|
18113
|
+
lines.push(
|
|
18114
|
+
` ${capability}${dependency.interface?.version ? `/${dependency.interface.version}` : ""}`
|
|
18115
|
+
);
|
|
18116
|
+
} else if (dependency.productId !== void 0) {
|
|
18117
|
+
lines.push(` ${dependency.productId}`);
|
|
18118
|
+
}
|
|
18093
18119
|
if (dependency.reason) lines.push(` ${dependency.reason}`);
|
|
18094
18120
|
}
|
|
18095
18121
|
}
|
|
18122
|
+
const outputs = product.outputs ?? [];
|
|
18123
|
+
if (outputs.length > 0) {
|
|
18124
|
+
lines.push("", " Publishes");
|
|
18125
|
+
for (const output of outputs) {
|
|
18126
|
+
lines.push(
|
|
18127
|
+
` ${output.key ?? ""} ${output.secret === true ? "secret" : output.type ?? ""}`.trimEnd()
|
|
18128
|
+
);
|
|
18129
|
+
}
|
|
18130
|
+
}
|
|
18131
|
+
const conditions = product.conditions ?? [];
|
|
18132
|
+
if (conditions.length > 0) {
|
|
18133
|
+
lines.push("", " Needs setting up outside the platform");
|
|
18134
|
+
for (const condition of conditions) {
|
|
18135
|
+
lines.push(` ${condition.key ?? ""} ${condition.displayName ?? ""}`.trimEnd());
|
|
18136
|
+
}
|
|
18137
|
+
}
|
|
18138
|
+
lines.push("", " `--output json` carries the whole declaration, this is a readable subset.");
|
|
18096
18139
|
return lines.join("\n");
|
|
18097
18140
|
}
|
|
18098
18141
|
function wrap(text, width) {
|
|
@@ -18441,6 +18484,12 @@ Run \`vfac get product-instance pri_\u2026\` to see which ones this credential m
|
|
|
18441
18484
|
`);
|
|
18442
18485
|
return 2;
|
|
18443
18486
|
}
|
|
18487
|
+
if (parsed.booleans.has("wait")) {
|
|
18488
|
+
process.stderr.write(
|
|
18489
|
+
"`--wait` belongs to `vfac apply`; `vfac lifecycle` does not support it.\nThis command answers with an operation id. Follow it with:\n vfac get operation op_\u2026\nand branch on the status it reports: SUCCEEDED, FAILED or CANCELLED. That\ncommand's exit code says whether the READ worked, never whether the operation\ndid \u2014 so a script that only checks the exit code reports a failed deploy as a\nsuccess.\n"
|
|
18490
|
+
);
|
|
18491
|
+
return 2;
|
|
18492
|
+
}
|
|
18444
18493
|
if (command === "delete" && !parsed.booleans.has("yes")) {
|
|
18445
18494
|
process.stderr.write(
|
|
18446
18495
|
`delete removes ${instanceId} and everything it is serving. This cannot be undone.
|
|
@@ -18547,7 +18596,7 @@ var USAGE = `vfac \u2014 deploy Varde Flyt resources from a manifest
|
|
|
18547
18596
|
vfac manifest init --product <productId> --name <name> [--key <key>]
|
|
18548
18597
|
[--region <region>] [--profile <profile>]
|
|
18549
18598
|
vfac validate -f resource.yaml
|
|
18550
|
-
vfac plan -f resource.yaml
|
|
18599
|
+
vfac plan -f resource.yaml [--secret NAME=env:VAR]
|
|
18551
18600
|
vfac apply -f resource.yaml [--secret NAME=env:VAR] [--adopt pri_\u2026] [--wait]
|
|
18552
18601
|
vfac get product-instances
|
|
18553
18602
|
vfac get product-instance pri_\u2026 what it is, and its outputs
|
|
@@ -18564,9 +18613,12 @@ Options
|
|
|
18564
18613
|
--project the Project to act in. Defaults to the stored context
|
|
18565
18614
|
--endpoint your organization's portal. Defaults to VFAC_ENDPOINT, then the
|
|
18566
18615
|
stored context
|
|
18567
|
-
--secret NAME=env:VARIABLE \u2014 the value is read from the
|
|
18568
|
-
|
|
18569
|
-
|
|
18616
|
+
--secret plan and apply: NAME=env:VARIABLE \u2014 the value is read from the
|
|
18617
|
+
environment. Plan a run that sets a secret with the same
|
|
18618
|
+
--secret inputs the apply will carry; without them the plan
|
|
18619
|
+
answers about a different request. A value on the command line
|
|
18620
|
+
is in your shell history and in the process table, so it is
|
|
18621
|
+
refused
|
|
18570
18622
|
--product which Product to write a starting manifest for
|
|
18571
18623
|
--name what a person will call the resource
|
|
18572
18624
|
--key its stable identity. Derived from --name when omitted
|