confman 0.0.2

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.
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .testconfman/
19
+ bin/.confman
20
+
21
+ # vim artifacts
22
+ **.swp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in confman.gemspec
4
+ gem 'pry-debugger'
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Masahji Stewart
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,27 @@
1
+ # Confman
2
+
3
+ Ruby client to access Confman Server
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'confman'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install confman
18
+
19
+ ## Usage
20
+
21
+ Confman.server = '<confman server>'
22
+ Confman.key = '<key>'
23
+ Confman.secret = '<secret>'
24
+
25
+ Confman.load_conf_set('somename', 'One')
26
+ # Assuming the presence of conf pair ('foo', 'bar')
27
+ Confman.somename.foo.should == 'bar'
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/confman ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
6
+
7
+ require "confman/cli"
8
+
9
+ Confman::CLI.start(ARGV)
data/config/test.yml ADDED
@@ -0,0 +1,4 @@
1
+ confman:
2
+ endpoint_url: 'https://appforce.synctree.com/api/confman'
3
+ api_key: 'f5dcebf81236dcace1545fda8a3ede6'
4
+ secret: '7O8EJXt6fMMfWy0/sQeuVX1VOk8FCwemtMgiJHQR'
data/confman.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'confman/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "confman"
8
+ spec.version = Confman::VERSION
9
+ spec.authors = ["Masahji Stewart"]
10
+ spec.email = ["masahji@synctree.com"]
11
+ spec.description = 'Confman ruby client'
12
+ spec.summary = ''
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rest-client", "~> 1"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rspec", "~> 2.6"
25
+ spec.add_development_dependency "rake"
26
+ end
data/lib/confman.rb ADDED
@@ -0,0 +1,79 @@
1
+ require "confman/version"
2
+ require "confman/data_store"
3
+ require "confman/api"
4
+ require "confman/access"
5
+ require 'logger'
6
+
7
+ module Confman
8
+ class << self
9
+ attr_writer :logger
10
+
11
+ def load_conf_set(getter, conf_set_name)
12
+ pairs = begin
13
+ conf_set = Confman.api.find_by_name(conf_set_name)
14
+ DataStore.write(getter, conf_set_name, conf_set.pairs.to_json)
15
+ conf_set.pairs
16
+ rescue => ex
17
+ logger.error("load_conf_set(#{getter}, #{conf_set_name}): #{ex}")
18
+ logger.error(ex.backtrace[0..5].join("\n"))
19
+ d = DataStore.read(getter, conf_set_name)
20
+ raise(ex) if d.nil? || d.blank?
21
+ JSON.parse(d)
22
+ end
23
+
24
+ self.define_singleton_method(getter.to_s.to_sym) do
25
+ OpenStruct.new(pairs)
26
+ end
27
+ end
28
+
29
+ def api
30
+ @api ||= Confman::API.new
31
+ @api
32
+ end
33
+
34
+ def access
35
+ @access ||= Confman::Access.new(api)
36
+ @access
37
+ end
38
+
39
+ def logger
40
+ @logger ||= Logger.new(STDERR)
41
+ @logger
42
+ end
43
+
44
+ end # end class << self
45
+
46
+ class ConfFileNotFoundError < StandardError
47
+ def initialize(msg)
48
+ super(msg)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ unless Hash.new.respond_to?(:symbolize_keys!)
55
+ class Hash
56
+ def symbolize_keys!
57
+ keys.each do |key|
58
+ self[(key.to_sym rescue key) || key] = delete(key)
59
+ end
60
+ self
61
+ end
62
+ end
63
+ end
64
+
65
+ unless nil.respond_to?(:blank?)
66
+ class NilClass
67
+ def blank?
68
+ true
69
+ end
70
+ end
71
+ end
72
+
73
+ unless "".respond_to?(:blank?)
74
+ class String
75
+ def blank?
76
+ self !~ /[^[:space:]]/
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,107 @@
1
+ require 'confman'
2
+ require 'openssl'
3
+
4
+ class Confman::Access
5
+ attr_accessor :api
6
+
7
+ def initialize(api = Confman.api)
8
+ self.api = api
9
+ end
10
+
11
+ def extract_keys(file = authorized_keys_location)
12
+ r = { :keys => [] }
13
+ return r unless File.exists?(file)
14
+ File.readlines(file).each do |key|
15
+ key.chomp!
16
+ if key =~ /^#\sAM\s([^=]+)=(.*)$/
17
+ r[$1.to_sym] = $2
18
+ elsif key =~ /^ssh-/
19
+ r[:keys].push(key.chomp)
20
+ end
21
+ end
22
+ r
23
+ end
24
+
25
+ def save_keys(key_info, file = "#{authorized_keys_location}.#{Time.now.to_i}")
26
+ File.open(file, "w") do |fh|
27
+ key_info.each do |attribute, value|
28
+
29
+ if attribute == :manual_keys
30
+ key_info[attribute].each do |k|
31
+ fh.puts k
32
+ end
33
+
34
+ elsif attribute == :users
35
+ key_info[attribute].each do |u, keys|
36
+ keys.each do |k|
37
+ fh.puts("environment=\"AM_USER=#{u}\" #{k}")
38
+ end
39
+ end
40
+
41
+ else
42
+ fh.puts("# AM #{attribute}=#{value}")
43
+ end
44
+
45
+ end
46
+ end
47
+
48
+ File.chmod(0600, file)
49
+
50
+ file
51
+ end
52
+
53
+ def reset_keys
54
+ current_keys = extract_keys
55
+ new_keys = request_new_keys
56
+
57
+ if new_keys[:updated_at] != current_keys[:updated_at]
58
+ new_keys[:manual_keys] = current_keys[:keys].reject { |key| key =~ /AM_USER/ }
59
+
60
+ new_authorized_keys_file = "#{authorized_keys_location}.#{Time.now.to_i}"
61
+ save_keys(new_keys, new_authorized_keys_file)
62
+ FileUtils.cp(new_authorized_keys_file, authorized_keys_location)
63
+ end
64
+
65
+ end
66
+
67
+ def authorized_keys_location
68
+ ssh_dir = "#{ENV["HOME"]}/.ssh"
69
+ FileUtils.mkdir_p(ssh_dir) unless File.exists?(ssh_dir)
70
+ return "#{ssh_dir}/authorized_keys"
71
+ end
72
+
73
+ def decrypt(encrypted_data)
74
+ encrypted_data = Base64.decode64(encrypted_data)
75
+ if encrypted_data =~ /^0A/
76
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
77
+ cipher.decrypt
78
+ cipher.key = rsa.public_decrypt(encrypted_data[2, 128])
79
+ cipher.iv = rsa.public_decrypt(encrypted_data[130, 128])
80
+ data = cipher.update(encrypted_data[258..-1])
81
+ data << cipher.final
82
+ return data
83
+ else
84
+ raise "invalid data found"
85
+ end
86
+ end
87
+
88
+ def rsa
89
+ @rsa ||= OpenSSL::PKey::RSA.new(File.read("#{self.api.config_dir}/.asym.key"))
90
+ @rsa
91
+ end
92
+
93
+ def request_new_keys
94
+ begin
95
+ results, response = Confman.api.request(:get, "computing_resources/access_keys", {})
96
+ rescue RestClient::Conflict
97
+ STDERR.puts("This instance has no key. Please run 'confman init' as root to reset your key for this instance")
98
+ return nil
99
+ end
100
+
101
+ results.update(JSON.parse(decrypt(results[:data])))
102
+ results.symbolize_keys!
103
+ results.delete(:data)
104
+ return results
105
+ end
106
+
107
+ end
@@ -0,0 +1,176 @@
1
+ require 'rest_client'
2
+ require 'ostruct'
3
+ require 'json'
4
+ require 'timeout'
5
+ require 'base64'
6
+
7
+
8
+ module Confman
9
+ class API
10
+ attr_accessor :endpoint_url
11
+ attr_accessor :api_key
12
+ attr_accessor :secret
13
+ attr_accessor :no_cloud
14
+ attr_writer :config_dir
15
+
16
+ def initialize
17
+ self.config_dir = "/etc/confman"
18
+ end
19
+
20
+ def config_dir
21
+ # Create the directory
22
+ unless Dir.exists?(@config_dir)
23
+ FileUtils.mkdir_p(@config_dir)
24
+ File.chmod(0755, @config_dir)
25
+ end
26
+
27
+ @config_dir
28
+ end
29
+
30
+ def config_path
31
+ File.join(config_dir, "config.json")
32
+ end
33
+
34
+ def load_config(path = config_path)
35
+ if File.exists?(path)
36
+ config_hash = JSON.parse IO.read(path)
37
+
38
+ config_hash.each do |key, value|
39
+ send("#{key}=", value) if respond_to?("#{key}=")
40
+ end
41
+ return config_hash
42
+ end
43
+ return nil
44
+ end
45
+
46
+ def find_by_name(name)
47
+ begin
48
+ results = search(name: name)
49
+ raise RestClient::ResourceNotFound if results[:count] == 0
50
+ conf_set_hash = results[:results].first
51
+ DataStore.write(@api_key, name, conf_set_hash.to_json)
52
+ ConfSet.new(self, conf_set_hash)
53
+ rescue => ex
54
+ Confman.logger.error("find_by_name(#{name}): #{ex}")
55
+ Confman.logger.error(ex.backtrace[0..5].join("\n"))
56
+ if conf_set_str = DataStore.read(@api_key, name)
57
+ ConfSet.new(self, JSON.parse(conf_set_str))
58
+ else
59
+ raise ex
60
+ end
61
+ end
62
+ end
63
+
64
+ def search(query = {})
65
+ results, response = request(:get, "confman/sets/search", query)
66
+ results
67
+ end
68
+
69
+ def conf_sets(query = {})
70
+ results, response = request(:get, "confman/sets", query)
71
+ response
72
+ end
73
+
74
+ def reset_server_key!
75
+ results, response = Confman.api.request(:get, "computing_resources/key", {})
76
+ File.open("#{config_dir}/.asym.key", "w") do |fh|
77
+ fh.write results[:data]
78
+ end
79
+ File.chmod(0644, "#{config_dir}/.asym.key")
80
+ end
81
+
82
+ def request(method, path, object)
83
+ request_args = [{ accept: :json, content_type: :json }]
84
+
85
+ if method == :get
86
+ request_args.first[:params] = object
87
+ else
88
+ request_args.unshift(object.to_json)
89
+ end
90
+
91
+ response = resource[path].send(method, *request_args)
92
+ results = JSON.parse(response.to_s) if response.to_s.length > 0
93
+ results.symbolize_keys! if results.kind_of?(Hash)
94
+ return results, response
95
+ end
96
+
97
+ def resource
98
+ timestamp = Time.now.utc.to_i
99
+ secret_hash = Digest::MD5.hexdigest("#{secret}:#{timestamp}")
100
+
101
+ @resource ||= RestClient::Resource.new(endpoint_url, :headers => {
102
+ :cloud_meta => Base64.encode64(cloud_metadata.to_json).gsub(/\s+/, "")
103
+ })
104
+ @resource.options[:user] = api_key
105
+ @resource.options[:password] = "#{secret_hash}:#{timestamp}"
106
+ @resource
107
+ end
108
+
109
+ def cloud_metadata
110
+ return nil if no_cloud
111
+ @cloud_metadata ||= aws_metadata
112
+ @cloud_metadata
113
+ end
114
+
115
+ def aws_metadata(fields = %w(
116
+ ami-id availability-zone
117
+ instance-id instance-type
118
+ kernel-id local-hostname
119
+ mac public-hostname))
120
+
121
+ meta = {}
122
+ begin
123
+ fields.each do |key|
124
+ Timeout::timeout(1) do
125
+ begin
126
+ meta[key] = RestClient.get("http://169.254.169.254/latest/meta-data/#{key}").strip
127
+ rescue RestClient::ResourceNotFound => ex
128
+ Confman.logger.info("aws_metadata:#{key} #{ex}")
129
+ end
130
+ end
131
+ end
132
+ rescue => ex
133
+ Confman.logger.info("aws_metadata:#{ex}")
134
+ end
135
+ meta['type'] = 'aws' if meta.size > 0
136
+ return meta
137
+ end
138
+
139
+ end
140
+
141
+ class ConfSet
142
+ attr_reader :api
143
+ attr_accessor :id, :created_at, :updated_at, :name, :conf_pairs
144
+
145
+ def initialize(api, fields = {})
146
+ @api = api
147
+ fields.each do |k,v|
148
+ self.send("#{k}=", v) if self.respond_to?("#{k}=")
149
+ end
150
+ end
151
+
152
+ def update_pairs(pairs)
153
+ results, response = api.request(:put, "confman/sets/#{id}/update_pairs", conf_pairs: pairs)
154
+ end
155
+
156
+ def pairs
157
+ Hash[conf_pairs.collect { |p| p.symbolize_keys!; [p[:name], p[:value]] }]
158
+ end
159
+
160
+ def as_json
161
+ {
162
+ :id => id,
163
+ :name => name,
164
+ :created_at => created_at,
165
+ :updated_at => updated_at,
166
+ :conf_pairs => conf_pairs
167
+ }
168
+ end
169
+
170
+ def to_json
171
+ as_json.to_json
172
+ end
173
+ end
174
+
175
+ end
176
+
@@ -0,0 +1,106 @@
1
+ require 'confman'
2
+ require 'optparse'
3
+
4
+ class Confman::CLI
5
+ @@options = {}
6
+ @@opt_parser = nil
7
+
8
+ def self.start(args)
9
+ Confman.logger.level = 2
10
+
11
+ command = args.shift
12
+
13
+ begin
14
+ Confman.api.load_config
15
+ rescue Errno::EACCES => ex
16
+ Confman.logger.error("Unable to load config: #{ex}\nPlease run 'confman init' as root to continue")
17
+ exit
18
+ end
19
+
20
+ @@opt_parser = OptionParser.new do |opt|
21
+ opt.banner = "Usage: confman COMMAND OPTIONS"
22
+ opt.separator ""
23
+ opt.separator "Commands"
24
+ opt.separator " exportall -f <outputfile>: Imports all the conf sets into a file."
25
+ opt.separator " export -n <name> -f <outputfile>: Imports conf_set named 'name' into a file."
26
+ opt.separator " init -e <endpoint> -k <key>: Sets up config. Run this before querying the ConfMan server.(run as root)"
27
+ opt.separator " reset_keys: Resets authorized keys for the current user."
28
+ opt.separator ""
29
+ opt.separator "Options"
30
+
31
+ opt.on('-k key', String, 'ConfMan API Key') do |key|
32
+ @@options[:key] = key
33
+ end
34
+
35
+ opt.on('-e endpoint', String, 'ConfMan API Endpoint') do |ep|
36
+ @@options[:endpoint] = ep
37
+ end
38
+
39
+ opt.on('-f outputfile', String, 'Output file') do |of|
40
+ @@options[:outputfile] = of
41
+ end
42
+
43
+ opt.on('-n name', String, 'Name') do |name|
44
+ @@options[:name] = name
45
+ end
46
+ end
47
+
48
+ @@opt_parser.parse!(args)
49
+
50
+ if respond_to?(command)
51
+ send(command)
52
+ else
53
+ puts @@opt_parser
54
+ end
55
+ end
56
+
57
+
58
+ def self.init
59
+
60
+ config_hash = Confman.api.load_config || {}
61
+ config_hash.symbolize_keys!
62
+
63
+ %w(endpoint_url api_key secret).each do |c|
64
+
65
+ if @@options[c.to_sym].blank?
66
+ puts "Please enter your #{c}: [#{config_hash[c.to_sym]}]"
67
+ value = STDIN.gets.chomp
68
+ unless value.blank?
69
+ config_hash[c.to_sym] = value
70
+ end
71
+
72
+ else
73
+ config_hash[c.to_sym] = @@options[c.to_sym]
74
+ end
75
+ end
76
+
77
+ # Write to file
78
+ File.open Confman.api.config_path, "w" do |file|
79
+ file.write(config_hash.to_json)
80
+ end
81
+
82
+ Confman.api.load_config
83
+ Confman.api.reset_server_key!
84
+ end
85
+
86
+ def self.reset_keys
87
+ Confman.access.reset_keys
88
+ end
89
+
90
+ def self.exportall
91
+ out = @@options[:outputfile] ? File.open(@@options[:outputfile], "w") : STDOUT
92
+ out.write(Confman.api.conf_sets)
93
+ end
94
+
95
+ def self.export
96
+ out = @@options[:outputfile] ? File.open(@@options[:outputfile], "w") : STDOUT
97
+
98
+ begin
99
+ conf_set = Confman.api.find_by_name(@@options[:name])
100
+ out.write(conf_set.to_json)
101
+ rescue RestClient::ResourceNotFound
102
+ Confman.logger.error("ConfSet #{@@options[:name]} not found")
103
+ end
104
+ end
105
+
106
+ end
@@ -0,0 +1,36 @@
1
+ module Confman
2
+ class DataStore
3
+ @@dir = '.confman'
4
+
5
+ def self.dir= dir
6
+ @@dir = dir
7
+ end
8
+
9
+ def self.dir
10
+ @@dir
11
+ end
12
+
13
+ def self.write(key, conf_set_name, data)
14
+ create_directory_if_not_present
15
+
16
+ filepath = compute_file_path(key, conf_set_name)
17
+ File.open filepath, "w" do |file|
18
+ file.write(data)
19
+ end
20
+ end
21
+
22
+ def self.read(key, conf_set_name)
23
+ filepath = compute_file_path(key, conf_set_name)
24
+ IO.read(filepath) if File.exists?(filepath)
25
+ end
26
+
27
+ def self.create_directory_if_not_present
28
+ Dir.mkdir(@@dir) unless Dir.exists?(dir)
29
+ end
30
+
31
+ def self.compute_file_path(key, conf_set_name)
32
+ "#{dir}/#{key}_#{Digest::MD5.hexdigest conf_set_name}"
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Confman
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,216 @@
1
+ require 'confman'
2
+ require 'yaml'
3
+
4
+ describe Confman do
5
+ before :all do
6
+ DataStore.dir = '.testconfman'
7
+ @fake_search_results = {
8
+ count: 1,
9
+ results: [
10
+ {
11
+ name:"One",
12
+ notification_url:"",
13
+ read_permission:"public", write_permission:"public",
14
+ conf_pairs: [
15
+ { name:"foo", value:"bar" },
16
+ { name:"password", value:"something" }
17
+ ]
18
+ }
19
+ ]
20
+ }
21
+
22
+ @config = YAML.load(File.open(File.join("config", "#{ENV['TEST_ENV'] || 'test'}.yml")))
23
+ Confman.api.endpoint_url = @config['confman']['endpoint_url']
24
+ Confman.api.api_key = @config['confman']['api_key']
25
+ Confman.api.secret = @config['confman']['secret']
26
+ end
27
+
28
+ describe :load_conf_set do
29
+ it 'can be loaded twice' do
30
+ Confman.api.should_receive(:search).and_return(@fake_search_results)
31
+ Confman.load_conf_set('somename', 'some_conf_set')
32
+ Confman.api.should_receive(:search).and_return(@fake_search_results)
33
+ lambda {Confman.load_conf_set('somename', 'some_conf_set')}.should_not raise_error
34
+ lambda {Confman.somename}.should_not raise_error
35
+ end
36
+
37
+ it 'creates a getter function which returns the conf_set' do
38
+ Confman.api.should_receive(:search).and_return(@fake_search_results)
39
+ Confman.load_conf_set('somename', 'some_conf_set')
40
+ lambda {Confman.somename}.should_not raise_error
41
+ end
42
+
43
+ it 'even works with symbols' do
44
+ Confman.api.should_receive(:search).and_return(@fake_search_results)
45
+ Confman.load_conf_set(:oauth, 'some_conf_set')
46
+ lambda {Confman.oauth}.should_not raise_error
47
+ end
48
+
49
+ it 'loads the data into an OpenStruct object' do
50
+ Confman.api.should_receive(:search).and_return(@fake_search_results)
51
+ Confman.load_conf_set('somename', 'One')
52
+ Confman.somename.class == OpenStruct
53
+ Confman.somename.foo.should == 'bar'
54
+ end
55
+
56
+ describe :not_found do
57
+ it 'throws an ConfSetNotFound exception when the conf_set is not found in the server' do
58
+ Confman.api.should_receive(:search).and_return({count: 0})
59
+
60
+ expect {Confman.load_conf_set('somename', 'non_existent_conf_set')}.to raise_error(RestClient::ResourceNotFound)
61
+ end
62
+
63
+ it 'throws an ConfSetNotFound exception when get_conf_set raises any kind of error' do
64
+ Confman.api.should_receive(:search).and_return({count: 0})
65
+ expect {Confman.load_conf_set('somename', 'network_error')}.to raise_error(RestClient::ResourceNotFound)
66
+ end
67
+ end
68
+ end
69
+
70
+ # Really an integration test - Uncomment and run it wrt your local server.
71
+ describe 'read:public:write:public' do
72
+ before :all do
73
+ Confman.api.should_receive(:aws_metadata).and_return({"ami-id"=>"ami-137bcf7a", "instance-id"=>"i-3be58146", "instance-type"=>"m1.small", "kernel-id"=>"aki-825ea7eb", "local-hostname"=>"ip-10-86-154-126.ec2.internal", "mac"=>"12:31:38:19:9C:90", "public-hostname"=>"ec2-107-20-165-98.compute-1.amazonaws.com"})
74
+ @conf_set = Confman.api.find_by_name('read:public:write:public')
75
+ end
76
+
77
+ it 'has a @conf_set with an id' do
78
+ @conf_set.id.should be_a_kind_of(Fixnum)
79
+ end
80
+
81
+ it 'calls a real server and retrieves the result' do
82
+ Confman.load_conf_set('o', 'read:public:write:public')
83
+ Confman.o.boolean_attribute.should == 'true'
84
+ end
85
+
86
+ it 'updates a confset' do
87
+ @conf_set.update_pairs(updated_boolean: false).should be_true
88
+ end
89
+
90
+ it 'cannot set a non boolean value to a boolean attribute' do
91
+ expect {@conf_set.update_pairs(updated_boolean: "bleh")}.to raise_error(RestClient::UnprocessableEntity)
92
+ end
93
+
94
+ it 'updates a confset' do
95
+ @conf_set.update_pairs(password_attribute: '12345').should be_true
96
+ end
97
+ end
98
+
99
+ =begin
100
+ describe 'ravi integration tests' do
101
+ before :all do
102
+ Confman.api.endpoint_url = "http://localhost:3000/api/confman"
103
+ Confman.api.api_key = "e2a5ee9cdc6b41ef72f614cd2078c61"
104
+ Confman.api.secret = "8XxvpFAuq+s99lawHi2gJ4W3fGJ0IlhJSjHUzcis"
105
+ end
106
+
107
+ it 'updates the confset' do
108
+ @conf_set = Confman.api.find_by_name('Set1')
109
+ @conf_set.update_pairs(foo: 'fromruby').should be_true
110
+ end
111
+
112
+ it 'retrieves all the confsets' do
113
+ conf_sets_json = Confman.api.conf_sets
114
+ JSON.parse(conf_sets_json).class.should == Array
115
+ end
116
+
117
+ describe :find_by_name do
118
+ it 'retrieves the confset' do
119
+ conf_set = Confman.api.find_by_name('Set1')
120
+ conf_set.name.should == 'Set1'
121
+ end
122
+
123
+ it 'caches the confset locally' do
124
+ conf_set = Confman.api.find_by_name('Set1')
125
+ file_path = DataStore.compute_file_path(Confman.api.api_key, 'Set1')
126
+ File.exists?(file_path).should == true
127
+ end
128
+
129
+ it 'raises ResourceNotFound if the confset is not present' do
130
+ expect {Confman.api.find_by_name('NonExistant')}.to raise_error(RestClient::ResourceNotFound)
131
+ end
132
+
133
+ it 'raises exception if endpoint is not reachable and there is no local copy' do
134
+ FileUtils.rm_rf(DataStore.dir, secure:true)
135
+ Confman.api.endpoint_url = "http://localhost:3001/api/confman"
136
+ # Since resource is memoized
137
+ Confman.api.instance_variable_set(:@resource, nil)
138
+ expect {Confman.api.find_by_name('Set1')}.to raise_error(Exception)
139
+ end
140
+
141
+ it 'reads the confset locally in case of network errors' do
142
+ FileUtils.rm_rf(DataStore.dir, secure:true)
143
+ Confman.api.endpoint_url = "http://localhost:3000/api/confman"
144
+
145
+ # Since resource is memoized
146
+ Confman.api.instance_variable_set(:@resource, nil)
147
+ conf_set = Confman.api.find_by_name('Set1')
148
+ Confman.api.endpoint_url = "http://localhost:3001/api/confman"
149
+ Confman.api.instance_variable_set(:@resource, nil)
150
+ conf_set_dup = Confman.api.find_by_name('Set1')
151
+ conf_set_dup.name.should == 'Set1'
152
+ end
153
+ end
154
+ end
155
+ =end
156
+
157
+
158
+ describe 'read:public:write:private' do
159
+ before :all do
160
+ @conf_set = Confman.api.find_by_name('read:public:write:private')
161
+ end
162
+
163
+ it 'has a @conf_set with an id' do
164
+ @conf_set.id.should be_a_kind_of(Fixnum)
165
+ end
166
+
167
+ it 'calls a real server and retrieves the result' do
168
+ Confman.load_conf_set('o', 'read:public:write:public')
169
+ Confman.o.boolean_attribute.should == 'true'
170
+ end
171
+
172
+ it 'cannot update a confset boolean' do
173
+ expect{@conf_set.update_pairs(updated_boolean: false)}.to raise_error(RestClient::PermissionDenied)
174
+ end
175
+
176
+ it 'cannot set a non boolean value to a boolean attribute' do
177
+ expect {@conf_set.update_pairs(updated_boolean: "bleh")}.to raise_error(RestClient::PermissionDenied)
178
+ end
179
+
180
+ it 'cannot update a confset password' do
181
+ expect {@conf_set.update_pairs(password_attribute: '12345')}.to raise_error(RestClient::PermissionDenied)
182
+ end
183
+
184
+ end
185
+
186
+ read_private_write_private = proc do
187
+ before :all do
188
+ @conf_set = Confman.api.find_by_name('read:private:write:private')
189
+ end
190
+
191
+ it 'has a @conf_set with an id' do
192
+ @conf_set.id.should be_a_kind_of(Fixnum)
193
+ end
194
+
195
+ it 'calls a real server and retrieves the result' do
196
+ Confman.load_conf_set('o', 'read:public:write:public')
197
+ Confman.o.boolean_attribute.should == 'true'
198
+ end
199
+
200
+ it 'updates a confset' do
201
+ @conf_set.update_pairs(updated_boolean: false).should be_true
202
+ end
203
+
204
+ it 'cannot set a non boolean value to a boolean attribute' do
205
+ expect {@conf_set.update_pairs(updated_boolean: "bleh")}.to raise_error(RestClient::UnprocessableEntity)
206
+ end
207
+
208
+ it 'updates a confset' do
209
+ @conf_set.update_pairs(password_attribute: '12345').should be_true
210
+ end
211
+ end
212
+
213
+ describe 'read:private:write:private', read_private_write_private
214
+ describe 'read:private:write:public', read_private_write_private
215
+
216
+ end
@@ -0,0 +1,53 @@
1
+ require 'confman'
2
+ require 'fileutils'
3
+
4
+ include Confman
5
+
6
+ describe Confman::DataStore do
7
+ before :all do
8
+ DataStore.dir = '.testconfman'
9
+ end
10
+
11
+ describe :create_directory_if_not_present do
12
+ it 'creates the directory if not present' do
13
+ FileUtils.rm_rf(DataStore.dir, secure:true)
14
+ DataStore.create_directory_if_not_present
15
+ Dir.exists?(DataStore.dir).should be_true
16
+ Dir.rmdir(DataStore.dir) if Dir.exists?(DataStore.dir)
17
+ end
18
+ end
19
+
20
+ describe :write do
21
+ before :each do
22
+ FileUtils.rm_rf(DataStore.dir, secure:true)
23
+ DataStore.write('key','foo','some_content')
24
+ end
25
+
26
+ after :each do
27
+ FileUtils.rm_rf(DataStore.dir, secure:true)
28
+ end
29
+
30
+ it 'creates the signature file name' do
31
+ filename = "key_#{Digest::MD5.hexdigest 'foo'}"
32
+ File.exists?("#{DataStore.dir}/#{filename}").should be_true
33
+ end
34
+ end
35
+
36
+ describe :read do
37
+ after :each do
38
+ FileUtils.rm_rf(DataStore.dir, secure:true)
39
+ end
40
+
41
+ it 'reads back the written content' do
42
+ Dir.rmdir(DataStore.dir) if Dir.exists?(DataStore.dir)
43
+ DataStore.write(2,'foo','some_content')
44
+ DataStore.read(2,'foo').should == 'some_content'
45
+ end
46
+
47
+ it 'returns nil if the conf_set was not previously written' do
48
+ Dir.rmdir(DataStore.dir) if Dir.exists?(DataStore.dir)
49
+ DataStore.read(2,'foo').should be_nil
50
+ end
51
+
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: confman
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Masahji Stewart
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.3'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.3'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.6'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.6'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Confman ruby client
79
+ email:
80
+ - masahji@synctree.com
81
+ executables:
82
+ - confman
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - bin/confman
92
+ - config/test.yml
93
+ - confman.gemspec
94
+ - lib/confman.rb
95
+ - lib/confman/access.rb
96
+ - lib/confman/api.rb
97
+ - lib/confman/cli.rb
98
+ - lib/confman/data_store.rb
99
+ - lib/confman/version.rb
100
+ - spec/confman_spec.rb
101
+ - spec/data_store_spec.rb
102
+ homepage: ''
103
+ licenses:
104
+ - MIT
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.23
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: ''
127
+ test_files:
128
+ - spec/confman_spec.rb
129
+ - spec/data_store_spec.rb