ceph_storage 0.1.0
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.
- 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
|