forked from kopia/kopia
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommand_policy_import.go
More file actions
129 lines (100 loc) · 3 KB
/
Copy pathcommand_policy_import.go
File metadata and controls
129 lines (100 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package cli
import (
"context"
"encoding/json"
"io"
"os"
"slices"
"github.com/pkg/errors"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/snapshot/policy"
)
type commandPolicyImport struct {
policyTargetFlags
filePath string
allowUnknownFields bool
deleteOtherPolicies bool
svc appServices
}
func (c *commandPolicyImport) setup(svc appServices, parent commandParent) {
cmd := parent.Command("import", "Imports policies from a specified file, or stdin if no file is specified.")
cmd.Flag("from-file", "File path to import from").StringVar(&c.filePath)
cmd.Flag("allow-unknown-fields", "Allow unknown fields in the policy file").BoolVar(&c.allowUnknownFields)
cmd.Flag("delete-other-policies", "Delete all other policies, keeping only those that got imported").BoolVar(&c.deleteOtherPolicies)
c.policyTargetFlags.setup(cmd)
c.svc = svc
cmd.Action(svc.repositoryWriterAction(c.run))
}
func (c *commandPolicyImport) run(ctx context.Context, rep repo.RepositoryWriter) error {
var input io.Reader
var err error
if c.filePath != "" {
file, err := os.Open(c.filePath)
if err != nil {
return errors.Wrap(err, "unable to read policy file")
}
defer file.Close() //nolint:errcheck
input = file
} else {
input = c.svc.stdin()
}
policies := make(map[string]*policy.Policy)
d := json.NewDecoder(input)
if !c.allowUnknownFields {
d.DisallowUnknownFields()
}
err = d.Decode(&policies)
if err != nil {
return errors.Wrap(err, "unable to decode policy file as valid json")
}
var targetLimit []snapshot.SourceInfo
if c.global || len(c.targets) > 0 {
targetLimit, err = c.policyTargets(ctx, rep)
if err != nil {
return err
}
}
shouldImportSource := func(target snapshot.SourceInfo) bool {
if targetLimit == nil {
return true
}
return slices.Contains(targetLimit, target)
}
importedSources := make([]string, 0, len(policies))
for ts, newPolicy := range policies {
target, err := snapshot.ParseSourceInfo(ts, rep.ClientOptions().Hostname, rep.ClientOptions().Username)
if err != nil {
return errors.Wrapf(err, "unable to parse source info: %q", ts)
}
if !shouldImportSource(target) {
continue
}
// used for deleteOtherPolicies
importedSources = append(importedSources, ts)
if err := policy.SetPolicy(ctx, rep, target, newPolicy); err != nil {
return errors.Wrapf(err, "can't save policy for %v", target)
}
}
if c.deleteOtherPolicies {
err := deleteOthers(ctx, rep, importedSources)
if err != nil {
return err
}
}
return nil
}
func deleteOthers(ctx context.Context, rep repo.RepositoryWriter, importedSources []string) error {
ps, err := policy.ListPolicies(ctx, rep)
if err != nil {
return errors.Wrap(err, "failed to list policies")
}
for _, p := range ps {
if !slices.Contains(importedSources, p.Target().String()) {
if err := policy.RemovePolicy(ctx, rep, p.Target()); err != nil {
return errors.Wrapf(err, "can't delete policy for %v", p.Target())
}
}
}
return nil
}