ceph_storage 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.cluster.yml.example +19 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +110 -0
- data/Guardfile +20 -0
- data/README.md +108 -0
- data/Rakefile +7 -0
- data/ceph_storage.gemspec +36 -0
- data/lib/ceph_storage.rb +28 -0
- data/lib/ceph_storage/cluster.rb +93 -0
- data/lib/ceph_storage/cluster_factory.rb +24 -0
- data/lib/ceph_storage/cluster_wrapper.rb +16 -0
- data/lib/ceph_storage/pool.rb +126 -0
- data/lib/ceph_storage/pool_enumerator.rb +24 -0
- data/lib/ceph_storage/pool_factory.rb +15 -0
- data/lib/ceph_storage/pool_wrapper.rb +17 -0
- data/lib/ceph_storage/storage_object.rb +48 -0
- data/lib/ceph_storage/storage_object/file_storage_object.rb +28 -0
- data/lib/ceph_storage/storage_object/rados_storage_object.rb +41 -0
- data/lib/ceph_storage/storage_object/rados_storage_object_enumerator.rb +29 -0
- data/lib/ceph_storage/storage_object/rados_wrapper.rb +21 -0
- data/lib/ceph_storage/storage_object/url_storage_object.rb +34 -0
- data/lib/ceph_storage/storage_object/xattr.rb +18 -0
- data/lib/ceph_storage/storage_object/xattr_enumerator.rb +29 -0
- data/lib/ceph_storage/version.rb +3 -0
- data/spec/ceph_storage_cluster_factory_spec.rb +14 -0
- data/spec/ceph_storage_cluster_spec.rb +76 -0
- data/spec/ceph_storage_file_storage_object_spec.rb +31 -0
- data/spec/ceph_storage_pool_enumerator.rb +34 -0
- data/spec/ceph_storage_pool_factory_spec.rb +14 -0
- data/spec/ceph_storage_pool_spec.rb +167 -0
- data/spec/ceph_storage_rados_storage_object_enumerator_spec.rb +72 -0
- data/spec/ceph_storage_rados_storage_object_spec.rb +112 -0
- data/spec/ceph_storage_storage_object_spec.rb +98 -0
- data/spec/ceph_storage_xattr_enumerator_spec.rb +75 -0
- data/spec/ceph_storage_xattr_spec.rb +69 -0
- data/spec/spec_helper.rb +30 -0
- data/tasks/rspec.rake +4 -0
- data/tasks/rubocop.rake +13 -0
- metadata +281 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# Factory Class to create a Cluster reference object
|
3
|
+
class ClusterFactory < ::CephRuby::Cluster
|
4
|
+
# Defaults
|
5
|
+
CONFIG_DIR = '/etc/ceph'.freeze
|
6
|
+
CLUSTER = 'ceph'.freeze
|
7
|
+
USER = 'client.admin'.freeze
|
8
|
+
FLAGS = 0
|
9
|
+
class << self
|
10
|
+
# Create a factory method for creating Cluster Objects
|
11
|
+
def build(config_dir: CONFIG_DIR, cluster: CLUSTER,
|
12
|
+
user: USER, flags: FLAGS)
|
13
|
+
c = Cluster.new(cluster: cluster, config_dir: config_dir,
|
14
|
+
user: user, flags: flags)
|
15
|
+
yield(c) if block_given?
|
16
|
+
c
|
17
|
+
end
|
18
|
+
|
19
|
+
# Make this private otherwise the self.new {} returns a different
|
20
|
+
# Object to self.new {CONFIG_DIR, CLUSTER, USER}
|
21
|
+
private :new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# This code is here to wrap around CephRuby::Cluster
|
3
|
+
# Methods. It assigns the rados cluster object around
|
4
|
+
# the called method
|
5
|
+
module ClusterWrapper
|
6
|
+
def wrap_me(*method_names)
|
7
|
+
method_names.each do |m|
|
8
|
+
define_method(m) do |*args|
|
9
|
+
rados_cluster do |c|
|
10
|
+
c.send(m, *args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# A reference to a Ceph pool
|
3
|
+
# This is a collection of held open pool IOctx's for a given pool
|
4
|
+
class Pool < PoolFactory
|
5
|
+
extend CephStorage::PoolWrapper
|
6
|
+
include Multiton
|
7
|
+
attr_accessor :cartridges, :cluster, :name, :close_lock, :pop_lock
|
8
|
+
|
9
|
+
wrap_me :create, :exists?, :id, :auid=, :auid,
|
10
|
+
:rados_block_device, :destroy, :stat, :flush_aio
|
11
|
+
|
12
|
+
def initialize(cluster, name)
|
13
|
+
log("init #{name}")
|
14
|
+
self.close_lock = Mutex.new
|
15
|
+
self.pop_lock = Mutex.new
|
16
|
+
self.cluster = cluster
|
17
|
+
self.name = name.to_s
|
18
|
+
self.cartridges = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def rados_pool
|
22
|
+
close_lock.synchronize {}
|
23
|
+
h = pop
|
24
|
+
return h unless block_given?
|
25
|
+
begin
|
26
|
+
yield(h)
|
27
|
+
ensure
|
28
|
+
push(h)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def rados_pool=(pool)
|
33
|
+
push(pool)
|
34
|
+
end
|
35
|
+
|
36
|
+
def storage_object(name, &block)
|
37
|
+
CephStorage::StorageObject::RadosStorageObject.new(self, name, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def storage_object_enumerator(&block)
|
41
|
+
CephStorage::StorageObject::RadosStorageObjectEnumerator.new(self, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(message)
|
45
|
+
CephStorage.log("pool #{name} #{message}")
|
46
|
+
end
|
47
|
+
|
48
|
+
def size
|
49
|
+
pop_lock.synchronize do
|
50
|
+
cartridges.size
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def num_locked
|
55
|
+
pop_lock.synchronize do
|
56
|
+
cartridges.count { |c| c[:lock].locked? == true }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def num_free
|
61
|
+
pop_lock.synchronize do
|
62
|
+
cartridges.count { |c| c[:lock].locked? == false }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def close
|
67
|
+
close_lock.synchronize do
|
68
|
+
close_group(false)
|
69
|
+
close_group(true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def path
|
74
|
+
"ceph://#{cluster.cluster}/#{name}"
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def close_group(inuse)
|
80
|
+
log("close pool objects with locked==#{inuse}")
|
81
|
+
cartridges.select { |c| c[:lock].locked? == inuse }.each do |c|
|
82
|
+
c[:pool].close
|
83
|
+
cartridges.delete c
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def pop
|
88
|
+
pop_lock.synchronize do
|
89
|
+
cartridge = first_available_cartridge
|
90
|
+
log("pop #{cartridge[:pool]}, #{cartridge[:lock].locked?}")
|
91
|
+
cartridge[:lock].lock
|
92
|
+
cartridge[:pool]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def push(pool)
|
97
|
+
log("push #{pool}")
|
98
|
+
cartridge = cartridges.find { |c| c[:pool].equal?(pool) }
|
99
|
+
cartridge[:lock].unlock if cartridge
|
100
|
+
end
|
101
|
+
|
102
|
+
def first_available_cartridge
|
103
|
+
cartridge = cartridges.find { |c| c[:lock].locked? == false }
|
104
|
+
cartridge = create_cartridge if cartridge.nil?
|
105
|
+
cartridge
|
106
|
+
end
|
107
|
+
|
108
|
+
def create_cartridge
|
109
|
+
log('create cartridge')
|
110
|
+
cartridge = new_cartridge
|
111
|
+
cartridges << cartridge
|
112
|
+
cartridge
|
113
|
+
end
|
114
|
+
|
115
|
+
def new_cartridge
|
116
|
+
{
|
117
|
+
lock: Mutex.new,
|
118
|
+
pool: new_pool
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def new_pool
|
123
|
+
cluster.rados_cluster { |c| c.pool(name) }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# Enumerator of Ceph pools
|
3
|
+
class PoolEnumerator
|
4
|
+
include Enumerable
|
5
|
+
attr_accessor :cluster_factory
|
6
|
+
def initialize(cluster_factory)
|
7
|
+
self.cluster_factory = cluster_factory
|
8
|
+
@rados_pool_enumerator = cluster_factory.rados_cluster.pools
|
9
|
+
yield self if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
return enum_for(:each) unless block_given?
|
14
|
+
|
15
|
+
@rados_pool_enumerator.each do |pool|
|
16
|
+
yield PoolFactory.build(cluster_factory, pool.name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
cluster.rados_cluster.pools.size
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# Creates a Pool Object
|
3
|
+
# Returns only a single pool object out of the cartridges available
|
4
|
+
class PoolFactory < ::CephRuby::Pool
|
5
|
+
class << self
|
6
|
+
def build(cluster, name)
|
7
|
+
p = CephStorage::Pool.new(cluster, name)
|
8
|
+
yield(p) if block_given?
|
9
|
+
p
|
10
|
+
end
|
11
|
+
# So behaviour is consistent with the cluster factory class
|
12
|
+
private :new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# This code is here to wrap around CephRuby::Pool
|
3
|
+
# Methods. It assigns one of the pool_factory cartridges
|
4
|
+
# to the method being calledt
|
5
|
+
module PoolWrapper
|
6
|
+
def wrap_me(*method_names)
|
7
|
+
method_names.each do |m|
|
8
|
+
define_method(m) do |*args|
|
9
|
+
log("wrapping #{m}")
|
10
|
+
rados_pool do |p|
|
11
|
+
p.send(m, *args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CephStorage
|
2
|
+
# core representation of a file.
|
3
|
+
# This is a mixin module for other storage object modules
|
4
|
+
module StorageObject
|
5
|
+
# Represent an object that can be written to or read from
|
6
|
+
# This is designed to be modular so that you can expand into other
|
7
|
+
# technologies
|
8
|
+
|
9
|
+
attr_accessor :name
|
10
|
+
def move(dst_object)
|
11
|
+
log("move to '#{dst_object.class}/#{dst_object.name}'")
|
12
|
+
dst_object.write_file(read_file)
|
13
|
+
copy_xattrs(dst_object)
|
14
|
+
destroy
|
15
|
+
end
|
16
|
+
|
17
|
+
def copy(dst_object)
|
18
|
+
log("copy to '#{dst_object.class}/#{dst_object.name}'")
|
19
|
+
dst_object.write_file(read_file)
|
20
|
+
copy_xattrs(dst_object)
|
21
|
+
end
|
22
|
+
|
23
|
+
def copy_xattrs(dst_object)
|
24
|
+
log('copy xattrs')
|
25
|
+
return unless xattr_supported?(dst_object)
|
26
|
+
xattr_enumerator.each do |source_xattr|
|
27
|
+
dst_object.xattr(source_xattr.name) do |dst_xattr|
|
28
|
+
dst_xattr.value = source_xattr.value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def xattr_supported?(dst_object)
|
34
|
+
CephStorage::StorageObject.supports_xattr?(self) &&
|
35
|
+
CephStorage::StorageObject.supports_xattr?(dst_object)
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
def supports_xattr?(obj)
|
40
|
+
obj.respond_to? :xattr_enumerator
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(message)
|
45
|
+
CephStorage.log("storage object #{name} #{message}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CephStorage
|
2
|
+
module StorageObject
|
3
|
+
# File Storage Object
|
4
|
+
class FileStorageObject < ::File
|
5
|
+
include CephStorage::StorageObject
|
6
|
+
|
7
|
+
def name
|
8
|
+
path
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_file
|
12
|
+
buf = read
|
13
|
+
rewind
|
14
|
+
buf
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_file(contents)
|
18
|
+
write(contents)
|
19
|
+
flush
|
20
|
+
rewind
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy
|
24
|
+
File.unlink(path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module CephStorage
|
2
|
+
module StorageObject
|
3
|
+
# Ceph Storage Object
|
4
|
+
class RadosStorageObject < ::CephRuby::RadosObject
|
5
|
+
extend CephStorage::StorageObject::RadosWrapper
|
6
|
+
include CephStorage::StorageObject
|
7
|
+
attr_accessor :pool_factory
|
8
|
+
|
9
|
+
def initialize(pool_factory, name)
|
10
|
+
log("init #{name}")
|
11
|
+
self.pool_factory = pool_factory
|
12
|
+
super(nil, name)
|
13
|
+
end
|
14
|
+
|
15
|
+
wrap_me :write, :append, :read, :destroy,
|
16
|
+
:resize, :overwrite, :stat
|
17
|
+
|
18
|
+
def read_file
|
19
|
+
log('read file')
|
20
|
+
read_full
|
21
|
+
end
|
22
|
+
|
23
|
+
def write_file(contents)
|
24
|
+
log("write file #{contents.length}")
|
25
|
+
overwrite(contents)
|
26
|
+
end
|
27
|
+
|
28
|
+
def xattr(name, &block)
|
29
|
+
Xattr.new(self, name, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def xattr_enumerator(&block)
|
33
|
+
XattrEnumerator.new(self, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def path
|
37
|
+
"ceph://#{pool_factory.cluster.cluster}/#{pool_factory.name}/#{name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module CephStorage
|
2
|
+
module StorageObject
|
3
|
+
# Wrapper for RadosObjectEnumerator
|
4
|
+
class RadosStorageObjectEnumerator < ::CephRuby::RadosObjectEnumerator
|
5
|
+
extend CephStorage::StorageObject::RadosWrapper
|
6
|
+
attr_accessor :pool_factory
|
7
|
+
|
8
|
+
wrap_me :open, :close, :position, :seek, :next_rados_object
|
9
|
+
|
10
|
+
def initialize(pool_factory)
|
11
|
+
self.pool_factory = pool_factory
|
12
|
+
super(nil)
|
13
|
+
yield self if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def each
|
17
|
+
return enum_for(:each) unless block_given?
|
18
|
+
|
19
|
+
super do |rados_object|
|
20
|
+
yield pool_factory.storage_object(rados_object.name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def log(message)
|
25
|
+
CephStorage.log("RadosStorageObjectEnumerator #{message}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CephStorage
|
2
|
+
module StorageObject
|
3
|
+
# This code is here to wrap around CephRuby::rados_object
|
4
|
+
# Methods. It assigns one of the pool_factory cartridges
|
5
|
+
# to the RadosObject
|
6
|
+
module RadosWrapper
|
7
|
+
def wrap_me(*method_names)
|
8
|
+
method_names.each do |m|
|
9
|
+
define_method(m) do |*args|
|
10
|
+
log("#{m} wrapping with rados_pool")
|
11
|
+
pool_factory.rados_pool do |p|
|
12
|
+
p.ensure_open
|
13
|
+
self.pool = p
|
14
|
+
super(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
module CephStorage
|
3
|
+
module StorageObject
|
4
|
+
# Remote URL Storage Object
|
5
|
+
class URLStorageObject
|
6
|
+
include CephStorage::StorageObject
|
7
|
+
attr_accessor :url
|
8
|
+
|
9
|
+
def initialize(url)
|
10
|
+
self.name = url
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
url
|
15
|
+
end
|
16
|
+
|
17
|
+
def path
|
18
|
+
url
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_file
|
22
|
+
open(url).read
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_file(_contents)
|
26
|
+
raise 'Unsupported file operation'
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy
|
30
|
+
raise 'Unsupported file operation'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CephStorage
|
2
|
+
module StorageObject
|
3
|
+
# Wrapper for RadosObjectEnumerator
|
4
|
+
class Xattr < ::CephRuby::Xattr
|
5
|
+
extend CephStorage::StorageObject::RadosWrapper
|
6
|
+
attr_accessor :pool_factory, :object
|
7
|
+
|
8
|
+
wrap_me :read, :write, :destroy
|
9
|
+
|
10
|
+
def initialize(object, name)
|
11
|
+
self.pool_factory = object.pool_factory
|
12
|
+
self.object = object
|
13
|
+
self.name = name
|
14
|
+
super(object, name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|