coral_core 0.1.10 → 0.2.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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.2.1)
4
+ diff-lcs (1.2.4)
5
5
  git (1.2.5)
6
6
  jeweler (1.8.4)
7
7
  bundler (~> 1.0)
@@ -10,7 +10,7 @@ GEM
10
10
  rdoc
11
11
  json (1.7.7)
12
12
  log4r (1.1.10)
13
- rake (10.0.3)
13
+ rake (10.0.4)
14
14
  rdoc (3.12.2)
15
15
  json (~> 1.4)
16
16
  rspec (2.13.0)
@@ -20,8 +20,8 @@ GEM
20
20
  rspec-core (2.13.1)
21
21
  rspec-expectations (2.13.0)
22
22
  diff-lcs (>= 1.1.3, < 2.0)
23
- rspec-mocks (2.13.0)
24
- yard (0.8.5.2)
23
+ rspec-mocks (2.13.1)
24
+ yard (0.8.6.1)
25
25
 
26
26
  PLATFORMS
27
27
  ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.10
1
+ 0.2.0
data/coral_core.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "coral_core"
8
- s.version = "0.1.10"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Adrian Webb"]
12
- s.date = "2013-03-15"
12
+ s.date = "2013-05-09"
13
13
  s.description = "= coral_core\n\nThis library provides core data elements and utilities used in other Coral gems.\n\nThe Coral core library contains functionality that is utilized by other\nCoral gems by providing basic utilities like Git, Shell, Disk, and Data\nmanipulation libraries, a UI system, and a core data model that supports\nEvents, Commands, Repositories, and Memory (version controlled JSON \nobjects). This library is only used as a starting point for other systems.\n\nNote: This library is still very early in development!\n\n== Contributing to coral_core\n \n* Check out the latest {major}.{minor} branch to make sure the feature hasn't \n been implemented or the bug hasn't been fixed yet.\n* Check out the issue tracker to make sure someone already hasn't requested \n it and/or contributed it.\n* Fork the project.\n* Start a feature/bugfix branch.\n* Commit and push until you are happy with your contribution.\n* Make sure to add tests for it. This is important so I don't break it in a \n future version unintentionally.\n* Please try not to mess with the Rakefile, version, or history. If you want \n to have your own version, or is otherwise necessary, that is fine, but \n please isolate to its own commit so I can cherry-pick around it.\n\n== Copyright\n\nLicensed under GPLv3. See LICENSE.txt for further details.\n\nCopyright (c) 2013 Adrian Webb <adrian.webb@coraltech.net>\nCoral Technology Group LLC"
14
14
  s.email = "adrian.webb@coraltech.net"
