j-enc 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +31 -0
  6. data/Rakefile +2 -0
  7. data/bin/j-enc +12 -0
  8. data/j-enc.gemspec +28 -0
  9. data/j-enc.iml +24 -0
  10. data/lib/enc/builder.rb +28 -0
  11. data/lib/enc/cache/exceptions.rb +6 -0
  12. data/lib/enc/cache/node_cache.rb +57 -0
  13. data/lib/enc/cache.rb +2 -0
  14. data/lib/enc/collins_helper/api.rb +43 -0
  15. data/lib/enc/collins_helper/connection.rb +26 -0
  16. data/lib/enc/collins_helper/node/exceptions.rb +9 -0
  17. data/lib/enc/collins_helper/node/node_asset.rb +135 -0
  18. data/lib/enc/collins_helper/node.rb +2 -0
  19. data/lib/enc/collins_helper.rb +3 -0
  20. data/lib/enc/config.rb +63 -0
  21. data/lib/enc/runner.rb +58 -0
  22. data/lib/enc/utils/logging.rb +68 -0
  23. data/lib/enc/utils.rb +1 -0
  24. data/lib/enc/version.rb +3 -0
  25. data/lib/enc.rb +38 -0
  26. data/spec/api_spec.rb +42 -0
  27. data/spec/builder_spec.rb +43 -0
  28. data/spec/cli_helper.rb +22 -0
  29. data/spec/config_spec.rb +15 -0
  30. data/spec/connection_spec.rb +9 -0
  31. data/spec/enc_spec.rb +25 -0
  32. data/spec/factories/api.rb +60 -0
  33. data/spec/factories/builder.rb +27 -0
  34. data/spec/factories/cache.rb +9 -0
  35. data/spec/factories/config.rb +21 -0
  36. data/spec/factories/connection.rb +11 -0
  37. data/spec/factories/node_asset.rb +20 -0
  38. data/spec/factories/response.rb +49 -0
  39. data/spec/factories/runner.rb +19 -0
  40. data/spec/factories.rb +21 -0
  41. data/spec/features/external_request_spec.rb +9 -0
  42. data/spec/node_asset_spec.rb +54 -0
  43. data/spec/node_cache_spec.rb +25 -0
  44. data/spec/runner_spec.rb +41 -0
  45. data/spec/spec_helper.rb +52 -0
  46. data/spec/support/factory_girl.rb +8 -0
  47. data/spec/support/utils.rb +37 -0
  48. metadata +197 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c8fb70746bbb43bcc52ad7eff52488f41dd45222
