etcdist 0.0.3
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/.gitignore +14 -0
- data/.rubocop.yml +15 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +109 -0
- data/Rakefile +23 -0
- data/TODO +9 -0
- data/etcdist.gemspec +29 -0
- data/lib/etcdist/log.rb +8 -0
- data/lib/etcdist/reader.rb +26 -0
- data/lib/etcdist/version.rb +3 -0
- data/lib/etcdist/writer.rb +47 -0
- data/lib/etcdist.rb +25 -0
- data/spec/data/etcdist/foo/one.config +2 -0
- data/spec/data/etcdist/foo/two.config +1 -0
- data/spec/etcdist/reader_spec.rb +14 -0
- data/spec/etcdist/writer_spec.rb +84 -0
- data/spec/etcdist_spec.rb +26 -0
- data/spec/spec_helper.rb +32 -0
- metadata +181 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 31d1efd6790453a5cc15c0c2400d7e3d6c629865
|
|
4
|
+
data.tar.gz: ad13049f8d7a5c640a1be8e52db5888af619c870
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7f638b9482640267f0b4f0e5172568705d7c1fea319613c981f737afc3d8c11adcf786782d1d5a2b578fde43708a78f906a6aa88455d6cbfef16e44c427e89e2
|
|
7
|
+
data.tar.gz: a8f872b5fd43654733b24db3b4e76e7e7e3d9f210ad21f309c6ef01b2ece0251aae412fa1d5c8e04602bb4cce461acf5605a48a76cf73a2e5192f052d9aa48bc
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Springer, Part of Springer Science+Business Media
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Etcdist
|
|
2
|
+
|
|
3
|
+
This is a small gem that helps you manage your etcd keys and values in a way that's easy to version control.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'etcdist'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install etcdist
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Create the data
|
|
24
|
+
|
|
25
|
+
Create your desired directory structure. This will be replicated in etcd. For example:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mkdir -p data/foo/bar
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then create a file in the leaf directory containing the keys and values that you want to go into etcd. For example:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cat <<EOT > data/foo/bar/food.data
|
|
35
|
+
fish=plankton
|
|
36
|
+
cows=grass
|
|
37
|
+
EOT
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The name of the file containing the keys and values doesn't matter. In fact, you can split the data into multiple files, if you want. An example would look like:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
./data
|
|
44
|
+
└── ./foo
|
|
45
|
+
└── ./bar
|
|
46
|
+
├── food.data # contains fish=plankton and cows=grass
|
|
47
|
+
└── more.data # could contain more keys and values
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Populate etcd
|
|
51
|
+
|
|
52
|
+
Then pass the path to your data directory to Etcdist. For example:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
#!/usr/bin/env ruby
|
|
56
|
+
require 'etcdist'
|
|
57
|
+
Etcdist.execute('data')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If you want Etcdist to remove data from etcd that is no longer in your data files, use `dangerous` mode:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
Etcdist.execute('data', dangerous: true)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If you just want to perform a trial run without making any changes, then use the `dry_run` mode:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
Etcdist.execute('data', dangerous: true, dry_run: true)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
### Etcd host
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
Etcdist.execute(dir) # defaults to localhost:4001
|
|
78
|
+
Etcdist.execute(dir, host: '127.0.0.1', port: 4003)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Log level
|
|
82
|
+
|
|
83
|
+
You can control the log level, as follows:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
Etcdist::Log.level = :info
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Developing
|
|
90
|
+
|
|
91
|
+
Clone the source code. To see what's possible, run:
|
|
92
|
+
|
|
93
|
+
$ rake -T
|
|
94
|
+
|
|
95
|
+
To get the acceptance test to pass, make sure you've got etcd running locally:
|
|
96
|
+
|
|
97
|
+
$ docker run -d -p 4001:4001 coreos/etcd
|
|
98
|
+
|
|
99
|
+
To continuously run tests, run:
|
|
100
|
+
|
|
101
|
+
$ guard
|
|
102
|
+
|
|
103
|
+
## Contributing
|
|
104
|
+
|
|
105
|
+
1. Fork it
|
|
106
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
107
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
108
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
109
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
require 'rdoc/task'
|
|
3
|
+
require 'rubocop/rake_task'
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new('spec')
|
|
7
|
+
|
|
8
|
+
task default: :test
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new do |task|
|
|
11
|
+
task.fail_on_error = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
RDoc::Task.new do |rdoc|
|
|
15
|
+
rdoc.main = 'README.rdoc'
|
|
16
|
+
rdoc.rdoc_files.include('lib /*.rb')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc 'Run specs and code checks.'
|
|
20
|
+
task :test do
|
|
21
|
+
Rake::Task['spec'].invoke
|
|
22
|
+
Rake::Task['rubocop'].invoke
|
|
23
|
+
end
|
data/TODO
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
* think about / improve error handling (for example: write operation is not atomic)
|
|
3
|
+
* gemspec: specify required ruby version
|
|
4
|
+
|
|
5
|
+
## Lower priority
|
|
6
|
+
* feature: **optionally** remove directories from etcd if no longer present
|
|
7
|
+
* feature: do not process directories that don't have any modified files
|
|
8
|
+
* feature: provide etcdist as a binary so that it can be executed from the command line.
|
|
9
|
+
|
data/etcdist.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'etcdist/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'etcdist'
|
|
8
|
+
spec.version = Etcdist::VERSION
|
|
9
|
+
spec.authors = ['Springer, Part of Springer Science+Business Media']
|
|
10
|
+
spec.summary = 'Populate etcd in a reproducable way. '
|
|
11
|
+
spec.homepage = 'https://github.com/springersbm/etcdist'
|
|
12
|
+
spec.license = 'MIT'
|
|
13
|
+
|
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
spec.require_paths = ['lib']
|
|
18
|
+
spec.required_ruby_version = '>= 2.0'
|
|
19
|
+
|
|
20
|
+
spec.add_runtime_dependency 'etcd', '~> 0.2.4'
|
|
21
|
+
spec.add_runtime_dependency 'mixlib-log'
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
26
|
+
spec.add_development_dependency 'rspec-mocks', '~> 3.0'
|
|
27
|
+
spec.add_development_dependency 'guard-rspec'
|
|
28
|
+
spec.add_development_dependency 'rubocop'
|
|
29
|
+
end
|
data/lib/etcdist/log.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'etcdist/log'
|
|
2
|
+
|
|
3
|
+
module Etcdist
|
|
4
|
+
# Reads data from file system into directories, keys and values.
|
|
5
|
+
class Reader
|
|
6
|
+
# @param [String] dir The path to the data directory
|
|
7
|
+
def initialize(dir)
|
|
8
|
+
@dir = dir
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Returns a hash of type { directory => { key => val } }
|
|
12
|
+
def read
|
|
13
|
+
@dir = File.expand_path(@dir)
|
|
14
|
+
files = Dir[File.join(@dir, '**', '*')].reject { |p| File.directory? p }
|
|
15
|
+
Log.info("found #{files.length} files in #{@dir}")
|
|
16
|
+
|
|
17
|
+
files.reduce(Hash.new { |h, k| h[k] = {} }) do |h, f|
|
|
18
|
+
directory = File.dirname(f).gsub(@dir, '')
|
|
19
|
+
entries = Hash[IO.readlines(f).map { |e| e.chomp.split('=') }]
|
|
20
|
+
Log.debug("found #{entries.length} entries in #{f.gsub(@dir, '')}: #{entries}")
|
|
21
|
+
h[directory].merge!(entries)
|
|
22
|
+
h
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'etcdist/log'
|
|
2
|
+
|
|
3
|
+
module Etcdist
|
|
4
|
+
# Writes data into etcd.
|
|
5
|
+
class Writer
|
|
6
|
+
# @param [Hash] opts Options
|
|
7
|
+
# @opts [String] :dangerous remove data from etcd (default false)
|
|
8
|
+
# @opts [String] :dry_run perform a trial run with no changes made (default false)
|
|
9
|
+
def initialize(etcd, opts = {})
|
|
10
|
+
@etcd = etcd
|
|
11
|
+
@dangerous = opts[:dangerous] || false
|
|
12
|
+
@dry_run = opts[:dry_run] || false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Writes data into etcd and optionally removes extra data from etcd
|
|
16
|
+
# @param [Hash] data of type { directory => { key => val } }
|
|
17
|
+
def write(data)
|
|
18
|
+
count = { put: 0, del: 0 }
|
|
19
|
+
data.each do |dir, entries|
|
|
20
|
+
count[:put] += put(dir, entries)
|
|
21
|
+
count[:del] += delete(dir, entries) if @dangerous
|
|
22
|
+
end
|
|
23
|
+
Log.info("#{count[:put]} entries added/modified. #{count[:del]} entries deleted.")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def put(dir, entries)
|
|
29
|
+
existing = entries_in(dir)
|
|
30
|
+
to_put = entries.select { |k, v| existing[k] != v }
|
|
31
|
+
to_put.each { |k, v| @etcd.set([dir, '/', k].join, value: v) } unless @dry_run
|
|
32
|
+
Log.debug("wrote #{to_put.length} entries to #{dir}: #{to_put}")
|
|
33
|
+
to_put.length
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def delete(dir, entries)
|
|
37
|
+
to_delete = entries_in(dir).keys - entries.keys
|
|
38
|
+
to_delete.each { |k| @etcd.delete([dir, '/', k].join) } unless @dry_run
|
|
39
|
+
Log.debug("deleted #{to_delete.length} entries from #{dir}: #{to_delete}")
|
|
40
|
+
to_delete.length
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def entries_in(dir)
|
|
44
|
+
@etcd.exists?(dir) ? Hash[@etcd.get(dir).children.map { |n| [n.key.sub(/.*\//, ''), n.value] }] : {}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/etcdist.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'etcd'
|
|
2
|
+
require 'etcdist/log'
|
|
3
|
+
require 'etcdist/reader'
|
|
4
|
+
require 'etcdist/writer'
|
|
5
|
+
|
|
6
|
+
# The Etcdist name space
|
|
7
|
+
module Etcdist
|
|
8
|
+
Log.level = :info
|
|
9
|
+
|
|
10
|
+
# Main entry point to read data from F/S and write into etcd.
|
|
11
|
+
#
|
|
12
|
+
# @param [String] dir The path to the data directory
|
|
13
|
+
# @param [Hash] opts Options
|
|
14
|
+
# @opts [String] :host IP address of the etcd server (default 127.0.0.1)
|
|
15
|
+
# @opts [Fixnum] :port Port number of the etcd server (default 4001)
|
|
16
|
+
def self.execute(dir, opts = {})
|
|
17
|
+
etcd = Etcd::Client.new(opts)
|
|
18
|
+
reader = Etcdist::Reader.new(dir)
|
|
19
|
+
writer = Etcdist::Writer.new(etcd, opts)
|
|
20
|
+
|
|
21
|
+
Log.info("using etcd host at: #{etcd.host}:#{etcd.port}")
|
|
22
|
+
writer.write(reader.read)
|
|
23
|
+
Log.info('finished successfully.')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dogs=bones
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Etcdist::Reader do
|
|
4
|
+
|
|
5
|
+
let(:reader) do
|
|
6
|
+
dir = File.join(File.dirname(__FILE__), '../data')
|
|
7
|
+
Etcdist::Reader.new(dir)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'should return directories pointing to key/values' do
|
|
11
|
+
expect(reader.read).to match('/etcdist/foo' => { 'fish' => 'plankton', 'cows' => 'grass', 'dogs' => 'bones' })
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Etcdist::Writer do
|
|
4
|
+
|
|
5
|
+
let(:etcd) do
|
|
6
|
+
double('etcd').as_null_object
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:writer) do
|
|
10
|
+
Etcdist::Writer.new(etcd)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe 'PUTs' do
|
|
14
|
+
|
|
15
|
+
it 'should put entries in etcd' do
|
|
16
|
+
pretend_etcd_contains(nothing)
|
|
17
|
+
expect(etcd).to receive(:set).with('/foo/bar/fish', value: 'plankton')
|
|
18
|
+
writer.write('/foo/bar' => { 'fish' => 'plankton' })
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should put entries in correct directory' do
|
|
22
|
+
pretend_etcd_contains(nothing)
|
|
23
|
+
expect(etcd).to receive(:set).with('/water/fish', value: 'plankton')
|
|
24
|
+
expect(etcd).to receive(:set).with('/land/cows', value: 'grass')
|
|
25
|
+
writer.write('/water' => { 'fish' => 'plankton' }, '/land' => { 'cows' => 'grass' })
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should not put unchanged entries' do
|
|
29
|
+
pretend_etcd_contains('/foo' => { 'fish' => 'plankton', 'cows' => 'grass' })
|
|
30
|
+
expect(etcd).not_to receive(:set)
|
|
31
|
+
writer.write('/foo' => { 'fish' => 'plankton' })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'dry run mode' do
|
|
35
|
+
let(:writer) do
|
|
36
|
+
Etcdist::Writer.new(etcd, dry_run: true)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'should not put entries in etcd' do
|
|
40
|
+
pretend_etcd_contains(nothing)
|
|
41
|
+
expect(etcd).not_to receive(:set)
|
|
42
|
+
writer.write( '/foo/bar' => { 'fish' => 'plankton' } )
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe 'DELETEs' do
|
|
48
|
+
|
|
49
|
+
it 'should not delete extra entries by default' do
|
|
50
|
+
pretend_etcd_contains('/foo' => { 'fish' => 'plankton' })
|
|
51
|
+
expect(etcd).not_to receive(:delete)
|
|
52
|
+
writer.write('/foo' => {})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'dangerous mode' do
|
|
56
|
+
|
|
57
|
+
let(:writer) do
|
|
58
|
+
Etcdist::Writer.new(etcd, dangerous: true)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'should delete extra entries' do
|
|
62
|
+
pretend_etcd_contains('/foo' => { 'fish' => 'plankton' })
|
|
63
|
+
expect(etcd).to receive(:delete).with('/foo/fish')
|
|
64
|
+
writer.write('/foo' => { 'cows' => 'grass' })
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context 'dry run mode' do
|
|
70
|
+
let(:writer) do
|
|
71
|
+
Etcdist::Writer.new(etcd, dangerous: true, dry_run: true)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should not delete entries' do
|
|
75
|
+
pretend_etcd_contains('/foo' => { 'fish' => 'plankton' })
|
|
76
|
+
expect(etcd).not_to receive(:delete)
|
|
77
|
+
writer.write( '/foo' => { 'cows' => 'grass'} )
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Etcdist do
|
|
4
|
+
|
|
5
|
+
describe 'acceptance test - expects etcd running on localhost:4001' do
|
|
6
|
+
|
|
7
|
+
let(:etcd_opts) do
|
|
8
|
+
{ host: 'localhost', port: 4001 }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
let(:etcd) do
|
|
12
|
+
Etcd.client(etcd_opts)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:dir) do
|
|
16
|
+
File.join(File.dirname(__FILE__), 'data')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should read data and put entries to etcd' do
|
|
20
|
+
Etcdist.execute(dir, etcd_opts)
|
|
21
|
+
expect(etcd.get('/etcdist/foo/fish').value).to eq('plankton')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
|
2
|
+
$LOAD_PATH.unshift(File.expand_path('../spec', __FILE__))
|
|
3
|
+
|
|
4
|
+
require 'etcdist'
|
|
5
|
+
require 'etcdist/log'
|
|
6
|
+
|
|
7
|
+
Etcdist::Log.level = :warn
|
|
8
|
+
|
|
9
|
+
module Etcdist
|
|
10
|
+
module SpecHelper
|
|
11
|
+
def nothing
|
|
12
|
+
{}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def pretend_etcd_contains(data = nothing)
|
|
16
|
+
allow(etcd).to receive(:exists?).with(any_args).and_return(!data.empty?)
|
|
17
|
+
data.each do |dir, entries|
|
|
18
|
+
nodes = entries.map { |k, v| { 'key' => k, 'value' => v } }
|
|
19
|
+
opts = { 'node' => { 'dir' => true, 'nodes' => nodes } }
|
|
20
|
+
allow(etcd).to receive(:get).with(dir).and_return(Etcd::Response.new(opts))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
RSpec.configure do |config|
|
|
27
|
+
config.include Etcdist::SpecHelper
|
|
28
|
+
config.color = true
|
|
29
|
+
config.expect_with :rspec do |c|
|
|
30
|
+
c.syntax = :expect
|
|
31
|
+
end
|
|
32
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: etcdist
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Springer, Part of Springer Science+Business Media
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: etcd
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.2.4
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.2.4
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: mixlib-log
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: bundler
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ~>
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.7'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.7'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rake
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '10.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '10.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ~>
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ~>
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rspec-mocks
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ~>
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ~>
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '3.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: guard-rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - '>='
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - '>='
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubocop
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - '>='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - '>='
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
description:
|
|
126
|
+
email:
|
|
127
|
+
executables: []
|
|
128
|
+
extensions: []
|
|
129
|
+
extra_rdoc_files: []
|
|
130
|
+
files:
|
|
131
|
+
- .gitignore
|
|
132
|
+
- .rubocop.yml
|
|
133
|
+
- Gemfile
|
|
134
|
+
- Guardfile
|
|
135
|
+
- LICENSE.txt
|
|
136
|
+
- README.md
|
|
137
|
+
- Rakefile
|
|
138
|
+
- TODO
|
|
139
|
+
- etcdist.gemspec
|
|
140
|
+
- lib/etcdist.rb
|
|
141
|
+
- lib/etcdist/log.rb
|
|
142
|
+
- lib/etcdist/reader.rb
|
|
143
|
+
- lib/etcdist/version.rb
|
|
144
|
+
- lib/etcdist/writer.rb
|
|
145
|
+
- spec/data/etcdist/foo/one.config
|
|
146
|
+
- spec/data/etcdist/foo/two.config
|
|
147
|
+
- spec/etcdist/reader_spec.rb
|
|
148
|
+
- spec/etcdist/writer_spec.rb
|
|
149
|
+
- spec/etcdist_spec.rb
|
|
150
|
+
- spec/spec_helper.rb
|
|
151
|
+
homepage: https://github.com/springersbm/etcdist
|
|
152
|
+
licenses:
|
|
153
|
+
- MIT
|
|
154
|
+
metadata: {}
|
|
155
|
+
post_install_message:
|
|
156
|
+
rdoc_options: []
|
|
157
|
+
require_paths:
|
|
158
|
+
- lib
|
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
160
|
+
requirements:
|
|
161
|
+
- - '>='
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: '2.0'
|
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
|
+
requirements:
|
|
166
|
+
- - '>='
|
|
167
|
+
- !ruby/object:Gem::Version
|
|
168
|
+
version: '0'
|
|
169
|
+
requirements: []
|
|
170
|
+
rubyforge_project:
|
|
171
|
+
rubygems_version: 2.0.3
|
|
172
|
+
signing_key:
|
|
173
|
+
specification_version: 4
|
|
174
|
+
summary: Populate etcd in a reproducable way.
|
|
175
|
+
test_files:
|
|
176
|
+
- spec/data/etcdist/foo/one.config
|
|
177
|
+
- spec/data/etcdist/foo/two.config
|
|
178
|
+
- spec/etcdist/reader_spec.rb
|
|
179
|
+
- spec/etcdist/writer_spec.rb
|
|
180
|
+
- spec/etcdist_spec.rb
|
|
181
|
+
- spec/spec_helper.rb
|