@homeflare/alchemy 0.34.0 → 0.36.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/dist/grafana/alert-rule-group-drop-warning.d.ts +25 -0
- package/dist/grafana/alert-rule-group-drop-warning.d.ts.map +1 -0
- package/dist/grafana/alert-rule-group-fixtures.d.ts +73 -0
- package/dist/grafana/alert-rule-group-fixtures.d.ts.map +1 -0
- package/dist/grafana/alert-rule-group-model.d.ts +28 -0
- package/dist/grafana/alert-rule-group-model.d.ts.map +1 -0
- package/dist/grafana/alert-rule-group.d.ts +60 -0
- package/dist/grafana/alert-rule-group.d.ts.map +1 -0
- package/dist/grafana/index.d.ts +6 -4
- package/dist/grafana/index.d.ts.map +1 -1
- package/dist/grafana/index.js +355 -139
- package/dist/grafana/index.js.map +14 -8
- package/dist/grafana/notification-policy-drop-warning.d.ts +27 -0
- package/dist/grafana/notification-policy-drop-warning.d.ts.map +1 -0
- package/dist/grafana/notification-policy-fixtures.d.ts +34 -0
- package/dist/grafana/notification-policy-fixtures.d.ts.map +1 -0
- package/dist/grafana/notification-policy-model.d.ts +53 -0
- package/dist/grafana/notification-policy-model.d.ts.map +1 -0
- package/dist/grafana/notification-policy.d.ts +57 -0
- package/dist/grafana/notification-policy.d.ts.map +1 -0
- package/dist/grafana/providers.d.ts +1 -1
- package/dist/grafana/providers.d.ts.map +1 -1
- package/dist/proxmox/index.js +349 -287
- package/dist/proxmox/index.js.map +8 -7
- package/dist/proxmox/network-apply-read.d.ts +12 -0
- package/dist/proxmox/network-apply-read.d.ts.map +1 -1
- package/dist/proxmox/network-apply.d.ts +2 -0
- package/dist/proxmox/network-apply.d.ts.map +1 -1
- package/dist/proxmox/node-network-form.d.ts +86 -54
- package/dist/proxmox/node-network-form.d.ts.map +1 -1
- package/dist/proxmox/node-network-wire.d.ts +100 -0
- package/dist/proxmox/node-network-wire.d.ts.map +1 -0
- package/dist/proxmox/node-network.d.ts +21 -106
- package/dist/proxmox/node-network.d.ts.map +1 -1
- package/docs/grafana-alerting-rules.md +143 -0
- package/docs/grafana-alerting.md +7 -4
- package/docs/grafana-notification-policy.md +127 -0
- package/docs/grafana.md +12 -6
- package/docs/upstream-conformance.md +30 -4
- package/package.json +1 -1
- package/src/grafana/alert-rule-group-drop-warning.test.ts +107 -0
- package/src/grafana/alert-rule-group-drop-warning.ts +41 -0
- package/src/grafana/alert-rule-group-fixtures.ts +46 -0
- package/src/grafana/alert-rule-group-model.test.ts +75 -0
- package/src/grafana/alert-rule-group-model.ts +66 -0
- package/src/grafana/alert-rule-group-provenance.test.ts +116 -0
- package/src/grafana/alert-rule-group.test.ts +164 -0
- package/src/grafana/alert-rule-group.ts +231 -0
- package/src/grafana/index.ts +18 -4
- package/src/grafana/notification-policy-drop-warning.test.ts +163 -0
- package/src/grafana/notification-policy-drop-warning.ts +60 -0
- package/src/grafana/notification-policy-fixtures.ts +27 -0
- package/src/grafana/notification-policy-model.test.ts +104 -0
- package/src/grafana/notification-policy-model.ts +100 -0
- package/src/grafana/notification-policy-refusals.test.ts +119 -0
- package/src/grafana/notification-policy.test.ts +86 -0
- package/src/grafana/notification-policy.ts +191 -0
- package/src/grafana/providers.ts +4 -0
- package/src/proxmox/constraints-host-forms.test.ts +2 -2
- package/src/proxmox/network-apply-read.ts +12 -0
- package/src/proxmox/network-apply.ts +2 -0
- package/src/proxmox/node-network-form.ts +93 -99
- package/src/proxmox/node-network-read-failure.test.ts +206 -0
- package/src/proxmox/node-network-wire.ts +239 -0
- package/src/proxmox/node-network.ts +155 -167
package/dist/grafana/index.js
CHANGED
|
@@ -1,17 +1,77 @@
|
|
|
1
|
-
// src/grafana/
|
|
1
|
+
// src/grafana/alert-rule-group.ts
|
|
2
|
+
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
2
3
|
import { Resource } from "alchemy";
|
|
3
4
|
import * as Provider from "alchemy/Provider";
|
|
4
5
|
import * as grafana from "@distilled.cloud/grafana";
|
|
6
|
+
import * as Effect5 from "effect/Effect";
|
|
7
|
+
|
|
8
|
+
// src/grafana/alert-rule-group-drop-warning.ts
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
var warnOnDroppedRules = (folderUid, group, declaredUids, liveRules) => Effect.gen(function* () {
|
|
11
|
+
const dropped = (liveRules ?? []).filter((rule) => typeof rule.uid === "string").filter((rule) => !declaredUids.has(rule.uid));
|
|
12
|
+
if (dropped.length === 0)
|
|
13
|
+
return;
|
|
14
|
+
const names = dropped.map((rule) => `${typeof rule.title === "string" ? rule.title : "(untitled)"} (${rule.uid})`).join(", ");
|
|
15
|
+
yield* Effect.logWarning(`Grafana.AlertRuleGroup ${folderUid}/${group}: this update REMOVES ${dropped.length} ` + `rule(s) not in the declaration: ${names}. Whole-group replacement is by design — add ` + `them to the declaration to keep them, or give them their own group.`);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// src/grafana/alert-rule-group-model.ts
|
|
19
|
+
var RULE_VOLATILE_FIELDS = ["id", "updated", "provenance"];
|
|
20
|
+
var normalizeRule = (rule, folderUid, group) => {
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const [key, value] of Object.entries(rule)) {
|
|
23
|
+
if (key === "folderUID" || key === "ruleGroup" || key === "orgID")
|
|
24
|
+
continue;
|
|
25
|
+
if (RULE_VOLATILE_FIELDS.includes(key))
|
|
26
|
+
continue;
|
|
27
|
+
out[key] = value;
|
|
28
|
+
}
|
|
29
|
+
out.folderUID = folderUid;
|
|
30
|
+
out.ruleGroup = group;
|
|
31
|
+
out.orgID = 1;
|
|
32
|
+
return out;
|
|
33
|
+
};
|
|
34
|
+
var toWireRule = (rule, folderUid, group) => ({
|
|
35
|
+
...rule,
|
|
36
|
+
folderUID: folderUid,
|
|
37
|
+
orgID: 1,
|
|
38
|
+
ruleGroup: group
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// src/grafana/alerting-provenance.ts
|
|
5
42
|
import * as Effect3 from "effect/Effect";
|
|
6
43
|
|
|
44
|
+
// src/grafana/provisioned.ts
|
|
45
|
+
import * as Data from "effect/Data";
|
|
46
|
+
import * as Effect2 from "effect/Effect";
|
|
47
|
+
|
|
48
|
+
class GrafanaProvisionedObjectError extends Data.TaggedError("GrafanaProvisionedObjectError") {
|
|
49
|
+
}
|
|
50
|
+
var refuseIfProvisioned = (kind, uid, owner) => {
|
|
51
|
+
const ownerClause = owner === undefined || owner === "" ? `(this Grafana instance did not report an owning file)` : `by ${owner}`;
|
|
52
|
+
return Effect2.fail(new GrafanaProvisionedObjectError({
|
|
53
|
+
message: `${kind} '${uid}' is file-provisioned ${ownerClause} and read-only through the classic ` + `write API this family calls. Edit the provisioning file instead — declaring this ` + `object read-only (a declaration matching what is live) is safe and will never reach ` + `this refusal.`
|
|
54
|
+
}));
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/grafana/alerting-provenance.ts
|
|
58
|
+
var WRITABLE_PROVENANCES = new Set(["", "api"]);
|
|
59
|
+
var isForeignProvenance = (provenance) => provenance === undefined || !WRITABLE_PROVENANCES.has(provenance);
|
|
60
|
+
var refuseIfForeignProvenance = (kind, id, provenance) => {
|
|
61
|
+
const reason = provenance === undefined ? `did not report a provenance at all — this family cannot tell whether it is safe to own` : `has provenance '${provenance}', not '(none)' or 'api'`;
|
|
62
|
+
return Effect3.fail(new GrafanaProvisionedObjectError({
|
|
63
|
+
message: `${kind} '${id}' ${reason} — something other than this API may own it (file ` + `provisioning, the Prometheus-rules importer, or similar), and writing here could take ` + `over or corrupt an object this family does not actually control. Edit it at its actual ` + `source instead — declaring this object read-only (a declaration matching what is live) ` + `is safe and will never reach this refusal.`
|
|
64
|
+
}));
|
|
65
|
+
};
|
|
66
|
+
|
|
7
67
|
// src/grafana/resource.ts
|
|
8
68
|
import { isResolved } from "alchemy/Diff";
|
|
9
|
-
import * as
|
|
69
|
+
import * as Effect4 from "effect/Effect";
|
|
10
70
|
var grafanaOperations = (spec) => {
|
|
11
|
-
const read = (props) => spec.fetchLive(props).pipe(
|
|
71
|
+
const read = (props) => spec.fetchLive(props).pipe(Effect4.map((live) => live === undefined ? undefined : spec.attributes(live, props)));
|
|
12
72
|
return {
|
|
13
73
|
read,
|
|
14
|
-
diff: (news, output) =>
|
|
74
|
+
diff: (news, output) => Effect4.gen(function* () {
|
|
15
75
|
if (output === undefined || !isResolved(news))
|
|
16
76
|
return;
|
|
17
77
|
const live = yield* read(news);
|
|
@@ -21,7 +81,7 @@ var grafanaOperations = (spec) => {
|
|
|
21
81
|
return { action: "noop" };
|
|
22
82
|
return spec.update === undefined ? { action: "replace" } : { action: "update" };
|
|
23
83
|
}),
|
|
24
|
-
reconcile: (news) =>
|
|
84
|
+
reconcile: (news) => Effect4.gen(function* () {
|
|
25
85
|
const before = yield* spec.fetchLive(news);
|
|
26
86
|
if (before === undefined) {
|
|
27
87
|
yield* spec.create(news);
|
|
@@ -33,11 +93,11 @@ var grafanaOperations = (spec) => {
|
|
|
33
93
|
}
|
|
34
94
|
const after = yield* read(news);
|
|
35
95
|
if (after === undefined) {
|
|
36
|
-
return yield*
|
|
96
|
+
return yield* Effect4.die(new Error("grafanaOperations: the write returned no error but the object is still absent. " + "Read back rather than trusting the response status."));
|
|
37
97
|
}
|
|
38
98
|
return after;
|
|
39
99
|
}),
|
|
40
|
-
destroy: (olds) =>
|
|
100
|
+
destroy: (olds) => Effect4.gen(function* () {
|
|
41
101
|
const live = yield* spec.fetchLive(olds);
|
|
42
102
|
if (live === undefined)
|
|
43
103
|
return;
|
|
@@ -48,7 +108,7 @@ var grafanaOperations = (spec) => {
|
|
|
48
108
|
var grafanaHandlers = (spec) => {
|
|
49
109
|
const ops = grafanaOperations(spec);
|
|
50
110
|
return {
|
|
51
|
-
list: () =>
|
|
111
|
+
list: () => Effect4.succeed([]),
|
|
52
112
|
read: ({ olds }) => ops.read(olds),
|
|
53
113
|
diff: ({ news, output }) => ops.diff(news, output),
|
|
54
114
|
reconcile: ({ news }) => ops.reconcile(news),
|
|
@@ -56,20 +116,212 @@ var grafanaHandlers = (spec) => {
|
|
|
56
116
|
};
|
|
57
117
|
};
|
|
58
118
|
|
|
119
|
+
// src/grafana/subset-match.ts
|
|
120
|
+
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
121
|
+
var declaredContentMatches = (declared, live) => {
|
|
122
|
+
if (declared == null)
|
|
123
|
+
return true;
|
|
124
|
+
if (Array.isArray(declared)) {
|
|
125
|
+
return Array.isArray(live) && declared.length === live.length && declared.every((item, index) => declaredContentMatches(item, live[index]));
|
|
126
|
+
}
|
|
127
|
+
if (isPlainObject(declared)) {
|
|
128
|
+
return isPlainObject(live) && Object.entries(declared).every(([key, value]) => declaredContentMatches(value, live[key]));
|
|
129
|
+
}
|
|
130
|
+
return declared === live;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// src/grafana/alert-rule-group.ts
|
|
134
|
+
var GrafanaAlertRuleGroup = Resource("Grafana.AlertRuleGroup", {
|
|
135
|
+
defaultRemovalPolicy: "retain"
|
|
136
|
+
});
|
|
137
|
+
var findForeignRule = (rules) => (rules ?? []).find((rule) => isForeignProvenance(rule.provenance));
|
|
138
|
+
var body = (props) => ({
|
|
139
|
+
folderUid: props.folderUid,
|
|
140
|
+
interval: props.interval,
|
|
141
|
+
rules: props.rules.map((rule) => toWireRule(rule, props.folderUid, props.group)),
|
|
142
|
+
title: props.group
|
|
143
|
+
});
|
|
144
|
+
var refuseForForeignRule = (props, foreign) => refuseIfForeignProvenance("Grafana.AlertRuleGroup", `${props.folderUid}/${props.group}`, foreign.provenance);
|
|
145
|
+
var declaredUids = (props) => new Set(props.rules.map((rule) => rule.uid));
|
|
146
|
+
var spec = {
|
|
147
|
+
attributes: (live, props) => ({
|
|
148
|
+
folderUid: live.folderUid ?? props.folderUid,
|
|
149
|
+
group: props.group,
|
|
150
|
+
interval: live.interval ?? 0,
|
|
151
|
+
rules: (live.rules ?? []).map((rule) => normalizeRule(rule, props.folderUid, props.group))
|
|
152
|
+
}),
|
|
153
|
+
create: (props) => grafana.routePutAlertRuleGroup({
|
|
154
|
+
FolderUID: props.folderUid,
|
|
155
|
+
Group: props.group,
|
|
156
|
+
...body(props)
|
|
157
|
+
}),
|
|
158
|
+
destroy: (props, live) => Effect5.gen(function* () {
|
|
159
|
+
const foreign = findForeignRule(live.rules);
|
|
160
|
+
if (foreign !== undefined)
|
|
161
|
+
return yield* refuseForForeignRule(props, foreign);
|
|
162
|
+
yield* grafana.routeDeleteAlertRuleGroup({ FolderUID: props.folderUid, Group: props.group });
|
|
163
|
+
}),
|
|
164
|
+
fetchLive: (props) => grafana.routeGetAlertRuleGroup({ FolderUID: props.folderUid, Group: props.group }).pipe(Effect5.catchTag("NotFound", () => Effect5.succeed(undefined))),
|
|
165
|
+
matches: (attributes, props) => attributes.interval === props.interval && declaredContentMatches(props.rules.map((rule) => normalizeRule(rule, props.folderUid, props.group)), attributes.rules),
|
|
166
|
+
update: (props, live) => Effect5.gen(function* () {
|
|
167
|
+
const foreign = findForeignRule(live.rules);
|
|
168
|
+
if (foreign !== undefined)
|
|
169
|
+
return yield* refuseForForeignRule(props, foreign);
|
|
170
|
+
yield* warnOnDroppedRules(props.folderUid, props.group, declaredUids(props), live.rules);
|
|
171
|
+
yield* grafana.routePutAlertRuleGroup({
|
|
172
|
+
FolderUID: props.folderUid,
|
|
173
|
+
Group: props.group,
|
|
174
|
+
...body(props)
|
|
175
|
+
});
|
|
176
|
+
})
|
|
177
|
+
};
|
|
178
|
+
var diff = ({
|
|
179
|
+
news,
|
|
180
|
+
output
|
|
181
|
+
}) => Effect5.gen(function* () {
|
|
182
|
+
if (output === undefined || !isResolved2(news))
|
|
183
|
+
return;
|
|
184
|
+
const live = yield* spec.fetchLive(news);
|
|
185
|
+
if (live === undefined)
|
|
186
|
+
return { action: "update" };
|
|
187
|
+
yield* warnOnDroppedRules(news.folderUid, news.group, declaredUids(news), live.rules);
|
|
188
|
+
const mapped = spec.attributes(live, news);
|
|
189
|
+
return mapped !== undefined && spec.matches(mapped, news) ? { action: "noop" } : { action: "update" };
|
|
190
|
+
});
|
|
191
|
+
var handlers = { ...grafanaHandlers(spec), diff };
|
|
192
|
+
var GrafanaAlertRuleGroupProvider = () => Provider.effect(GrafanaAlertRuleGroup, Effect5.succeed(GrafanaAlertRuleGroup.Provider.of(handlers)));
|
|
193
|
+
// src/grafana/notification-policy.ts
|
|
194
|
+
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
195
|
+
import { Resource as Resource2 } from "alchemy";
|
|
196
|
+
import * as Provider2 from "alchemy/Provider";
|
|
197
|
+
import * as grafana2 from "@distilled.cloud/grafana";
|
|
198
|
+
import * as Effect7 from "effect/Effect";
|
|
199
|
+
|
|
200
|
+
// src/grafana/notification-policy-model.ts
|
|
201
|
+
var ROUTE_VOLATILE_FIELDS = ["provenance"];
|
|
202
|
+
var normalizeRoute = (route) => {
|
|
203
|
+
const out = {};
|
|
204
|
+
for (const [key, value] of Object.entries(route)) {
|
|
205
|
+
if (ROUTE_VOLATILE_FIELDS.includes(key))
|
|
206
|
+
continue;
|
|
207
|
+
if (key === "routes" && Array.isArray(value)) {
|
|
208
|
+
out.routes = value.map((child) => normalizeRoute(child));
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
out[key] = value;
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
};
|
|
215
|
+
var ownFieldsJson = (route) => {
|
|
216
|
+
const { routes: _routes, ...ownFields } = route;
|
|
217
|
+
return JSON.stringify(ownFields);
|
|
218
|
+
};
|
|
219
|
+
var flattenRoutes = (route, path = "root", ancestorKey = "") => {
|
|
220
|
+
const children = Array.isArray(route.routes) ? route.routes : [];
|
|
221
|
+
const ownJson = ownFieldsJson(route);
|
|
222
|
+
const key = ancestorKey === "" ? ownJson : `${ancestorKey}\x00${ownJson}`;
|
|
223
|
+
const self = {
|
|
224
|
+
key,
|
|
225
|
+
path,
|
|
226
|
+
receiver: typeof route.receiver === "string" ? route.receiver : "(inherited)"
|
|
227
|
+
};
|
|
228
|
+
return [
|
|
229
|
+
self,
|
|
230
|
+
...children.flatMap((child, index) => flattenRoutes(child, `${path}.${index}`, key))
|
|
231
|
+
];
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// src/grafana/notification-policy-drop-warning.ts
|
|
235
|
+
import * as Effect6 from "effect/Effect";
|
|
236
|
+
var countByKey = (routes) => {
|
|
237
|
+
const counts = new Map;
|
|
238
|
+
for (const route of routes)
|
|
239
|
+
counts.set(route.key, (counts.get(route.key) ?? 0) + 1);
|
|
240
|
+
return counts;
|
|
241
|
+
};
|
|
242
|
+
var warnOnDroppedRoutes = (declared, live) => Effect6.gen(function* () {
|
|
243
|
+
const declaredNodes = flattenRoutes(normalizeRoute(declared)).filter((r) => r.path !== "root");
|
|
244
|
+
const liveNodes = flattenRoutes(normalizeRoute(live)).filter((r) => r.path !== "root");
|
|
245
|
+
const declaredCounts = countByKey(declaredNodes);
|
|
246
|
+
const liveCounts = countByKey(liveNodes);
|
|
247
|
+
const dropped = [];
|
|
248
|
+
for (const [key, liveCount] of liveCounts) {
|
|
249
|
+
const extra = liveCount - (declaredCounts.get(key) ?? 0);
|
|
250
|
+
if (extra <= 0)
|
|
251
|
+
continue;
|
|
252
|
+
const occurrences = liveNodes.filter((route) => route.key === key);
|
|
253
|
+
dropped.push(...occurrences.slice(-extra));
|
|
254
|
+
}
|
|
255
|
+
if (dropped.length === 0)
|
|
256
|
+
return;
|
|
257
|
+
const names = dropped.map((route) => `${route.receiver} (${route.path})`).join(", ");
|
|
258
|
+
yield* Effect6.logWarning(`Grafana.NotificationPolicy: this update REMOVES ${dropped.length} route(s)/matcher(s) not ` + `in the declaration: ${names}. Whole-tree replacement is by design — add them to the ` + `declared tree to keep them.`);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// src/grafana/notification-policy.ts
|
|
262
|
+
var GrafanaNotificationPolicy = Resource2("Grafana.NotificationPolicy", { defaultRemovalPolicy: "retain" });
|
|
263
|
+
var body2 = (props) => props.route;
|
|
264
|
+
var spec2 = {
|
|
265
|
+
attributes: (live) => ({
|
|
266
|
+
provenance: live.provenance,
|
|
267
|
+
route: normalizeRoute(live)
|
|
268
|
+
}),
|
|
269
|
+
create: (props) => grafana2.routePutPolicyTree(body2(props)),
|
|
270
|
+
destroy: (props, live) => Effect7.gen(function* () {
|
|
271
|
+
if (isForeignProvenance(live.provenance)) {
|
|
272
|
+
return yield* refuseIfForeignProvenance("Grafana.NotificationPolicy", "default", live.provenance);
|
|
273
|
+
}
|
|
274
|
+
if (props.allowReset !== true) {
|
|
275
|
+
yield* Effect7.logWarning("Grafana.NotificationPolicy: destroy requested but allowReset is not set -- the policy " + "tree is RETAINED, not reset. Grafana always needs a root route; resetting wipes " + "every declared route/receiver/matcher back to Grafana's own default for the WHOLE " + "instance. Set allowReset: true to actually call routeResetPolicyTree.");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
yield* grafana2.routeResetPolicyTree({});
|
|
279
|
+
}),
|
|
280
|
+
fetchLive: (_props) => grafana2.routeGetPolicyTree({}),
|
|
281
|
+
matches: (attributes, props) => declaredContentMatches(normalizeRoute(props.route), attributes.route),
|
|
282
|
+
update: (props, live) => Effect7.gen(function* () {
|
|
283
|
+
if (isForeignProvenance(live.provenance)) {
|
|
284
|
+
return yield* refuseIfForeignProvenance("Grafana.NotificationPolicy", "default", live.provenance);
|
|
285
|
+
}
|
|
286
|
+
yield* warnOnDroppedRoutes(props.route, live);
|
|
287
|
+
yield* grafana2.routePutPolicyTree(body2(props));
|
|
288
|
+
})
|
|
289
|
+
};
|
|
290
|
+
var diff2 = ({
|
|
291
|
+
news,
|
|
292
|
+
output
|
|
293
|
+
}) => Effect7.gen(function* () {
|
|
294
|
+
if (output === undefined || !isResolved3(news))
|
|
295
|
+
return;
|
|
296
|
+
const live = yield* spec2.fetchLive(news);
|
|
297
|
+
if (live === undefined)
|
|
298
|
+
return { action: "update" };
|
|
299
|
+
yield* warnOnDroppedRoutes(news.route, live);
|
|
300
|
+
const mapped = spec2.attributes(live, news);
|
|
301
|
+
return mapped !== undefined && spec2.matches(mapped, news) ? { action: "noop" } : { action: "update" };
|
|
302
|
+
});
|
|
303
|
+
var handlers2 = { ...grafanaHandlers(spec2), diff: diff2 };
|
|
304
|
+
var GrafanaNotificationPolicyProvider = () => Provider2.effect(GrafanaNotificationPolicy, Effect7.succeed(GrafanaNotificationPolicy.Provider.of(handlers2)));
|
|
305
|
+
// src/grafana/datasource.ts
|
|
306
|
+
import { Resource as Resource3 } from "alchemy";
|
|
307
|
+
import * as Provider3 from "alchemy/Provider";
|
|
308
|
+
import * as grafana3 from "@distilled.cloud/grafana";
|
|
309
|
+
import * as Effect9 from "effect/Effect";
|
|
310
|
+
|
|
59
311
|
// src/grafana/secret-refs.ts
|
|
60
|
-
import * as
|
|
61
|
-
import * as
|
|
312
|
+
import * as Data2 from "effect/Data";
|
|
313
|
+
import * as Effect8 from "effect/Effect";
|
|
62
314
|
|
|
63
|
-
class GrafanaSecretRefUnsetError extends
|
|
315
|
+
class GrafanaSecretRefUnsetError extends Data2.TaggedError("GrafanaSecretRefUnsetError") {
|
|
64
316
|
}
|
|
65
|
-
var resolveSecretRefs = (refs, describeField) =>
|
|
317
|
+
var resolveSecretRefs = (refs, describeField) => Effect8.gen(function* () {
|
|
66
318
|
if (refs === undefined)
|
|
67
319
|
return;
|
|
68
320
|
const out = {};
|
|
69
321
|
for (const [field, envVar] of Object.entries(refs)) {
|
|
70
322
|
const raw = process.env[envVar];
|
|
71
323
|
if (raw === undefined || raw.trim() === "") {
|
|
72
|
-
return yield*
|
|
324
|
+
return yield* Effect8.fail(new GrafanaSecretRefUnsetError({
|
|
73
325
|
message: `${envVar} is unset. Export the value of ${describeField(field)} there — ` + "never as an Alchemy prop."
|
|
74
326
|
}));
|
|
75
327
|
}
|
|
@@ -79,7 +331,7 @@ var resolveSecretRefs = (refs, describeField) => Effect2.gen(function* () {
|
|
|
79
331
|
});
|
|
80
332
|
|
|
81
333
|
// src/grafana/datasource.ts
|
|
82
|
-
var GrafanaDatasource =
|
|
334
|
+
var GrafanaDatasource = Resource3("Grafana.Datasource");
|
|
83
335
|
var resolveSecureJsonData = (refs) => resolveSecretRefs(refs, (field) => `secureJsonData.${field}`);
|
|
84
336
|
var fields = (props) => ({
|
|
85
337
|
name: props.name,
|
|
@@ -94,7 +346,7 @@ var fields = (props) => ({
|
|
|
94
346
|
...props.user === undefined ? {} : { user: props.user },
|
|
95
347
|
...props.withCredentials === undefined ? {} : { withCredentials: props.withCredentials }
|
|
96
348
|
});
|
|
97
|
-
var
|
|
349
|
+
var spec3 = {
|
|
98
350
|
attributes: (live) => ({
|
|
99
351
|
access: live.access ?? "",
|
|
100
352
|
id: live.id ?? 0,
|
|
@@ -107,42 +359,28 @@ var spec = {
|
|
|
107
359
|
url: live.url ?? "",
|
|
108
360
|
version: live.version ?? 0
|
|
109
361
|
}),
|
|
110
|
-
create: (props) =>
|
|
362
|
+
create: (props) => Effect9.flatMap(resolveSecureJsonData(props.secureJsonDataRefs), (secureJsonData) => grafana3.addDataSource({
|
|
111
363
|
...fields(props),
|
|
112
364
|
...secureJsonData === undefined ? {} : { secureJsonData },
|
|
113
365
|
uid: props.uid
|
|
114
366
|
})),
|
|
115
|
-
destroy: (props) =>
|
|
116
|
-
fetchLive: (props) =>
|
|
367
|
+
destroy: (props) => grafana3.deleteDataSourceByUID({ uid: props.uid }),
|
|
368
|
+
fetchLive: (props) => grafana3.getDataSourceByUID({ uid: props.uid }).pipe(Effect9.catchTag("NotFound", () => Effect9.succeed(undefined))),
|
|
117
369
|
matches: (attributes, props) => (props.name === undefined || attributes.name === props.name) && (props.type === undefined || attributes.type === props.type) && (props.url === undefined || attributes.url === props.url) && (props.access === undefined || attributes.access === props.access) && (props.isDefault === undefined || attributes.isDefault === props.isDefault),
|
|
118
|
-
update: (props, live) =>
|
|
370
|
+
update: (props, live) => Effect9.flatMap(resolveSecureJsonData(props.secureJsonDataRefs), (secureJsonData) => grafana3.updateDataSourceByUID({
|
|
119
371
|
...fields(props),
|
|
120
372
|
...secureJsonData === undefined ? {} : { secureJsonData },
|
|
121
373
|
...live.version === undefined ? {} : { version: live.version },
|
|
122
374
|
uid: props.uid
|
|
123
375
|
}))
|
|
124
376
|
};
|
|
125
|
-
var
|
|
126
|
-
var GrafanaDatasourceProvider = () =>
|
|
377
|
+
var handlers3 = grafanaHandlers(spec3);
|
|
378
|
+
var GrafanaDatasourceProvider = () => Provider3.effect(GrafanaDatasource, Effect9.succeed(GrafanaDatasource.Provider.of(handlers3)));
|
|
127
379
|
// src/grafana/dashboard.ts
|
|
128
|
-
import { Resource as
|
|
129
|
-
import * as
|
|
130
|
-
import * as
|
|
131
|
-
import * as
|
|
132
|
-
|
|
133
|
-
// src/grafana/subset-match.ts
|
|
134
|
-
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
135
|
-
var declaredContentMatches = (declared, live) => {
|
|
136
|
-
if (declared == null)
|
|
137
|
-
return true;
|
|
138
|
-
if (Array.isArray(declared)) {
|
|
139
|
-
return Array.isArray(live) && declared.length === live.length && declared.every((item, index) => declaredContentMatches(item, live[index]));
|
|
140
|
-
}
|
|
141
|
-
if (isPlainObject(declared)) {
|
|
142
|
-
return isPlainObject(live) && Object.entries(declared).every(([key, value]) => declaredContentMatches(value, live[key]));
|
|
143
|
-
}
|
|
144
|
-
return declared === live;
|
|
145
|
-
};
|
|
380
|
+
import { Resource as Resource4 } from "alchemy";
|
|
381
|
+
import * as Provider4 from "alchemy/Provider";
|
|
382
|
+
import * as grafana4 from "@distilled.cloud/grafana";
|
|
383
|
+
import * as Effect10 from "effect/Effect";
|
|
146
384
|
|
|
147
385
|
// src/grafana/dashboard-model.ts
|
|
148
386
|
var VOLATILE_FIELDS = ["id", "version", "iteration"];
|
|
@@ -160,23 +398,10 @@ var normalizeModel = (model, uid) => {
|
|
|
160
398
|
};
|
|
161
399
|
var modelTitle = (model) => typeof model.title === "string" ? model.title : "";
|
|
162
400
|
|
|
163
|
-
// src/grafana/provisioned.ts
|
|
164
|
-
import * as Data2 from "effect/Data";
|
|
165
|
-
import * as Effect4 from "effect/Effect";
|
|
166
|
-
|
|
167
|
-
class GrafanaProvisionedObjectError extends Data2.TaggedError("GrafanaProvisionedObjectError") {
|
|
168
|
-
}
|
|
169
|
-
var refuseIfProvisioned = (kind, uid, owner) => {
|
|
170
|
-
const ownerClause = owner === undefined || owner === "" ? `(this Grafana instance did not report an owning file)` : `by ${owner}`;
|
|
171
|
-
return Effect4.fail(new GrafanaProvisionedObjectError({
|
|
172
|
-
message: `${kind} '${uid}' is file-provisioned ${ownerClause} and read-only through the classic ` + `write API this family calls. Edit the provisioning file instead — declaring this ` + `object read-only (a declaration matching what is live) is safe and will never reach ` + `this refusal.`
|
|
173
|
-
}));
|
|
174
|
-
};
|
|
175
|
-
|
|
176
401
|
// src/grafana/dashboard.ts
|
|
177
|
-
var GrafanaDashboard =
|
|
402
|
+
var GrafanaDashboard = Resource4("Grafana.Dashboard");
|
|
178
403
|
var modelOf = (live) => live.dashboard !== null && typeof live.dashboard === "object" ? live.dashboard : {};
|
|
179
|
-
var
|
|
404
|
+
var spec4 = {
|
|
180
405
|
attributes: (live, props) => {
|
|
181
406
|
const model = normalizeModel(modelOf(live), props.uid);
|
|
182
407
|
return {
|
|
@@ -190,23 +415,23 @@ var spec2 = {
|
|
|
190
415
|
version: live.meta?.version ?? 0
|
|
191
416
|
};
|
|
192
417
|
},
|
|
193
|
-
create: (props) =>
|
|
418
|
+
create: (props) => grafana4.postDashboard({
|
|
194
419
|
dashboard: normalizeModel(props.dashboard, props.uid),
|
|
195
420
|
...props.folderUid === undefined ? {} : { folderUid: props.folderUid }
|
|
196
421
|
}),
|
|
197
|
-
destroy: (props, live) =>
|
|
422
|
+
destroy: (props, live) => Effect10.gen(function* () {
|
|
198
423
|
if (live.meta?.provisioned) {
|
|
199
424
|
return yield* refuseIfProvisioned("Grafana.Dashboard", props.uid, live.meta.provisionedExternalId);
|
|
200
425
|
}
|
|
201
|
-
yield*
|
|
426
|
+
yield* grafana4.deleteDashboard({ uid: props.uid });
|
|
202
427
|
}),
|
|
203
|
-
fetchLive: (props) =>
|
|
428
|
+
fetchLive: (props) => grafana4.getDashboard({ uid: props.uid }).pipe(Effect10.catchTag("NotFound", () => Effect10.succeed(undefined))),
|
|
204
429
|
matches: (attributes, props) => (props.folderUid === undefined || attributes.folderUid === props.folderUid) && declaredContentMatches(normalizeModel(props.dashboard, props.uid), attributes.dashboard),
|
|
205
|
-
update: (props, live) =>
|
|
430
|
+
update: (props, live) => Effect10.gen(function* () {
|
|
206
431
|
if (live.meta?.provisioned) {
|
|
207
432
|
return yield* refuseIfProvisioned("Grafana.Dashboard", props.uid, live.meta.provisionedExternalId);
|
|
208
433
|
}
|
|
209
|
-
return yield*
|
|
434
|
+
return yield* grafana4.postDashboard({
|
|
210
435
|
dashboard: {
|
|
211
436
|
...normalizeModel(props.dashboard, props.uid),
|
|
212
437
|
...live.meta?.version === undefined ? {} : { version: live.meta.version }
|
|
@@ -215,21 +440,21 @@ var spec2 = {
|
|
|
215
440
|
});
|
|
216
441
|
})
|
|
217
442
|
};
|
|
218
|
-
var
|
|
219
|
-
var GrafanaDashboardProvider = () =>
|
|
443
|
+
var handlers4 = grafanaHandlers(spec4);
|
|
444
|
+
var GrafanaDashboardProvider = () => Provider4.effect(GrafanaDashboard, Effect10.succeed(GrafanaDashboard.Provider.of(handlers4)));
|
|
220
445
|
// src/grafana/folder.ts
|
|
221
|
-
import { Resource as
|
|
222
|
-
import * as
|
|
223
|
-
import * as
|
|
446
|
+
import { Resource as Resource5 } from "alchemy";
|
|
447
|
+
import * as Provider5 from "alchemy/Provider";
|
|
448
|
+
import * as grafana5 from "@distilled.cloud/grafana";
|
|
224
449
|
import * as Data3 from "effect/Data";
|
|
225
|
-
import * as
|
|
226
|
-
var GrafanaFolder =
|
|
450
|
+
import * as Effect11 from "effect/Effect";
|
|
451
|
+
var GrafanaFolder = Resource5("Grafana.Folder", {
|
|
227
452
|
defaultRemovalPolicy: "retain"
|
|
228
453
|
});
|
|
229
454
|
|
|
230
455
|
class GrafanaFolderReparentError extends Data3.TaggedError("GrafanaFolderReparentError") {
|
|
231
456
|
}
|
|
232
|
-
var
|
|
457
|
+
var spec5 = {
|
|
233
458
|
attributes: (live) => ({
|
|
234
459
|
id: live.id ?? 0,
|
|
235
460
|
managedBy: live.managedBy ?? "",
|
|
@@ -239,30 +464,30 @@ var spec3 = {
|
|
|
239
464
|
url: live.url ?? "",
|
|
240
465
|
version: live.version ?? 0
|
|
241
466
|
}),
|
|
242
|
-
create: (props) =>
|
|
467
|
+
create: (props) => grafana5.createFolder({
|
|
243
468
|
uid: props.uid,
|
|
244
469
|
title: props.title,
|
|
245
470
|
...props.description === undefined ? {} : { description: props.description },
|
|
246
471
|
...props.parentUid === undefined ? {} : { parentUid: props.parentUid }
|
|
247
472
|
}),
|
|
248
|
-
destroy: (props, live) =>
|
|
473
|
+
destroy: (props, live) => Effect11.gen(function* () {
|
|
249
474
|
if (live.managedBy) {
|
|
250
475
|
return yield* refuseIfProvisioned("Grafana.Folder", props.uid, live.managedBy);
|
|
251
476
|
}
|
|
252
|
-
yield*
|
|
477
|
+
yield* grafana5.deleteFolder({ folder_uid: props.uid });
|
|
253
478
|
}),
|
|
254
|
-
fetchLive: (props) =>
|
|
479
|
+
fetchLive: (props) => grafana5.getFolderByUID({ folder_uid: props.uid }).pipe(Effect11.catchTag("NotFound", () => Effect11.succeed(undefined))),
|
|
255
480
|
matches: (attributes, props) => attributes.title === props.title && (props.parentUid === undefined || attributes.parentUid === props.parentUid),
|
|
256
|
-
update: (props, live) =>
|
|
481
|
+
update: (props, live) => Effect11.gen(function* () {
|
|
257
482
|
if (live.managedBy) {
|
|
258
483
|
return yield* refuseIfProvisioned("Grafana.Folder", props.uid, live.managedBy);
|
|
259
484
|
}
|
|
260
485
|
if (props.parentUid !== undefined && props.parentUid !== (live.parentUid ?? undefined)) {
|
|
261
|
-
return yield*
|
|
486
|
+
return yield* Effect11.fail(new GrafanaFolderReparentError({
|
|
262
487
|
message: `Grafana.Folder '${props.uid}' declares parentUid '${props.parentUid}' but is ` + `live under '${live.parentUid ?? "(root)"}'. PUT /folders/{uid} cannot reparent a ` + `folder — move it by hand in Grafana, then update the declaration to match.`
|
|
263
488
|
}));
|
|
264
489
|
}
|
|
265
|
-
return yield*
|
|
490
|
+
return yield* grafana5.updateFolder({
|
|
266
491
|
folder_uid: props.uid,
|
|
267
492
|
title: props.title,
|
|
268
493
|
...props.description === undefined ? {} : { description: props.description },
|
|
@@ -270,27 +495,14 @@ var spec3 = {
|
|
|
270
495
|
});
|
|
271
496
|
})
|
|
272
497
|
};
|
|
273
|
-
var
|
|
274
|
-
var GrafanaFolderProvider = () =>
|
|
275
|
-
// src/grafana/contact-point.ts
|
|
276
|
-
import { Resource as Resource4 } from "alchemy";
|
|
277
|
-
import * as Provider4 from "alchemy/Provider";
|
|
278
|
-
import * as grafana4 from "@distilled.cloud/grafana";
|
|
279
|
-
import * as Effect8 from "effect/Effect";
|
|
280
|
-
|
|
281
|
-
// src/grafana/alerting-provenance.ts
|
|
282
|
-
import * as Effect7 from "effect/Effect";
|
|
283
|
-
var WRITABLE_PROVENANCES = new Set(["", "api"]);
|
|
284
|
-
var isForeignProvenance = (provenance) => provenance === undefined || !WRITABLE_PROVENANCES.has(provenance);
|
|
285
|
-
var refuseIfForeignProvenance = (kind, id, provenance) => {
|
|
286
|
-
const reason = provenance === undefined ? `did not report a provenance at all — this family cannot tell whether it is safe to own` : `has provenance '${provenance}', not '(none)' or 'api'`;
|
|
287
|
-
return Effect7.fail(new GrafanaProvisionedObjectError({
|
|
288
|
-
message: `${kind} '${id}' ${reason} — something other than this API may own it (file ` + `provisioning, the Prometheus-rules importer, or similar), and writing here could take ` + `over or corrupt an object this family does not actually control. Edit it at its actual ` + `source instead — declaring this object read-only (a declaration matching what is live) ` + `is safe and will never reach this refusal.`
|
|
289
|
-
}));
|
|
290
|
-
};
|
|
291
|
-
|
|
498
|
+
var handlers5 = grafanaHandlers(spec5);
|
|
499
|
+
var GrafanaFolderProvider = () => Provider5.effect(GrafanaFolder, Effect11.succeed(GrafanaFolder.Provider.of(handlers5)));
|
|
292
500
|
// src/grafana/contact-point.ts
|
|
293
|
-
|
|
501
|
+
import { Resource as Resource6 } from "alchemy";
|
|
502
|
+
import * as Provider6 from "alchemy/Provider";
|
|
503
|
+
import * as grafana6 from "@distilled.cloud/grafana";
|
|
504
|
+
import * as Effect12 from "effect/Effect";
|
|
505
|
+
var GrafanaContactPoint = Resource6("Grafana.ContactPoint");
|
|
294
506
|
var nonSecretSettings = (props) => {
|
|
295
507
|
const refs = props.secureSettingsRefs;
|
|
296
508
|
if (refs === undefined)
|
|
@@ -302,8 +514,8 @@ var nonSecretSettings = (props) => {
|
|
|
302
514
|
}
|
|
303
515
|
return out;
|
|
304
516
|
};
|
|
305
|
-
var resolveSettings = (props) =>
|
|
306
|
-
var
|
|
517
|
+
var resolveSettings = (props) => Effect12.map(resolveSecretRefs(props.secureSettingsRefs, (field) => `settings.${field}`), (secrets) => secrets === undefined ? props.settings : { ...props.settings, ...secrets });
|
|
518
|
+
var spec6 = {
|
|
307
519
|
attributes: (live) => ({
|
|
308
520
|
disableResolveMessage: live.disableResolveMessage ?? false,
|
|
309
521
|
name: live.name ?? "",
|
|
@@ -312,27 +524,27 @@ var spec4 = {
|
|
|
312
524
|
type: live.type,
|
|
313
525
|
uid: live.uid ?? ""
|
|
314
526
|
}),
|
|
315
|
-
create: (props) =>
|
|
527
|
+
create: (props) => Effect12.flatMap(resolveSettings(props), (settings) => grafana6.routePostContactpoints({
|
|
316
528
|
name: props.name,
|
|
317
529
|
settings,
|
|
318
530
|
type: props.type,
|
|
319
531
|
uid: props.uid,
|
|
320
532
|
...props.disableResolveMessage === undefined ? {} : { disableResolveMessage: props.disableResolveMessage }
|
|
321
533
|
})),
|
|
322
|
-
destroy: (props, live) =>
|
|
534
|
+
destroy: (props, live) => Effect12.gen(function* () {
|
|
323
535
|
if (isForeignProvenance(live.provenance)) {
|
|
324
536
|
return yield* refuseIfForeignProvenance("Grafana.ContactPoint", props.uid, live.provenance);
|
|
325
537
|
}
|
|
326
|
-
yield*
|
|
538
|
+
yield* grafana6.routeDeleteContactpoints({ UID: props.uid });
|
|
327
539
|
}),
|
|
328
|
-
fetchLive: (props) =>
|
|
540
|
+
fetchLive: (props) => grafana6.routeGetContactpoints({}).pipe(Effect12.map((points) => points.find((point) => point.uid === props.uid))),
|
|
329
541
|
matches: (attributes, props) => attributes.name === props.name && attributes.type === props.type && attributes.disableResolveMessage === (props.disableResolveMessage ?? false) && declaredContentMatches(nonSecretSettings(props), attributes.settings),
|
|
330
|
-
update: (props, live) =>
|
|
542
|
+
update: (props, live) => Effect12.gen(function* () {
|
|
331
543
|
if (isForeignProvenance(live.provenance)) {
|
|
332
544
|
return yield* refuseIfForeignProvenance("Grafana.ContactPoint", props.uid, live.provenance);
|
|
333
545
|
}
|
|
334
546
|
const settings = yield* resolveSettings(props);
|
|
335
|
-
yield*
|
|
547
|
+
yield* grafana6.routePutContactpoint({
|
|
336
548
|
UID: props.uid,
|
|
337
549
|
name: props.name,
|
|
338
550
|
settings,
|
|
@@ -342,99 +554,101 @@ var spec4 = {
|
|
|
342
554
|
});
|
|
343
555
|
})
|
|
344
556
|
};
|
|
345
|
-
var
|
|
346
|
-
var GrafanaContactPointProvider = () =>
|
|
557
|
+
var handlers6 = grafanaHandlers(spec6);
|
|
558
|
+
var GrafanaContactPointProvider = () => Provider6.effect(GrafanaContactPoint, Effect12.succeed(GrafanaContactPoint.Provider.of(handlers6)));
|
|
347
559
|
// src/grafana/message-template.ts
|
|
348
|
-
import { Resource as
|
|
349
|
-
import * as
|
|
350
|
-
import * as
|
|
351
|
-
import * as
|
|
352
|
-
var GrafanaMessageTemplate =
|
|
353
|
-
var
|
|
560
|
+
import { Resource as Resource7 } from "alchemy";
|
|
561
|
+
import * as Provider7 from "alchemy/Provider";
|
|
562
|
+
import * as grafana7 from "@distilled.cloud/grafana";
|
|
563
|
+
import * as Effect13 from "effect/Effect";
|
|
564
|
+
var GrafanaMessageTemplate = Resource7("Grafana.MessageTemplate");
|
|
565
|
+
var spec7 = {
|
|
354
566
|
attributes: (live) => ({
|
|
355
567
|
name: live.name ?? "",
|
|
356
568
|
provenance: live.provenance,
|
|
357
569
|
template: live.template ?? ""
|
|
358
570
|
}),
|
|
359
|
-
create: (props) =>
|
|
360
|
-
destroy: (props, live) =>
|
|
571
|
+
create: (props) => grafana7.routePutTemplate({ name: props.name, template: props.template }),
|
|
572
|
+
destroy: (props, live) => Effect13.gen(function* () {
|
|
361
573
|
if (isForeignProvenance(live.provenance)) {
|
|
362
574
|
return yield* refuseIfForeignProvenance("Grafana.MessageTemplate", props.name, live.provenance);
|
|
363
575
|
}
|
|
364
|
-
yield*
|
|
576
|
+
yield* grafana7.routeDeleteTemplate({ name: props.name });
|
|
365
577
|
}),
|
|
366
|
-
fetchLive: (props) =>
|
|
578
|
+
fetchLive: (props) => grafana7.routeGetTemplate({ name: props.name }).pipe(Effect13.catchTag("NotFound", () => Effect13.succeed(undefined))),
|
|
367
579
|
matches: (attributes, props) => attributes.template === props.template,
|
|
368
|
-
update: (props, live) =>
|
|
580
|
+
update: (props, live) => Effect13.gen(function* () {
|
|
369
581
|
if (isForeignProvenance(live.provenance)) {
|
|
370
582
|
return yield* refuseIfForeignProvenance("Grafana.MessageTemplate", props.name, live.provenance);
|
|
371
583
|
}
|
|
372
|
-
yield*
|
|
584
|
+
yield* grafana7.routePutTemplate({
|
|
373
585
|
name: props.name,
|
|
374
586
|
template: props.template,
|
|
375
587
|
...live.version === undefined ? {} : { version: live.version }
|
|
376
588
|
});
|
|
377
589
|
})
|
|
378
590
|
};
|
|
379
|
-
var
|
|
380
|
-
var GrafanaMessageTemplateProvider = () =>
|
|
591
|
+
var handlers7 = grafanaHandlers(spec7);
|
|
592
|
+
var GrafanaMessageTemplateProvider = () => Provider7.effect(GrafanaMessageTemplate, Effect13.succeed(GrafanaMessageTemplate.Provider.of(handlers7)));
|
|
381
593
|
// src/grafana/mute-timing.ts
|
|
382
|
-
import { Resource as
|
|
383
|
-
import * as
|
|
384
|
-
import * as
|
|
385
|
-
import * as
|
|
386
|
-
var GrafanaMuteTiming =
|
|
387
|
-
var
|
|
594
|
+
import { Resource as Resource8 } from "alchemy";
|
|
595
|
+
import * as Provider8 from "alchemy/Provider";
|
|
596
|
+
import * as grafana8 from "@distilled.cloud/grafana";
|
|
597
|
+
import * as Effect14 from "effect/Effect";
|
|
598
|
+
var GrafanaMuteTiming = Resource8("Grafana.MuteTiming");
|
|
599
|
+
var spec8 = {
|
|
388
600
|
attributes: (live) => ({
|
|
389
601
|
name: live.name ?? "",
|
|
390
602
|
provenance: live.provenance,
|
|
391
603
|
timeIntervals: live.time_intervals ?? []
|
|
392
604
|
}),
|
|
393
|
-
create: (props) =>
|
|
605
|
+
create: (props) => grafana8.routePostMuteTiming({
|
|
394
606
|
name: props.name,
|
|
395
607
|
time_intervals: props.timeIntervals
|
|
396
608
|
}),
|
|
397
|
-
destroy: (props, live) =>
|
|
609
|
+
destroy: (props, live) => Effect14.gen(function* () {
|
|
398
610
|
if (isForeignProvenance(live.provenance)) {
|
|
399
611
|
return yield* refuseIfForeignProvenance("Grafana.MuteTiming", props.name, live.provenance);
|
|
400
612
|
}
|
|
401
|
-
yield*
|
|
613
|
+
yield* grafana8.routeDeleteMuteTiming({
|
|
402
614
|
name: props.name,
|
|
403
615
|
...live.version === undefined ? {} : { version: live.version }
|
|
404
616
|
});
|
|
405
617
|
}),
|
|
406
|
-
fetchLive: (props) =>
|
|
618
|
+
fetchLive: (props) => grafana8.routeGetMuteTiming({ name: props.name }).pipe(Effect14.map((live) => live), Effect14.catchTag("NotFound", () => Effect14.succeed(undefined))),
|
|
407
619
|
matches: (attributes, props) => declaredContentMatches(props.timeIntervals, attributes.timeIntervals),
|
|
408
|
-
update: (props, live) =>
|
|
620
|
+
update: (props, live) => Effect14.gen(function* () {
|
|
409
621
|
if (isForeignProvenance(live.provenance)) {
|
|
410
622
|
return yield* refuseIfForeignProvenance("Grafana.MuteTiming", props.name, live.provenance);
|
|
411
623
|
}
|
|
412
|
-
yield*
|
|
624
|
+
yield* grafana8.routePutMuteTiming({
|
|
413
625
|
name: props.name,
|
|
414
626
|
time_intervals: props.timeIntervals
|
|
415
627
|
});
|
|
416
628
|
})
|
|
417
629
|
};
|
|
418
|
-
var
|
|
419
|
-
var GrafanaMuteTimingProvider = () =>
|
|
630
|
+
var handlers8 = grafanaHandlers(spec8);
|
|
631
|
+
var GrafanaMuteTimingProvider = () => Provider8.effect(GrafanaMuteTiming, Effect14.succeed(GrafanaMuteTiming.Provider.of(handlers8)));
|
|
420
632
|
// src/grafana/credentials.ts
|
|
421
633
|
import { Credentials } from "@distilled.cloud/grafana/Credentials";
|
|
422
634
|
import { ConfigError } from "@distilled.cloud/grafana/Errors";
|
|
423
|
-
import * as
|
|
635
|
+
import * as Effect15 from "effect/Effect";
|
|
424
636
|
import * as Layer from "effect/Layer";
|
|
425
637
|
import * as Redacted from "effect/Redacted";
|
|
426
|
-
var resolve = (target) =>
|
|
638
|
+
var resolve = (target) => Effect15.sync(() => process.env[target.tokenEnv]).pipe(Effect15.flatMap((raw) => raw === undefined || raw.trim() === "" ? Effect15.fail(new ConfigError({
|
|
427
639
|
message: `${target.tokenEnv} is not set. Export the Grafana service-account token there ` + `— never as an Alchemy prop — before running a stack that declares a resource ` + `against ${target.baseUrl}.`
|
|
428
|
-
})) :
|
|
640
|
+
})) : Effect15.succeed({
|
|
429
641
|
apiBaseUrl: target.baseUrl.replace(/\/+$/, ""),
|
|
430
642
|
token: Redacted.make(raw.trim()),
|
|
431
643
|
...target.orgId === undefined ? {} : { orgId: target.orgId }
|
|
432
|
-
})),
|
|
644
|
+
})), Effect15.orDie);
|
|
433
645
|
var grafanaCredentials = (target) => Layer.succeed(Credentials, resolve(target));
|
|
434
646
|
// src/grafana/providers.ts
|
|
435
647
|
import * as Layer2 from "effect/Layer";
|
|
436
|
-
var grafanaProviders = (target) => Layer2.mergeAll(GrafanaDatasourceProvider(), GrafanaFolderProvider(), GrafanaDashboardProvider(), GrafanaContactPointProvider(), GrafanaMuteTimingProvider(), GrafanaMessageTemplateProvider()).pipe(Layer2.provide(grafanaCredentials(target)));
|
|
648
|
+
var grafanaProviders = (target) => Layer2.mergeAll(GrafanaDatasourceProvider(), GrafanaFolderProvider(), GrafanaDashboardProvider(), GrafanaContactPointProvider(), GrafanaMuteTimingProvider(), GrafanaMessageTemplateProvider(), GrafanaAlertRuleGroupProvider(), GrafanaNotificationPolicyProvider()).pipe(Layer2.provide(grafanaCredentials(target)));
|
|
437
649
|
export {
|
|
650
|
+
GrafanaAlertRuleGroup,
|
|
651
|
+
GrafanaAlertRuleGroupProvider,
|
|
438
652
|
GrafanaContactPoint,
|
|
439
653
|
GrafanaContactPointProvider,
|
|
440
654
|
GrafanaDashboard,
|
|
@@ -448,11 +662,13 @@ export {
|
|
|
448
662
|
GrafanaMessageTemplateProvider,
|
|
449
663
|
GrafanaMuteTiming,
|
|
450
664
|
GrafanaMuteTimingProvider,
|
|
665
|
+
GrafanaNotificationPolicy,
|
|
666
|
+
GrafanaNotificationPolicyProvider,
|
|
451
667
|
GrafanaProvisionedObjectError,
|
|
452
668
|
GrafanaSecretRefUnsetError,
|
|
453
669
|
grafanaCredentials,
|
|
454
670
|
grafanaProviders
|
|
455
671
|
};
|
|
456
672
|
|
|
457
|
-
//# debugId=
|
|
673
|
+
//# debugId=5578DCEDF956037C64756E2164756E21
|
|
458
674
|
//# sourceMappingURL=index.js.map
|