flipper-consul 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9374d60afac720f7e9a69537095d0ef18a446d8
4
+ data.tar.gz: 9c0168f2b70514831ec184861274b5c2f96c0ed8
5
+ SHA512:
6
+ metadata.gz: 45f3f908e1c96ce2e8c9d54fc10f264ece81a3364b0ef84a847de036328b40381881ebae2880574be03792e695a37f13d37e3b858a9eef74b95a1bd324706dbd
7
+ data.tar.gz: d9e9015f0ce965c8a82d5fbb899949e00c6d1c9e1c97ac8151b3350d1b5c9396241bb8a7507c6e0d1e131ba63cd1ee0b3f4d0147286a58ef7d44c27226c7b4d1
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ .vagrant
@@ -0,0 +1 @@
1
+ flipper-consul
@@ -0,0 +1 @@
1
+ ruby-2.1.0
@@ -0,0 +1,13 @@
1
+ sudo: required # don't run on container-based infrastructure
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+ - 2.2.0
8
+ before_script:
9
+ - wget 'https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip'
10
+ - unzip '0.5.2_linux_amd64.zip'
11
+ - ./consul --version
12
+ script:
13
+ - ./consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul &
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in flipper-consul.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
7
+ gem 'rspec-its'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Graham Davison
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.
@@ -0,0 +1,31 @@
1
+ # Flipper::Consul
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'flipper-consul'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install flipper-consul
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/flipper-consul/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,59 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ # All Vagrant configuration is done below. The "2" in Vagrant.configure
5
+ # configures the configuration version (we support older styles for
6
+ # backwards compatibility). Please don't change it unless you know what
7
+ # you're doing.
8
+ Vagrant.configure(2) do |config|
9
+ # Every Vagrant development environment requires a box. You can search for
10
+ # boxes at https://atlas.hashicorp.com/search.
11
+ config.vm.box = "hashicorp/precise64"
12
+
13
+ # config.berkshelf.enabled = true
14
+ # config.berkshelf.berksfile_path = "./Berksfile"
15
+
16
+ # Create a forwarded port mapping which allows access to a specific port
17
+ # within the machine from a port on the host machine. In the example below,
18
+ # accessing "localhost:8080" will access port 80 on the guest machine.
19
+ config.vm.network "forwarded_port", guest: 8500, host: 8500
20
+
21
+ # Create a private network, which allows host-only access to the machine
22
+ # using a specific IP.
23
+ # config.vm.network "private_network", ip: "192.168.33.10"
24
+
25
+ # Create a public network, which generally matched to bridged network.
26
+ # Bridged networks make the machine appear as another physical device on
27
+ # your network.
28
+ # config.vm.network "public_network"
29
+
30
+ # Enable provisioning with a shell script. Additional provisioners such as
31
+ # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
32
+ # documentation for more information about their specific syntax and use.
33
+ config.vm.provision "shell", inline: <<-SHELL
34
+ sudo apt-get update
35
+ #echo Installing dependencies...
36
+ #sudo apt-get install -y unzip curl
37
+ #echo Fetching Consul...
38
+ #cd /tmp/
39
+ #wget https://dl.bintray.com/mitchellh/consul/0.3.1_linux_amd64.zip -O consul.zip
40
+ #echo Installing Consul...
41
+ #unzip consul.zip
42
+ #sudo chmod +x consul
43
+ #sudo mv consul /usr/bin/consul
44
+ #echo Installing Ruby
45
+ #sudo apt-get install python-software-properties -y
46
+ #sudo apt-add-repository ppa:brightbox/ruby-ng -y
47
+ #sudo apt-get update
48
+ #sudo apt-get install ruby2.1 -y
49
+ wget -qO- https://get.docker.com/ | sh
50
+
51
+ # add vagrant to docker group
52
+ sudo usermod -aG docker vagrant
53
+
54
+ docker run -d -p 8400:8400 -p 8500:8500 -p 8600:53/udp -h node1 progrium/consul -server -bootstrap -ui-dir /ui
55
+ SHELL
56
+ # config.vm.provision "chef_zero" do |chef|
57
+ # chef.add_recipe "consul-cookbook"
58
+ # end
59
+ end
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/flipper/adapters/consul/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "flipper-consul"
6
+ spec.version = Flipper::Adapters::Consul::VERSION
7
+ spec.authors = ["Graham Davison"]
8
+ spec.email = ["g.m.davison@computer.org"]
9
+ spec.summary = %q{Consul adapter for Flipper}
10
+ spec.description = %q{Consul adapter for Flipper}
11
+ spec.homepage = "https://github.com/gdavison/flipper-consul"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+
18
+ spec.add_dependency 'flipper', '~> 0.7.0.beta6'
19
+ spec.add_dependency 'diplomat', '~> 0.11'
20
+ end
@@ -0,0 +1 @@
1
+ require 'flipper/adapters/consul'
@@ -0,0 +1,176 @@
1
+ require 'set'
2
+ require 'diplomat'
3
+ require 'flipper'
4
+
5
+ module Flipper
6
+ module Adapters
7
+ class Consul
8
+ include Flipper::Adapter
9
+
10
+ # Private: The key that stores the set of known features.
11
+ FeaturesKey = :flipper_features
12
+
13
+ # Public: The name of the adapter.
14
+ attr_reader :name
15
+
16
+ attr_reader :namespace
17
+
18
+ def initialize(client, namespace=nil)
19
+ @client = client
20
+ @name = :consul
21
+ if !namespace.nil?
22
+ namespace.strip!
23
+ if namespace == ''
24
+ namespace = nil
25
+ elsif namespace.start_with? '/'
26
+ namespace[0] = ''
27
+ end
28
+ end
29
+ @namespace = namespace
30
+ end
31
+
32
+ # Public: The set of known features.
33
+ def features
34
+ read_multiple build_path "#{FeaturesKey}/features"
35
+ end
36
+
37
+ # Public: Adds a feature to the set of known features.
38
+ def add(feature)
39
+ @client.put build_path("#{FeaturesKey}/features/#{feature.key}"), '1'
40
+ true
41
+ end
42
+
43
+ # Public: Removes a feature from the set of known features.
44
+ def remove(feature)
45
+ @client.delete build_path "#{FeaturesKey}/features/#{feature.key}"
46
+ clear feature
47
+ true
48
+ end
49
+
50
+ # Public: Clears the gate values for a feature.
51
+ def clear(feature)
52
+ @client.delete build_path "#{feature.key}/?recurse"
53
+ true
54
+ end
55
+
56
+ # Public: Gets the values for all gates for a given feature.
57
+ #
58
+ # Returns a Hash of Flipper::Gate#key => value.
59
+ def get(feature)
60
+ result = {}
61
+ values = get_feature_values(feature)
62
+
63
+ feature.gates.each do |gate|
64
+ result[gate.key] = case gate.data_type
65
+ when :boolean, :integer
66
+ values[gate.key.to_s]
67
+ when :set
68
+ gate_values_as_set(values, gate)
69
+ else
70
+ unsupported_data_type gate.data_type
71
+ end
72
+ end
73
+
74
+ result
75
+ end
76
+
77
+ # Public: Enables a gate for a given thing.
78
+ #
79
+ # feature - The Flipper::Feature for the gate.
80
+ # gate - The Flipper::Gate to disable.
81
+ # thing - The Flipper::Type being disabled for the gate.
82
+ #
83
+ # Returns true.
84
+ def enable(feature, gate, thing)
85
+ case gate.data_type
86
+ when :boolean, :integer
87
+ @client.put key(feature, gate), thing.value.to_s
88
+ when :set
89
+ @client.put set_member_key(feature, gate, thing), '1'
90
+ else
91
+ unsupported_data_type gate.data_type
92
+ end
93
+
94
+ true
95
+ end
96
+
97
+ # Public: Disables a gate for a given thing.
98
+ #
99
+ # feature - The Flipper::Feature for the gate.
100
+ # gate - The Flipper::Gate to disable.
101
+ # thing - The Flipper::Type being disabled for the gate.
102
+ #
103
+ # Returns true.
104
+ def disable(feature, gate, thing)
105
+ case gate.data_type
106
+ when :boolean
107
+ @client.delete build_path "#{feature}/?recurse"
108
+ when :integer
109
+ @client.put key(feature, gate), thing.value.to_s
110
+ when :set
111
+ @client.delete set_member_key(feature, gate, thing)
112
+ else
113
+ unsupported_data_type gate.data_type
114
+ end
115
+
116
+ true
117
+ end
118
+
119
+ private
120
+
121
+ # Private
122
+ def key(feature, gate)
123
+ build_path "#{feature.key}/#{gate.key}"
124
+ end
125
+
126
+ def set_member_key(feature, gate, thing)
127
+ build_path "#{feature.key}/#{gate.key}/#{thing.value.to_s}"
128
+ end
129
+
130
+ def build_path(key)
131
+ if namespace.nil?
132
+ key
133
+ else
134
+ "#{namespace}/#{key}"
135
+ end
136
+ end
137
+
138
+ def read_multiple(key_path)
139
+ begin
140
+ @client.get key_path, recurse: true
141
+ values = @client.raw
142
+ values = values.map do |item|
143
+ item['Key'].sub!("#{key_path}/", '')
144
+ end
145
+ value = values.to_set
146
+ rescue Diplomat::KeyNotFound
147
+ value = {}.to_set
148
+ end
149
+ value
150
+ end
151
+
152
+ def get_feature_values(feature)
153
+ begin
154
+ key_path = build_path(feature.key)
155
+ @client.get key_path, recurse: true
156
+ values = @client.raw
157
+ result = {}
158
+ values.each do |item|
159
+ result[item['Key'].sub!("#{key_path}/", '')] = Base64.decode64(item['Value'])
160
+ end
161
+ result
162
+ rescue Diplomat::KeyNotFound
163
+ {}
164
+ end
165
+ end
166
+
167
+ def gate_values_as_set(values, gate)
168
+ regex = /^#{Regexp.escape(gate.key.to_s)}\//
169
+ keys_for_gate = values.keys.grep regex
170
+ values = keys_for_gate.map { |key| key.split('/', 2).last }
171
+ values.to_set
172
+ end
173
+
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,7 @@
1
+ module Flipper
2
+ module Adapters
3
+ class Consul
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,61 @@
1
+ require 'helper'
2
+ require 'flipper/adapters/consul'
3
+ require 'flipper/spec/shared_adapter_specs'
4
+
5
+ describe Flipper::Adapters::Consul do
6
+ let(:client) { Diplomat::Kv.new }
7
+
8
+ before do
9
+ client.delete "/?recurse"
10
+ end
11
+
12
+ context 'with no namespace' do
13
+ subject { described_class.new(client) }
14
+
15
+ its(:namespace) { is_expected.to be_nil }
16
+
17
+ it_should_behave_like 'a flipper adapter'
18
+ end
19
+
20
+ context 'with a namespace' do
21
+
22
+ context 'with an empty namespace' do
23
+ subject { described_class.new(client, '') }
24
+ its(:namespace) { is_expected.to be_nil }
25
+ end
26
+
27
+ context 'namespace starts with /' do
28
+ subject { described_class.new(client, '/foo') }
29
+ its(:namespace) { is_expected.to eq 'foo' }
30
+ end
31
+
32
+ context 'adapter methods' do
33
+ subject { described_class.new(client, 'foo/bar') }
34
+
35
+ it_should_behave_like 'a flipper adapter'
36
+ end
37
+
38
+ context 'data is namespaced' do
39
+ let(:namespace) { 'foo/bar' }
40
+ subject { described_class.new(client, namespace) }
41
+ context 'feature data' do
42
+ it 'is namespaced' do
43
+ feature = Flipper::Feature.new :search, subject
44
+ subject.add feature
45
+
46
+ foo = client.get "#{namespace}/#{Flipper::Adapters::Consul::FeaturesKey}/features/search"
47
+ expect(foo).to eq '1'
48
+ end
49
+ end
50
+ context 'key/value data' do
51
+ it 'is namespaced' do
52
+ feature = Flipper::Feature.new :search, subject
53
+ subject.enable feature, feature.gate(:boolean), Flipper::Types::Boolean.new(true)
54
+
55
+ foo = client.get "#{namespace}/search/boolean"
56
+ expect(foo).to eq 'true'
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.expand_path('../../lib', __FILE__))
2
+
3
+ #require 'pathname'
4
+ #require 'logger'
5
+ #
6
+ #root_path = Pathname(__FILE__).dirname.join('..').expand_path
7
+ #lib_path = root_path.join('lib')
8
+ #log_path = root_path.join('log')
9
+ #log_path.mkpath
10
+ #
11
+ require 'rubygems'
12
+ require 'bundler'
13
+
14
+ Bundler.require(:default, :test)
15
+
16
+ require 'flipper-consul'
17
+
18
+ #Logger.new(log_path.join('test.log'))
19
+
20
+ RSpec.configure do |config|
21
+ config.filter_run :focused => true
22
+ config.alias_example_to :fit, :focused => true
23
+ config.alias_example_to :xit, :pending => true
24
+ config.run_all_when_everything_filtered = true
25
+ config.fail_fast = true
26
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flipper-consul
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Graham Davison
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: flipper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.0.beta6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.0.beta6
27
+ - !ruby/object:Gem::Dependency
28
+ name: diplomat
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.11'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.11'
41
+ description: Consul adapter for Flipper
42
+ email:
43
+ - g.m.davison@computer.org
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .ruby-gemset
50
+ - .ruby-version
51
+ - .travis.yml
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - Vagrantfile
57
+ - flipper-consul.gemspec
58
+ - lib/flipper-consul.rb
59
+ - lib/flipper/adapters/consul.rb
60
+ - lib/flipper/adapters/consul/version.rb
61
+ - spec/flipper/consul_spec.rb
62
+ - spec/helper.rb
63
+ homepage: https://github.com/gdavison/flipper-consul
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.0.14
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Consul adapter for Flipper
87
+ test_files:
88
+ - spec/flipper/consul_spec.rb
89
+ - spec/helper.rb