/
check.go
242 lines (211 loc) · 6.07 KB
/
check.go
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package cmd
import (
"bufio"
"encoding/json"
"fmt"
"net/url"
"os"
"strconv"
"github.com/cozy/cozy-stack/client/request"
"github.com/spf13/cobra"
)
var flagCheckFSIndexIntegrity bool
var flagCheckFSFilesConsistensy bool
var flagCheckFSFailFast bool
var flagCheckSharingsFast bool
var checkCmdGroup = &cobra.Command{
Use: "check <command>",
Short: "A set of tools to check that instances are in the expected state.",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Usage()
},
}
var checkFSCmd = &cobra.Command{
Use: "fs <domain>",
Short: "Check a vfs",
Long: `
This command checks that the files in the VFS are not desynchronized, ie a file
present in CouchDB but not swift/localfs, or present in swift/localfs but not
couchdb.
There are 2 steps:
- index integrity checks that there are nothing wrong in the index (CouchDB),
like a file present in a directory that has been deleted
- files consistency checks that the files are the same in the index (CouchDB)
and the storage (Swift or localfs).
By default, both operations are done, but you can choose one or the other via
the flags.
`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Usage()
}
return fsck(args[0])
},
}
func fsck(domain string) error {
if flagCheckFSFilesConsistensy && flagCheckFSIndexIntegrity {
flagCheckFSIndexIntegrity = false
flagCheckFSFilesConsistensy = false
}
ac := newAdminClient()
res, err := ac.Req(&request.Options{
Method: "GET",
Path: "/instances/" + url.PathEscape(domain) + "/fsck",
Queries: url.Values{
"IndexIntegrity": {strconv.FormatBool(flagCheckFSIndexIntegrity)},
"FilesConsistency": {strconv.FormatBool(flagCheckFSFilesConsistensy)},
"FailFast": {strconv.FormatBool(flagCheckFSFailFast)},
},
})
if err != nil {
return err
}
hasLogs := false
scanner := bufio.NewScanner(res.Body)
buf := make([]byte, 512*1024) // The default buffer can be too short for some lines
scanner.Buffer(buf, len(buf))
for scanner.Scan() {
hasLogs = true
fmt.Println(string(scanner.Bytes()))
}
if err := scanner.Err(); err != nil {
_ = res.Body.Close()
return err
}
if hasLogs {
// Needs to handle manually the body close because os.Exit bypass all the
// defer functions.
_ = res.Body.Close()
os.Exit(1)
}
_ = res.Body.Close()
return nil
}
var checkTriggers = &cobra.Command{
Use: "triggers <domain>",
Short: "Check the triggers",
Long: `
This command checks that the instance doesn't have duplicate triggers: several
triggers of the same type, for the same worker, and with the same arguments.
`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Usage()
}
domain := args[0]
ac := newAdminClient()
res, err := ac.Req(&request.Options{
Method: "POST",
Path: "/instances/" + url.PathEscape(domain) + "/checks/triggers",
})
if err != nil {
return err
}
var result []map[string]interface{}
err = json.NewDecoder(res.Body).Decode(&result)
if err != nil {
return err
}
if len(result) > 0 {
for _, r := range result {
j, _ := json.Marshal(r)
fmt.Fprintf(os.Stdout, "%s\n", j)
}
os.Exit(1)
}
return nil
},
}
var checkSharedCmd = &cobra.Command{
Use: "shared <domain>",
Short: "Check the io.cozy.shared documents",
Long: `
The io.cozy.shared documents have a tree of revisions. This command will check
that all revisions in this tree are either the root or their parent have a
generation smaller than their generation.
`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Usage()
}
domain := args[0]
ac := newAdminClient()
res, err := ac.Req(&request.Options{
Method: "POST",
Path: "/instances/" + url.PathEscape(domain) + "/checks/shared",
})
if err != nil {
return err
}
var result []map[string]interface{}
err = json.NewDecoder(res.Body).Decode(&result)
if err != nil {
return err
}
if len(result) > 0 {
for _, r := range result {
j, _ := json.Marshal(r)
fmt.Fprintf(os.Stdout, "%s\n", j)
}
os.Exit(1)
}
return nil
},
}
var checkSharingsCmd = &cobra.Command{
Use: "sharings <domain>",
Short: "Check the io.cozy.sharings documents",
Long: `
This command checks that the io.cozy.sharings have no inconsistencies. It can
be triggers that are missing on an active sharing, or missing credentials for
an active member.
There are 2 steps:
- setup integrity checks that there are nothing wrong in the configuration like
a missing trigger
- files and folders consistency checks that the shared documents are the same
for all members
By default, both operations are done, but you can choose to skip the consistency
check via the flags.
`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Usage()
}
domain := args[0]
ac := newAdminClient()
res, err := ac.Req(&request.Options{
Method: "POST",
Path: "/instances/" + url.PathEscape(domain) + "/checks/sharings",
Queries: url.Values{
"SkipFSConsistency": {strconv.FormatBool(flagCheckSharingsFast)},
},
})
if err != nil {
return err
}
var result []map[string]interface{}
err = json.NewDecoder(res.Body).Decode(&result)
if err != nil {
return err
}
if len(result) > 0 {
for _, r := range result {
j, _ := json.Marshal(r)
fmt.Fprintf(os.Stdout, "%s\n", j)
}
os.Exit(1)
}
return nil
},
}
func init() {
checkCmdGroup.AddCommand(checkFSCmd)
checkCmdGroup.AddCommand(checkTriggers)
checkCmdGroup.AddCommand(checkSharedCmd)
checkCmdGroup.AddCommand(checkSharingsCmd)
checkFSCmd.Flags().BoolVar(&flagCheckFSIndexIntegrity, "index-integrity", false, "Check the index integrity only")
checkFSCmd.Flags().BoolVar(&flagCheckFSFilesConsistensy, "files-consistency", false, "Check the files consistency only (between CouchDB and Swift)")
checkFSCmd.Flags().BoolVar(&flagCheckFSFailFast, "fail-fast", false, "Stop the FSCK on the first error")
checkSharingsCmd.Flags().BoolVar(&flagCheckSharingsFast, "fast", false, "Skip the sharings FS consistency check")
RootCmd.AddCommand(checkCmdGroup)
}