flipper-consul 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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