etcd-dump-log_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright 2018 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package main
  15. import (
  16. "bytes"
  17. "io/ioutil"
  18. "os"
  19. "os/exec"
  20. "path"
  21. "path/filepath"
  22. "strings"
  23. "testing"
  24. "go.etcd.io/etcd/auth/authpb"
  25. "go.etcd.io/etcd/etcdserver/etcdserverpb"
  26. "go.etcd.io/etcd/pkg/fileutil"
  27. "go.etcd.io/etcd/pkg/pbutil"
  28. "go.etcd.io/etcd/raft/raftpb"
  29. "go.etcd.io/etcd/wal"
  30. "go.uber.org/zap"
  31. )
  32. func TestEtcdDumpLogEntryType(t *testing.T) {
  33. // directory where the command is
  34. binDir, err := os.Getwd()
  35. if err != nil {
  36. t.Fatal(err)
  37. }
  38. dumpLogsBinary := path.Join(binDir + "/etcd-dump-logs")
  39. if !fileutil.Exist(dumpLogsBinary) {
  40. t.Skipf("%q does not exist", dumpLogsBinary)
  41. }
  42. decoder_correctoutputformat := filepath.Join(binDir, "/testdecoder/decoder_correctoutputformat.sh")
  43. decoder_wrongoutputformat := filepath.Join(binDir, "/testdecoder/decoder_wrongoutputformat.sh")
  44. p, err := ioutil.TempDir(os.TempDir(), "etcddumplogstest")
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. defer os.RemoveAll(p)
  49. memberdir := filepath.Join(p, "member")
  50. err = os.Mkdir(memberdir, 0744)
  51. if err != nil {
  52. t.Fatal(err)
  53. }
  54. waldir := walDir(p)
  55. snapdir := snapDir(p)
  56. w, err := wal.Create(zap.NewExample(), waldir, nil)
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. err = os.Mkdir(snapdir, 0744)
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. ents := make([]raftpb.Entry, 0)
  65. // append entries into wal log
  66. appendConfigChangeEnts(&ents)
  67. appendNormalRequestEnts(&ents)
  68. appendNormalIRREnts(&ents)
  69. appendUnknownNormalEnts(&ents)
  70. // force commit newly appended entries
  71. err = w.Save(raftpb.HardState{}, ents)
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. w.Close()
  76. argtests := []struct {
  77. name string
  78. args []string
  79. fileExpected string
  80. }{
  81. {"no entry-type", []string{p}, "expectedoutput/listAll.output"},
  82. {"confchange entry-type", []string{"-entry-type", "ConfigChange", p}, "expectedoutput/listConfigChange.output"},
  83. {"normal entry-type", []string{"-entry-type", "Normal", p}, "expectedoutput/listNormal.output"},
  84. {"request entry-type", []string{"-entry-type", "Request", p}, "expectedoutput/listRequest.output"},
  85. {"internalRaftRequest entry-type", []string{"-entry-type", "InternalRaftRequest", p}, "expectedoutput/listInternalRaftRequest.output"},
  86. {"range entry-type", []string{"-entry-type", "IRRRange", p}, "expectedoutput/listIRRRange.output"},
  87. {"put entry-type", []string{"-entry-type", "IRRPut", p}, "expectedoutput/listIRRPut.output"},
  88. {"del entry-type", []string{"-entry-type", "IRRDeleteRange", p}, "expectedoutput/listIRRDeleteRange.output"},
  89. {"txn entry-type", []string{"-entry-type", "IRRTxn", p}, "expectedoutput/listIRRTxn.output"},
  90. {"compaction entry-type", []string{"-entry-type", "IRRCompaction", p}, "expectedoutput/listIRRCompaction.output"},
  91. {"lease grant entry-type", []string{"-entry-type", "IRRLeaseGrant", p}, "expectedoutput/listIRRLeaseGrant.output"},
  92. {"lease revoke entry-type", []string{"-entry-type", "IRRLeaseRevoke", p}, "expectedoutput/listIRRLeaseRevoke.output"},
  93. {"confchange and txn entry-type", []string{"-entry-type", "ConfigChange,IRRCompaction", p}, "expectedoutput/listConfigChangeIRRCompaction.output"},
  94. {"decoder_correctoutputformat", []string{"-stream-decoder", decoder_correctoutputformat, p}, "expectedoutput/decoder_correctoutputformat.output"},
  95. {"decoder_wrongoutputformat", []string{"-stream-decoder", decoder_wrongoutputformat, p}, "expectedoutput/decoder_wrongoutputformat.output"},
  96. }
  97. for _, argtest := range argtests {
  98. t.Run(argtest.name, func(t *testing.T) {
  99. cmd := exec.Command(dumpLogsBinary, argtest.args...)
  100. actual, err := cmd.CombinedOutput()
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. expected, err := ioutil.ReadFile(path.Join(binDir, argtest.fileExpected))
  105. if err != nil {
  106. t.Fatal(err)
  107. }
  108. if !bytes.Equal(actual, expected) {
  109. t.Errorf(`Got input of length %d, wanted input of length %d
  110. ==== BEGIN RECEIVED FILE ====
  111. %s
  112. ==== END RECEIVED FILE ====
  113. ==== BEGIN EXPECTED FILE ====
  114. %s
  115. ==== END EXPECTED FILE ====
  116. `, len(actual), len(expected), actual, expected)
  117. }
  118. })
  119. }
  120. }
  121. func appendConfigChangeEnts(ents *[]raftpb.Entry) {
  122. configChangeData := []raftpb.ConfChange{
  123. {ID: 1, Type: raftpb.ConfChangeAddNode, NodeID: 2, Context: []byte("")},
  124. {ID: 2, Type: raftpb.ConfChangeRemoveNode, NodeID: 2, Context: []byte("")},
  125. {ID: 3, Type: raftpb.ConfChangeUpdateNode, NodeID: 2, Context: []byte("")},
  126. {ID: 4, Type: raftpb.ConfChangeAddLearnerNode, NodeID: 3, Context: []byte("")},
  127. }
  128. configChangeEntries := []raftpb.Entry{
  129. {Term: 1, Index: 1, Type: raftpb.EntryConfChange, Data: pbutil.MustMarshal(&configChangeData[0])},
  130. {Term: 2, Index: 2, Type: raftpb.EntryConfChange, Data: pbutil.MustMarshal(&configChangeData[1])},
  131. {Term: 2, Index: 3, Type: raftpb.EntryConfChange, Data: pbutil.MustMarshal(&configChangeData[2])},
  132. {Term: 2, Index: 4, Type: raftpb.EntryConfChange, Data: pbutil.MustMarshal(&configChangeData[3])},
  133. }
  134. *ents = append(*ents, configChangeEntries...)
  135. }
  136. func appendNormalRequestEnts(ents *[]raftpb.Entry) {
  137. a := true
  138. b := false
  139. requests := []etcdserverpb.Request{
  140. {ID: 0, Method: "", Path: "/path0", Val: "{\"hey\":\"ho\",\"hi\":[\"yo\"]}", Dir: true, PrevValue: "", PrevIndex: 0, PrevExist: &b, Expiration: 9, Wait: false, Since: 1, Recursive: false, Sorted: false, Quorum: false, Time: 1, Stream: false, Refresh: &b},
  141. {ID: 1, Method: "QGET", Path: "/path1", Val: "{\"0\":\"1\",\"2\":[\"3\"]}", Dir: false, PrevValue: "", PrevIndex: 0, PrevExist: &b, Expiration: 9, Wait: false, Since: 1, Recursive: false, Sorted: false, Quorum: false, Time: 1, Stream: false, Refresh: &b},
  142. {ID: 2, Method: "SYNC", Path: "/path2", Val: "{\"0\":\"1\",\"2\":[\"3\"]}", Dir: false, PrevValue: "", PrevIndex: 0, PrevExist: &b, Expiration: 2, Wait: false, Since: 1, Recursive: false, Sorted: false, Quorum: false, Time: 1, Stream: false, Refresh: &b},
  143. {ID: 3, Method: "DELETE", Path: "/path3", Val: "{\"hey\":\"ho\",\"hi\":[\"yo\"]}", Dir: false, PrevValue: "", PrevIndex: 0, PrevExist: &a, Expiration: 2, Wait: false, Since: 1, Recursive: false, Sorted: false, Quorum: false, Time: 1, Stream: false, Refresh: &b},
  144. {ID: 4, Method: "RANDOM", Path: "/path4/superlong" + strings.Repeat("/path", 30), Val: "{\"hey\":\"ho\",\"hi\":[\"yo\"]}", Dir: false, PrevValue: "", PrevIndex: 0, PrevExist: &b, Expiration: 2, Wait: false, Since: 1, Recursive: false, Sorted: false, Quorum: false, Time: 1, Stream: false, Refresh: &b},
  145. }
  146. for i, request := range requests {
  147. var currentry raftpb.Entry
  148. currentry.Term = 3
  149. currentry.Index = uint64(i + 5)
  150. currentry.Type = raftpb.EntryNormal
  151. currentry.Data = pbutil.MustMarshal(&request)
  152. *ents = append(*ents, currentry)
  153. }
  154. }
  155. func appendNormalIRREnts(ents *[]raftpb.Entry) {
  156. irrrange := &etcdserverpb.RangeRequest{Key: []byte("1"), RangeEnd: []byte("hi"), Limit: 6, Revision: 1, SortOrder: 1, SortTarget: 0, Serializable: false, KeysOnly: false, CountOnly: false, MinModRevision: 0, MaxModRevision: 20000, MinCreateRevision: 0, MaxCreateRevision: 20000}
  157. irrput := &etcdserverpb.PutRequest{Key: []byte("foo1"), Value: []byte("bar1"), Lease: 1, PrevKv: false, IgnoreValue: false, IgnoreLease: true}
  158. irrdeleterange := &etcdserverpb.DeleteRangeRequest{Key: []byte("0"), RangeEnd: []byte("9"), PrevKv: true}
  159. delInRangeReq := &etcdserverpb.RequestOp{Request: &etcdserverpb.RequestOp_RequestDeleteRange{
  160. RequestDeleteRange: &etcdserverpb.DeleteRangeRequest{
  161. Key: []byte("a"), RangeEnd: []byte("b"),
  162. },
  163. },
  164. }
  165. irrtxn := &etcdserverpb.TxnRequest{Success: []*etcdserverpb.RequestOp{delInRangeReq}, Failure: []*etcdserverpb.RequestOp{delInRangeReq}}
  166. irrcompaction := &etcdserverpb.CompactionRequest{Revision: 0, Physical: true}
  167. irrleasegrant := &etcdserverpb.LeaseGrantRequest{TTL: 1, ID: 1}
  168. irrleaserevoke := &etcdserverpb.LeaseRevokeRequest{ID: 2}
  169. irralarm := &etcdserverpb.AlarmRequest{Action: 3, MemberID: 4, Alarm: 5}
  170. irrauthenable := &etcdserverpb.AuthEnableRequest{}
  171. irrauthdisable := &etcdserverpb.AuthDisableRequest{}
  172. irrauthenticate := &etcdserverpb.InternalAuthenticateRequest{Name: "myname", Password: "password", SimpleToken: "token"}
  173. irrauthuseradd := &etcdserverpb.AuthUserAddRequest{Name: "name1", Password: "pass1", Options: &authpb.UserAddOptions{NoPassword: false}}
  174. irrauthuserdelete := &etcdserverpb.AuthUserDeleteRequest{Name: "name1"}
  175. irrauthuserget := &etcdserverpb.AuthUserGetRequest{Name: "name1"}
  176. irrauthuserchangepassword := &etcdserverpb.AuthUserChangePasswordRequest{Name: "name1", Password: "pass2"}
  177. irrauthusergrantrole := &etcdserverpb.AuthUserGrantRoleRequest{User: "user1", Role: "role1"}
  178. irrauthuserrevokerole := &etcdserverpb.AuthUserRevokeRoleRequest{Name: "user2", Role: "role2"}
  179. irrauthuserlist := &etcdserverpb.AuthUserListRequest{}
  180. irrauthrolelist := &etcdserverpb.AuthRoleListRequest{}
  181. irrauthroleadd := &etcdserverpb.AuthRoleAddRequest{Name: "role2"}
  182. irrauthroledelete := &etcdserverpb.AuthRoleDeleteRequest{Role: "role1"}
  183. irrauthroleget := &etcdserverpb.AuthRoleGetRequest{Role: "role3"}
  184. perm := &authpb.Permission{
  185. PermType: authpb.WRITE,
  186. Key: []byte("Keys"),
  187. RangeEnd: []byte("RangeEnd"),
  188. }
  189. irrauthrolegrantpermission := &etcdserverpb.AuthRoleGrantPermissionRequest{Name: "role3", Perm: perm}
  190. irrauthrolerevokepermission := &etcdserverpb.AuthRoleRevokePermissionRequest{Role: "role3", Key: []byte("key"), RangeEnd: []byte("rangeend")}
  191. irrs := []etcdserverpb.InternalRaftRequest{
  192. {ID: 5, Range: irrrange},
  193. {ID: 6, Put: irrput},
  194. {ID: 7, DeleteRange: irrdeleterange},
  195. {ID: 8, Txn: irrtxn},
  196. {ID: 9, Compaction: irrcompaction},
  197. {ID: 10, LeaseGrant: irrleasegrant},
  198. {ID: 11, LeaseRevoke: irrleaserevoke},
  199. {ID: 12, Alarm: irralarm},
  200. {ID: 13, AuthEnable: irrauthenable},
  201. {ID: 14, AuthDisable: irrauthdisable},
  202. {ID: 15, Authenticate: irrauthenticate},
  203. {ID: 16, AuthUserAdd: irrauthuseradd},
  204. {ID: 17, AuthUserDelete: irrauthuserdelete},
  205. {ID: 18, AuthUserGet: irrauthuserget},
  206. {ID: 19, AuthUserChangePassword: irrauthuserchangepassword},
  207. {ID: 20, AuthUserGrantRole: irrauthusergrantrole},
  208. {ID: 21, AuthUserRevokeRole: irrauthuserrevokerole},
  209. {ID: 22, AuthUserList: irrauthuserlist},
  210. {ID: 23, AuthRoleList: irrauthrolelist},
  211. {ID: 24, AuthRoleAdd: irrauthroleadd},
  212. {ID: 25, AuthRoleDelete: irrauthroledelete},
  213. {ID: 26, AuthRoleGet: irrauthroleget},
  214. {ID: 27, AuthRoleGrantPermission: irrauthrolegrantpermission},
  215. {ID: 28, AuthRoleRevokePermission: irrauthrolerevokepermission},
  216. }
  217. for i, irr := range irrs {
  218. var currentry raftpb.Entry
  219. currentry.Term = uint64(i + 4)
  220. currentry.Index = uint64(i + 10)
  221. currentry.Type = raftpb.EntryNormal
  222. currentry.Data = pbutil.MustMarshal(&irr)
  223. *ents = append(*ents, currentry)
  224. }
  225. }
  226. func appendUnknownNormalEnts(ents *[]raftpb.Entry) {
  227. var currentry raftpb.Entry
  228. currentry.Term = 27
  229. currentry.Index = 34
  230. currentry.Type = raftpb.EntryNormal
  231. currentry.Data = []byte("?")
  232. *ents = append(*ents, currentry)
  233. }