@highstate/restic 0.9.14 → 0.9.16

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.
@@ -1,10 +1,9 @@
1
- import "../chunk-G3PMV62Z.js";
1
+ import '../chunk-G3PMV62Z.js';
2
+ import { restic } from '@highstate/library';
3
+ import { forUnit, toPromise } from '@highstate/pulumi';
4
+ import { parseL34Endpoint, l34EndpointToString } from '@highstate/common';
5
+ import { uniqueBy } from 'remeda';
2
6
 
3
- // src/repo/index.ts
4
- import { restic } from "@highstate/library";
5
- import { forUnit, toPromise } from "@highstate/pulumi";
6
- import { l34EndpointToString, parseL34Endpoint } from "@highstate/common";
7
- import { uniqueBy } from "remeda";
8
7
  var { args, inputs, secrets, outputs } = forUnit(restic.repo);
9
8
  var remoteName = secrets.rcloneConfig.apply((config) => {
10
9
  const remoteNames = Array.from(config.matchAll(/(?<=\[).+?(?=\])/g));
@@ -34,7 +33,7 @@ var repo_default = outputs({
34
33
  remoteName,
35
34
  remoteEndpoints
36
35
  },
37
- $status: {
36
+ $statusFields: {
38
37
  remoteName,
39
38
  remoteEndpoints: {
40
39
  value: remoteEndpoints.map(l34EndpointToString),
@@ -42,7 +41,7 @@ var repo_default = outputs({
42
41
  }
43
42
  }
44
43
  });
45
- export {
46
- repo_default as default
47
- };
44
+
45
+ export { repo_default as default };
46
+ //# sourceMappingURL=index.js.map
48
47
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/repo/index.ts"],"sourcesContent":["import { restic } from \"@highstate/library\"\nimport { forUnit, toPromise } from \"@highstate/pulumi\"\nimport { l34EndpointToString, parseL34Endpoint } from \"@highstate/common\"\nimport { uniqueBy } from \"remeda\"\n\nconst { args, inputs, secrets, outputs } = forUnit(restic.repo)\n\nconst remoteName = secrets.rcloneConfig.apply(config => {\n const remoteNames = Array.from(config.matchAll(/(?<=\\[).+?(?=\\])/g))\n\n if (remoteNames.length === 0) {\n throw new Error(\"No remotes found in rclone config\")\n }\n\n if (remoteNames.length > 1) {\n throw new Error(\"Multiple remotes found in rclone config\")\n }\n\n return remoteNames[0][0]\n})\n\nconst { remoteL3Endpoints, remoteL4Endpoints } = await toPromise(inputs)\n\nconst remoteEndpoints = uniqueBy(\n [\n //\n ...args.remoteEndpoints.map(parseL34Endpoint),\n ...remoteL3Endpoints,\n ...remoteL4Endpoints,\n ],\n l34EndpointToString,\n)\n\nexport default outputs({\n repo: {\n type: \"rclone\",\n pathPattern: args.pathPattern,\n rcloneConfig: secrets.rcloneConfig,\n remoteName,\n remoteEndpoints,\n },\n\n $status: {\n remoteName,\n\n remoteEndpoints: {\n value: remoteEndpoints.map(l34EndpointToString),\n complementaryTo: \"remoteEndpoints\",\n },\n },\n})\n"],"mappings":";;;AAAA,SAAS,cAAc;AACvB,SAAS,SAAS,iBAAiB;AACnC,SAAS,qBAAqB,wBAAwB;AACtD,SAAS,gBAAgB;AAEzB,IAAM,EAAE,MAAM,QAAQ,SAAS,QAAQ,IAAI,QAAQ,OAAO,IAAI;AAE9D,IAAM,aAAa,QAAQ,aAAa,MAAM,YAAU;AACtD,QAAM,cAAc,MAAM,KAAK,OAAO,SAAS,mBAAmB,CAAC;AAEnE,MAAI,YAAY,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAEA,SAAO,YAAY,CAAC,EAAE,CAAC;AACzB,CAAC;AAED,IAAM,EAAE,mBAAmB,kBAAkB,IAAI,MAAM,UAAU,MAAM;AAEvE,IAAM,kBAAkB;AAAA,EACtB;AAAA;AAAA,IAEE,GAAG,KAAK,gBAAgB,IAAI,gBAAgB;AAAA,IAC5C,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAAA,EACA;AACF;AAEA,IAAO,eAAQ,QAAQ;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,KAAK;AAAA,IAClB,cAAc,QAAQ;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AAAA,EAEA,SAAS;AAAA,IACP;AAAA,IAEA,iBAAiB;AAAA,MACf,OAAO,gBAAgB,IAAI,mBAAmB;AAAA,MAC9C,iBAAiB;AAAA,IACnB;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/repo/index.ts"],"names":[],"mappings":";;;;;;AAKA,IAAM,EAAE,MAAM,MAAQ,EAAA,OAAA,EAAS,SAAY,GAAA,OAAA,CAAQ,OAAO,IAAI,CAAA;AAE9D,IAAM,UAAa,GAAA,OAAA,CAAQ,YAAa,CAAA,KAAA,CAAM,CAAU,MAAA,KAAA;AACtD,EAAA,MAAM,cAAc,KAAM,CAAA,IAAA,CAAK,MAAO,CAAA,QAAA,CAAS,mBAAmB,CAAC,CAAA;AAEnE,EAAI,IAAA,WAAA,CAAY,WAAW,CAAG,EAAA;AAC5B,IAAM,MAAA,IAAI,MAAM,mCAAmC,CAAA;AAAA;AAGrD,EAAI,IAAA,WAAA,CAAY,SAAS,CAAG,EAAA;AAC1B,IAAM,MAAA,IAAI,MAAM,yCAAyC,CAAA;AAAA;AAG3D,EAAO,OAAA,WAAA,CAAY,CAAC,CAAA,CAAE,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,IAAM,EAAE,iBAAmB,EAAA,iBAAA,EAAsB,GAAA,MAAM,UAAU,MAAM,CAAA;AAEvE,IAAM,eAAkB,GAAA,QAAA;AAAA,EACtB;AAAA;AAAA,IAEE,GAAG,IAAA,CAAK,eAAgB,CAAA,GAAA,CAAI,gBAAgB,CAAA;AAAA,IAC5C,GAAG,iBAAA;AAAA,IACH,GAAG;AAAA,GACL;AAAA,EACA;AACF,CAAA;AAEA,IAAO,eAAQ,OAAQ,CAAA;AAAA,EACrB,IAAM,EAAA;AAAA,IACJ,IAAM,EAAA,QAAA;AAAA,IACN,aAAa,IAAK,CAAA,WAAA;AAAA,IAClB,cAAc,OAAQ,CAAA,YAAA;AAAA,IACtB,UAAA;AAAA,IACA;AAAA,GACF;AAAA,EAEA,aAAe,EAAA;AAAA,IACb,UAAA;AAAA,IAEA,eAAiB,EAAA;AAAA,MACf,KAAA,EAAO,eAAgB,CAAA,GAAA,CAAI,mBAAmB,CAAA;AAAA,MAC9C,eAAiB,EAAA;AAAA;AACnB;AAEJ,CAAC","file":"index.js","sourcesContent":["import { restic } from \"@highstate/library\"\nimport { forUnit, toPromise } from \"@highstate/pulumi\"\nimport { l34EndpointToString, parseL34Endpoint } from \"@highstate/common\"\nimport { uniqueBy } from \"remeda\"\n\nconst { args, inputs, secrets, outputs } = forUnit(restic.repo)\n\nconst remoteName = secrets.rcloneConfig.apply(config => {\n const remoteNames = Array.from(config.matchAll(/(?<=\\[).+?(?=\\])/g))\n\n if (remoteNames.length === 0) {\n throw new Error(\"No remotes found in rclone config\")\n }\n\n if (remoteNames.length > 1) {\n throw new Error(\"Multiple remotes found in rclone config\")\n }\n\n return remoteNames[0][0]\n})\n\nconst { remoteL3Endpoints, remoteL4Endpoints } = await toPromise(inputs)\n\nconst remoteEndpoints = uniqueBy(\n [\n //\n ...args.remoteEndpoints.map(parseL34Endpoint),\n ...remoteL3Endpoints,\n ...remoteL4Endpoints,\n ],\n l34EndpointToString,\n)\n\nexport default outputs({\n repo: {\n type: \"rclone\",\n pathPattern: args.pathPattern,\n rcloneConfig: secrets.rcloneConfig,\n remoteName,\n remoteEndpoints,\n },\n\n $statusFields: {\n remoteName,\n\n remoteEndpoints: {\n value: remoteEndpoints.map(l34EndpointToString),\n complementaryTo: \"remoteEndpoints\",\n },\n },\n})\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highstate/restic",
3
- "version": "0.9.14",
3
+ "version": "0.9.16",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -17,18 +17,19 @@
17
17
  "access": "public"
18
18
  },
19
19
  "scripts": {
20
- "build": "highstate build"
20
+ "build": "highstate build",
21
+ "update-images": "../../scripts/update-images.sh ./assets/images.json"
21
22
  },
22
23
  "dependencies": {
23
- "@highstate/common": "^0.9.14",
24
- "@highstate/k8s": "^0.9.14",
25
- "@highstate/library": "^0.9.14",
26
- "@highstate/pulumi": "^0.9.14",
24
+ "@highstate/common": "^0.9.16",
25
+ "@highstate/k8s": "^0.9.16",
26
+ "@highstate/library": "^0.9.16",
27
+ "@highstate/pulumi": "^0.9.16",
27
28
  "@pulumi/kubernetes": "^4.18.0",
28
29
  "remeda": "^2.21.0"
29
30
  },
30
31
  "devDependencies": {
31
- "@highstate/cli": "^0.9.14"
32
+ "@highstate/cli": "^0.9.16"
32
33
  },
33
- "gitHead": "8b5d1079961cc5bf9cf8ea3c10f7313384e3a2ff"
34
+ "gitHead": "458d6f1f9f6d4aec0ba75a2b2c4c01408cb9c8df"
34
35
  }
package/src/job-pair.ts CHANGED
@@ -23,10 +23,12 @@ import {
23
23
  type ComponentResourceOptions,
24
24
  type Input,
25
25
  type InputArray,
26
+ type InstanceTerminal,
26
27
  type InstanceTrigger,
27
28
  type InstanceTriggerInvocation,
28
29
  } from "@highstate/pulumi"
29
30
  import { text } from "@highstate/contract"
31
+ import * as images from "../assets/images.json"
30
32
  import { backupEnvironment } from "./scripts"
31
33
 
32
34
  export type BackupJobPairArgs = CommonArgs & {
@@ -38,7 +40,7 @@ export type BackupJobPairArgs = CommonArgs & {
38
40
  /**
39
41
  * The repository to backup/restore to/from.
40
42
  */
41
- resticRepo: Input<restic.Repo>
43
+ resticRepo: Input<restic.Repository>
42
44
 
43
45
  /**
44
46
  * The password used to encrypt the backups.
@@ -123,6 +125,11 @@ export class BackupJobPair extends ComponentResource {
123
125
  */
124
126
  readonly backupJob: Output<CronJob>
125
127
 
128
+ /**
129
+ * The full name of the Restic repository.
130
+ */
131
+ readonly resticRepoPath: Output<string>
132
+
126
133
  constructor(
127
134
  private readonly name: string,
128
135
  private readonly args: BackupJobPairArgs,
@@ -146,65 +153,71 @@ export class BackupJobPair extends ComponentResource {
146
153
  )
147
154
  })
148
155
 
149
- const environment = output(args).apply(args => {
150
- const repositoryPath = args.resticRepo.pathPattern
156
+ this.resticRepoPath = output(args).apply(args => {
157
+ const relativePath = args.resticRepo.pathPattern
151
158
  .replace(/\$clusterName/g, args.cluster.name)
152
159
  .replace(/\$appName/g, name)
153
160
  .replace(/\$unitName/g, getUnitInstanceName())
154
161
 
155
- return {
156
- alpine: {
157
- packages: ["rclone"],
158
- },
162
+ return `rclone:${args.resticRepo.remoteName}:${relativePath}`
163
+ })
164
+
165
+ const environment = output({ args, repoPath: this.resticRepoPath }).apply(
166
+ ({ args, repoPath }) => {
167
+ return {
168
+ alpine: {
169
+ packages: ["rclone"],
170
+ },
159
171
 
160
- ubuntu: {
161
- preInstallPackages: ["curl", "unzip"],
172
+ ubuntu: {
173
+ preInstallPackages: ["curl", "unzip"],
162
174
 
163
- preInstallScripts: {
164
- "rclone.sh": text`
175
+ preInstallScripts: {
176
+ "rclone.sh": text`
165
177
  #!/bin/sh
166
178
  set -e
167
179
 
168
180
  curl https://rclone.org/install.sh | bash
169
181
  `,
182
+ },
183
+
184
+ allowedEndpoints: ["rclone.org:443", "downloads.rclone.org:443"],
170
185
  },
171
186
 
172
- allowedEndpoints: ["rclone.org:443", "downloads.rclone.org:443"],
173
- },
187
+ allowedEndpoints: [
188
+ ...(args.allowedEndpoints ?? []),
189
+ ...(args.resticRepo.remoteEndpoints ?? []),
190
+ ],
174
191
 
175
- allowedEndpoints: [
176
- ...(args.allowedEndpoints ?? []),
177
- ...(args.resticRepo.remoteEndpoints ?? []),
178
- ],
179
-
180
- environment: {
181
- RESTIC_REPOSITORY: `rclone:${args.resticRepo.remoteName}:${repositoryPath}`,
182
- RESTIC_PASSWORD_FILE: "/credentials/password",
183
- RESTIC_HOSTNAME: "default",
184
- RCLONE_CONFIG: "/credentials/rclone.conf",
185
- EXTRA_BACKUP_OPTIONS: args.backupOptions?.join(" "),
186
- },
192
+ environment: {
193
+ RESTIC_REPOSITORY: repoPath,
194
+ RESTIC_PASSWORD_FILE: "/credentials/password",
195
+ RESTIC_HOSTNAME: "default",
196
+ RCLONE_CONFIG: "/credentials/rclone.conf",
197
+ EXTRA_BACKUP_OPTIONS: args.backupOptions?.join(" "),
198
+ },
187
199
 
188
- volumes: [this.credentials, ...(args.volume ? [args.volume] : [])],
200
+ volumes: [this.credentials, ...(args.volume ? [args.volume] : [])],
189
201
 
190
- volumeMounts: [
191
- {
192
- volume: this.credentials,
193
- mountPath: "/credentials",
194
- readOnly: true,
195
- },
196
- ...(args.volume
197
- ? [
198
- {
199
- volume: args.volume,
200
- mountPath: "/data",
201
- subPath: args.subPath,
202
- },
203
- ]
204
- : []),
205
- ],
206
- } satisfies ScriptEnvironment
207
- })
202
+ volumeMounts: [
203
+ {
204
+ volume: this.credentials,
205
+ mountPath: "/credentials",
206
+ readOnly: true,
207
+ },
208
+ ...(args.volume
209
+ ? [
210
+ {
211
+ volume: args.volume,
212
+ mountPath: "/data",
213
+ subPath: args.subPath,
214
+ },
215
+ ]
216
+ : []),
217
+ ],
218
+ } satisfies ScriptEnvironment
219
+ },
220
+ )
208
221
 
209
222
  this.scriptBundle = output(args).apply(args => {
210
223
  return new ScriptBundle(
@@ -291,6 +304,38 @@ export class BackupJobPair extends ComponentResource {
291
304
  }
292
305
  }
293
306
 
307
+ createTerminal(): InstanceTerminal {
308
+ return {
309
+ name: "restic",
310
+
311
+ meta: {
312
+ title: "Restic",
313
+ description: "Manage Restic repository",
314
+ icon: "material-symbols:backup",
315
+ },
316
+
317
+ image: images["terminal-restic"].image,
318
+ command: ["bash", "/welcome.sh"],
319
+
320
+ files: {
321
+ "/welcome.sh": text`
322
+ echo "Use 'restic' to manage the repository."
323
+ echo
324
+
325
+ exec bash
326
+ `,
327
+
328
+ "/credentials/password": output(this.args).backupPassword,
329
+ "/root/.config/rclone/rclone.conf": output(this.args).resticRepo.rcloneConfig,
330
+ },
331
+
332
+ env: {
333
+ RESTIC_REPOSITORY: this.resticRepoPath,
334
+ RESTIC_PASSWORD_FILE: "/credentials/password",
335
+ },
336
+ }
337
+ }
338
+
294
339
  private async createBackupOnDestroyJob(): Promise<void> {
295
340
  new batch.v1.Job(
296
341
  `${this.name}-backup-on-destroy`,
package/src/repo/index.ts CHANGED
@@ -40,7 +40,7 @@ export default outputs({
40
40
  remoteEndpoints,
41
41
  },
42
42
 
43
- $status: {
43
+ $statusFields: {
44
44
  remoteName,
45
45
 
46
46
  remoteEndpoints: {