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