leo_manager_client 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +178 -0
- data/README.md +24 -0
- data/Rakefile +33 -0
- data/leo_manager_client.gemspec +18 -0
- data/lib/leo_manager_client.rb +418 -0
- data/lib/leo_manager_models.rb +275 -0
- data/spec/dummy_tcp_server.rb +162 -0
- data/spec/leo_manager_client_spec.rb +281 -0
- metadata +57 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
# ======================================================================
|
2
|
+
#
|
3
|
+
# LeoFS Manager Client
|
4
|
+
#
|
5
|
+
# Copyright (c) 2012 Rakuten, Inc.
|
6
|
+
#
|
7
|
+
# This file is provided to you under the Apache License,
|
8
|
+
# Version 2.0 (the "License"); you may not use this file
|
9
|
+
# except in compliance with the License. You may obtain
|
10
|
+
# a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
#
|
21
|
+
# ======================================================================
|
22
|
+
module LeoManager
|
23
|
+
|
24
|
+
# ==========================
|
25
|
+
# System Information Model
|
26
|
+
# ==========================
|
27
|
+
class Status
|
28
|
+
# Node
|
29
|
+
attr_reader :node_stat
|
30
|
+
# System
|
31
|
+
attr_reader :system_info
|
32
|
+
# Array of Node
|
33
|
+
attr_reader :node_list
|
34
|
+
|
35
|
+
def initialize(h)
|
36
|
+
@node_stat = NodeStat.new(h[:node_stat]) if h.has_key?(:node_stat)
|
37
|
+
@system_info = System.new(h[:system_info]) if h.has_key?(:system_info)
|
38
|
+
@node_list = h[:node_list].map {|node| Node.new(node) } if h.has_key?(:node_list)
|
39
|
+
end
|
40
|
+
|
41
|
+
class System
|
42
|
+
attr_reader :version, :ring_size, :ring_cur, :ring_prev
|
43
|
+
|
44
|
+
# number of replicas
|
45
|
+
attr_reader :n
|
46
|
+
# number of replicas needed for a successful READ operation
|
47
|
+
attr_reader :r
|
48
|
+
# number of replicas needed for a successful WRITE operation
|
49
|
+
attr_reader :w
|
50
|
+
# number of replicas needed for a successful DELETE operation
|
51
|
+
attr_reader :d
|
52
|
+
|
53
|
+
def initialize(h)
|
54
|
+
@version = h[:version]
|
55
|
+
@n = Integer(h[:n])
|
56
|
+
@r = Integer(h[:r])
|
57
|
+
@w = Integer(h[:w])
|
58
|
+
@d = Integer(h[:d])
|
59
|
+
@ring_size = Integer(h[:ring_size])
|
60
|
+
#XXX: leo_manager returns ring_hash_(cur|prev) as decimal (not hex)
|
61
|
+
@ring_cur = Integer(h[:ring_hash_cur]).to_s(16)
|
62
|
+
@ring_prev = Integer(h[:ring_hash_prev]).to_s(16)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Node Status Model
|
67
|
+
class Node
|
68
|
+
attr_reader :type, :node, :state, :ring_cur, :ring_prev, :when
|
69
|
+
|
70
|
+
def initialize(h)
|
71
|
+
@type = h[:type]
|
72
|
+
@node = h[:node]
|
73
|
+
@when = Time.parse(h[:when])
|
74
|
+
@state = h[:state]
|
75
|
+
#XXX: these are written in hex
|
76
|
+
@ring_cur = h[:ring_cur]
|
77
|
+
@ring_prev = h[:ring_prev]
|
78
|
+
end
|
79
|
+
|
80
|
+
alias joined_at when
|
81
|
+
end
|
82
|
+
|
83
|
+
class NodeStat
|
84
|
+
@@properties = [
|
85
|
+
:version, :log_dir, :ring_cur, :ring_prev, :vm_version,
|
86
|
+
:total_mem_usage, :system_mem_usage, :procs_mem_usage,
|
87
|
+
:ets_mem_usage, :num_of_procs, :limit_of_procs, :thread_pool_size,
|
88
|
+
:replication_msgs, :sync_vnode_msgs, :rebalance_msgs, :kernel_poll
|
89
|
+
]
|
90
|
+
|
91
|
+
attr_reader *@@properties
|
92
|
+
|
93
|
+
def initialize(h)
|
94
|
+
@@properties.each do |property|
|
95
|
+
instance_variable_set("@#{property}", h[property])
|
96
|
+
end
|
97
|
+
@kernel_poll = (h[:kernel_poll] == "true") if h.has_key?(:kernel_poll)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# ==========================
|
103
|
+
# Assigned file info Model
|
104
|
+
# ==========================
|
105
|
+
class AssignedFile
|
106
|
+
attr_reader :node, :vnode_id, :size, :clock, :checksum, :timestamp, :delete, :num_of_chunks
|
107
|
+
|
108
|
+
def initialize(h)
|
109
|
+
@node = h[:node]
|
110
|
+
@vnode_id = h[:vnode_id]
|
111
|
+
@size = h[:size]
|
112
|
+
@clock = h[:clock]
|
113
|
+
@checksum = h[:checksum]
|
114
|
+
timestamp = h[:timestamp]
|
115
|
+
@timestamp = timestamp.empty? ? timestamp : Time.parse(timestamp)
|
116
|
+
@delete = h[:delete] != 0 # bool
|
117
|
+
@num_of_chunks = h[:num_of_chunks]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# ==========================
|
122
|
+
# Storage Status Model
|
123
|
+
# ==========================
|
124
|
+
class StorageStat
|
125
|
+
attr_reader :active_num_of_objects, :total_num_of_objects,
|
126
|
+
:active_size_of_objects, :total_size_of_objects,
|
127
|
+
:ratio_of_active_size,
|
128
|
+
:last_compaction_start, :last_compaction_end
|
129
|
+
|
130
|
+
alias total_of_objects total_num_of_objects # for compatibility
|
131
|
+
|
132
|
+
def initialize(h)
|
133
|
+
@active_num_of_objects = h[:active_num_of_objects]
|
134
|
+
@total_num_of_objects = h[:total_num_of_objects]
|
135
|
+
@active_size_of_objects = h[:active_size_of_objects]
|
136
|
+
@total_size_of_objects = h[:total_size_of_objects]
|
137
|
+
@ratio_of_active_size = h[:ratio_of_active_size]
|
138
|
+
|
139
|
+
last_compaction_start = h[:last_compaction_start]
|
140
|
+
if last_compaction_start == "____-__-__ __:__:__"
|
141
|
+
@last_compaction_start = nil # you have never done compaction
|
142
|
+
else
|
143
|
+
@last_compaction_start = Time.parse(last_compaction_start)
|
144
|
+
end
|
145
|
+
|
146
|
+
last_compaction_end = h[:last_compaction_end]
|
147
|
+
if last_compaction_end == "____-__-__ __:__:__"
|
148
|
+
@last_compaction_end = nil
|
149
|
+
else
|
150
|
+
@last_compaction_end = Time.parse(last_compaction_end)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def file_size
|
155
|
+
warn "property 'file_size' is deprecated"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# ==========================
|
160
|
+
# S3 Credential Model
|
161
|
+
# ==========================
|
162
|
+
class Credential
|
163
|
+
# AWS_ACCESS_KEY_ID
|
164
|
+
attr_reader :access_key_id
|
165
|
+
# AWS_SECRET_ACCESS_KEY
|
166
|
+
attr_reader :secret_access_key
|
167
|
+
|
168
|
+
def initialize(h)
|
169
|
+
@access_key_id = h[:access_key_id]
|
170
|
+
@secret_access_key = h[:secret_access_key]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# ==========================
|
175
|
+
# Login Info Model
|
176
|
+
# ==========================
|
177
|
+
RoleDef = {
|
178
|
+
1 => :general,
|
179
|
+
9 => :admin
|
180
|
+
}
|
181
|
+
RoleDef.default_proc = proc {|_, key| raise "invalid @user_id: #{key}" }
|
182
|
+
RoleDef.freeze
|
183
|
+
|
184
|
+
class LoginInfo
|
185
|
+
attr_reader :id, :role_id, :access_key_id, :secret_key, :created_at
|
186
|
+
|
187
|
+
def initialize(h)
|
188
|
+
h = h[:user]
|
189
|
+
@id = h[:id]
|
190
|
+
@role_id = h[:role_id]
|
191
|
+
@access_key_id = h[:access_key_id]
|
192
|
+
@secret_key = h[:secret_key]
|
193
|
+
@created_at = Time.parse(h[:created_at])
|
194
|
+
end
|
195
|
+
|
196
|
+
def role
|
197
|
+
RoleDef[@role_id]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# ==========================
|
202
|
+
# User Info Model
|
203
|
+
# ==========================
|
204
|
+
class User
|
205
|
+
attr_reader :user_id, :role_id, :access_key_id, :created_at
|
206
|
+
|
207
|
+
def initialize(h)
|
208
|
+
@user_id = h[:user_id]
|
209
|
+
@role_id = h[:role_id]
|
210
|
+
@access_key_id = h[:access_key_id]
|
211
|
+
@created_at = Time.parse(h[:created_at])
|
212
|
+
end
|
213
|
+
|
214
|
+
def role
|
215
|
+
RoleDef[@role_id]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# ==========================
|
220
|
+
# Endpoint Model
|
221
|
+
# ==========================
|
222
|
+
class Endpoint
|
223
|
+
# host of the endpoint
|
224
|
+
attr_reader :endpoint
|
225
|
+
# When the endpoint created at
|
226
|
+
attr_reader :created_at
|
227
|
+
|
228
|
+
def initialize(h)
|
229
|
+
@endpoint = h[:endpoint]
|
230
|
+
@created_at = Time.parse(h[:created_at])
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# ==========================
|
235
|
+
# S3-Bucket Model
|
236
|
+
# ==========================
|
237
|
+
class Bucket
|
238
|
+
# name of bucket
|
239
|
+
attr_reader :name
|
240
|
+
# name of the bucket's owner
|
241
|
+
attr_reader :owner
|
242
|
+
# when the bucket created at
|
243
|
+
attr_reader :created_at
|
244
|
+
|
245
|
+
def initialize(h)
|
246
|
+
@name = h[:bucket]
|
247
|
+
@owner = h[:owner]
|
248
|
+
@created_at = Time.parse(h[:created_at])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# ==========================
|
253
|
+
# Compaction Status Model
|
254
|
+
# ==========================
|
255
|
+
class CompactionStatus
|
256
|
+
attr_reader :status, :last_compaction_start,
|
257
|
+
:total_targets, :num_of_pending_targets,
|
258
|
+
:num_of_ongoing_targets, :num_of_out_of_targets
|
259
|
+
|
260
|
+
def initialize(h)
|
261
|
+
@status = h[:status]
|
262
|
+
@total_targets = h[:total_targets]
|
263
|
+
@num_of_pending_targets = h[:num_of_pending_targets]
|
264
|
+
@num_of_ongoing_targets = h[:num_of_ongoing_targets]
|
265
|
+
@num_of_out_of_targets = h[:num_of_out_of_targets]
|
266
|
+
|
267
|
+
last_compaction_start = h[:last_compaction_start]
|
268
|
+
if last_compaction_start == "____-__-__ __:__:__"
|
269
|
+
@last_compaction_start = nil # you have never done compaction
|
270
|
+
else
|
271
|
+
@last_compaction_start = Time.parse(last_compaction_start)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# ======================================================================
|
2
|
+
#
|
3
|
+
# LeoFS Manager Client
|
4
|
+
#
|
5
|
+
# Copyright (c) 2012 Rakuten, Inc.
|
6
|
+
#
|
7
|
+
# This file is provided to you under the Apache License,
|
8
|
+
# Version 2.0 (the "License"); you may not use this file
|
9
|
+
# except in compliance with the License. You may obtain
|
10
|
+
# a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
#
|
21
|
+
# ======================================================================
|
22
|
+
|
23
|
+
require "socket"
|
24
|
+
|
25
|
+
module Dummy
|
26
|
+
module Response
|
27
|
+
Login = {
|
28
|
+
:user => {
|
29
|
+
:id => "foo",
|
30
|
+
:role_id => 0,
|
31
|
+
:access_key_id => "855d2f9bf21f51b4fd38",
|
32
|
+
:secret_key => "ea6d9540d6385f32d674c925929748e00e0e961a",
|
33
|
+
:created_at => "2012-11-29 17:18:39 +0900"
|
34
|
+
}
|
35
|
+
}.to_json
|
36
|
+
|
37
|
+
Status = {
|
38
|
+
:system_info => {
|
39
|
+
:version => "0.10.1",
|
40
|
+
:n => "1",
|
41
|
+
:r => "1",
|
42
|
+
:w => "1",
|
43
|
+
:d => "1",
|
44
|
+
:ring_size => "128",
|
45
|
+
:ring_hash_cur => "2688134336",
|
46
|
+
:ring_hash_prev => "2688134336"},
|
47
|
+
:node_list => [
|
48
|
+
{
|
49
|
+
:type => "S",
|
50
|
+
:node => "storage_0@127.0.0.1",
|
51
|
+
:state => "running",
|
52
|
+
:ring_cur => "a039acc0",
|
53
|
+
:ring_prev => "a039acc0",
|
54
|
+
:when => "2012-09-21 15:08:22 +0900"
|
55
|
+
}, {
|
56
|
+
:type => "G",
|
57
|
+
:node => "gateway_0@127.0.0.1",
|
58
|
+
:state => "running",
|
59
|
+
:ring_cur => "a039acc0",
|
60
|
+
:ring_prev => "a039acc0",
|
61
|
+
:when => "2012-09-21 15:08:25 +0900"
|
62
|
+
}
|
63
|
+
]
|
64
|
+
}.to_json
|
65
|
+
|
66
|
+
Whereis = {
|
67
|
+
:assigned_info => [
|
68
|
+
{
|
69
|
+
:node => "storage_0@127.0.0.1",
|
70
|
+
:vnode_id => "",
|
71
|
+
:size => "",
|
72
|
+
:clock => "",
|
73
|
+
:checksum => "",
|
74
|
+
:timestamp => "2012-12-07 16:51:08 +0900",
|
75
|
+
:delete => 0,
|
76
|
+
:num_of_chunks => 0
|
77
|
+
}
|
78
|
+
]
|
79
|
+
}.to_json
|
80
|
+
|
81
|
+
StorageStat = {
|
82
|
+
:active_num_of_objects => 0,
|
83
|
+
:total_num_of_objects => 0,
|
84
|
+
:active_size_of_objects => 0,
|
85
|
+
:total_size_of_objects => 0,
|
86
|
+
:ratio_of_active_size => 0,
|
87
|
+
:last_compaction_start => "2013-03-13 09:11:04 +0900",
|
88
|
+
:last_compaction_end => "2013-03-13 09:11:04 +0900"
|
89
|
+
}.to_json
|
90
|
+
|
91
|
+
GetEndpoints = {:endpoints => [{:endpoint => "s3.amazonaws.com", :created_at=>"2012-09-21 15:08:11 +0900"},
|
92
|
+
{:endpoint => "localhost", :created_at=>"2012-09-21 15:08:11 +0900"},
|
93
|
+
{:endpoint => "foo", :created_at=>"2012-09-21 18:51:08 +0900"},
|
94
|
+
{:endpoint => "leofs.org", :created_at=>"2012-09-21 15:08:11 +0900"}
|
95
|
+
]}.to_json
|
96
|
+
GetBuckets = {:buckets => [{:bucket => "test",
|
97
|
+
:owner => "test",
|
98
|
+
:created_at => "2012-09-24 15:38:49 +0900"
|
99
|
+
}]}.to_json
|
100
|
+
|
101
|
+
GetUsers = {:users => [{:access_key_id => "05236",
|
102
|
+
:user_id => "_test_leofs_",
|
103
|
+
:role_id => 1,
|
104
|
+
:created_at => "2012-11-20 15:13:20 +0900"}]}.to_json
|
105
|
+
|
106
|
+
CreateUser = {:access_key_id => "xxxxxxxxxxxxxxxxxxxx",
|
107
|
+
:secret_access_key => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}.to_json
|
108
|
+
end
|
109
|
+
|
110
|
+
Argument = "arg" # passed to command which requires some arguments.
|
111
|
+
|
112
|
+
# dummy Manager
|
113
|
+
class Manager
|
114
|
+
def initialize
|
115
|
+
t = Thread.new do
|
116
|
+
TCPServer.open(Host, Port) do |server|
|
117
|
+
loop do
|
118
|
+
begin
|
119
|
+
socket = server.accept
|
120
|
+
while line = socket.readline.split.first
|
121
|
+
response = process_line(line)
|
122
|
+
socket.puts(response)
|
123
|
+
end
|
124
|
+
rescue EOFError
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
nil until t.stop? # wait server start
|
130
|
+
end
|
131
|
+
|
132
|
+
def process_line(line)
|
133
|
+
line.rstrip!
|
134
|
+
begin
|
135
|
+
case line
|
136
|
+
when "login"
|
137
|
+
Response::Login
|
138
|
+
when "status"
|
139
|
+
Response::Status
|
140
|
+
when "get-buckets"
|
141
|
+
Response::GetBuckets
|
142
|
+
when "whereis"
|
143
|
+
Response::Whereis
|
144
|
+
when "get-endpoints"
|
145
|
+
Response::GetEndpoints
|
146
|
+
when "get-buckets"
|
147
|
+
Response::GetBuckets
|
148
|
+
when "get-users"
|
149
|
+
Response::GetUsers
|
150
|
+
when "create-user"
|
151
|
+
Response::CreateUser
|
152
|
+
when /^du/
|
153
|
+
Response::StorageStat
|
154
|
+
else
|
155
|
+
{ :result => line }.to_json
|
156
|
+
end
|
157
|
+
rescue => ex
|
158
|
+
{ :error => ex.message }.to_json
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
# ======================================================================
|
2
|
+
#
|
3
|
+
# LeoFS Manager Client
|
4
|
+
#
|
5
|
+
# Copyright (c) 2012 Rakuten, Inc.
|
6
|
+
#
|
7
|
+
# This file is provided to you under the Apache License,
|
8
|
+
# Version 2.0 (the "License"); you may not use this file
|
9
|
+
# except in compliance with the License. You may obtain
|
10
|
+
# a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
#
|
21
|
+
# ======================================================================
|
22
|
+
|
23
|
+
require "json"
|
24
|
+
require_relative "dummy_tcp_server"
|
25
|
+
require_relative "../lib/leo_manager_client"
|
26
|
+
|
27
|
+
Host = "localhost"
|
28
|
+
Port = 50000
|
29
|
+
|
30
|
+
$DEBUG = false
|
31
|
+
|
32
|
+
# key: api_name, value: num of args
|
33
|
+
NoResultAPIs = {
|
34
|
+
:start => 0,
|
35
|
+
:detach => 1,
|
36
|
+
:rebalance => 0,
|
37
|
+
:purge => 1,
|
38
|
+
:set_endpoint => 1,
|
39
|
+
:del_endpoint => 1,
|
40
|
+
:add_bucket => 2,
|
41
|
+
:delete_bucket => 2
|
42
|
+
}
|
43
|
+
|
44
|
+
include LeoManager
|
45
|
+
|
46
|
+
describe LeoManager do
|
47
|
+
describe StorageStat do
|
48
|
+
shared_examples_for StorageStat do
|
49
|
+
its(:active_num_of_objects) { should == 0 }
|
50
|
+
its(:total_num_of_objects) { should == 0 }
|
51
|
+
its(:active_size_of_objects) { should == 0 }
|
52
|
+
its(:total_size_of_objects) { should == 0 }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "there is no last compaction" do
|
56
|
+
subject do
|
57
|
+
StorageStat.new(:active_num_of_objects => 0,
|
58
|
+
:total_num_of_objects => 0,
|
59
|
+
:active_size_of_objects => 0,
|
60
|
+
:total_size_of_objects => 0,
|
61
|
+
:ratio_of_active_size => "0.0%",
|
62
|
+
:last_compaction_start => "____-__-__ __:__:__",
|
63
|
+
:last_compaction_end => "____-__-__ __:__:__"
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it_behaves_like StorageStat
|
68
|
+
|
69
|
+
its(:last_compaction_start) { should be_nil }
|
70
|
+
its(:last_compaction_end) { should be_nil }
|
71
|
+
end
|
72
|
+
|
73
|
+
context "there is last compaction" do
|
74
|
+
let(:time_str) { Time.now.to_s }
|
75
|
+
|
76
|
+
subject do
|
77
|
+
StorageStat.new(
|
78
|
+
:active_num_of_objects => 0,
|
79
|
+
:total_num_of_objects => 0,
|
80
|
+
:active_size_of_objects => 0,
|
81
|
+
:total_size_of_objects => 0,
|
82
|
+
:last_compaction_start => time_str,
|
83
|
+
:last_compaction_end => time_str
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
it_behaves_like StorageStat
|
88
|
+
|
89
|
+
its(:last_compaction_start) { subject.to_s == time_str }
|
90
|
+
its(:last_compaction_end) { subject.to_s == time_str }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe Status do
|
95
|
+
describe Status::System do
|
96
|
+
let(:ring_hash) { "1679896365" }
|
97
|
+
|
98
|
+
subject do
|
99
|
+
Status::System.new({
|
100
|
+
:version => "0.14.0",
|
101
|
+
:n => "2",
|
102
|
+
:r => "1",
|
103
|
+
:w => "1",
|
104
|
+
:d => "1",
|
105
|
+
:ring_size => "128",
|
106
|
+
:ring_hash_cur => ring_hash,
|
107
|
+
:ring_hash_prev => ring_hash
|
108
|
+
})
|
109
|
+
end
|
110
|
+
|
111
|
+
[:n, :r, :w, :d, :ring_size].each do |property|
|
112
|
+
its(property) { should be_a Integer }
|
113
|
+
end
|
114
|
+
|
115
|
+
[:ring_cur, :ring_prev].each do |property|
|
116
|
+
its(property) { should be_a String }
|
117
|
+
its(property) { should == Integer(ring_hash).to_s(16) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe Status::NodeStat do
|
122
|
+
config = {
|
123
|
+
:version => "0.14.0-RC2",
|
124
|
+
:log_dir => "./log",
|
125
|
+
:ring_cur => "64212f2d",
|
126
|
+
:ring_prev => "64212f2d",
|
127
|
+
:vm_version => "5.9.3.1",
|
128
|
+
:total_mem_usage => 29281552,
|
129
|
+
:system_mem_usage => 11874433,
|
130
|
+
:procs_mem_usage => 17411895,
|
131
|
+
:ets_mem_usage => 1022392,
|
132
|
+
:num_of_procs => 325,
|
133
|
+
:limit_of_procs => 1048576,
|
134
|
+
:kernel_poll => "true",
|
135
|
+
:thread_pool_size => 32,
|
136
|
+
:replication_msgs => 0,
|
137
|
+
:sync_vnode_msgs => 0,
|
138
|
+
:rebalance_msgs => 0
|
139
|
+
}
|
140
|
+
|
141
|
+
subject do
|
142
|
+
Status::NodeStat.new(config)
|
143
|
+
end
|
144
|
+
|
145
|
+
its(:kernel_poll) { should == (config[:kernel_poll] == "true") }
|
146
|
+
_config = config.reject {|key| key == :kernel_poll }
|
147
|
+
_config.each {|key, value| its(key) { should == value } }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe Client do
|
152
|
+
before(:all) do
|
153
|
+
Dummy::Manager.new
|
154
|
+
@manager = Client.new("#{Host}:#{Port}")
|
155
|
+
end
|
156
|
+
subject { @manager }
|
157
|
+
|
158
|
+
it "raises error when it is passed invalid params" do
|
159
|
+
lambda { Client.new }.should raise_error
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#login" do
|
163
|
+
it "returns LoginInfo" do
|
164
|
+
subject.login("user_id", "pass").should be_a LoginInfo
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#status" do
|
169
|
+
its(:status) { should be_a Status }
|
170
|
+
its("status.system_info") { should be_a Status::System }
|
171
|
+
its("status.node_list") do
|
172
|
+
should be_a Array
|
173
|
+
should be_all {|node| node.is_a?(Status::Node) }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#whereis" do
|
178
|
+
it "returns Array of WhereInfo" do
|
179
|
+
result = subject.whereis("path")
|
180
|
+
result.should be_a Array
|
181
|
+
result.each do |where_info|
|
182
|
+
where_info.should be_a AssignedFile
|
183
|
+
where_info.num_of_chunks.should be_a Integer
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "#du" do
|
189
|
+
it "returns DiskUsage" do
|
190
|
+
subject.du("node").should be_a StorageStat
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#create_user" do
|
195
|
+
it "returns Credential" do
|
196
|
+
subject.create_user("user_id", "password").should be_a Credential
|
197
|
+
end
|
198
|
+
|
199
|
+
it "goes with only user_id" do
|
200
|
+
subject.create_user("user_id").should be_a Credential
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "#update_user_role" do
|
205
|
+
it "returns nil" do
|
206
|
+
subject.update_user_role("user_id", "admin").should be_nil
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "#update_user_password" do
|
211
|
+
it "returns nil" do
|
212
|
+
subject.update_user_password("user_id", "new_password").should be_nil
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "#delete_user" do
|
217
|
+
it "returns nil" do
|
218
|
+
subject.delete_user("user_id").should be_nil
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
its(:get_users) do
|
223
|
+
should be_a Array
|
224
|
+
should be_all do |account|
|
225
|
+
account.is_a?(User)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
its(:get_endpoints) do
|
230
|
+
should be_a Array
|
231
|
+
should be_all do |endpoint|
|
232
|
+
endpoint.is_a?(Endpoint)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
its(:get_buckets) do
|
237
|
+
should be_a Array
|
238
|
+
should be_all do |bucket|
|
239
|
+
bucket.is_a?(Bucket)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#recover_file" do
|
244
|
+
it do
|
245
|
+
subject.recover_file("path").should be_nil
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
describe "#recover_node" do
|
250
|
+
it do
|
251
|
+
subject.recover_node("node").should be_nil
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "#recover_ring" do
|
256
|
+
it do
|
257
|
+
subject.recover_ring("node").should be_nil
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
NoResultAPIs.each do |api, num_of_args|
|
262
|
+
describe "##{api}" do
|
263
|
+
it "returns nil" do
|
264
|
+
subject.send(api, *(["argument"] * num_of_args)).should be_nil
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe "#disconnect!" do
|
270
|
+
it "returns nil" do
|
271
|
+
subject.disconnect!.should be_nil
|
272
|
+
end
|
273
|
+
|
274
|
+
it "accepts no more requests" do
|
275
|
+
lambda {
|
276
|
+
subject.status
|
277
|
+
}.should raise_error
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|