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