Skip to content

Commit 3603d37

Browse files
committedNov 18, 2012
initial commit
0 parents  commit 3603d37

14 files changed

+412
-0
lines changed
 

‎.gitignore

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
*.gem
2+
*.rbc
3+
.bundle
4+
.config
5+
.yardoc
6+
Gemfile.lock
7+
InstalledFiles
8+
_yardoc
9+
coverage
10+
doc/
11+
lib/bundler/man
12+
pkg
13+
rdoc
14+
spec/reports
15+
test/tmp
16+
test/version_tmp
17+
tmp

‎Gemfile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source 'https://rubygems.org'
2+
3+
# Specify your gem's dependencies in ceph-ruby.gemspec
4+
gemspec

‎LICENSE.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2012 Corin Langosch
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

‎README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Ceph::Ruby
2+
3+
TODO: Write a gem description
4+
5+
## Installation
6+
7+
Add this line to your application's Gemfile:
8+
9+
gem 'ceph-ruby'
10+
11+
And then execute:
12+
13+
$ bundle
14+
15+
Or install it yourself as:
16+
17+
$ gem install ceph-ruby
18+
19+
## Usage
20+
21+
TODO: Write usage instructions here
22+
23+
## Contributing
24+
25+
1. Fork it
26+
2. Create your feature branch (`git checkout -b my-new-feature`)
27+
3. Commit your changes (`git commit -am 'Add some feature'`)
28+
4. Push to the branch (`git push origin my-new-feature`)
29+
5. Create new Pull Request

‎Rakefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require "bundler/gem_tasks"

‎ceph-ruby.gemspec

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- encoding: utf-8 -*-
2+
lib = File.expand_path('../lib', __FILE__)
3+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4+
require 'ceph-ruby/version'
5+
6+
Gem::Specification.new do |gem|
7+
gem.name = "ceph-ruby"
8+
gem.version = CephRuby::VERSION
9+
gem.authors = ["Corin Langosch"]
10+
gem.email = ["info@corinlangosch.com"]
11+
gem.description = %q{TODO: Write a gem description}
12+
gem.summary = %q{TODO: Write a gem summary}
13+
gem.homepage = ""
14+
15+
gem.files = `git ls-files`.split($/)
16+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18+
gem.require_paths = ["lib"]
19+
20+
gem.add_dependency('ffi', '~> 1.1.5')
21+
end

‎lib/ceph-ruby.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require "ffi"
2+
3+
require "ceph-ruby/version"
4+
require "ceph-ruby/rados"
5+
require "ceph-ruby/rbd"
6+
7+
module CephRuby
8+
end

‎lib/ceph-ruby/rados.rb

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
require "ceph-ruby/rados/lib"
2+
require "ceph-ruby/rados/pool"
3+
4+
module CephRuby
5+
class Rados
6+
attr_accessor :state, :cluster
7+
8+
def self.version
9+
major = FFI::MemoryPointer.new(:int)
10+
minor= FFI::MemoryPointer.new(:int)
11+
extra = FFI::MemoryPointer.new(:int)
12+
Lib.rados_version(major, minor, extra)
13+
{
14+
:major => major.get_int(0),
15+
:minor => minor.get_int(0),
16+
:extra => extra.get_int(0),
17+
}
18+
end
19+
20+
def initialize(configuration_path = "/etc/ceph/ceph.conf")
21+
cluster_p = FFI::MemoryPointer.new(:pointer)
22+
ret = Lib.rados_create(cluster_p, nil)
23+
raise "could not initialize rados cluster: #{ret}" if ret < 0
24+
self.cluster = cluster_p.get_pointer(0)
25+
self.state = :initialized
26+
read_configuration_file(configuration_path)
27+
28+
if block_given?
29+
connect
30+
yield self
31+
shutdown
32+
end
33+
end
34+
35+
def read_configuration_file(path = "/etc/ceph/ceph.conf")
36+
require_state(:initialized, :connected)
37+
raise ArgumentError, "path must be a string" unless path.is_a?(String)
38+
ret = Lib.rados_conf_read_file(cluster, path)
39+
raise "error reading configuration file '#{path}': #{ret}" if ret < 0
40+
end
41+
42+
def shutdown
43+
return unless cluster
44+
Lib.rados_shutdown(cluster)
45+
self.cluster = nil
46+
self.state = :shutdown
47+
end
48+
49+
def connect
50+
require_state(:initialized)
51+
ret = Lib.rados_connect(cluster)
52+
raise "could not connect to cluster: #{ret}" if ret < 0
53+
self.state = :connected
54+
end
55+
56+
def exists?(name)
57+
require_state(:connected)
58+
raise ArgumentError, "name must be a string" unless name.is_a?(String)
59+
ret = Lib.rados_pool_lookup(cluster, name)
60+
return true if ret >= 0
61+
return false if ret == -Errno::ENOENT::Errno
62+
raise "error looking up pool '#{name}': #{ret}"
63+
end
64+
65+
def pool(name, &block)
66+
require_state(:connected)
67+
raise ArgumentError, "name must be a string" unless name.is_a?(String)
68+
ioctx_p = FFI::MemoryPointer.new(:pointer)
69+
ret = Lib.rados_ioctx_create(cluster, name, ioctx_p)
70+
raise "error creating io context for '#{name}': #{ret}" if ret < 0
71+
Pool.new(self, name, ioctx_p.get_pointer(0), &block)
72+
end
73+
74+
def rbd(name, &block)
75+
pool(name) do |pool|
76+
Rbd.new(pool, &block)
77+
end
78+
end
79+
80+
private
81+
82+
def require_state(*states)
83+
return if states.include?(state)
84+
raise "current state must be one of: #{states*", "}"
85+
end
86+
end
87+
end

