blob: 14ab1190ed9885edf98be32da58228db117b48b8 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2016 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
15package membership
16
17import (
18 "encoding/json"
19 "fmt"
20 "path"
21
22 "go.etcd.io/etcd/etcdserver/api/v2store"
23 "go.etcd.io/etcd/mvcc/backend"
24 "go.etcd.io/etcd/pkg/types"
25
26 "github.com/coreos/go-semver/semver"
27)
28
29const (
30 attributesSuffix = "attributes"
31 raftAttributesSuffix = "raftAttributes"
32
33 // the prefix for stroing membership related information in store provided by store pkg.
34 storePrefix = "/0"
35)
36
37var (
38 membersBucketName = []byte("members")
39 membersRemovedBucketName = []byte("members_removed")
40 clusterBucketName = []byte("cluster")
41
42 StoreMembersPrefix = path.Join(storePrefix, "members")
43 storeRemovedMembersPrefix = path.Join(storePrefix, "removed_members")
44)
45
46func mustSaveMemberToBackend(be backend.Backend, m *Member) {
47 mkey := backendMemberKey(m.ID)
48 mvalue, err := json.Marshal(m)
49 if err != nil {
50 plog.Panicf("marshal raftAttributes should never fail: %v", err)
51 }
52
53 tx := be.BatchTx()
54 tx.Lock()
55 tx.UnsafePut(membersBucketName, mkey, mvalue)
56 tx.Unlock()
57}
58
59func mustDeleteMemberFromBackend(be backend.Backend, id types.ID) {
60 mkey := backendMemberKey(id)
61
62 tx := be.BatchTx()
63 tx.Lock()
64 tx.UnsafeDelete(membersBucketName, mkey)
65 tx.UnsafePut(membersRemovedBucketName, mkey, []byte("removed"))
66 tx.Unlock()
67}
68
69func mustSaveClusterVersionToBackend(be backend.Backend, ver *semver.Version) {
70 ckey := backendClusterVersionKey()
71
72 tx := be.BatchTx()
73 tx.Lock()
74 defer tx.Unlock()
75 tx.UnsafePut(clusterBucketName, ckey, []byte(ver.String()))
76}
77
78func mustSaveMemberToStore(s v2store.Store, m *Member) {
79 b, err := json.Marshal(m.RaftAttributes)
80 if err != nil {
81 plog.Panicf("marshal raftAttributes should never fail: %v", err)
82 }
83 p := path.Join(MemberStoreKey(m.ID), raftAttributesSuffix)
84 if _, err := s.Create(p, false, string(b), false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}); err != nil {
85 plog.Panicf("create raftAttributes should never fail: %v", err)
86 }
87}
88
89func mustDeleteMemberFromStore(s v2store.Store, id types.ID) {
90 if _, err := s.Delete(MemberStoreKey(id), true, true); err != nil {
91 plog.Panicf("delete member should never fail: %v", err)
92 }
93 if _, err := s.Create(RemovedMemberStoreKey(id), false, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}); err != nil {
94 plog.Panicf("create removedMember should never fail: %v", err)
95 }
96}
97
98func mustUpdateMemberInStore(s v2store.Store, m *Member) {
99 b, err := json.Marshal(m.RaftAttributes)
100 if err != nil {
101 plog.Panicf("marshal raftAttributes should never fail: %v", err)
102 }
103 p := path.Join(MemberStoreKey(m.ID), raftAttributesSuffix)
104 if _, err := s.Update(p, string(b), v2store.TTLOptionSet{ExpireTime: v2store.Permanent}); err != nil {
105 plog.Panicf("update raftAttributes should never fail: %v", err)
106 }
107}
108
109func mustUpdateMemberAttrInStore(s v2store.Store, m *Member) {
110 b, err := json.Marshal(m.Attributes)
111 if err != nil {
112 plog.Panicf("marshal raftAttributes should never fail: %v", err)
113 }
114 p := path.Join(MemberStoreKey(m.ID), attributesSuffix)
115 if _, err := s.Set(p, false, string(b), v2store.TTLOptionSet{ExpireTime: v2store.Permanent}); err != nil {
116 plog.Panicf("update raftAttributes should never fail: %v", err)
117 }
118}
119
120func mustSaveClusterVersionToStore(s v2store.Store, ver *semver.Version) {
121 if _, err := s.Set(StoreClusterVersionKey(), false, ver.String(), v2store.TTLOptionSet{ExpireTime: v2store.Permanent}); err != nil {
122 plog.Panicf("save cluster version should never fail: %v", err)
123 }
124}
125
126// nodeToMember builds member from a key value node.
127// the child nodes of the given node MUST be sorted by key.
128func nodeToMember(n *v2store.NodeExtern) (*Member, error) {
129 m := &Member{ID: MustParseMemberIDFromKey(n.Key)}
130 attrs := make(map[string][]byte)
131 raftAttrKey := path.Join(n.Key, raftAttributesSuffix)
132 attrKey := path.Join(n.Key, attributesSuffix)
133 for _, nn := range n.Nodes {
134 if nn.Key != raftAttrKey && nn.Key != attrKey {
135 return nil, fmt.Errorf("unknown key %q", nn.Key)
136 }
137 attrs[nn.Key] = []byte(*nn.Value)
138 }
139 if data := attrs[raftAttrKey]; data != nil {
140 if err := json.Unmarshal(data, &m.RaftAttributes); err != nil {
141 return nil, fmt.Errorf("unmarshal raftAttributes error: %v", err)
142 }
143 } else {
144 return nil, fmt.Errorf("raftAttributes key doesn't exist")
145 }
146 if data := attrs[attrKey]; data != nil {
147 if err := json.Unmarshal(data, &m.Attributes); err != nil {
148 return m, fmt.Errorf("unmarshal attributes error: %v", err)
149 }
150 }
151 return m, nil
152}
153
154func backendMemberKey(id types.ID) []byte {
155 return []byte(id.String())
156}
157
158func backendClusterVersionKey() []byte {
159 return []byte("clusterVersion")
160}
161
162func mustCreateBackendBuckets(be backend.Backend) {
163 tx := be.BatchTx()
164 tx.Lock()
165 defer tx.Unlock()
166 tx.UnsafeCreateBucket(membersBucketName)
167 tx.UnsafeCreateBucket(membersRemovedBucketName)
168 tx.UnsafeCreateBucket(clusterBucketName)
169}
170
171func MemberStoreKey(id types.ID) string {
172 return path.Join(StoreMembersPrefix, id.String())
173}
174
175func StoreClusterVersionKey() string {
176 return path.Join(storePrefix, "version")
177}
178
179func MemberAttributesStorePath(id types.ID) string {
180 return path.Join(MemberStoreKey(id), attributesSuffix)
181}
182
183func MustParseMemberIDFromKey(key string) types.ID {
184 id, err := types.IDFromString(path.Base(key))
185 if err != nil {
186 plog.Panicf("unexpected parse member id error: %v", err)
187 }
188 return id
189}
190
191func RemovedMemberStoreKey(id types.ID) string {
192 return path.Join(storeRemovedMembersPrefix, id.String())
193}