Skip to content

Commit

Permalink
feat: add opt-in auto-unlock feature to remove locks on forget and pr…
Browse files Browse the repository at this point in the history
…une (#107)
  • Loading branch information
garethgeorge authored Feb 19, 2024
1 parent 40e3e04 commit c1ee33f
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 149 deletions.
226 changes: 118 additions & 108 deletions gen/go/v1/config.pb.go

Large diffs are not rendered by default.

87 changes: 48 additions & 39 deletions gen/go/v1/restic.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions internal/orchestrator/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,20 @@ func (r *RepoOrchestrator) Restore(ctx context.Context, snapshotId string, path
return protoutil.RestoreProgressEntryToProto(summary), nil
}

// UnlockIfAutoEnabled unlocks the repo if the auto unlock feature is enabled.
func (r *RepoOrchestrator) UnlockIfAutoEnabled(ctx context.Context) error {
if !r.repoConfig.AutoUnlock {
return nil
}

r.mu.Lock()
defer r.mu.Unlock()

zap.L().Debug("AutoUnlocking repo", zap.String("repo", r.repoConfig.Id))

return r.repo.Unlock(ctx)
}

func (r *RepoOrchestrator) Unlock(ctx context.Context) error {
r.mu.Lock()
defer r.mu.Unlock()
Expand Down
5 changes: 5 additions & 0 deletions internal/orchestrator/taskforget.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func (t *ForgetTask) Run(ctx context.Context) error {
return fmt.Errorf("get repo %q: %w", t.plan.Repo, err)
}

err = repo.UnlockIfAutoEnabled(ctx)
if err != nil {
return fmt.Errorf("auto unlock repo %q: %w", t.plan.Repo, err)
}

forgot, err := repo.Forget(ctx, t.plan)
if err != nil {
return fmt.Errorf("forget: %w", err)
Expand Down
5 changes: 5 additions & 0 deletions internal/orchestrator/taskprune.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ func (t *PruneTask) Run(ctx context.Context) error {
return fmt.Errorf("get repo %v: %w", t.plan.Repo, err)
}

err = repo.UnlockIfAutoEnabled(ctx)
if err != nil {
return fmt.Errorf("auto unlock repo %q: %w", t.plan.Repo, err)
}

opPrune := &v1.Operation_OperationPrune{
OperationPrune: &v1.OperationPrune{},
}
Expand Down
1 change: 1 addition & 0 deletions proto/v1/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ message Repo {
repeated string flags = 5 [json_name="flags"]; // extra flags set on the restic command.
PrunePolicy prune_policy = 6 [json_name="prunePolicy"]; // policy for when to run prune.
repeated Hook hooks = 7 [json_name="hooks"]; // hooks to run on events for this repo.
bool auto_unlock = 8 [json_name="autoUnlock"]; // automatically unlock the repo when needed.
}

message Plan {
Expand Down
8 changes: 8 additions & 0 deletions webui/gen/ts/v1/config_pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ export class Repo extends Message<Repo> {
*/
hooks: Hook[] = [];

/**
* automatically unlock the repo when needed.
*
* @generated from field: bool auto_unlock = 8;
*/
autoUnlock = false;

constructor(data?: PartialMessage<Repo>) {
super();
proto3.util.initPartial(data, this);
Expand All @@ -141,6 +148,7 @@ export class Repo extends Message<Repo> {
{ no: 5, name: "flags", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
{ no: 6, name: "prune_policy", kind: "message", T: PrunePolicy },
{ no: 7, name: "hooks", kind: "message", T: Hook, repeated: true },
{ no: 8, name: "auto_unlock", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
]);

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Repo {
Expand Down
6 changes: 6 additions & 0 deletions webui/gen/ts/v1/restic_pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ export class BackupProgressError extends Message<BackupProgressError> {
*/
during = "";

/**
* @generated from field: string message = 3;
*/
message = "";

constructor(data?: PartialMessage<BackupProgressError>) {
super();
proto3.util.initPartial(data, this);
Expand All @@ -394,6 +399,7 @@ export class BackupProgressError extends Message<BackupProgressError> {
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "item", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "during", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "message", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): BackupProgressError {
Expand Down
12 changes: 10 additions & 2 deletions webui/src/views/AddRepoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
InputNumber,
FormInstance,
Collapse,
Checkbox,
} from "antd";
import React, { useEffect, useState } from "react";
import { useShowModal } from "../components/ModalManager";
Expand Down Expand Up @@ -421,6 +422,13 @@ export const AddRepoModal = ({
</Form.Item>
</Form.Item>

<Form.Item label={<Tooltip title={"Auto-unlock will remove lockfiles at the start of forget and prune operations. "
+ "This is potentially unsafe if the repo is shared by multiple client devices. Opt-in (and disabled) by default."}>
Auto Unlock
</Tooltip>} name="autoUnlock" valuePropName="checked">
<Checkbox />
</Form.Item>

<Form.Item
label={<Tooltip title={hooksListTooltipText}>Hooks</Tooltip>}
>
Expand All @@ -446,7 +454,7 @@ export const AddRepoModal = ({
)}
</Form.Item>
</Form>
</Modal>
</Modal >
</>
);
};
Expand Down Expand Up @@ -547,7 +555,7 @@ const checkSchemeEnvVars = (scheme: string, envVarNames: string[]): Promise<void
const formatMissingEnvVars = (partialMatches: string[][]): string => {
return partialMatches.map(x => {
if (x.length > 1) {
return `[ ${ x.join(", ") } ]`;
return `[ ${x.join(", ")} ]`;
}
return x[0];
}).join(" or ");
Expand Down

0 comments on commit c1ee33f

Please sign in to comment.