‎lib/ceph-ruby/rados/lib.rb

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require "ffi"
2+
3+
module CephRuby
4+
class Rados
5+
module Lib
6+
extend FFI::Library
7+
8+
ffi_lib ['rados', 'librados.so.2']
9+
10+
attach_function 'rados_version', [:pointer, :pointer, :pointer], :void
11+
12+
attach_function 'rados_create', [:pointer, :string], :int
13+
attach_function 'rados_connect', [:pointer], :int
14+
attach_function 'rados_conf_read_file', [:pointer, :string], :int
15+
attach_function 'rados_shutdown', [:pointer], :void
16+
17+
attach_function 'rados_pool_lookup', [:pointer, :string], :int
18+
19+
attach_function 'rados_ioctx_create', [:pointer, :string, :pointer], :int
20+
attach_function 'rados_ioctx_destroy', [:pointer], :void
21+
22+
attach_function 'rados_write', [:pointer, :string, :buffer_in, :size_t, :off_t], :int
23+
attach_function 'rados_read', [:pointer, :string, :buffer_out, :size_t, :off_t], :int
24+
end
25+
end
26+
end

‎lib/ceph-ruby/rados/pool.rb

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module CephRuby
2+
class Rados
3+
class Pool
4+
attr_accessor :state, :cluster, :name, :ioctx
5+
6+
def initialize(cluster, name, ioctx)
7+
self.cluster = cluster
8+
self.name = name
9+
self.ioctx = ioctx
10+
self.state = :initialized
11+
12+
if block_given?
13+
yield self
14+
close
15+
end
16+
end
17+
18+
def close
19+
require_state(:initialized)
20+
Lib.rados_ioctx_destroy(ioctx)
21+
self.state = :closed
22+
end
23+
24+
private
25+
26+
def require_state(*states)
27+
return if states.include?(state)
28+
raise "current state must be one of: #{states*", "}"
29+
end
30+
end
31+
end
32+
end

‎lib/ceph-ruby/rbd.rb

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require "ceph-ruby/rbd/lib"
2+
require "ceph-ruby/rbd/image"
3+
4+
module CephRuby
5+
class Rbd
6+
attr_accessor :pool
7+
8+
def self.version
9+
major = FFI::MemoryPointer.new(:int)
10+
minor= FFI::MemoryPointer.new(:int)
11+
extra = FFI::MemoryPointer.new(:int)
12+
Lib.rbd_version(major, minor, extra)
13+
{
14+
:major => major.get_int(0),
15+
:minor => minor.get_int(0),
16+
:extra => extra.get_int(0),
17+
}
18+
end
19+
20+
def initialize(pool)
21+
self.pool = pool
22+
if block_given?
23+
yield self
24+
close
25+
end
26+
end
27+
28+
def close
29+
end
30+
31+
def create(name, size, order = 0, &block)
32+
raise ArgumentError, "name must be a string" unless name.is_a?(String)
33+
raise ArgumentError, "size must be an integer" unless size.is_a?(Integer)
34+
raise ArgumentError, "order must be an integer" unless order.is_a?(Integer)
35+
36+
order_p = FFI::MemoryPointer.new(:int)
37+
order_p.put_int(0, order)
38+
ret = Lib.rbd_create(pool.ioctx, name, size, order_p)
39+
raise "error creating rbd image '#{name}': #{ret}" if ret < 0
40+
41+
Image.new(self, name, &block) if block
42+
end
43+
44+
def open(name, &block)
45+
Image.new(self, name, &block)
46+
end
47+
48+
def destroy(name)
49+
raise ArgumentError, "name must be a string" unless name.is_a?(String)
50+
ret = Lib.rbd_remove(pool.ioctx, name)
51+
raise "error destroying rbd image '#{name}': #{ret}" if ret < 0
52+
end
53+
end
54+
end

