mirror of
https://github.com/kopia/kopia.git
synced 2025-12-23 22:57:50 -05:00
```
~# ./kopia policy show /home/donatas/tests
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x18b7b84]
goroutine 1 [running]:
github.com/kopia/kopia/cli.appendOSSnapshotPolicyRows({0xc005759008, 0x26, 0x55}, 0xc005754600?, 0xc005764008)
/home/donatas/projects/kopia/cli/command_policy_show.go:490 +0x44
github.com/kopia/kopia/cli.printPolicy(0xc0000f5d48, 0xc005754600, 0xc005764008)
/home/donatas/projects/kopia/cli/command_policy_show.go:135 +0x5e5
github.com/kopia/kopia/cli.(*commandPolicyShow).run(0xc0000f5d10, {0x2311ef8, 0xc0002e5320}, {0x7fb83829f3d0, 0xc0052eeb00})
/home/donatas/projects/kopia/cli/command_policy_show.go:46 +0x18d
github.com/kopia/kopia/cli.(*App).repositoryReaderAction.func1({0x2311ef8?, 0xc0002e5320?}, {0x7fb83829f3d0?, 0xc0052eeb00?})
/home/donatas/projects/kopia/cli/app.go:477 +0x2b
github.com/kopia/kopia/cli.(*App).repositoryReaderAction.(*App).maybeRepositoryAction.func2({0x2311ef8, 0xc0002e5320})
/home/donatas/projects/kopia/cli/app.go:571 +0xbd
github.com/kopia/kopia/cli.(*App).repositoryReaderAction.(*App).maybeRepositoryAction.(*App).baseActionWithContext.func3.1.1()
/home/donatas/projects/kopia/cli/app.go:554 +0x6e
github.com/kopia/kopia/cli.(*profileFlags).withProfiling(0x0?, 0xc0004a09c0?)
/home/donatas/projects/kopia/cli/profile.go:45 +0x2b9
github.com/kopia/kopia/cli.(*App).repositoryReaderAction.(*App).maybeRepositoryAction.(*App).baseActionWithContext.func3.1({0x2311ef8?, 0xc0002e5320?})
/home/donatas/projects/kopia/cli/app.go:549 +0x50
github.com/kopia/kopia/cli.(*App).runAppWithContext.func1(0xc0000f48d0?, 0xc0000f4808, 0xc0000efd30, {0x2311ef8, 0xc0002e52f0})
/home/donatas/projects/kopia/cli/app.go:521 +0x186
github.com/kopia/kopia/cli.(*App).runAppWithContext(0xc0000f4808, 0xc0002b88f0, 0xc0000efd30)
/home/donatas/projects/kopia/cli/app.go:522 +0x1a9
github.com/kopia/kopia/cli.(*App).repositoryReaderAction.(*App).maybeRepositoryAction.(*App).baseActionWithContext.func3(0x22e2801?)
/home/donatas/projects/kopia/cli/app.go:548 +0x3c
github.com/alecthomas/kingpin/v2.(*actionMixin).applyActions(...)
/home/donatas/go/pkg/mod/github.com/alecthomas/kingpin/v2@v2.4.0/actions.go:28
github.com/alecthomas/kingpin/v2.(*Application).applyActions(0xc0001b8500?, 0xc000453050)
/home/donatas/go/pkg/mod/github.com/alecthomas/kingpin/v2@v2.4.0/app.go:568 +0xd0
github.com/alecthomas/kingpin/v2.(*Application).execute(0xc0001b8500, 0xc000453050, {0xc0004b6d80, 0x2, 0x2})
/home/donatas/go/pkg/mod/github.com/alecthomas/kingpin/v2@v2.4.0/app.go:398 +0x65
github.com/alecthomas/kingpin/v2.(*Application).Parse(0xc0001b8500, {0xc00014e090?, 0xc0001b8500?, 0x22e8c80?})
/home/donatas/go/pkg/mod/github.com/alecthomas/kingpin/v2@v2.4.0/app.go:230 +0x14a
main.main()
/home/donatas/projects/kopia/main.go:77 +0x1cc
```
This is happening if we apply this before:
```
~# ./kopia policy set --inherit=false --clear-ignore /home/donatas/tests
```
Default value for `p.OSSnapshotPolicy.VolumeShadowCopy.Enable` is nil, so it's not set
which is inherited from a global one and is 0 (never).
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
510 lines
16 KiB
Go
510 lines
16 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/internal/units"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/snapshot"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
type commandPolicyShow struct {
|
|
policyTargetFlags
|
|
jo jsonOutput
|
|
out textOutput
|
|
}
|
|
|
|
func (c *commandPolicyShow) setup(svc appServices, parent commandParent) {
|
|
cmd := parent.Command("show", "Show snapshot policy.").Alias("get")
|
|
c.policyTargetFlags.setup(cmd)
|
|
c.jo.setup(svc, cmd)
|
|
c.out.setup(svc)
|
|
cmd.Action(svc.repositoryReaderAction(c.run))
|
|
}
|
|
|
|
func (c *commandPolicyShow) run(ctx context.Context, rep repo.Repository) error {
|
|
targets, err := c.policyTargets(ctx, rep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, target := range targets {
|
|
effective, definition, _, err := policy.GetEffectivePolicy(ctx, rep, target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "can't get effective policy for %q", target)
|
|
}
|
|
|
|
if c.jo.jsonOutput {
|
|
c.out.printStdout("%s\n", c.jo.jsonBytes(effective))
|
|
} else {
|
|
printPolicy(&c.out, effective, definition)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type policyTableRow struct {
|
|
name string
|
|
value string
|
|
def string
|
|
}
|
|
|
|
func alignedPolicyTableRows(v []policyTableRow) string {
|
|
var nameValueLen int
|
|
|
|
const (
|
|
nameValueSpace = " "
|
|
defSpace = " "
|
|
)
|
|
|
|
for _, it := range v {
|
|
if it.value == "" {
|
|
continue
|
|
}
|
|
|
|
t := it.name
|
|
if it.value != "" {
|
|
t += nameValueSpace + it.value
|
|
}
|
|
|
|
if len(t) > nameValueLen {
|
|
nameValueLen = len(t)
|
|
}
|
|
}
|
|
|
|
var lines []string
|
|
|
|
for _, it := range v {
|
|
l := it.name
|
|
|
|
if it.value != "" || it.def != "" {
|
|
if spaces := nameValueLen - len(l) - len(it.value); spaces > 0 {
|
|
l += strings.Repeat(" ", spaces)
|
|
}
|
|
|
|
l += it.value
|
|
}
|
|
|
|
if it.def != "" {
|
|
l += defSpace
|
|
l += it.def
|
|
}
|
|
|
|
lines = append(lines, l)
|
|
}
|
|
|
|
return strings.Join(lines, "\n")
|
|
}
|
|
|
|
func definitionPointToString(target, src snapshot.SourceInfo) string {
|
|
if src == target {
|
|
return "(defined for this target)"
|
|
}
|
|
|
|
return "inherited from " + src.String()
|
|
}
|
|
|
|
func printPolicy(out *textOutput, p *policy.Policy, def *policy.Definition) {
|
|
var rows []policyTableRow
|
|
|
|
rows = appendRetentionPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendFilesPolicyValue(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendErrorHandlingPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendSchedulingPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendUploadPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendCompressionPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendMetadataCompressionPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendSplitterPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendActionsPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendOSSnapshotPolicyRows(rows, p, def)
|
|
rows = append(rows, policyTableRow{})
|
|
rows = appendLoggingPolicyRows(rows, p, def)
|
|
|
|
out.printStdout("Policy for %v:\n\n%v\n", p.Target(), alignedPolicyTableRows(rows))
|
|
}
|
|
|
|
func appendRetentionPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
return append(rows,
|
|
policyTableRow{"Retention:", "", ""},
|
|
policyTableRow{" Annual snapshots:", valueOrNotSet(p.RetentionPolicy.KeepAnnual), definitionPointToString(p.Target(), def.RetentionPolicy.KeepAnnual)},
|
|
policyTableRow{" Monthly snapshots:", valueOrNotSet(p.RetentionPolicy.KeepMonthly), definitionPointToString(p.Target(), def.RetentionPolicy.KeepMonthly)},
|
|
policyTableRow{" Weekly snapshots:", valueOrNotSet(p.RetentionPolicy.KeepWeekly), definitionPointToString(p.Target(), def.RetentionPolicy.KeepWeekly)},
|
|
policyTableRow{" Daily snapshots:", valueOrNotSet(p.RetentionPolicy.KeepDaily), definitionPointToString(p.Target(), def.RetentionPolicy.KeepDaily)},
|
|
policyTableRow{" Hourly snapshots:", valueOrNotSet(p.RetentionPolicy.KeepHourly), definitionPointToString(p.Target(), def.RetentionPolicy.KeepHourly)},
|
|
policyTableRow{" Latest snapshots:", valueOrNotSet(p.RetentionPolicy.KeepLatest), definitionPointToString(p.Target(), def.RetentionPolicy.KeepLatest)},
|
|
policyTableRow{" Ignore identical snapshots:", boolToString(p.RetentionPolicy.IgnoreIdenticalSnapshots.OrDefault(false)), definitionPointToString(p.Target(), def.RetentionPolicy.IgnoreIdenticalSnapshots)},
|
|
)
|
|
}
|
|
|
|
func boolToString(v bool) string {
|
|
if v {
|
|
return "true"
|
|
}
|
|
|
|
return "false"
|
|
}
|
|
|
|
func logDetailToString(v policy.LogDetail) string {
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
|
|
func appendFilesPolicyValue(items []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
items = append(items,
|
|
policyTableRow{"Files policy:", "", ""},
|
|
policyTableRow{
|
|
" Ignore cache directories:",
|
|
boolToString(p.FilesPolicy.IgnoreCacheDirectories.OrDefault(true)),
|
|
definitionPointToString(p.Target(), def.FilesPolicy.IgnoreCacheDirectories),
|
|
})
|
|
|
|
if len(p.FilesPolicy.IgnoreRules) > 0 {
|
|
items = append(items, policyTableRow{
|
|
" Ignore rules:", "", definitionPointToString(p.Target(), def.FilesPolicy.IgnoreRules),
|
|
})
|
|
for _, rule := range p.FilesPolicy.IgnoreRules {
|
|
items = append(items, policyTableRow{" " + rule, "", ""})
|
|
}
|
|
} else {
|
|
items = append(items, policyTableRow{" No ignore rules:", "", ""})
|
|
}
|
|
|
|
if len(p.FilesPolicy.DotIgnoreFiles) > 0 {
|
|
items = append(items, policyTableRow{
|
|
" Read ignore rules from files:", "",
|
|
definitionPointToString(p.Target(), def.FilesPolicy.DotIgnoreFiles),
|
|
})
|
|
|
|
for _, dotFile := range p.FilesPolicy.DotIgnoreFiles {
|
|
items = append(items, policyTableRow{" " + dotFile, "", ""})
|
|
}
|
|
}
|
|
|
|
if maxSize := p.FilesPolicy.MaxFileSize; maxSize > 0 {
|
|
items = append(items, policyTableRow{
|
|
" Ignore files above:",
|
|
units.BytesString(maxSize),
|
|
definitionPointToString(p.Target(), def.FilesPolicy.MaxFileSize),
|
|
})
|
|
}
|
|
|
|
items = append(items, policyTableRow{
|
|
" Scan one filesystem only:",
|
|
boolToString(p.FilesPolicy.OneFileSystem.OrDefault(false)),
|
|
definitionPointToString(p.Target(), def.FilesPolicy.OneFileSystem),
|
|
})
|
|
|
|
return items
|
|
}
|
|
|
|
func appendErrorHandlingPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
return append(rows,
|
|
policyTableRow{"Error handling policy:", "", ""},
|
|
policyTableRow{
|
|
" Ignore file read errors:",
|
|
boolToString(p.ErrorHandlingPolicy.IgnoreFileErrors.OrDefault(false)),
|
|
definitionPointToString(p.Target(), def.ErrorHandlingPolicy.IgnoreFileErrors),
|
|
},
|
|
policyTableRow{
|
|
" Ignore directory read errors:",
|
|
boolToString(p.ErrorHandlingPolicy.IgnoreDirectoryErrors.OrDefault(false)),
|
|
definitionPointToString(p.Target(), def.ErrorHandlingPolicy.IgnoreDirectoryErrors),
|
|
},
|
|
policyTableRow{
|
|
" Ignore unknown types:",
|
|
boolToString(p.ErrorHandlingPolicy.IgnoreUnknownTypes.OrDefault(true)),
|
|
definitionPointToString(p.Target(), def.ErrorHandlingPolicy.IgnoreUnknownTypes),
|
|
},
|
|
)
|
|
}
|
|
|
|
func appendLoggingPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
return append(rows,
|
|
policyTableRow{
|
|
fmt.Sprintf("Logging details (%v-none, %v-maximum):", policy.LogDetailNone, policy.LogDetailMax), "", "",
|
|
},
|
|
policyTableRow{
|
|
" Directory snapshotted:",
|
|
logDetailToString(p.LoggingPolicy.Directories.Snapshotted.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Directories.Snapshotted),
|
|
},
|
|
policyTableRow{
|
|
" Directory ignored:",
|
|
logDetailToString(p.LoggingPolicy.Directories.Ignored.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Directories.Ignored),
|
|
},
|
|
policyTableRow{
|
|
" Entry snapshotted:",
|
|
logDetailToString(p.LoggingPolicy.Entries.Snapshotted.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Entries.Snapshotted),
|
|
},
|
|
policyTableRow{
|
|
" Entry ignored:",
|
|
logDetailToString(p.LoggingPolicy.Entries.Ignored.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Entries.Ignored),
|
|
},
|
|
policyTableRow{
|
|
" Entry cache hit:",
|
|
logDetailToString(p.LoggingPolicy.Entries.CacheHit.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Entries.CacheHit),
|
|
},
|
|
policyTableRow{
|
|
" Entry cache miss:",
|
|
logDetailToString(p.LoggingPolicy.Entries.CacheMiss.OrDefault(policy.LogDetailNone)),
|
|
definitionPointToString(p.Target(), def.LoggingPolicy.Entries.CacheMiss),
|
|
},
|
|
)
|
|
}
|
|
|
|
func appendUploadPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
return append(rows,
|
|
policyTableRow{"Uploads:", "", ""},
|
|
policyTableRow{" Max parallel snapshots (server/UI):", valueOrNotSet(p.UploadPolicy.MaxParallelSnapshots), definitionPointToString(p.Target(), def.UploadPolicy.MaxParallelSnapshots)},
|
|
policyTableRow{" Max parallel file reads:", valueOrNotSet(p.UploadPolicy.MaxParallelFileReads), definitionPointToString(p.Target(), def.UploadPolicy.MaxParallelFileReads)},
|
|
policyTableRow{" Parallel upload above size:", valueOrNotSetOptionalInt64Bytes(p.UploadPolicy.ParallelUploadAboveSize), definitionPointToString(p.Target(), def.UploadPolicy.ParallelUploadAboveSize)},
|
|
)
|
|
}
|
|
|
|
func appendSchedulingPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
rows = append(rows, policyTableRow{"Scheduling policy:", "", ""})
|
|
|
|
hasAny := false
|
|
|
|
rows = append(rows, policyTableRow{" Scheduled snapshots:", "", ""})
|
|
|
|
if p.SchedulingPolicy.Interval() != 0 {
|
|
rows = append(rows, policyTableRow{
|
|
" Snapshot interval:",
|
|
p.SchedulingPolicy.Interval().String(),
|
|
definitionPointToString(p.Target(), def.SchedulingPolicy.IntervalSeconds),
|
|
})
|
|
|
|
hasAny = true
|
|
}
|
|
|
|
if len(p.SchedulingPolicy.TimesOfDay) > 0 {
|
|
rows = append(rows,
|
|
policyTableRow{
|
|
" Run missed snapshots:",
|
|
boolToString(p.SchedulingPolicy.RunMissed.OrDefault(false)),
|
|
definitionPointToString(p.Target(), def.SchedulingPolicy.RunMissed),
|
|
},
|
|
policyTableRow{
|
|
" Snapshot times:",
|
|
"",
|
|
definitionPointToString(p.Target(), def.SchedulingPolicy.TimesOfDay),
|
|
})
|
|
|
|
for _, tod := range p.SchedulingPolicy.TimesOfDay {
|
|
rows = append(rows, policyTableRow{" " + tod.String(), "", ""})
|
|
}
|
|
|
|
hasAny = true
|
|
}
|
|
|
|
if len(p.SchedulingPolicy.Cron) > 0 {
|
|
rows = append(rows, policyTableRow{" Crontab expressions:", "", definitionPointToString(p.Target(), def.SchedulingPolicy.Cron)})
|
|
|
|
for _, cron := range p.SchedulingPolicy.Cron {
|
|
rows = append(rows, policyTableRow{" " + cron, "", ""})
|
|
}
|
|
|
|
hasAny = true
|
|
}
|
|
|
|
if !hasAny {
|
|
rows = append(rows, policyTableRow{" None.", "", ""})
|
|
}
|
|
|
|
rows = append(rows, policyTableRow{" Manual snapshot:", boolToString(p.SchedulingPolicy.Manual), definitionPointToString(p.Target(), def.SchedulingPolicy.Manual)})
|
|
|
|
return rows
|
|
}
|
|
|
|
func appendCompressionPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
if p.CompressionPolicy.CompressorName == "" || p.CompressionPolicy.CompressorName == "none" {
|
|
rows = append(rows, policyTableRow{"Compression disabled.", "", ""})
|
|
return rows
|
|
}
|
|
|
|
rows = append(rows,
|
|
policyTableRow{"Compression:", "", ""},
|
|
policyTableRow{" Compressor:", string(p.CompressionPolicy.CompressorName), definitionPointToString(p.Target(), def.CompressionPolicy.CompressorName)})
|
|
|
|
switch {
|
|
case len(p.CompressionPolicy.OnlyCompress) > 0:
|
|
rows = append(rows, policyTableRow{
|
|
" Only compress files with the following extensions:", "",
|
|
definitionPointToString(p.Target(), def.CompressionPolicy.OnlyCompress),
|
|
})
|
|
|
|
for _, rule := range p.CompressionPolicy.OnlyCompress {
|
|
rows = append(rows, policyTableRow{" - " + rule, "", ""})
|
|
}
|
|
|
|
case len(p.CompressionPolicy.NeverCompress) > 0:
|
|
rows = append(rows, policyTableRow{
|
|
" Compress all files except the following extensions:", "",
|
|
definitionPointToString(p.Target(), def.CompressionPolicy.NeverCompress),
|
|
})
|
|
|
|
for _, rule := range p.CompressionPolicy.NeverCompress {
|
|
rows = append(rows, policyTableRow{" " + rule, "", ""})
|
|
}
|
|
|
|
default:
|
|
rows = append(rows, policyTableRow{" Compress files regardless of extensions.", "", ""})
|
|
}
|
|
|
|
switch {
|
|
case p.CompressionPolicy.MaxSize > 0:
|
|
rows = append(rows, policyTableRow{fmt.Sprintf(
|
|
" Only compress files between %v and %v.",
|
|
units.BytesString(p.CompressionPolicy.MinSize),
|
|
units.BytesString(p.CompressionPolicy.MaxSize)), "", ""})
|
|
|
|
case p.CompressionPolicy.MinSize > 0:
|
|
rows = append(rows, policyTableRow{fmt.Sprintf(
|
|
" Only compress files bigger than %v.",
|
|
units.BytesString(p.CompressionPolicy.MinSize)), "", ""})
|
|
|
|
default:
|
|
rows = append(rows, policyTableRow{" Compress files of all sizes.", "", ""})
|
|
}
|
|
|
|
return rows
|
|
}
|
|
|
|
func appendMetadataCompressionPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
if p.MetadataCompressionPolicy.CompressorName == "" || p.MetadataCompressionPolicy.CompressorName == "none" {
|
|
rows = append(rows, policyTableRow{"Metadata compression disabled.", "", ""})
|
|
return rows
|
|
}
|
|
|
|
return append(rows,
|
|
policyTableRow{"Metadata compression:", "", ""},
|
|
policyTableRow{" Compressor:", string(p.MetadataCompressionPolicy.CompressorName), definitionPointToString(p.Target(), def.MetadataCompressionPolicy.CompressorName)})
|
|
}
|
|
|
|
func appendSplitterPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
algorithm := p.SplitterPolicy.Algorithm
|
|
if algorithm == "" {
|
|
algorithm = "(repository default)"
|
|
}
|
|
|
|
rows = append(rows,
|
|
policyTableRow{"Splitter:", "", ""},
|
|
policyTableRow{" Algorithm override:", algorithm, definitionPointToString(p.Target(), def.SplitterPolicy.Algorithm)})
|
|
|
|
return rows
|
|
}
|
|
|
|
func appendActionsPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
var anyActions bool
|
|
|
|
if h := p.Actions.BeforeSnapshotRoot; h != nil {
|
|
rows = append(rows,
|
|
policyTableRow{"Run command before snapshot root:", "", definitionPointToString(p.Target(), def.Actions.BeforeSnapshotRoot)})
|
|
rows = appendActionCommandRows(rows, h)
|
|
|
|
anyActions = true
|
|
}
|
|
|
|
if h := p.Actions.AfterSnapshotRoot; h != nil {
|
|
rows = append(rows, policyTableRow{"Run command after snapshot root:", "", definitionPointToString(p.Target(), def.Actions.AfterSnapshotRoot)})
|
|
rows = appendActionCommandRows(rows, h)
|
|
|
|
anyActions = true
|
|
}
|
|
|
|
if h := p.Actions.BeforeFolder; h != nil {
|
|
rows = append(rows, policyTableRow{"Run command before this folder:", "", "(non-inheritable)"})
|
|
rows = appendActionCommandRows(rows, h)
|
|
|
|
anyActions = true
|
|
}
|
|
|
|
if h := p.Actions.AfterFolder; h != nil {
|
|
rows = append(rows, policyTableRow{"Run command after this folder:", "", "(non-inheritable)"})
|
|
rows = appendActionCommandRows(rows, h)
|
|
|
|
anyActions = true
|
|
}
|
|
|
|
if !anyActions {
|
|
rows = append(rows, policyTableRow{"No actions defined.", "", ""})
|
|
}
|
|
|
|
return rows
|
|
}
|
|
|
|
func appendActionCommandRows(rows []policyTableRow, h *policy.ActionCommand) []policyTableRow {
|
|
if h.Script != "" {
|
|
rows = append(rows,
|
|
policyTableRow{" Embedded script (stored in repository):", "", ""},
|
|
policyTableRow{indentMultilineString(h.Script, " "), "", ""},
|
|
)
|
|
} else {
|
|
rows = append(rows,
|
|
policyTableRow{" Command:", "", ""},
|
|
policyTableRow{" " + h.Command + " " + strings.Join(h.Arguments, " "), "", ""})
|
|
}
|
|
|
|
actualMode := h.Mode
|
|
if actualMode == "" {
|
|
actualMode = "sync"
|
|
}
|
|
|
|
rows = append(rows,
|
|
policyTableRow{" Mode:", actualMode, ""},
|
|
policyTableRow{" Timeout:", (time.Second * time.Duration(h.TimeoutSeconds)).String(), ""},
|
|
policyTableRow{"", "", ""},
|
|
)
|
|
|
|
return rows
|
|
}
|
|
|
|
func appendOSSnapshotPolicyRows(rows []policyTableRow, p *policy.Policy, def *policy.Definition) []policyTableRow {
|
|
rows = append(rows,
|
|
policyTableRow{"OS-level snapshot support:", "", ""},
|
|
policyTableRow{
|
|
" Volume Shadow Copy:",
|
|
p.OSSnapshotPolicy.VolumeShadowCopy.Enable.OrDefault(policy.OSSnapshotNever).String(),
|
|
definitionPointToString(p.Target(), def.OSSnapshotPolicy.VolumeShadowCopy.Enable),
|
|
},
|
|
)
|
|
|
|
return rows
|
|
}
|
|
|
|
func valueOrNotSet(p *policy.OptionalInt) string {
|
|
if p == nil {
|
|
return "-"
|
|
}
|
|
|
|
return fmt.Sprintf("%v", *p)
|
|
}
|
|
|
|
func valueOrNotSetOptionalInt64Bytes(p *policy.OptionalInt64) string {
|
|
if p == nil {
|
|
return "-"
|
|
}
|
|
|
|
return units.BytesString(*p)
|
|
}
|