carinadigital-hiera-cloudformation 0.0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 921c7ea7efc3b03457499dd609ddfb3f57ec8d9d
4
+ data.tar.gz: e2c167dbf96e4aa198f46e61cb5c805ce3319d02
5
+ SHA512:
6
+ metadata.gz: 4d078b8a89eca0ab8357bde1f1333dcc2f10bc008decd132e881633b3106815f26daf49d141effab3e738400924b619851b60359de2e99fb8db7db187bff1567
7
+ data.tar.gz: 51e97025b3e3bc337cb6cd5d83d5a52912004dee7e22801302db6224e1d4d02b8b09e1ca21fc151868025e4a762389be9878684f0fdd69ee5cd55e21ed6fa5a6
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Hugh Cole-Baker
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,112 @@
1
+ # Hiera::Cloudformation
2
+
3
+ This backend for Hiera can retrieve information from:
4
+
5
+ * the outputs of a CloudFormation stack
6
+ * the metadata of a resource in a stack
7
+
8
+ ## Installation
9
+
10
+ gem install hiera-cloudformation
11
+
12
+ ## Usage
13
+
14
+ Add the backend to the list of backends in hiera.yaml:
15
+
16
+ ---
17
+ :backends:
18
+ - yaml
19
+ - cloudformation
20
+
21
+ To provide the backend with an AWS access key, you can add the following configuration to the
22
+ `:cloudformation` section in hiera.yaml:
23
+
24
+ :cloudformation:
25
+ :access_key_id: Your_AWS_Access_Key_ID_Here
26
+ :secret_access_key: Your_AWS_Secret_Access_Key_Here
27
+
28
+ If you do not add these keys to your configuration file, the access keys will be looked up from
29
+ the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables, or from an IAM
30
+ instance role (if you are running Hiera on an EC2 instance with an IAM role assigned).
31
+
32
+ You can also add a region setting to the `:cloudformation` section in
33
+ hiera.yaml:
34
+
35
+ :cloudformation:
36
+ :region: us-west-2
37
+
38
+ If not specified, the region setting will be looked up from the `AWS_REGION`
39
+ environment variable, or `us-west-2` if not set.
40
+
41
+ To use this backend you also need to add entries to your "hierarchy" in your hiera.yaml file.
42
+ If you put an entry of this form in your hierarchy:
43
+
44
+ cfstack/<stack name>/outputs
45
+
46
+ the backend will request the outputs of the stack named `<stack name>` and search for an output
47
+ named the same as the requested key. If an output named the same as the key is found, the backend
48
+ will return the value of that output (as a string).
49
+ If you put an entry of this form in your hierarchy:
50
+
51
+ cfstack/<stack name>/resources/<logical resource ID>
52
+
53
+ the backend will request the JSON metadata of the logical resource identified by the given ID,
54
+ in the named stack, and look for a JSON object under the top-level key "hiera" in the metadata.
55
+ If a JSON object is present under the top-level key "hiera", the backend will search for the
56
+ requested key in that JSON object, and return the value of the key if present.
57
+
58
+ The recommended way of constructing your hierarchy so that Puppet-managed nodes can retrieve
59
+ data relating to the CloudFormation stack they're part of, is to create facts on the Puppet nodes
60
+ describing what CloudFormation stack they're part of and what logical resource ID corresponds to
61
+ their instance. Then, assuming you have two facts "cloudformation_stack" and "cloudformation_resource"
62
+ reported on your node, you can add these entries to the "hierarchy" in hiera.yaml:
63
+
64
+ - cfstack/%{cloudformation_stack}/outputs
65
+ - cfstack/%{cloudformation_stack}/resources/%{cloudformation_resource}
66
+
67
+ and Hiera will replace the `%{...}` placeholders with the value of the facts on the node, enabling
68
+ the node to look up information about the stack it "belongs" to.
69
+
70
+ For example, if this snippet is included in your CloudFormation template, and you include an entry
71
+
72
+ cfstack/<stack name>/outputs
73
+
74
+ in your hierarchy, you can look up the key "example_key" in Hiera and get the value of the logical
75
+ resource identified by "AWSEC2Instance" (for example, this might be an EC2 instance, so Hiera
76
+ would return the instance ID)
77
+
78
+ "Outputs" : {
79
+ "example_key": {
80
+ "Description" : "AWSEC2Instance is the logical resource ID of the instance that was created",
81
+ "Value" : { "Ref": "AWSEC2Instance" }
82
+ }
83
+ }
84
+
85
+ As another example, if you define an EC2 instance with the following snippet in your CloudFormation
86
+ template, including some metadata:
87
+
88
+ "Resources" : {
89
+ "MyIAMKey" : {
90
+ "Type" : "AWS::IAM::AccessKey",
91
+ ...
92
+ },
93
+ "AWSEC2Instance" : {
94
+ "Type" : "AWS::EC2::Instance",
95
+ "Properties" : {
96
+ ...
97
+ },
98
+ "Metadata" : {
99
+ "hiera" : {
100
+ "class::access_key_id": { "Ref": "MyIAMKey" },
101
+ "class::secret_access_key": { "Fn::GetAtt" : [ "MyIAMKey" , "SecretAccessKey" ] }
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ and you include an entry:
108
+
109
+ cfstack/<stack name>/resources/AWSEC2Instance
110
+
111
+ in your hierarchy, you can query hiera for the key "class::access_key_id" or "class::secret_access_key"
112
+ and retrieve the attributes of the "MyIAMKey" resource created by CloudFormation.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ =begin
2
+ Copyright 2013 FanDuel Ltd.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ require 'rubygems'
18
+ require 'rubygems/package_task'
19
+
20
+ spec = Gem::Specification.new do |gem|
21
+ gem.name = "carinadigital-hiera-cloudformation"
22
+ gem.version = '0.0.1.3'
23
+ gem.authors = ["carinadigital"]
24
+ gem.email = ["carinadigital@gmail.com"]
25
+ gem.summary = %q{CloudFormation backend for Hiera}
26
+ gem.description = %q{Forked from hiera-cloudformation. Queries CloudFormation stack outputs or resource metadata for Hiera data.}
27
+ gem.homepage = "https://github.com/carinadigital/hiera-cloudformation"
28
+ gem.license = "Apache License (2.0)"
29
+
30
+ gem.files = Dir['{bin,lib,man,test,spec}/**/*', 'Rakefile', 'README*', 'LICENSE*']
31
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
33
+ gem.require_paths = ["lib"]
34
+
35
+ gem.add_development_dependency "rake"
36
+ gem.add_runtime_dependency "aws-sdk", "~> 1.33.0"
37
+ gem.add_runtime_dependency "timedcache", "~> 0.4.0"
38
+ gem.add_runtime_dependency "json", "~> 1.8.0"
39
+ end
40
+
41
+ Gem::PackageTask.new(spec) do |pkg|
42
+ pkg.need_tar = true
43
+ end
@@ -0,0 +1,145 @@
1
+ =begin
2
+ Copyright 2013 FanDuel Ltd.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ =end
16
+
17
+ class Hiera
18
+ module Backend
19
+ class Cloudformation_backend
20
+ TIMEOUT = 60 # 1 minute timeout for AWS API response caching
21
+
22
+ def initialize
23
+ begin
24
+ require 'aws'
25
+ require 'timedcache'
26
+ require 'json'
27
+ rescue LoadError
28
+ require 'rubygems'
29
+ require 'aws'
30
+ require 'timedcache'
31
+ require 'json'
32
+ end
33
+
34
+ if Config.include?(:cloudformation) && !Config[:cloudformation].nil?
35
+ aws_config = {}
36
+ if Config[:cloudformation].include?(:access_key_id) && Config[:cloudformation].include?(:secret_access_key)
37
+ Hiera.debug("Found AWS access key from configuration")
38
+ aws_config[:access_key_id] = Config[:cloudformation][:access_key_id]
39
+ aws_config[:secret_access_key] = Config[:cloudformation][:secret_access_key]
40
+ end
41
+ if Config[:cloudformation].include?(:region)
42
+ Hiera.debug("Found AWS region from configuration")
43
+ aws_config[:region] = Config[:cloudformation][:region]
44
+ end
45
+ if aws_config.length == 0
46
+ Hiera.debug("CloudFormation configuration is found, but none of the settings are recognized.")
47
+ else
48
+ AWS.config(aws_config)
49
+ end
50
+ else
51
+ Hiera.debug("No configuration found, will fall back to env variables or IAM role")
52
+ end
53
+
54
+ @cf = AWS::CloudFormation.new
55
+ @output_cache = TimedCache.new
56
+ @resource_cache = TimedCache.new
57
+
58
+ Hiera.debug("Hiera cloudformation backend loaded")
59
+ end
60
+
61
+ def lookup(key, scope, order_override, resolution_type)
62
+ answer = nil
63
+
64
+ Backend.datasources(scope, order_override) do |elem|
65
+ case elem
66
+ when /cfstack\/([^\/]+)\/outputs/
67
+ Hiera.debug("Looking up #{key} as an output of stack #{$1}")
68
+ raw_answer = stack_output_query($1, key)
69
+ when /cfstack\/([^\/]+)\/resources\/([^\/]+)/
70
+ Hiera.debug("Looking up #{key} in metadata of stack #{$1} resource #{$2}")
71
+ raw_answer = stack_resource_query($1, $2, key)
72
+ else
73
+ Hiera.debug("#{elem} doesn't seem to be a CloudFormation hierarchy element")
74
+ next
75
+ end
76
+
77
+ next if raw_answer.nil?
78
+
79
+ new_answer = Backend.parse_answer(raw_answer, scope)
80
+
81
+ case resolution_type
82
+ when :array
83
+ raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
84
+ answer ||= []
85
+ answer << new_answer
86
+ when :hash
87
+ raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
88
+ answer ||= {}
89
+ answer = Backend.merge_answer(new_answer, answer)
90
+ else
91
+ answer = new_answer
92
+ break
93
+ end
94
+ end
95
+
96
+ return answer
97
+ end
98
+
99
+ def stack_output_query(stack_name, key)
100
+ outputs = @output_cache.get(stack_name)
101
+
102
+ if outputs.nil? then
103
+ Hiera.debug("#{stack_name} outputs not cached, fetching...")
104
+ begin
105
+ outputs = @cf.stacks[stack_name].outputs
106
+ rescue AWS::CloudFormation::Errors::ValidationError
107
+ Hiera.debug("Stack #{stack_name} outputs can't be retrieved")
108
+ outputs = [] # this is just a non-nil value to serve as marker in cache
109
+ end
110
+ @output_cache.put(stack_name, outputs, TIMEOUT)
111
+ end
112
+
113
+ output = outputs.select { |item| item.key == key }
114
+
115
+ return output.empty? ? nil : output.shift.value
116
+ end
117
+
118
+ def stack_resource_query(stack_name, resource_id, key)
119
+ metadata = @resource_cache.get({:stack => stack_name, :resource => resource_id})
120
+
121
+ if metadata.nil? then
122
+ Hiera.debug("#{stack_name} #{resource_id} metadata not cached, fetching")
123
+ begin
124
+ metadata = @cf.stacks[stack_name].resources[resource_id].metadata
125
+ rescue AWS::CloudFormation::Errors::ValidationError
126
+ # Stack or resource doesn't exist
127
+ Hiera.debug("Stack #{stack_name} resource #{resource_id} can't be retrieved")
128
+ metadata = "{}" # This is just a non-nil value to serve as marker in cache
129
+ end
130
+ @resource_cache.put({:stack => stack_name, :resource => resource_id}, metadata, TIMEOUT)
131
+ end
132
+
133
+ if metadata.respond_to?(:to_str) then
134
+ data = JSON.parse(metadata)
135
+
136
+ if data.include?('hiera') then
137
+ return data['hiera'][key] if data['hiera'].include?(key)
138
+ end
139
+ end
140
+
141
+ return nil
142
+ end
143
+ end
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: carinadigital-hiera-cloudformation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - carinadigital
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.33.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.33.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: timedcache
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.4.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.4.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.8.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.8.0
69
+ description: Forked from hiera-cloudformation. Queries CloudFormation stack outputs
70
+ or resource metadata for Hiera data.
71
+ email:
72
+ - carinadigital@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - lib/hiera/backend/cloudformation_backend.rb
78
+ - Rakefile
79
+ - README.md
80
+ - LICENSE.txt
81
+ homepage: https://github.com/carinadigital/hiera-cloudformation
82
+ licenses:
83
+ - Apache License (2.0)
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.0.7
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: CloudFormation backend for Hiera
105
+ test_files: []