ceph_storage 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.cluster.yml.example +19 -0
  3. data/.gitignore +1 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +110 -0
  7. data/Guardfile +20 -0
  8. data/README.md +108 -0
  9. data/Rakefile +7 -0
  10. data/ceph_storage.gemspec +36 -0
  11. data/lib/ceph_storage.rb +28 -0
  12. data/lib/ceph_storage/cluster.rb +93 -0
  13. data/lib/ceph_storage/cluster_factory.rb +24 -0
  14. data/lib/ceph_storage/cluster_wrapper.rb +16 -0
  15. data/lib/ceph_storage/pool.rb +126 -0
  16. data/lib/ceph_storage/pool_enumerator.rb +24 -0
  17. data/lib/ceph_storage/pool_factory.rb +15 -0
  18. data/lib/ceph_storage/pool_wrapper.rb +17 -0
  19. data/lib/ceph_storage/storage_object.rb +48 -0
  20. data/lib/ceph_storage/storage_object/file_storage_object.rb +28 -0
  21. data/lib/ceph_storage/storage_object/rados_storage_object.rb +41 -0
  22. data/lib/ceph_storage/storage_object/rados_storage_object_enumerator.rb +29 -0
  23. data/lib/ceph_storage/storage_object/rados_wrapper.rb +21 -0
  24. data/lib/ceph_storage/storage_object/url_storage_object.rb +34 -0
  25. data/lib/ceph_storage/storage_object/xattr.rb +18 -0
  26. data/lib/ceph_storage/storage_object/xattr_enumerator.rb +29 -0
  27. data/lib/ceph_storage/version.rb +3 -0
  28. data/spec/ceph_storage_cluster_factory_spec.rb +14 -0
  29. data/spec/ceph_storage_cluster_spec.rb +76 -0
  30. data/spec/ceph_storage_file_storage_object_spec.rb +31 -0
  31. data/spec/ceph_storage_pool_enumerator.rb +34 -0
  32. data/spec/ceph_storage_pool_factory_spec.rb +14 -0
  33. data/spec/ceph_storage_pool_spec.rb +167 -0
  34. data/spec/ceph_storage_rados_storage_object_enumerator_spec.rb +72 -0
  35. data/spec/ceph_storage_rados_storage_object_spec.rb +112 -0
  36. data/spec/ceph_storage_storage_object_spec.rb +98 -0
  37. data/spec/ceph_storage_xattr_enumerator_spec.rb +75 -0
  38. data/spec/ceph_storage_xattr_spec.rb +69 -0
  39. data/spec/spec_helper.rb +30 -0
  40. data/tasks/rspec.rake +4 -0
  41. data/tasks/rubocop.rake +13 -0
  42. 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