mock_registry.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright 2015 flannel 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 subnet
  15. import (
  16. "fmt"
  17. "path"
  18. "sort"
  19. "strings"
  20. "time"
  21. etcd "github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/etcd/client"
  22. "github.com/coreos/flannel/Godeps/_workspace/src/golang.org/x/net/context"
  23. )
  24. type MockSubnetRegistry struct {
  25. networks map[string]*etcd.Node
  26. events chan *etcd.Response
  27. index uint64
  28. ttl time.Duration
  29. }
  30. const networkKeyPrefix = "/coreos.com/network"
  31. func NewMockRegistry(ttlOverride time.Duration, network, config string, initialSubnets []*etcd.Node) *MockSubnetRegistry {
  32. index := uint64(0)
  33. node := &etcd.Node{Key: normalizeNetKey(network), Value: config, ModifiedIndex: 0, Nodes: make([]*etcd.Node, 0, 20)}
  34. for _, n := range initialSubnets {
  35. if n.ModifiedIndex > index {
  36. index = n.ModifiedIndex
  37. }
  38. node.Nodes = append(node.Nodes, n)
  39. }
  40. msr := &MockSubnetRegistry{
  41. events: make(chan *etcd.Response, 1000),
  42. index: index + 1,
  43. ttl: ttlOverride,
  44. }
  45. msr.networks = make(map[string]*etcd.Node)
  46. msr.networks[network] = node
  47. return msr
  48. }
  49. func (msr *MockSubnetRegistry) getNetworkConfig(ctx context.Context, network string) (*etcd.Response, error) {
  50. return &etcd.Response{
  51. Index: msr.index,
  52. Node: msr.networks[network],
  53. }, nil
  54. }
  55. func (msr *MockSubnetRegistry) setConfig(network, config string) error {
  56. n, ok := msr.networks[network]
  57. if !ok {
  58. return fmt.Errorf("Network %s not found", network)
  59. }
  60. n.Value = config
  61. return nil
  62. }
  63. func (msr *MockSubnetRegistry) getSubnets(ctx context.Context, network string) (*etcd.Response, error) {
  64. n, ok := msr.networks[network]
  65. if !ok {
  66. return nil, fmt.Errorf("Network %s not found", network)
  67. }
  68. return &etcd.Response{
  69. Node: n,
  70. Index: msr.index,
  71. }, nil
  72. }
  73. func (msr *MockSubnetRegistry) createSubnet(ctx context.Context, network, sn, data string, ttl time.Duration) (*etcd.Response, error) {
  74. n, ok := msr.networks[network]
  75. if !ok {
  76. return nil, fmt.Errorf("Network %s not found", network)
  77. }
  78. msr.index += 1
  79. if msr.ttl > 0 {
  80. ttl = msr.ttl
  81. }
  82. exp := time.Now().Add(ttl)
  83. node := &etcd.Node{
  84. Key: sn,
  85. Value: data,
  86. ModifiedIndex: msr.index,
  87. Expiration: &exp,
  88. }
  89. n.Nodes = append(n.Nodes, node)
  90. msr.events <- &etcd.Response{
  91. Action: "add",
  92. Node: node,
  93. }
  94. return &etcd.Response{
  95. Node: node,
  96. Index: msr.index,
  97. }, nil
  98. }
  99. func (msr *MockSubnetRegistry) updateSubnet(ctx context.Context, network, sn, data string, ttl time.Duration) (*etcd.Response, error) {
  100. n, ok := msr.networks[network]
  101. if !ok {
  102. return nil, fmt.Errorf("Network %s not found", network)
  103. }
  104. msr.index += 1
  105. exp := time.Now().Add(ttl)
  106. for _, sub := range n.Nodes {
  107. if sub.Key == sn {
  108. sub.Value = data
  109. sub.ModifiedIndex = msr.index
  110. sub.Expiration = &exp
  111. msr.events <- &etcd.Response{
  112. Action: "add",
  113. Node: sub,
  114. }
  115. return &etcd.Response{
  116. Node: sub,
  117. Index: msr.index,
  118. }, nil
  119. }
  120. }
  121. return nil, fmt.Errorf("Subnet not found")
  122. }
  123. func (msr *MockSubnetRegistry) deleteSubnet(ctx context.Context, network, sn string) (*etcd.Response, error) {
  124. n, ok := msr.networks[network]
  125. if !ok {
  126. return nil, fmt.Errorf("Network %s not found", network)
  127. }
  128. msr.index += 1
  129. for i, sub := range n.Nodes {
  130. if sub.Key == sn {
  131. n.Nodes[i] = n.Nodes[len(n.Nodes)-1]
  132. n.Nodes = n.Nodes[:len(n.Nodes)-1]
  133. sub.ModifiedIndex = msr.index
  134. msr.events <- &etcd.Response{
  135. Action: "delete",
  136. Node: sub,
  137. }
  138. return &etcd.Response{
  139. Node: sub,
  140. Index: msr.index,
  141. }, nil
  142. }
  143. }
  144. return nil, fmt.Errorf("Subnet not found")
  145. }
  146. func (msr *MockSubnetRegistry) watch(ctx context.Context, network string, since uint64) (*etcd.Response, error) {
  147. for {
  148. if since < msr.index {
  149. return nil, etcd.Error{
  150. Code: etcd.ErrorCodeEventIndexCleared,
  151. Cause: "out of date",
  152. Message: "cursor is out of date",
  153. Index: msr.index,
  154. }
  155. }
  156. select {
  157. case <-ctx.Done():
  158. return nil, ctx.Err()
  159. case r := <-msr.events:
  160. if r.Node.ModifiedIndex <= since {
  161. continue
  162. }
  163. return r, nil
  164. }
  165. }
  166. }
  167. func (msr *MockSubnetRegistry) hasSubnet(network, sn string) bool {
  168. n, ok := msr.networks[network]
  169. if !ok {
  170. return false
  171. }
  172. for _, sub := range n.Nodes {
  173. if sub.Key == sn {
  174. return true
  175. }
  176. }
  177. return false
  178. }
  179. func (msr *MockSubnetRegistry) expireSubnet(network, sn string) {
  180. n, ok := msr.networks[network]
  181. if !ok {
  182. return
  183. }
  184. for i, sub := range n.Nodes {
  185. if sub.Key == sn {
  186. msr.index += 1
  187. n.Nodes[i] = n.Nodes[len(n.Nodes)-1]
  188. n.Nodes = n.Nodes[:len(n.Nodes)-2]
  189. sub.ModifiedIndex = msr.index
  190. msr.events <- &etcd.Response{
  191. Action: "expire",
  192. Node: sub,
  193. }
  194. return
  195. }
  196. }
  197. }
  198. func configKeyToNetworkKey(configKey string) string {
  199. if !strings.HasSuffix(configKey, "/config") {
  200. return ""
  201. }
  202. return strings.TrimSuffix(configKey, "/config")
  203. }
  204. func (msr *MockSubnetRegistry) getNetworks(ctx context.Context) (*etcd.Response, error) {
  205. var keys []string
  206. for k := range msr.networks {
  207. keys = append(keys, k)
  208. }
  209. sort.Strings(keys)
  210. // mimic etcd by returning a multi-level response where each top-level
  211. // node is a network node, and each network node has a single child
  212. // 'config' node. eg:
  213. //
  214. // /coreos.com/network
  215. // /coreos.com/network/blue
  216. // /coreos.com/network/blue/config
  217. // /coreos.com/network/red
  218. // /coreos.com/network/red/config
  219. //
  220. toplevel := &etcd.Node{Key: networkKeyPrefix, Value: "", ModifiedIndex: msr.index, Nodes: make([]*etcd.Node, 0, len(keys))}
  221. for _, k := range keys {
  222. netKey := configKeyToNetworkKey(msr.networks[k].Key)
  223. if netKey == "" {
  224. continue
  225. }
  226. network := &etcd.Node{
  227. Key: netKey,
  228. Value: "",
  229. ModifiedIndex: msr.index,
  230. Nodes: []*etcd.Node{msr.networks[k]},
  231. }
  232. toplevel.Nodes = append(toplevel.Nodes, network)
  233. }
  234. return &etcd.Response{
  235. Node: toplevel,
  236. Index: msr.index,
  237. }, nil
  238. }
  239. func (msr *MockSubnetRegistry) getNetwork(ctx context.Context, network string) (*etcd.Response, error) {
  240. n, ok := msr.networks[network]
  241. if !ok {
  242. return nil, fmt.Errorf("Network %s not found", network)
  243. }
  244. return &etcd.Response{
  245. Node: n,
  246. Index: msr.index,
  247. }, nil
  248. }
  249. func (msr *MockSubnetRegistry) CreateNetwork(ctx context.Context, network, config string) (*etcd.Response, error) {
  250. _, ok := msr.networks[network]
  251. if ok {
  252. return nil, fmt.Errorf("Network %s already exists", network)
  253. }
  254. msr.index += 1
  255. node := &etcd.Node{
  256. Key: normalizeNetKey(network),
  257. Value: config,
  258. ModifiedIndex: msr.index,
  259. }
  260. msr.networks[network] = node
  261. msr.events <- &etcd.Response{
  262. Action: "add",
  263. Node: node,
  264. }
  265. return &etcd.Response{
  266. Node: node,
  267. Index: msr.index,
  268. }, nil
  269. }
  270. func (msr *MockSubnetRegistry) DeleteNetwork(ctx context.Context, network string) (*etcd.Response, error) {
  271. n, ok := msr.networks[network]
  272. if !ok {
  273. return nil, fmt.Errorf("Network %s not found", network)
  274. }
  275. msr.index += 1
  276. n.ModifiedIndex = msr.index
  277. delete(msr.networks, network)
  278. msr.events <- &etcd.Response{
  279. Action: "delete",
  280. Node: n,
  281. }
  282. return &etcd.Response{
  283. Node: n,
  284. Index: msr.index,
  285. }, nil
  286. }
  287. func normalizeNetKey(key string) string {
  288. match := networkKeyPrefix
  289. newKey := key
  290. if !strings.HasPrefix(newKey, match+"/") {
  291. newKey = path.Join(match, key)
  292. }
  293. if !strings.HasSuffix(newKey, "/config") {
  294. newKey = path.Join(newKey, "config")
  295. }
  296. return newKey
  297. }