15
15
  s.extra_rdoc_files = [
@@ -27,12 +27,19 @@ Gem::Specification.new do |s|
27
27
  "coral_core.gemspec",
28
28
  "lib/coral_core.rb",
29
29
  "lib/coral_core/command.rb",
30
+ "lib/coral_core/config.rb",
30
31
  "lib/coral_core/core.rb",
31
32
  "lib/coral_core/event.rb",
32
33
  "lib/coral_core/event/regexp_event.rb",
33
34
  "lib/coral_core/interface.rb",
34
35
  "lib/coral_core/memory.rb",
35
36
  "lib/coral_core/repository.rb",
37
+ "lib/coral_core/resource.rb",
38
+ "lib/coral_core/template.rb",
39
+ "lib/coral_core/template/environment.rb",
40
+ "lib/coral_core/template/json.rb",
41
+ "lib/coral_core/template/wrapper.rb",
42
+ "lib/coral_core/template/yaml.rb",
36
43
  "lib/coral_core/util/data.rb",
37
44
  "lib/coral_core/util/disk.rb",
38
45
  "lib/coral_core/util/git.rb",
@@ -40,6 +47,7 @@ Gem::Specification.new do |s|
40
47
  "lib/coral_core/util/git/lib.rb",
41
48
  "lib/coral_core/util/git/remote.rb",
42
49
  "lib/coral_core/util/shell.rb",
50
+ "lib/hiera_backend.rb",
43
51
  "spec/coral_core/interface_spec.rb",
44
52
  "spec/coral_mock_input.rb",
45
53
  "spec/coral_test_kernel.rb",
@@ -0,0 +1,239 @@
1
+
2
+ module Coral
3
+ class Config < Core
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Global configuration
7
+
8
+ @@properties = {}
9
+
10
+ #---
11
+
12
+ def self.properties
13
+ return @@properties
14
+ end
15
+
16
+ #---
17
+
18
+ def self.set_property(name, value)
19
+ @@properties[name] = value
20
+ end
21
+
22
+ #-----------------------------------------------------------------------------
23
+ # Hiera configuration
24
+
25
+ @@hiera = nil
26
+
27
+ #---
28
+
29
+ def self.hiera_config
30
+ config_file = Puppet.settings[:hiera_config]
31
+ config = {}
32
+
33
+ if File.exist?(config_file)
34
+ config = Hiera::Config.load(config_file)
35
+ else
36
+ ui.warning "Config file #{config_file} not found, using Hiera defaults"
37
+ end
38
+
39
+ config[:logger] = 'puppet'
40
+ return config
41
+ end
42
+
43
+ #---
44
+
45
+ def self.hiera
46
+ @@hiera = Hiera.new(:config => hiera_config) unless @@hiera
47
+ return @@hiera
48
+ end
49
+
50
+ #---
51
+
52
+ def hiera
53
+ return self.class.hiera
54
+ end
55
+
56
+ #-----------------------------------------------------------------------------
57
+ # Configuration lookup
58
+
59
+ def self.initialized?(options = {})
60
+ config = Config.ensure(options)
61
+ begin
62
+ require 'hiera_puppet'
63
+
64
+ scope = config.get(:scope, {})
65
+
66
+ sep = config.get(:sep, '::')
67
+ prefix = config.get(:prefix, true)
68
+ prefix_text = prefix ? sep : ''
69
+
70
+ init_fact = prefix_text + config.get(:init_fact, 'hiera_ready')
71
+ coral_fact = prefix_text + config.get(:coral_fact, 'coral_exists')
72
+
73
+ if Puppet::Parser::Functions.function('hiera')
74
+ if scope.respond_to?('lookupvar')
75
+ return true if Util::Data.true?(scope.lookupvar(init_fact)) && Util::Data.true?(scope.lookupvar(coral_fact))
76
+ else
77
+ return true
78
+ end
79
+ end
80
+
81
+ rescue Exception # Prevent abortions.
82
+ end
83
+ return false
84
+ end
85
+
86
+ #---
87
+
88
+ def self.lookup(name, default = nil, options = {})
89
+ config = Config.ensure(options)
90
+ value = nil
91
+
92
+ context = config.get(:context, :priority)
93
+ scope = config.get(:scope, {})
94
+ override = config.get(:override, nil)
95
+
96
+ base_names = config.get(:search, nil)
97
+ sep = config.get(:sep, '::')
98
+ prefix = config.get(:prefix, true)
99
+ prefix_text = prefix ? sep : ''
100
+
101
+ search_name = config.get(:search_name, true)
102
+
103
+ #dbg(default, "lookup -> #{name}")
104
+
105
+ if Config.initialized?(options)
106
+ unless scope.respond_to?("[]")
107
+ scope = Hiera::Scope.new(scope)
108
+ end
109
+ value = hiera.lookup(name, default, scope, override, context)
110
+ #dbg(value, "hiera -> #{name}")
111
+ end
112
+
113
+ if Util::Data.undef?(value) && scope.respond_to?('lookupvar')
114
+ log_level = Puppet::Util::Log.level
115
+ Puppet::Util::Log.level = :err # Don't want failed parameter lookup warnings here.
116
+
117
+ if base_names
118
+ if base_names.is_a?(String)
119
+ base_names = [ base_names ]
120
+ end
121
+ base_names.each do |item|
122
+ value = scope.lookupvar("#{prefix_text}#{item}#{sep}#{name}")
123
+ #dbg(value, "#{prefix_text}#{item}#{sep}#{name}")
124
+ break unless Util::Data.undef?(value)
125
+ end
126
+ end
127
+ if Util::Data.undef?(value) && search_name
128
+ value = scope.lookupvar("#{prefix_text}#{name}")
129
+ #dbg(value, "#{prefix_text}#{name}")
130
+ end
131
+ Puppet::Util::Log.level = log_level
132
+ end
133
+ value = default if Util::Data.undef?(value)
134
+ value = Util::Data.value(value)
135
+
136
+ set_property(name, value)
137
+
138
+ #dbg(value, "result -> #{name}")
139
+ return value
140
+ end
141
+
142
+ #-----------------------------------------------------------------------------
143
+ # Instance generator
144
+
145
+ def self.ensure(config)
146
+ case config
147
+ when Coral::Config
148
+ return config
149
+ when Hash
150
+ return Config.new(config)
151
+ end
152
+ return Config.new
153
+ end
154
+
155
+ #-----------------------------------------------------------------------------
156
+ # Configuration instance
157
+
158
+ def initialize(data = {}, defaults = {}, force = true)
159
+ @force = force
160
+
161
+ if defaults.is_a?(Hash) && ! defaults.empty?
162
+ symbolized = {}
163
+ defaults.each do |key, value|
164
+ symbolized[key.to_sym] = value
165
+ end
166
+ defaults = symbolized
167
+ end
168
+
169
+ case data
170
+ when Coral::Config
171
+ @options = Util::Data.merge([ defaults, data.options ], force)
172
+ when Hash
173
+ @options = {}
174
+ if data.is_a?(Hash)
175
+ symbolized = {}
176
+ data.each do |key, value|
177
+ symbolized[key.to_sym] = value
178
+ end
179
+ @options = Util::Data.merge([ defaults, symbolized ], force)
180
+ end
181
+ end
182
+ end
183
+
184
+ #---
185
+
186
+ def import(data, options = {})
187
+ config = Config.new(options, { :force => @force }).set(:context, :hash)
188
+
189
+ case data
190
+ when Hash
191
+ symbolized = {}
192
+ data.each do |key, value|
193
+ symbolized[key.to_sym] = value
194
+ end
195
+ @options = Util::Data.merge([ @options, symbolized ], config)
196
+
197
+ when String
198
+ data = Util::Data.lookup(data, {}, config)
199
+ Util::Data.merge([ @options, data ], config)
200
+
201
+ when Array
202
+ data.each do |item|
203
+ import(item, config)
204
+ end
205
+ end
206
+
207
+ return self
208
+ end
209
+
210
+ #---
211
+
212
+ def set(name, value)
213
+ @options[name.to_sym] = value
214
+ return self
215
+ end
216
+
217
+ def []=(name, value)
218
+ set(name, value)
219
+ end
220
+
221
+ #---
222
+
223
+ def get(name, default = nil)
224
+ name = name.to_sym
225
+ return @options[name] if @options.has_key?(name)
226
+ return default
227
+ end
228
+
229
+ def [](name, default = nil)
230
+ get(name, default)
231
+ end
232
+
233
+ #---
234
+
235
+ def options
236
+ return @options
237
+ end
238
+ end
239
+ end
@@ -5,13 +5,13 @@ class Core
5
5
  #-----------------------------------------------------------------------------
6
6
  # Properties
7
7
 
8
- @@ui = Coral::Interface.new("coral::core")
8
+ @@ui = Interface.new("coral")
9
9
 
10
10
  #-----------------------------------------------------------------------------
11
11
  # Constructor / Destructor
12
12
 
13
13
  def initialize(options = {})
14
- @ui = Coral::Interface.new(options)
14
+ @@ui = Interface.new(options)
15
15
  end
16
16
 
17
17
  #-----------------------------------------------------------------------------
@@ -197,8 +197,7 @@ class Core
197
197
  #---
198
198
 
199
199
  def self.test(data)
200
- return false if ! data || data.empty?
201
- return false if data.is_a?(String) && data =~ /^(FALSE|false|False|No|no|N|n)$/
200
+ return false if Util::Data.empty?(data)
202
201
  return true
203
202
  end
204
203
 
@@ -0,0 +1,238 @@
1
+
2
+ module Coral
3
+ module Resource
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Resource groups
7
+
8
+ @@resource_groups = {}
9
+
10
+ #---
11
+
12
+ def self.groups
13
+ return @@resource_groups
14
+ end
15
+
16
+ #---
17
+
18
+ def self.clear_groups
19
+ @@resource_groups = {}
20
+ end
21
+
22
+ #---
23
+
24
+ def self.add_members(group_name, resource_names)
25
+ @@resource_groups[group_name] = [] unless @@resource_groups[group_name].is_a?(Array)
26
+
27
+ unless resource_names.is_a?(Array)
28
+ resource_names = [ resource_names ]
29
+ end
30
+
31
+ resource_names.each do |name|
32
+ unless @@resource_groups[group_name].include?(name)
33
+ @@resource_groups[group_name] << name
34
+ end
35
+ end
36
+ end
37
+
38
+ #-----------------------------------------------------------------------------
39
+ # Resource operations
40
+
41
+ def self.normalize(type_name, resources, options)
42
+ clear_groups
43
+
44
+ config = Config.ensure(options)
45
+ resources = Util::Data.value(resources)
46
+
47
+ #dbg(resources, 'normalize -> init')
48
+
49
+ unless Util::Data.empty?(resources)
50
+ resources.keys.each do |name|
51
+ #dbg(name, 'normalize -> name')
52
+ if ! resources[name] || resources[name].empty? || ! resources[name].is_a?(Hash)
53
+ resources.delete(name)
54
+ else
55
+ normalize = true
56
+
57
+ namevar = namevar(type_name, name)
58
+ if resources[name].has_key?(namevar)
59
+ value = resources[name][namevar]
60
+ if Util::Data.empty?(value)
61
+ #dbg(value, "delete #{name}")
62
+ resources.delete(name)
63
+ normalize = false
64
+
65
+ elsif value.is_a?(Array)
66
+ value.each do |item|
67
+ item_name = "#{name}_#{item}".gsub(/\-/, '_')
68
+
69
+ new_resource = resources[name].clone
70
+ new_resource[namevar] = item
71
+
72
+ resources[item_name] = render(new_resource, config)
73
+ add_members(name, item_name)
74
+ end
75
+ resources.delete(name)
76
+ normalize = false
77
+ end
78
+ end
79
+
80
+ #dbg(resources, 'normalize -> resources')
81
+
82
+ if normalize
83
+ resources[name] = render(resources[name], config)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ return resources
89
+ end
90
+
91
+ #---
92
+
93
+ def self.render(resource, options = {})
94
+ config = Config.ensure(options)
95
+
96
+ Core.string_map(resource).keys.each do |name|
97
+ if match = name.match(/^(.+)_template$/)
98
+ target = match.captures[0]
99
+
100
+ config.set(:noralize_template, config.get("normalize_#{target}", true))
101
+ config.set(:interpolate_template, config.get("interpolate_#{target}", true))
102
+
103
+ resource[target] = Template.render(resource[name], resource[target], config)
104
+ resource.delete(name)
105
+ end
106
+ end
107
+
108
+ return resource
109
+ end
110
+
111
+ #---
112
+
113
+ def self.translate(type_name, resources, options = {})
114
+ config = Config.ensure(options)
115
+ resources = Util::Data.value(resources)
116
+ results = {}
117
+
118
+ #dbg(resources, 'resources -> translate')
119
+
120
+ prefix = config.get(:resource_prefix, '')
121
+
122
+ name_map = {}
123
+ resources.keys.each do |name|
124
+ name_map[name] = true
125
+ end
126
+ config[:resource_names] = name_map
127
+
128
+ resources.each do |name, data|
129
+ #dbg(name, 'name')
130
+ #dbg(data, 'data')
131
+
132
+ resource = resources[name]
133
+ resource['before'] = translate_resource_refs(type_name, data['before'], config) if data.has_key?('before')
134
+ resource['notify'] = translate_resource_refs(type_name, data['notify'], config) if data.has_key?('notify')
135
+ resource['require'] = translate_resource_refs(type_name, data['require'], config) if data.has_key?('require')
136
+ resource['subscribe'] = translate_resource_refs(type_name, data['subscribe'], config) if data.has_key?('subscribe')
137
+
138
+ unless prefix.empty?
139
+ name = "#{prefix}_#{name}"
140
+ end
141
+ results[name] = resource
142
+ end
143
+ return results
144
+ end
145
+
146
+ #---
147
+
148
+ def self.translate_resource_refs(type_name, resource_refs, options = {})
149
+ return :undef if Util::Data.undef?(resource_refs)
150
+
151
+ config = Config.ensure(options)
152
+ resource_names = config.get(:resource_names, {})
153
+ title_prefix = config.get(:title_prefix, '')
154
+
155
+ title_pattern = config.get(:title_pattern, '^\s*([^\[\]]+)\s*$')
156
+ title_group = config.get(:title_var_group, 1)
157
+ title_flags = config.get(:title_flags, '')
158
+ title_regexp = Regexp.new(title_pattern, title_flags.split(''))
159
+
160
+ allow_single = config.get(:allow_single_return, true)
161
+
162
+ type_name = type_name.sub(/^\@?\@/, '')
163
+ values = []
164
+
165
+ case resource_refs
166
+ when String
167
+ if resource_refs.empty?
168
+ return :undef
169
+ else
170
+ resource_refs = resource_refs.split(/\s*,\s*/)
171
+ end
172
+
173
+ when Puppet::Resource
174
+ resource_refs = [ resource_refs ]
175
+ end
176
+
177
+ resource_refs.collect! do |value|
178
+ if value.is_a?(Puppet::Resource) || ! value.match(title_regexp)
179
+ value
180
+
181
+ elsif resource_names.has_key?(value)
182
+ if ! title_prefix.empty?
183
+ "#{title_prefix}_#{value}"
184
+ else
185
+ value
186
+ end
187
+
188
+ elsif groups.has_key?(value) && ! groups[value].empty?
189
+ results = []
190
+ groups[value].each do |resource_name|
191
+ unless title_prefix.empty?
192
+ resource_name = "#{title_prefix}_#{resource_name}"
193
+ end
194
+ results << resource_name
195
+ end
196
+ results
197
+
198
+ else
199
+ nil
200
+ end
201
+ end
202
+
203
+ resource_refs.flatten.each do |ref|
204
+ #dbg(ref, 'reference -> init')
205
+ unless ref.nil?
206
+ unless ref.is_a?(Puppet::Resource)
207
+ ref = ref.match(title_regexp) ? Puppet::Resource.new(type_name, ref) : Puppet::Resource.new(ref)
208
+ end
209
+ #dbg(ref, 'reference -> final')
210
+ values << ref unless ref.nil?
211
+ end
212
+ end
213
+ return values[0] if allow_single && values.length == 1
214
+ return values
215
+ end
216
+
217
+ #-----------------------------------------------------------------------------
218
+ # Utilities
219
+
220
+ def self.type_name(value) # Basically borrowed from Puppet (damn private methods!)
221
+ return :main if value == :main
222
+ return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
223
+ return value.to_s.split("::").collect { |s| s.capitalize }.join("::")
224
+ end
225
+
226
+ #---
227
+
228
+ def self.namevar(type_name, resource_name) # Basically borrowed from Puppet (damn private methods!)
229
+ resource = Puppet::Resource.new(type_name.sub(/^\@?\@/, ''), resource_name)
230
+
231
+ if resource.builtin_type? and type = resource.resource_type and type.key_attributes.length == 1
232
+ return type.key_attributes.first.to_s
233
+ else
234
+ return 'name'
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,72 @@
1
+
2
+ module Coral
3
+ module Template
4
+ class Environment < Base
5
+ #-----------------------------------------------------------------------------
6
+ # Renderers
7
+
8
+ def render(input)
9
+ output = ''
10
+
11
+ case input
12
+ when Hash
13
+ input.each do |name, value|
14
+ output << render_assignment(name, value)
15
+ end
16
+ end
17
+ return output
18
+ end
19
+
20
+ #-----------------------------------------------------------------------------
21
+
22
+ def render_assignment(name, value)
23
+ name = render_name(name)
24
+ value = render_value(value)
25
+
26
+ export = get(:export, true)
27
+ export_text = export ? get(:export_text, 'export ') : ''
28
+ operator = get(:operator, '=')
29
+
30
+ return "#{export_text}#{name}#{operator}#{value}\n"
31
+ end
32
+
33
+ #---
34
+
35
+ def render_name(name)
36
+ prefix = get(:name_prefix, '')
37
+ prefix_sep = prefix.empty? ? '' : get(:name_prefix_sep, '_')
38
+
39
+ suffix = get(:name_suffix, '')
40
+ suffix_sep = suffix.empty? ? '' : get(:name_suffix_sep, '')
41
+
42
+ unless prefix.empty?
43
+ name = "#{prefix}#{prefix_sep}#{name}#{suffix_sep}#{suffix}"
44
+ end
45
+ return name
46
+ end
47
+
48
+ #---
49
+
50
+ def render_value(value)
51
+ sep = get(:value_sep, ' ')
52
+ quote = get(:quote, true)
53
+
54
+ array_prefix = get(:array_prefix, '(')
55
+ array_suffix = get(:array_suffix, ')')
56
+
57
+ case value
58
+ when Array
59
+ values = []
60
+ value.each do |item|
61
+ values << quote ? "'#{item}'" : "#{item}"
62
+ end
63
+ value = "#{array_prefix}#{values.join(sep)}#{array_suffix}"
64
+
65
+ when String
66
+ value = quote ? "'#{value}'" : "#{value}"
67
+ end
68
+ return value
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Coral
3
+ module Template
4
+ class JSON < Base
5
+ #-----------------------------------------------------------------------------
6
+ # Renderers
7
+
8
+ def render(input)
9
+ return Data.to_json(input)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Coral
3
+ module Template
4
+ class Wrapper < Base
5
+ #-----------------------------------------------------------------------------
6
+ # Renderers
7
+
8
+ def render(input)
9
+ return get(:template_prefix, '') + input.to_s + get(:template_suffix, '')
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Coral
3
+ module Template
4
+ class JSON < Base
5
+ #-----------------------------------------------------------------------------
6
+ # Renderers
7
+
8
+ def render(input)
9
+ return Data.to_yaml(input)
10
+ end
11
+ end
12
+ end
13
+ end