4
+ data.tar.gz: 0582985c08fe3ab505572beac8b80bc5f3c94b06
5
+ SHA512:
6
+ metadata.gz: 0a67465a92406e9a4aefa32180d1f4f8cdcc975baa01e1d42f03b13aedff2b46e0f76a58a4e6ff1b86b8896d2c83022436d6e4eb6dde564c9f644546d536a02d
7
+ data.tar.gz: f7c3f72d7ca574f5f5a932b4a448d06d7a4e7d26040a0f710fcdef43a565fbe480369c15ed2e2f97b87979783803954d1460a80622e4ad3ce4bfe9686ab4e705
data/.gitignore ADDED
@@ -0,0 +1,15 @@
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
+ binstubs
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in j-enc.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jestin Woods
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,31 @@
1
+ # Collins::Enc
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 'j-enc'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install j-enc
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/j-enc/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
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/j-enc ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'enc'
5
+ rescue LoadError
6
+ unless $:.include?(File.dirname(__FILE__) + '/../lib/')
7
+ $: << File.dirname(__FILE__) + '/../lib'
8
+ end
9
+ require 'enc'
10
+ end
11
+
12
+ Enc.run(ARGV)
data/j-enc.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'enc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "j-enc"
8
+ spec.version = Enc::VERSION
9
+ spec.authors = ["Jestin Woods"]
10
+ spec.email = ["jestin.woods@jivesoftware.com"]
11
+ spec.summary = %q{Puppet ENC using Collins.}
12
+ spec.description = %q{Puppet ENC using Collins.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.1"
24
+ spec.add_development_dependency "webmock", "~> 1.20"
25
+ spec.add_development_dependency "factory_girl", "~> 4.5"
26
+
27
+ spec.add_runtime_dependency "collins_client", "~> 0.2"
28
+ end
data/j-enc.iml ADDED
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="CompassSettings">
4
+ <option name="compassSupportEnabled" value="true" />
5
+ </component>
6
+ <component name="FacetManager">
7
+ <facet type="gem" name="Ruby Gem">
8
+ <configuration>
9
+ <option name="GEM_APP_ROOT_PATH" value="$MODULE_DIR$" />
10
+ <option name="GEM_APP_TEST_PATH" value="" />
11
+ <option name="GEM_APP_LIB_PATH" value="" />
12
+ </configuration>
13
+ </facet>
14
+ </component>
15
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
16
+ <exclude-output />
17
+ <content url="file://$MODULE_DIR$" />
18
+ <orderEntry type="jdk" jdkName="RVM: ruby-2.0.0-p247" jdkType="RUBY_SDK" />
19
+ <orderEntry type="sourceFolder" forTests="false" />
20
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v1.7.4, RVM: ruby-2.0.0-p247) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.3.2, RVM: ruby-2.0.0-p247) [gem]" level="application" />
22
+ </component>
23
+ </module>
24
+
@@ -0,0 +1,28 @@
1
+ module Enc
2
+ class Builder
3
+ def initialize(asset)
4
+ @asset = asset
5
+ end
6
+
7
+ def to_yaml
8
+ return String.new.to_yaml unless @asset.uses_enc?
9
+ output = {'parameters' => {'deployment_environment' => @asset.get_deployment_environment,
10
+ 'datacenter' => @asset.get_datacenter,
11
+ 'roles' => @asset.get_roles}}
12
+
13
+ # Do not require the puppet environment until we upgrade to puppet 3.x.
14
+ # output[:environment] => @asset.get_puppet_environment
15
+
16
+ # We do this to satisfy the current requirement to have a roleN for each role, where N is the sorted index of the
17
+ # role list.
18
+ @asset.get_roles_by_index.each do |index, role|
19
+ output['parameters']['role' + (index + 1).to_s] = role
20
+ end
21
+
22
+ # It's not strictly necessary, but nice to have the $collins parameter at the end of the output.
23
+ output['parameters']['collins'] = @asset.get_flattened_attributes
24
+ output.to_yaml
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module Enc
2
+ module Cache
3
+ class CacheDoesNotExist < Exception; end
4
+ class UnableToCreateCacheDirectory < Exception; end
5
+ end
6
+ end
@@ -0,0 +1,57 @@
1
+ module Enc
2
+ module Cache
3
+ class NodeCache
4
+ include Enc::Utils::Logging
5
+
6
+ def initialize(config)
7
+ ensure_cache_dir(config.get('jive_enc_cache_dir'))
8
+ end
9
+
10
+ def exists?(hostname)
11
+ logger.debug("Checking to see if cache file #{cache_path(hostname)} exists")
12
+ File.exist?(cache_path(hostname))
13
+ end
14
+
15
+ def read(hostname)
16
+ logger.debug("Attempting to read cache #{cache_path(hostname)}")
17
+ begin
18
+ File.open(cache_path(hostname), 'r') { |file| Marshal.load(file.read)}
19
+ rescue Errno::ENOENT
20
+ logger.error("The node #{hostname} does not exist in the cache.")
21
+ raise CacheDoesNotExist, "The node #{hostname} does not exist in the cache."
22
+ end
23
+ end
24
+
25
+ def write(hostname, node)
26
+ logger.debug("Writing to cache #{cache_path(hostname)}")
27
+ File.open(cache_path(hostname), 'w') { |file| file.write(Marshal.dump(node)) }
28
+ end
29
+
30
+ def delete!(hostname)
31
+ logger.debug("Deleting cache #{cache_path(hostname)}")
32
+ File.delete(cache_path(hostname)) if File.exist?(cache_path(hostname))
33
+ end
34
+
35
+ protected
36
+
37
+ def cache_path(node)
38
+ if node.is_a?String
39
+ return "#{@cache_dir}/#{node}"
40
+ end
41
+ "#{@cache_dir}/#{node.get_hostname}"
42
+ end
43
+
44
+ def ensure_cache_dir(cache_dir)
45
+ @cache_dir = cache_dir
46
+ unless File.directory?(@cache_dir)
47
+ logger.debug("Creating cache directory #{@cache_dir}")
48
+ begin
49
+ Dir.mkdir(@cache_dir)
50
+ rescue => e
51
+ raise UnableToCreateCacheDirectory, e
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
data/lib/enc/cache.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'enc/cache/exceptions'
2
+ require 'enc/cache/node_cache'
@@ -0,0 +1,43 @@
1
+ require 'collins_client'
2
+
3
+ module Enc
4
+ module CollinsHelper
5
+ class Api < Collins::Client
6
+ # The logger method is used by Collins::Client, so an override is needed rather than a simple include.
7
+ def logger
8
+ Enc::Utils::Logging.logger_for(self.class.name)
9
+ end
10
+
11
+ class TooManyAssets < Exception; end
12
+ class NoAssets < Exception; end
13
+ class AssetNotValid < Exception; end
14
+ class CannotConnect < Exception; end
15
+
16
+ def safe_find(options = {})
17
+ query = asset_hash_to_find_query(options)
18
+ params = query.to_a.map do |param|
19
+ (key, val) = param
20
+ if val.is_a?(Array)
21
+ val.map{|v| "#{key}=#{asset_escape_attribute(v)}"}.join('&')
22
+ else
23
+ "#{key}=#{asset_escape_attribute(val)}"
24
+ end
25
+ end.reject{|s| s.empty?}
26
+ logger.debug("Searching for asset using query: #{params.join('&')}")
27
+ begin
28
+ response = http_get('/api/assets', params) do |r|
29
+ parse_response(r, :expects => 200, :as => :paginated)
30
+ end
31
+ rescue SocketError, TimeoutError => e
32
+ raise CannotConnect, e
33
+ end
34
+ logger.debug("Got response: #{response.inspect}")
35
+ raise TooManyAssets, 'Too many assets' if response.count > 1
36
+ raise NoAssets, 'No assets found' if response.first.nil? or response.first.empty?
37
+ asset = CollinsHelper::Node::NodeAsset.from_json(response.first)
38
+ raise AssetNotValid, 'Asset is not valid' unless asset.is_valid?
39
+ asset
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ module Enc
2
+ module CollinsHelper
3
+ class Connection
4
+ include Enc::Utils::Logging
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ @session = nil
9
+
10
+ end
11
+
12
+ def api
13
+ unless @session
14
+ logger.debug("Attempting to connect to #{@config.get('host')} as user #{@config.get('username')}")
15
+ @session = Enc::CollinsHelper::Api.new(:host => @config.get('host'),
16
+ :username => @config.get('username'),
17
+ :password => @config.get('password'),
18
+ :timeout => @config.get('timeout'),
19
+ :strict => true)
20
+ end
21
+ @session
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Enc
2
+ module CollinsHelper
3
+ module Node
4
+ class NoDatacenter < Exception; end
5
+ class NoDeploymentEnvironment < Exception; end
6
+ class NoHostname < Exception; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,135 @@
1
+ require 'collins_client'
2
+
3
+ # Suppress warnings from Collins::Asset class.
4
+ $VERBOSE = nil
5
+
6
+ module Enc
7
+ module CollinsHelper
8
+ module Node
9
+ class NodeAsset < Collins::Asset
10
+ # Note: Do not include the logging module here. If the logging module loads a file handle, the Marshal.dump will
11
+ # fail horribly. This class is meant to be used as a resource.
12
+
13
+ VALID_ENC_FLAGS = %w(1 true yes y on)
14
+
15
+ class << self
16
+ def from_json(json_hash, bare_asset=false)
17
+ raise Collins::CollinsError, 'Invalid JSON specified for Asset.from_json' if
18
+ (json_hash.nil? || !json_hash.is_a?(Hash))
19
+ json = deep_copy_hash(json_hash)
20
+ json = json['data'] && json['data'] || json
21
+ if bare_asset or !json.include?('ASSET')
22
+ asset = NodeAsset.new json
23
+ else
24
+ asset = NodeAsset.new json.delete('ASSET')
25
+ end
26
+ asset.send('ipmi='.to_sym, Collins::Ipmi.from_json(json.delete('IPMI')))
27
+ asset.send('addresses='.to_sym, Collins::Address.from_json(json.delete('ADDRESSES')))
28
+ asset.send('power='.to_sym, Collins::Power.from_json(json.delete('POWER')))
29
+ asset.send('location=', json.delete('LOCATION'))
30
+ asset.send('extras=', json)
31
+ asset
32
+ end
33
+ end
34
+
35
+ def is_valid?
36
+ begin
37
+ get_hostname
38
+ get_deployment_environment
39
+ get_datacenter
40
+ rescue NoHostname, NoDeploymentEnvironment, NoDatacenter
41
+ return false
42
+ end
43
+ true
44
+ end
45
+
46
+ def uses_enc?
47
+ has_attribute?('PUPPET_ENC') && VALID_ENC_FLAGS.include?(get_attribute('PUPPET_ENC').to_s.downcase)
48
+ end
49
+
50
+ def has_attribute?(attribute)
51
+ begin
52
+ get_safe_attribute(attribute)
53
+ rescue KeyError
54
+ return false
55
+ end
56
+ true
57
+ end
58
+
59
+ def get_hostname
60
+ begin
61
+ value = get_safe_attribute('HOSTNAME')
62
+ rescue KeyError
63
+ raise NoHostname, 'The node does not have a hostname tag set'
64
+ end
65
+ value
66
+ end
67
+
68
+ def get_deployment_environment
69
+ begin
70
+ value = get_safe_attribute('ENVIRONMENT')
71
+ rescue KeyError
72
+ raise NoDeploymentEnvironment, 'The node does not have an environment tag set'
73
+ end
74
+ value
75
+ end
76
+
77
+ def get_datacenter
78
+ begin
79
+ value = get_safe_attribute('DATA_CENTER')
80
+ rescue KeyError
81
+ raise NoDatacenter, 'The node does not have a data_center tag set'
82
+ end
83
+ value
84
+ end
85
+
86
+ def get_puppet_environment
87
+ begin
88
+ value = get_safe_attribute('PUPPET_ENVIRONMENT')
89
+ rescue KeyError
90
+ value = 'production'
91
+ end
92
+ value
93
+ end
94
+
95
+ def get_roles
96
+ get_multi_attribute('CONFIGURATION_ROLES')
97
+ end
98
+
99
+ def get_roles_by_index
100
+ get_multi_attribute_with_index('CONFIGURATION_ROLES')
101
+ end
102
+
103
+ # We need to take all the attributes and make them more human-readable.
104
+ # TODO: Make it not so ugly.
105
+ def get_flattened_attributes
106
+ flattened_attributes = Hash.new
107
+ Hash[extract(extras, 'ATTRIBS').inject({}){ |hash, (k, v)| hash.merge(k.to_i => v) }.
108
+ sort_by {|k,_| k} ].each { |_,hash| hash.each {
109
+ |k,v| flattened_attributes.has_key?(k) && (flattened_attributes[k].is_a?(Array) &&
110
+ (flattened_attributes[k] << (v)) ||
111
+ (flattened_attributes[k] = [flattened_attributes[k], v])) ||
112
+ flattened_attributes[k] = v
113
+ }
114
+ }
115
+ flattened_attributes
116
+ end
117
+
118
+ def get_safe_attribute(attribute)
119
+ value = get_attribute(attribute)
120
+ raise KeyError unless value
121
+ value
122
+ end
123
+
124
+ def get_multi_attribute_with_index(attribute)
125
+ Hash[extract(extras, 'ATTRIBS').inject({}){ |hash, (k, v)| hash.merge(k.to_i => v[attribute]) if
126
+ v.has_key?(attribute) }.sort_by {|k,_| k} ]
127
+ end
128
+
129
+ def get_multi_attribute(attribute)
130
+ get_multi_attribute_with_index(attribute).values
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,2 @@
1
+ require 'enc/collins_helper/node/exceptions'
2
+ require 'enc/collins_helper/node/node_asset'
@@ -0,0 +1,3 @@
1
+ require 'enc/collins_helper/connection'
2
+ require 'enc/collins_helper/api'
3
+ require 'enc/collins_helper/node'
data/lib/enc/config.rb ADDED
@@ -0,0 +1,63 @@
1
+ module Enc
2
+ class Config
3
+ attr_reader :config_file
4
+
5
+ class InvalidConfiguration < Exception; end
6
+ class ConfigurationDoesNotExist < Exception; end
7
+
8
+ def initialize(config_file=nil, options={}, use_file=true)
9
+ @config_file = get_default_config(config_file)
10
+ @options = options.each { |k,v| {k.to_sym => v} }
11
+ @use_file = use_file
12
+ end
13
+
14
+ def get(key)
15
+ load[key.to_sym]
16
+ end
17
+
18
+ def load
19
+ if @options.empty?
20
+ @options = YAML.load_file(@config_file).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
21
+ end
22
+ set_defaults
23
+ @options
24
+ end
25
+
26
+ def config_file_exists
27
+ File.exist?(@config_file)
28
+ end
29
+
30
+ def create!
31
+ raise InvalidConfiguration, 'Configuration requires host, username and password to be present.' unless
32
+ @options[:host] and @options[:username] and @options[:password]
33
+ File.open(@config_file, 'w') {|f| f.write @options.to_yaml }
34
+ end
35
+
36
+ def delete!
37
+ File.delete(@config_file) if File.exist?(@config_file)
38
+ end
39
+
40
+ protected
41
+
42
+ def set_defaults
43
+ @options[:timeout] = 30 unless @options.has_key?(:timeout)
44
+ @options[:jive_enc_cache_dir] = '/var/tmp/enc_cache' unless @options.has_key?(:jive_enc_cache_dir)
45
+ @options[:jive_enc_log_file] = '/var/log/enc.log' unless @options.has_key?(:jive_enc_log_file)
46
+ end
47
+
48
+ # Control the default config location order here. We need to assume at least this much so we know where to load the
49
+ # main collins config file.
50
+ def get_default_config(config_file=nil)
51
+ if config_file.nil? or config_file == ''
52
+ return "#{ENV['HOME']}/.collins.yaml" if File.exists?("#{ENV['HOME']}/.collins.yaml")
53
+ return'/var/lib/collins/.collins.yaml' if File.exists?('/var/lib/collins/.collins.yaml')
54
+ raise ConfigurationDoesNotExist,
55
+ 'Could not find configuration in ~/.collins.yaml or /var/lib/collins/.collins.yaml.'
56
+ else
57
+ raise ConfigurationDoesNotExist, "Config file #{config_file} does not exist" if
58
+ (not File.exists?(config_file) and @use_file)
59
+ config_file
60
+ end
61
+ end
62
+ end
63
+ end
data/lib/enc/runner.rb ADDED
@@ -0,0 +1,58 @@
1
+ module Enc
2
+ class Runner
3
+ include Enc::Utils::Logging
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ @cache = get_cache
8
+ end
9
+
10
+ def build(hostname)
11
+ asset, from_collins = get_asset(hostname)
12
+ # Do not rewrite the cache unless the asset comes from Collins.
13
+ @cache.write(hostname, asset) if from_collins
14
+ Enc::Builder.new(asset)
15
+ end
16
+
17
+ protected
18
+
19
+ def get_cache
20
+ begin
21
+ return Enc::Cache::NodeCache.new(@config)
22
+ rescue Enc::Cache::UnableToCreateCacheDirectory => e
23
+ bail('Could access cache directory', e)
24
+ end
25
+ end
26
+
27
+ def get_asset(hostname)
28
+ # It's important to handle any errors here so we know when to fall back to the cache.
29
+ begin
30
+ connection = Enc::CollinsHelper::Connection.new(@config)
31
+ return connection.api.safe_find(:hostname => hostname, :details => true), true
32
+ rescue Enc::CollinsHelper::Api::TooManyAssets,
33
+ Enc::CollinsHelper::Api::AssetNotValid,
34
+ Enc::CollinsHelper::Api::CannotConnect,
35
+ Collins::AuthenticationError,
36
+ Collins::RequestError
37
+ logger.error('Failed to connect to Collins. Attempting to read from cache')
38
+ # If the asset does not exist in Collins, it's important to save an empty asset in the cache that way in the case
39
+ # Collins is down, we will still return a valid, empty, response to puppet.
40
+ rescue Enc::CollinsHelper::Api::NoAssets
41
+ logger.info("Did not find any assets with hostname #{hostname}, saving an empty asset to the cache")
42
+ return Enc::CollinsHelper::Node::NodeAsset.new, true
43
+ end
44
+ begin
45
+ return @cache.read(hostname), false
46
+ rescue Enc::Cache::CacheDoesNotExist => e
47
+ bail('Could not find asset anywhere', e)
48
+ end
49
+ end
50
+
51
+ def bail(msg, exception)
52
+ logger.fatal("#{msg}: #{exception.message}")
53
+ logger.debug("Backtrace: #{exception.backtrace}")
54
+ exit(2)
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,68 @@
1
+ require 'logger'
2
+
3
+ module Enc
4
+ module Utils
5
+ module Logging
6
+ def logger
7
+ unless @logger
8
+ @logger = Logging.logger_for(self.class.name)
9
+ end
10
+ @logger
11
+ end
12
+
13
+ @loggers = {}
14
+
15
+ class << self
16
+ def logger_for(classname)
17
+ unless @loggers.has_key?(classname)
18
+ set_config
19
+ set_log_level
20
+ set_log_file
21
+ @loggers[classname] = configure_logger(classname)
22
+ end
23
+ @loggers[classname]
24
+ end
25
+
26
+ def configure_logger(classname)
27
+ logger = Logger.new(@file)
28
+ logger.level = @level
29
+ logger.progname = classname
30
+ logger
31
+ end
32
+
33
+ def set_config
34
+ unless @config
35
+ @config = Enc::Config.new
36
+ end
37
+ @config
38
+ end
39
+
40
+ def set_log_level
41
+ unless @level
42
+ @level = convert_log_level(@config.get('jive_enc_log_level'))
43
+ end
44
+ @level
45
+ end
46
+
47
+ def set_log_file
48
+ unless @file
49
+ @file = @config.get('jive_enc_log_file')
50
+ end
51
+ end
52
+
53
+ def convert_log_level(level)
54
+ case level
55
+ when 'warn'
56
+ Logger::WARN
57
+ when 'error'
58
+ Logger::ERROR
59
+ when 'debug'
60
+ Logger::DEBUG
61
+ else
62
+ Logger::INFO
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
data/lib/enc/utils.rb ADDED
@@ -0,0 +1 @@
1
+ require 'enc/utils/logging'
@@ -0,0 +1,3 @@
1
+ module Enc
2
+ VERSION = "0.0.2"
3
+ end