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 130 131 132 133 134 135 136 137 138 139 140 141
|
package main
import (
"encoding/json"
"fmt"
"os"
"time"
"github.com/containers/storage"
"github.com/containers/storage/pkg/mflag"
)
var (
quickCheck, repair, forceRepair bool
maximumUnreferencedLayerAge string
)
func check(flags *mflag.FlagSet, action string, m storage.Store, args []string) (int, error) {
if forceRepair {
repair = true
}
defer func() {
if _, err := m.Shutdown(true); err != nil {
fmt.Fprintf(os.Stderr, "shutdown: %v\n", err)
}
}()
checkOptions := storage.CheckEverything()
if quickCheck {
checkOptions = storage.CheckMost()
}
if maximumUnreferencedLayerAge != "" {
age, err := time.ParseDuration(maximumUnreferencedLayerAge)
if err != nil {
return 1, err
}
checkOptions.LayerUnreferencedMaximumAge = &age
}
report, err := m.Check(checkOptions)
if err != nil {
return 1, err
}
outputNonJSON := func(report storage.CheckReport) {
for id, errs := range report.Layers {
if len(errs) > 0 {
fmt.Fprintf(os.Stdout, "layer %s:\n", id)
}
for _, err := range errs {
fmt.Fprintf(os.Stdout, " %v\n", err)
}
}
for id, errs := range report.ROLayers {
if len(errs) > 0 {
fmt.Fprintf(os.Stdout, "read-only layer %s:\n", id)
}
for _, err := range errs {
fmt.Fprintf(os.Stdout, " %v\n", err)
}
}
for id, errs := range report.Images {
if len(errs) > 0 {
fmt.Fprintf(os.Stdout, "image %s:\n", id)
}
for _, err := range errs {
fmt.Fprintf(os.Stdout, " %v\n", err)
}
}
for id, errs := range report.ROImages {
if len(errs) > 0 {
fmt.Fprintf(os.Stdout, "read-only image %s:\n", id)
}
for _, err := range errs {
fmt.Fprintf(os.Stdout, " %v\n", err)
}
}
for id, errs := range report.Containers {
if len(errs) > 0 {
fmt.Fprintf(os.Stdout, "container %s:\n", id)
}
for _, err := range errs {
fmt.Fprintf(os.Stdout, " %v\n", err)
}
}
}
if jsonOutput {
if err := json.NewEncoder(os.Stdout).Encode(report); err != nil {
return 1, err
}
} else {
outputNonJSON(report)
}
if !repair {
if len(report.Layers) > 0 || len(report.ROLayers) > 0 || len(report.Images) > 0 || len(report.ROImages) > 0 || len(report.Containers) > 0 {
return 1, fmt.Errorf("%d layer errors, %d read-only layer errors, %d image errors, %d read-only image errors, %d container errors", len(report.Layers), len(report.ROLayers), len(report.Images), len(report.ROImages), len(report.Containers))
}
} else {
options := storage.RepairOptions{
RemoveContainers: forceRepair,
}
if errs := m.Repair(report, &options); len(errs) != 0 {
if jsonOutput {
if err := json.NewEncoder(os.Stdout).Encode(errs); err != nil {
return 1, err
}
} else {
for _, err := range errs {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
}
return 1, errs[0]
}
if len(report.ROLayers) > 0 || len(report.ROImages) > 0 || (!options.RemoveContainers && len(report.Containers) > 0) {
var err error
if options.RemoveContainers {
err = fmt.Errorf("%d read-only layer errors, %d read-only image errors", len(report.ROLayers), len(report.ROImages))
} else {
err = fmt.Errorf("%d read-only layer errors, %d read-only image errors, %d container errors", len(report.ROLayers), len(report.ROImages), len(report.Containers))
}
return 1, err
}
}
return 0, nil
}
func init() {
commands = append(commands, command{
names: []string{"check"},
usage: "Check storage consistency",
minArgs: 0,
maxArgs: 0,
action: check,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&jsonOutput, []string{"-json", "j"}, jsonOutput, "Prefer JSON output")
flags.StringVar(&maximumUnreferencedLayerAge, []string{"-max", "m"}, "24h", "Maximum allowed age for unreferenced layers")
flags.BoolVar(&repair, []string{"-repair", "r"}, repair, "Remove damaged images and layers")
flags.BoolVar(&forceRepair, []string{"-force", "f"}, forceRepair, "Remove damaged containers")
flags.BoolVar(&quickCheck, []string{"-quick", "q"}, quickCheck, "Perform only quick checks")
},
})
}
|