‎lib/ceph-ruby/rbd/image.rb

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module CephRuby
2+
class Rbd
3+
class Image
4+
attr_accessor :state, :rbd, :name, :image
5+
6+
def initialize(rbd, name, snapshot = nil)
7+
raise ArgumentError, "name must be a string" unless name.is_a?(String)
8+
raise ArgumentError, "snapshot must be a string" if snapshot && !snapshot.is_a?(String)
9+
10+
image_p = FFI::MemoryPointer.new(:pointer)
11+
ret = Lib.rbd_open(rbd.pool.ioctx, name, image_p, snapshot)
12+
raise "could not open rbd image '#{name}': #{ret}" if ret < 0
13+
14+
self.image = image_p.get_pointer(0)
15+
self.rbd = rbd
16+
self.name = name
17+
self.state = :initialized
18+
19+
if block_given?
20+
yield self
21+
close
22+
end
23+
end
24+
25+
def close
26+
require_state(:initialized)
27+
Lib.rbd_close(image)
28+
self.state = :closed
29+
end
30+
31+
def write(offset, data)
32+
require_state(:initialized)
33+
raise ArgumentError, "offset must be an integer" unless offset.is_a?(Integer)
34+
size = data.bytesize
35+
ret = Lib.rbd_write(image, offset, size, data)
36+
raise "error writing #{size} bytes to image '#{name}': #{ret}" if ret < 0
37+
raise "wrote only #{ret} of #{size} bytes to image '#{name}' @ #{offset}" if ret < size
38+
end
39+
40+
def read(offset, size)
41+
require_state(:initialized)
42+
raise ArgumentError, "offset must be an integer" unless offset.is_a?(Integer)
43+
raise ArgumentError, "size must be an integer" unless size.is_a?(Integer)
44+
data_p = FFI::MemoryPointer.new(:char, size)
45+
ret = Lib.rbd_read(image, offset, size, data_p)
46+
raise "error reading #{size} bytes from image '#{name}' @ #{offset}: #{ret}" if ret < 0
47+
data_p.get_bytes(0, ret)
48+
end
49+
50+
def stat
51+
stat = Lib::StatStruct.new
52+
ret = Lib.rbd_stat(image, stat, stat.size)
53+
raise "error getting stat of image '#{name}'" if ret < 0
54+
stat
55+
end
56+
57+
def resize(size)
58+
ret = Lib.rbd_resize(image, size)
59+
raise "error resizing image '#{name}' to #{size} bytes" if ret < 0
60+
end
61+
62+
def size
63+
stat[:size]
64+
end
65+
66+
private
67+
68+
def require_state(*states)
69+
return if states.include?(state)
70+
raise "current state must be one of: #{states*", "}"
71+
end
72+
end
73+
end
74+
end

‎lib/ceph-ruby/rbd/lib.rb

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require "ffi"
2+
3+
module CephRuby
4+
class Rbd
5+
module Lib
6+
extend FFI::Library
7+
8+
ffi_lib ['rbd', 'librbd.so.1']
9+
10+
attach_function 'rbd_version', [:pointer, :pointer, :pointer], :void
11+
12+
attach_function 'rbd_create', [:pointer, :string, :size_t, :pointer], :int
13+
attach_function 'rbd_remove', [:pointer, :string], :int
14+
15+
attach_function 'rbd_open', [:pointer, :string, :pointer, :string], :int
16+
attach_function 'rbd_close', [:pointer], :void
17+
18+
attach_function 'rbd_write', [:pointer, :off_t, :size_t, :buffer_in], :int
19+
attach_function 'rbd_read', [:pointer, :off_t, :size_t, :buffer_out], :int
20+
attach_function 'rbd_stat', [:pointer, :pointer, :size_t], :int
21+
attach_function 'rbd_resize', [:pointer, :size_t], :int
22+
23+
class StatStruct < FFI::Struct
24+
layout :size, :int,
25+
:obj_size, :int,
26+
:num_objs, :int,
27+
:order, :int,
28+
:block_name_prefix, [:char, 24],
29+
:parent_pool, :int,
30+
:parent_name, [:char, 96]
31+
end
32+
end
33+
end
34+
end

‎lib/ceph-ruby/version.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module CephRuby
2+
VERSION = "0.0.1"
3+
end

0 commit comments

Comments
 (0)
Please sign in to comment.