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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f11517603a21b107977fee01ece18f2974dc0d98
4
+ data.tar.gz: 033f874f008ff2e9e30f658bb68a8ed195877dd4
5
+ SHA512:
6
+ metadata.gz: 79aa89777a93a9fa26d30e2db0886b6aa70ba0ab6ee008e7a3be6d0abf46597246fc56851cc3e9bda9921af26358e758eedea21237ebf26eaf754ecebe8e1506
7
+ data.tar.gz: dbe0c85a8d9739bc50f78ac44783341c8717ca13f7692d8fc0bfec40af556812a3c2bb1b2ba61ccdb26c2c07e46049d78e3574a543758a5879e07900dc1654c5
@@ -0,0 +1,19 @@
1
+ ---
2
+ :cluster: ceph
3
+ :config_dir: "/etc/ceph"
4
+ :user: client.admin
5
+ :flags: 0
6
+ :readable: true # User has +r mon cap
7
+ :writable: true # User has +w mon cap
8
+ :pool:
9
+ :name: rspec_test
10
+ :create_delete: true # Means you can run create and delete on this pool {beware of dragons!}
11
+ # If you accidentally set this and you have a pool with the same 'name' (see above) it will
12
+ # delete it at the end of the rspec test along with all of the data in it!
13
+ # This only works if the user has +w mon cap
14
+ :rule_id: 2
15
+ :writable: true # Means this pool has read/write permissions {beware of dragons!}
16
+ # If you accidentally set this to true and you have objects in your pool
17
+ # that you want to keep with name = object_name, it will overwrite and then delete them!
18
+ # this only works if the user has +w osd cap at least on pool[:name]
19
+ :object_name: rspec_test_object
@@ -0,0 +1 @@
1
+ .cluster.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,110 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ceph_storage (0.1.0)
5
+ activesupport (~> 3.0)
6
+ ceph-ruby-livelink (~> 1.5)
7
+ facets (~> 3.0)
8
+ ffi (~> 1.9)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (3.2.22.2)
14
+ i18n (~> 0.6, >= 0.6.4)
15
+ multi_json (~> 1.0)
16
+ ast (2.2.0)
17
+ ceph-ruby-livelink (1.5.1)
18
+ activesupport (~> 3.0)
19
+ ffi (~> 1.9)
20
+ coderay (1.1.1)
21
+ diff-lcs (1.2.5)
22
+ facets (3.1.0)
23
+ ffi (1.9.10)
24
+ formatador (0.2.5)
25
+ guard (2.14.0)
26
+ formatador (>= 0.2.4)
27
+ listen (>= 2.7, < 4.0)
28
+ lumberjack (~> 1.0)
29
+ nenv (~> 0.1)
30
+ notiffany (~> 0.0)
31
+ pry (>= 0.9.12)
32
+ shellany (~> 0.0)
33
+ thor (>= 0.18.1)
34
+ guard-bundler (2.1.0)
35
+ bundler (~> 1.0)
36
+ guard (~> 2.2)
37
+ guard-compat (~> 1.1)
38
+ guard-compat (1.2.1)
39
+ guard-rake (1.0.0)
40
+ guard
41
+ rake
42
+ guard-rspec (4.7.0)
43
+ guard (~> 2.1)
44
+ guard-compat (~> 1.1)
45
+ rspec (>= 2.99.0, < 4.0)
46
+ i18n (0.7.0)
47
+ listen (3.0.6)
48
+ rb-fsevent (>= 0.9.3)
49
+ rb-inotify (>= 0.9.7)
50
+ lumberjack (1.0.10)
51
+ method_source (0.8.2)
52
+ multi_json (1.12.1)
53
+ nenv (0.3.0)
54
+ notiffany (0.1.0)
55
+ nenv (~> 0.1)
56
+ shellany (~> 0.0)
57
+ parser (2.3.1.0)
58
+ ast (~> 2.2)
59
+ powerpack (0.1.1)
60
+ pry (0.10.3)
61
+ coderay (~> 1.1.0)
62
+ method_source (~> 0.8.1)
63
+ slop (~> 3.4)
64
+ rainbow (2.1.0)
65
+ rake (11.1.2)
66
+ rb-fsevent (0.9.7)
67
+ rb-inotify (0.9.7)
68
+ ffi (>= 0.5.0)
69
+ rspec (3.4.0)
70
+ rspec-core (~> 3.4.0)
71
+ rspec-expectations (~> 3.4.0)
72
+ rspec-mocks (~> 3.4.0)
73
+ rspec-core (3.4.4)
74
+ rspec-support (~> 3.4.0)
75
+ rspec-expectations (3.4.0)
76
+ diff-lcs (>= 1.2.0, < 2.0)
77
+ rspec-support (~> 3.4.0)
78
+ rspec-mocks (3.4.1)
79
+ diff-lcs (>= 1.2.0, < 2.0)
80
+ rspec-support (~> 3.4.0)
81
+ rspec-support (3.4.1)
82
+ rubocop (0.40.0)
83
+ parser (>= 2.3.1.0, < 3.0)
84
+ powerpack (~> 0.1)
85
+ rainbow (>= 1.99.1, < 3.0)
86
+ ruby-progressbar (~> 1.7)
87
+ unicode-display_width (~> 1.0, >= 1.0.1)
88
+ ruby-progressbar (1.8.1)
89
+ shellany (0.0.1)
90
+ slop (3.6.0)
91
+ thor (0.19.1)
92
+ unicode-display_width (1.0.5)
93
+
94
+ PLATFORMS
95
+ ruby
96
+
97
+ DEPENDENCIES
98
+ bundler (~> 1.3)
99
+ ceph_storage!
100
+ guard (~> 2.13)
101
+ guard-bundler (~> 2.1)
102
+ guard-rake (~> 1.0)
103
+ guard-rspec (~> 4.6)
104
+ listen (= 3.0.6)
105
+ rake (~> 11.1)
106
+ rspec (~> 3.4)
107
+ rubocop (~> 0.39)
108
+
109
+ BUNDLED WITH
110
+ 1.11.2
@@ -0,0 +1,20 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ guard 'rake', task: 'test' do
19
+ watch(%r{^(spec|lib/.*)/.*.rb})
20
+ end
@@ -0,0 +1,108 @@
1
+ # Ceph::Storage
2
+
3
+ A userspace wrapper around the [http://github.com/ceph/ceph-ruby/](Ceph::Ruby) library to allow applications to pool their requests to the ceph backend and conduct thread safe operations with ceph
4
+
5
+ ## Installation
6
+ Add this line to your appication's Gemfile
7
+ gem 'ceph_storage'
8
+
9
+ And then execute:
10
+ $ bundle
11
+
12
+ Or install it yourself as:
13
+ $gem install ceph_storage
14
+
15
+
16
+ ## About
17
+ The Ceph-ruby gem provides an FFI wrapper around librados in order to facilitate connections to ceph and to provide an easy management of objects and cluster settings.
18
+ There are some limitations of this model in that when using it to download large amounts of files in many scenarios there can be significant overhead of connecting to
19
+ the cluster.
20
+
21
+ This library uses the Facets::Multiton model in order to ensure that if you pass the same attributes into cluster and pool objects, you will always get the same objects
22
+ back.
23
+
24
+ ## Pool collection
25
+ In order to provide thread safety, the Pool object carries with it a collection of `::CephRuby::Pool` objects. As such operations on this will reuse an unused connection or spawn a new pool
26
+ connection if no free one exists. On completion (or push) the pool object will continue to stay open to serve further objects.
27
+
28
+ ## Usage
29
+
30
+ require 'ceph_storage'
31
+ config = { cluster: 'ceph', user: 'client.admin', flags: 0, config_dir: '/etc/ceph' } # defaults
32
+
33
+ cluster1 = CephStorage::ClusterFactory.build(config)
34
+
35
+ cluster2 = CephStorage::ClusterFactory.build(config)
36
+
37
+ cluster1.equal? cluster2 # => true
38
+
39
+ pool1 = cluster1.pool('foo')
40
+
41
+ pool2 = cluster2.pool('foo')
42
+
43
+ pool1.equal? pool2 # => true
44
+
45
+
46
+ pool1.storage_object('bar') do |file|
47
+ puts file.read_file
48
+ end
49
+
50
+ ### Using blocks
51
+ # Will connect to ceph, open a pool, download the contents
52
+ # of a file
53
+ CephStorage::ClusterFactory.build(config) do |c|
54
+ c.pool('foo') do |p|
55
+ # NB Storage_object as opposed to rados_object
56
+ p.storage_object('bar') |f|
57
+ puts f.read_file
58
+ end
59
+ end
60
+ end
61
+
62
+ # Does the same thing, but should reuse the same objects
63
+ # Hence the only latency is downloading the file contents
64
+ CephStorage::ClusterFactory.build(config) do |c|
65
+ c.pool('foo') do |p|
66
+ p.storage_object('bar') |f|
67
+ puts f.read_file
68
+ end
69
+ end
70
+ end
71
+
72
+ ## Raw Pool object
73
+
74
+ If there is some functionality that you need that isn't provided, you can expose the raw `::CephRuby::Pool` objects by calling `pool.rados_pool`. This will return an object and mark it 'in use' until you push it back into the collection via `rados_object=` Be sure to do this lest your memory leak.
75
+
76
+ ### Storage Object interfaces
77
+
78
+ The `StorageObject` interface provides some additional functionality to ceph on top of the CephRuby bindings
79
+
80
+ * `CephStorage::StorageObject::FileStorageObject` (wrapper for ::File)
81
+ * `CephStorage::StorageObject::URLStorageObject` (wrapper for url-open)
82
+
83
+ These classes are designed to allow you to copy and move files from ceph to other storage mechanisms. It is designed to be extensible
84
+
85
+ f_storage_obj1 = CephStorage::StorageObject::FileStorageObject.new 'path/to/file1'
86
+ f_storage_obj2 = CephStorage::StorageObject::URLStorageObject.new 'http://example.com'
87
+
88
+ CephStorage::ClusterFactory.build(config) do |c|
89
+ c.pool('foo') do |p|
90
+ p.storage_object('bar') |f|
91
+ f.move f_storage_obj1
92
+ end
93
+ end
94
+ end
95
+
96
+ CephStorage::ClusterFactory.build(config) do |c|
97
+ c.pool('foo') do |p|
98
+ p.storage_object('baz') |f|
99
+ f_storage_obj1.copy f
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ In order for this to work, you class should extend CephStorage::StorageObject and implement `read_file` and `write_file` methods.
106
+ URLStorageObject will raise exception for `write_file` as not implemented (hence move will not work).
107
+
108
+
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ Dir.glob('tasks/**/*.rake').each(&method(:import))
4
+
5
+ task test: [:rubocop_test, :spec]
6
+
7
+ task dev_test: [:rubocop_dev, :spec]
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ceph_storage/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'ceph_storage'
8
+ gem.version = CephStorage::VERSION
9
+ gem.authors = ['Livelink Technology LTD', 'Stuart Harland']
10
+ gem.email = ['infraops@livelinktechnology.net']
11
+ gem.description = 'Easy access of Objects in ceph'
12
+ gem.summary = 'Ceph-ruby provides an API, however this gem provides '\
13
+ 'consistent connection to ceph pools and clusters '\
14
+ 'using multiton objects'
15
+ gem.homepage = 'https://github.com/livelink/ceph_storage'
16
+ gem.license = 'MIT'
17
+
18
+ gem.files = `git ls-files`.split($RS)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ['lib']
22
+
23
+ gem.add_dependency('ffi', '~> 1.9')
24
+ gem.add_dependency('ceph-ruby-livelink', '~> 1.5')
25
+ gem.add_dependency('activesupport', '~> 3.0')
26
+ gem.add_dependency('facets', '~> 3.0')
27
+ gem.add_development_dependency 'guard', '~> 2.13'
28
+ gem.add_development_dependency 'listen', '= 3.0.6'
29
+ gem.add_development_dependency 'guard-rake', '~> 1.0'
30
+ gem.add_development_dependency 'guard-rspec', '~> 4.6'
31
+ gem.add_development_dependency 'guard-bundler', '~> 2.1'
32
+ gem.add_development_dependency 'rubocop', '~> 0.39'
33
+ gem.add_development_dependency 'rspec', '~> 3.4'
34
+ gem.add_development_dependency 'rake', '~> 11.1'
35
+ gem.add_development_dependency 'bundler', '~> 1.3'
36
+ end
@@ -0,0 +1,28 @@
1
+ require 'thread'
2
+ require 'ceph-ruby'
3
+ require 'facets/multiton'
4
+ require 'ceph_storage/cluster_wrapper'
5
+ require 'ceph_storage/cluster_factory'
6
+ require 'ceph_storage/cluster'
7
+ require 'ceph_storage/pool_wrapper'
8
+ require 'ceph_storage/pool_factory'
9
+ require 'ceph_storage/pool'
10
+ require 'ceph_storage/pool_enumerator'
11
+ require 'ceph_storage/storage_object'
12
+ require 'ceph_storage/storage_object/rados_wrapper'
13
+ require 'ceph_storage/storage_object/rados_storage_object'
14
+ require 'ceph_storage/storage_object/rados_storage_object_enumerator'
15
+ require 'ceph_storage/storage_object/file_storage_object'
16
+ require 'ceph_storage/storage_object/url_storage_object'
17
+ require 'ceph_storage/storage_object/xattr'
18
+ require 'ceph_storage/storage_object/xattr_enumerator'
19
+
20
+ # An application for moving files into and out of Ceph
21
+ module CephStorage
22
+ mattr_accessor :logger
23
+
24
+ def self.log(message)
25
+ return unless logger
26
+ logger.info("CephStorage: #{message}")
27
+ end
28
+ end
@@ -0,0 +1,93 @@
1
+ module CephStorage
2
+ # Create a cluster object
3
+ # Returns only a single cluster object for given settings
4
+ class Cluster < ClusterFactory
5
+ extend CephStorage::ClusterWrapper
6
+ include Multiton
7
+ # Configure default values for this object
8
+ attr_reader :cluster_fd, :cluster, :config_dir, :user, :flags
9
+
10
+ wrap_me :pool_id_by_name, :pool_name_by_id, :status, :fsid
11
+
12
+ private :connect, :setup_using_file
13
+
14
+ # Create a new object
15
+ def initialize(config_dir: CONFIG_DIR, cluster: CLUSTER,
16
+ user: USER, flags: FLAGS)
17
+ CephRuby.logger = CephStorage.logger
18
+ init(config_dir, cluster, user, flags)
19
+ log("init config_dir #{config_dir}, cluster #{cluster}, user: #{user}")
20
+
21
+ open
22
+
23
+ yield(@cluster_fd) if block_given?
24
+ rescue StandardError
25
+ log("unable to open cluster #{cluster}")
26
+ raise
27
+ end
28
+
29
+ def rados_cluster
30
+ return @cluster_fd unless block_given?
31
+ yield(@cluster_fd)
32
+ end
33
+
34
+ def pool(name)
35
+ ensure_open
36
+ p = CephStorage::PoolFactory.build(self, name)
37
+ yield(p) if block_given?
38
+ p
39
+ end
40
+
41
+ def pools
42
+ CephStorage::PoolEnumerator.new(self)
43
+ end
44
+
45
+ def shutdown
46
+ return unless open?
47
+ log('shutdown')
48
+ @cluster_fd.shutdown
49
+ end
50
+
51
+ def open?
52
+ !@cluster_fd.nil? && !@cluster_fd.handle.nil?
53
+ end
54
+
55
+ def ensure_open
56
+ return if open?
57
+ open
58
+ end
59
+
60
+ def open
61
+ return if open?
62
+ log('open')
63
+ fd_init unless @cluster_fd
64
+ @cluster_fd.connect unless open?
65
+ end
66
+
67
+ def path
68
+ "ceph://#{cluster}"
69
+ end
70
+
71
+ private
72
+
73
+ def log(message)
74
+ CephStorage.log("cluster #{cluster} #{message}")
75
+ end
76
+
77
+ def fd_init
78
+ @cluster_fd = ::CephRuby::Cluster.new(
79
+ config_path: config_dir,
80
+ cluster: cluster,
81
+ user: user,
82
+ flags: flags
83
+ )
84
+ end
85
+
86
+ def init(config_dir, cluster, user, flags)
87
+ @cluster = cluster
88
+ @user = user
89
+ @config_dir = config_dir
90
+ @flags = flags
91
+ end
92
+ end
93
+ end