1 require 'mogilefs/client'
4 # A MogileFS Administration Client
6 class MogileFS::Admin < MogileFS::Client
9 # Enumerates fids using #list_fids.
15 max = get_stats('fids')['fids']['max']
17 0.step max, 100 do |high|
18 fids = list_fids low, high
19 fids.each { |fid| yield fid }
25 # Returns an Array of host status Hashes. If +hostid+ is given only that
32 # [{"status"=>"alive",
33 # "http_get_port"=>"",
37 # "hostname"=>"rur-1",
38 # "remoteroot"=>"/mnt/mogilefs/rur-1",
42 def get_hosts(hostid = nil)
43 args = hostid ? { :hostid => hostid } : {}
44 res = @backend.get_hosts args
45 return clean('hosts', 'host', res)
49 # Returns an Array of device status Hashes. If devid is given only that
56 # [{"status"=>"alive",
64 def get_devices(devid = nil)
65 args = devid ? { :devid => devid } : {}
66 res = @backend.get_devices args
67 return clean('devices', 'dev', res)
71 # Returns an Array of fid Hashes from +from_fid+ to +to_fid+.
73 # admin.list_fids 0, 100
88 # "key"=>"new_new_key"}]
90 def list_fids(from_fid, to_fid)
91 res = @backend.list_fids :from => from_fid, :to => to_fid
92 return clean('fid_count', 'fid_', res)
96 # Returns a statistics structure representing the state of mogilefs.
102 # {"fids"=>{"max"=>"99", "count"=>"2"},
104 # [{"status"=>"alive", "files"=>"2", "id"=>"1", "host"=>"rur-1"},
105 # {"status"=>"alive", "files"=>"2", "id"=>"2", "host"=>"rur-2"}],
107 # [{"files"=>"2", "class"=>"normal", "devcount"=>"2", "domain"=>"test"}],
108 # "file"=>[{"files"=>"2", "class"=>"normal", "domain"=>"test"}]}
110 def get_stats(type = 'all')
111 res = @backend.stats type => 1
114 stats['device'] = clean 'devicescount', 'devices', res, false
115 stats['file'] = clean 'filescount', 'files', res, false
116 stats['replication'] = clean 'replicationcount', 'replication', res, false
118 if res['fidmax'] or res['fidcount'] then
120 'max' => res['fidmax'].to_i,
121 'count' => res['fidcount'].to_i
125 stats.delete 'device' if stats['device'].empty?
126 stats.delete 'file' if stats['file'].empty?
127 stats.delete 'replication' if stats['replication'].empty?
133 # Returns the domains present in the mogilefs.
139 # {"test"=>{"normal"=>3, "default"=>2}}
142 res = @backend.get_domains
145 (1..res['domains'].to_i).each do |i|
146 domain = clean "domain#{i}classes", "domain#{i}class", res, false
147 domain = domain.map { |d| [d.values.first, d.values.last.to_i] }
148 domains[res["domain#{i}"]] = Hash[*domain.flatten]
155 # Creates a new domain named +domain+. Returns nil if creation failed.
157 def create_domain(domain)
158 raise MogileFS::ReadOnlyError if readonly?
159 res = @backend.create_domain :domain => domain
160 return res['domain'] unless res.nil?
164 # Deletes +domain+. Returns true if successful, false if not.
166 def delete_domain(domain)
167 raise MogileFS::ReadOnlyError if readonly?
168 res = @backend.delete_domain :domain => domain
173 # Creates a new class in +domain+ named +klass+ with files replicated to
174 # +mindevcount+ devices. Returns nil on failure.
176 def create_class(domain, klass, mindevcount)
177 return modify_class(domain, klass, mindevcount, :create)
181 # Updates class +klass+ in +domain+ to be replicated to +mindevcount+
182 # devices. Returns nil on failure.
184 def update_class(domain, klass, mindevcount)
185 return modify_class(domain, klass, mindevcount, :update)
189 # Removes class +klass+ from +domain+. Returns true if successful, false if
192 def delete_class(domain, klass)
193 res = @backend.delete_class :domain => domain, :class => klass
198 # Creates a new host named +host+. +args+ must contain :ip and :port.
199 # Returns true if successful, false if not.
201 def create_host(host, args = {})
202 raise ArgumentError, "Must specify ip and port" unless \
203 args.include? :ip and args.include? :port
205 return modify_host(host, args, 'create')
209 # Updates +host+ with +args+. Returns true if successful, false if not.
211 def update_host(host, args = {})
212 return modify_host(host, args, 'update')
216 # Deletes host +host+. Returns nil on failure.
218 def delete_host(host)
219 raise MogileFS::ReadOnlyError if readonly?
220 res = @backend.delete_host :host => host
225 # Changes the device status of +device+ on +host+ to +state+ which can be
226 # 'alive', 'down', or 'dead'.
228 def change_device_state(host, device, state)
229 raise MogileFS::ReadOnlyError if readonly?
230 res = @backend.set_state :host => host, :device => device, :state => state
234 protected unless defined? $TESTING
237 # Modifies +klass+ on +domain+ to store files on +mindevcount+ devices via
238 # +action+. Returns the class name if successful, nil if not.
240 def modify_class(domain, klass, mindevcount, action)
241 raise MogileFS::ReadOnlyError if readonly?
242 res = @backend.send("#{action}_class", :domain => domain, :class => klass,
243 :mindevcount => mindevcount)
245 return res['class'] unless res.nil?
249 # Modifies +host+ using +args+ via +action+. Returns true if successful,
252 def modify_host(host, args = {}, action = 'create')
254 res = @backend.send "#{action}_host", args
259 # Turns the response +res+ from the backend into an Array of Hashes from 1
260 # to res[+count+]. If +underscore+ is true then a '_' character is assumed
261 # between the prefix and the hash key value.
263 # res = {"host1_remoteroot"=>"/mnt/mogilefs/rur-1",
264 # "host1_hostname"=>"rur-1",
265 # "host1_hostid"=>"1",
266 # "host1_http_get_port"=>"",
269 # "host1_hostip"=>"",
270 # "host1_http_port"=>"",
271 # "host1_status"=>"alive",
272 # "host1_altmask"=>""}
273 # admin.clean 'hosts', 'host', res
277 # [{"status"=>"alive",
278 # "http_get_port"=>"",
282 # "hostname"=>"rur-1",
283 # "remoteroot"=>"/mnt/mogilefs/rur-1",
287 def clean(count, prefix, res, underscore = true)
288 underscore = underscore ? '_' : ''
289 return (1..res[count].to_i).map do |i|
290 dev = res.select { |k,_| k =~ /^#{prefix}#{i}#{underscore}/ }.map do |k,v|
291 [k.sub(/^#{prefix}#{i}#{underscore}/, ''), v]