corl 0.4.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/.document +5 -0
- data/.gitmodules +4 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +123 -0
- data/LICENSE.txt +674 -0
- data/README.rdoc +27 -0
- data/Rakefile +78 -0
- data/VERSION +1 -0
- data/bin/corl +55 -0
- data/corl.gemspec +228 -0
- data/lib/corl/action/add.rb +69 -0
- data/lib/corl/action/bootstrap.rb +83 -0
- data/lib/corl/action/clone.rb +40 -0
- data/lib/corl/action/create.rb +55 -0
- data/lib/corl/action/exec.rb +41 -0
- data/lib/corl/action/extract.rb +49 -0
- data/lib/corl/action/image.rb +30 -0
- data/lib/corl/action/images.rb +55 -0
- data/lib/corl/action/lookup.rb +35 -0
- data/lib/corl/action/machines.rb +51 -0
- data/lib/corl/action/provision.rb +37 -0
- data/lib/corl/action/remove.rb +51 -0
- data/lib/corl/action/save.rb +53 -0
- data/lib/corl/action/seed.rb +115 -0
- data/lib/corl/action/spawn.rb +75 -0
- data/lib/corl/action/start.rb +37 -0
- data/lib/corl/action/stop.rb +30 -0
- data/lib/corl/action/update.rb +37 -0
- data/lib/corl/command/shell.rb +164 -0
- data/lib/corl/configuration/file.rb +386 -0
- data/lib/corl/event/puppet.rb +90 -0
- data/lib/corl/event/regex.rb +52 -0
- data/lib/corl/extension/puppetloader.rb +24 -0
- data/lib/corl/machine/fog.rb +310 -0
- data/lib/corl/machine/physical.rb +161 -0
- data/lib/corl/network/default.rb +26 -0
- data/lib/corl/node/aws.rb +90 -0
- data/lib/corl/node/fog.rb +198 -0
- data/lib/corl/node/google.rb +115 -0
- data/lib/corl/node/local.rb +26 -0
- data/lib/corl/node/rackspace.rb +89 -0
- data/lib/corl/project/git.rb +465 -0
- data/lib/corl/project/github.rb +108 -0
- data/lib/corl/provisioner/puppetnode/resource.rb +245 -0
- data/lib/corl/provisioner/puppetnode/resource_group.rb +205 -0
- data/lib/corl/provisioner/puppetnode.rb +407 -0
- data/lib/corl/template/environment.rb +73 -0
- data/lib/corl/template/json.rb +16 -0
- data/lib/corl/template/wrapper.rb +16 -0
- data/lib/corl/template/yaml.rb +16 -0
- data/lib/corl/translator/json.rb +27 -0
- data/lib/corl/translator/yaml.rb +27 -0
- data/lib/corl.rb +173 -0
- data/lib/corl_core/codes.rb +107 -0
- data/lib/corl_core/config/collection.rb +57 -0
- data/lib/corl_core/config/options.rb +70 -0
- data/lib/corl_core/config.rb +337 -0
- data/lib/corl_core/core.rb +59 -0
- data/lib/corl_core/corl.rb +254 -0
- data/lib/corl_core/errors.rb +84 -0
- data/lib/corl_core/facade.rb +126 -0
- data/lib/corl_core/gems.rb +72 -0
- data/lib/corl_core/manager.rb +425 -0
- data/lib/corl_core/mixin/action/commit.rb +58 -0
- data/lib/corl_core/mixin/action/keypair.rb +105 -0
- data/lib/corl_core/mixin/action/node.rb +129 -0
- data/lib/corl_core/mixin/action/project.rb +53 -0
- data/lib/corl_core/mixin/action/push.rb +52 -0
- data/lib/corl_core/mixin/config/collection.rb +53 -0
- data/lib/corl_core/mixin/config/ops.rb +53 -0
- data/lib/corl_core/mixin/config/options.rb +39 -0
- data/lib/corl_core/mixin/lookup.rb +196 -0
- data/lib/corl_core/mixin/macro/object_interface.rb +361 -0
- data/lib/corl_core/mixin/macro/plugin_interface.rb +380 -0
- data/lib/corl_core/mixin/settings.rb +46 -0
- data/lib/corl_core/mixin/sub_config.rb +148 -0
- data/lib/corl_core/mod/hash.rb +29 -0
- data/lib/corl_core/mod/hiera_backend.rb +63 -0
- data/lib/corl_core/plugin/action.rb +381 -0
- data/lib/corl_core/plugin/base.rb +374 -0
- data/lib/corl_core/plugin/command.rb +98 -0
- data/lib/corl_core/plugin/configuration.rb +177 -0
- data/lib/corl_core/plugin/event.rb +53 -0
- data/lib/corl_core/plugin/extension.rb +12 -0
- data/lib/corl_core/plugin/machine.rb +266 -0
- data/lib/corl_core/plugin/network.rb +359 -0
- data/lib/corl_core/plugin/node.rb +904 -0
- data/lib/corl_core/plugin/project.rb +927 -0
- data/lib/corl_core/plugin/provisioner.rb +51 -0
- data/lib/corl_core/plugin/template.rb +80 -0
- data/lib/corl_core/plugin/translator.rb +38 -0
- data/lib/corl_core/util/cli.rb +352 -0
- data/lib/corl_core/util/data.rb +404 -0
- data/lib/corl_core/util/disk.rb +114 -0
- data/lib/corl_core/util/git.rb +47 -0
- data/lib/corl_core/util/interface.rb +319 -0
- data/lib/corl_core/util/liquid.rb +17 -0
- data/lib/corl_core/util/package.rb +93 -0
- data/lib/corl_core/util/shell.rb +239 -0
- data/lib/corl_core/util/ssh.rb +286 -0
- data/lib/facter/corl_config_ready.rb +13 -0
- data/lib/facter/corl_exists.rb +15 -0
- data/lib/facter/corl_network.rb +17 -0
- data/lib/hiera/corl_logger.rb +18 -0
- data/lib/puppet/indirector/corl.rb +27 -0
- data/lib/puppet/indirector/data_binding/corl.rb +6 -0
- data/lib/puppet/parser/functions/config_initialized.rb +26 -0
- data/lib/puppet/parser/functions/corl_include.rb +44 -0
- data/lib/puppet/parser/functions/corl_resources.rb +58 -0
- data/lib/puppet/parser/functions/deep_merge.rb +21 -0
- data/lib/puppet/parser/functions/ensure.rb +29 -0
- data/lib/puppet/parser/functions/file_exists.rb +19 -0
- data/lib/puppet/parser/functions/global_array.rb +35 -0
- data/lib/puppet/parser/functions/global_hash.rb +35 -0
- data/lib/puppet/parser/functions/global_options.rb +23 -0
- data/lib/puppet/parser/functions/global_param.rb +43 -0
- data/lib/puppet/parser/functions/interpolate.rb +26 -0
- data/lib/puppet/parser/functions/is_false.rb +21 -0
- data/lib/puppet/parser/functions/is_true.rb +21 -0
- data/lib/puppet/parser/functions/module_array.rb +38 -0
- data/lib/puppet/parser/functions/module_hash.rb +38 -0
- data/lib/puppet/parser/functions/module_options.rb +23 -0
- data/lib/puppet/parser/functions/module_param.rb +48 -0
- data/lib/puppet/parser/functions/name.rb +21 -0
- data/lib/puppet/parser/functions/render.rb +33 -0
- data/lib/puppet/parser/functions/value.rb +21 -0
- data/locales/en.yml +232 -0
- data/spec/corl_core/interface_spec.rb +489 -0
- data/spec/corl_mock_input.rb +29 -0
- data/spec/corl_test_kernel.rb +22 -0
- data/spec/spec_helper.rb +15 -0
- metadata +406 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
|
2
|
+
module CORL
|
3
|
+
module Command
|
4
|
+
class Shell < Plugin::Command
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Command plugin interface
|
8
|
+
|
9
|
+
def normalize
|
10
|
+
super
|
11
|
+
command = executable(self)
|
12
|
+
|
13
|
+
logger.info("Setting command executable to #{command}")
|
14
|
+
set(:command, command)
|
15
|
+
end
|
16
|
+
|
17
|
+
#-----------------------------------------------------------------------------
|
18
|
+
# Command operations
|
19
|
+
|
20
|
+
def build(components = {}, overrides = nil, override_key = false)
|
21
|
+
command = string(components[:command])
|
22
|
+
flags = array( components.has_key?(:flags) ? components[:flags] : [] )
|
23
|
+
data = string_map(hash( components.has_key?(:data) ? components[:data] : {} ))
|
24
|
+
args = array( components.has_key?(:args) ? components[:args] : [] )
|
25
|
+
subcommand = hash( components.has_key?(:subcommand) ? components[:subcommand] : {} )
|
26
|
+
|
27
|
+
override_key = command unless override_key
|
28
|
+
override_key = override_key.to_sym
|
29
|
+
|
30
|
+
command_string = command.dup
|
31
|
+
subcommand_string = ''
|
32
|
+
|
33
|
+
escape_characters = /[\'\"]+/
|
34
|
+
escape_replacement = '\"'
|
35
|
+
|
36
|
+
dash_pattern = /^([\-]+)/
|
37
|
+
assignment_pattern = /\=$/
|
38
|
+
|
39
|
+
logger.info("Building command #{command}")
|
40
|
+
logger.debug("Command flags: #{flags.inspect}")
|
41
|
+
logger.debug("Command options: #{data.inspect}")
|
42
|
+
logger.debug("Command arguments: #{args.inspect}")
|
43
|
+
logger.debug("Command has sub command") unless subcommand.empty?
|
44
|
+
|
45
|
+
logger.debug("Overrides: #{overrides.inspect}")
|
46
|
+
logger.debug("Override key: #{override_key}")
|
47
|
+
|
48
|
+
# Flags
|
49
|
+
if overrides && overrides.has_key?(:flags)
|
50
|
+
if overrides[:flags].is_a?(Hash)
|
51
|
+
if overrides[:flags].has_key?(override_key)
|
52
|
+
flags = array(overrides[:flags][override_key])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
flags = array(overrides[:flags])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
flags.each do |flag|
|
59
|
+
flag = string(flag)
|
60
|
+
if ! flag.empty?
|
61
|
+
if flag.match(dash_pattern)
|
62
|
+
dashes = $1
|
63
|
+
else
|
64
|
+
dashes = ( flag.size == 1 ? '-' : '--' )
|
65
|
+
end
|
66
|
+
command_string << " #{dashes}#{flag}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Data
|
71
|
+
if overrides && overrides.has_key?(:data)
|
72
|
+
if overrides[:data].has_key?(override_key)
|
73
|
+
data = hash(overrides[:data][override_key])
|
74
|
+
else
|
75
|
+
override = true
|
76
|
+
overrides[:data].each do |key, value|
|
77
|
+
if ! value.is_a?(String)
|
78
|
+
override = false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
data = hash(overrides[:data]) if override
|
82
|
+
end
|
83
|
+
end
|
84
|
+
data.each do |key, value|
|
85
|
+
key = string(key)
|
86
|
+
value = string(value).strip.sub(escape_characters, escape_replacement)
|
87
|
+
|
88
|
+
if key.match(dash_pattern)
|
89
|
+
dashes = $1
|
90
|
+
else
|
91
|
+
dashes = ( key.size == 1 ? '-' : '--' )
|
92
|
+
end
|
93
|
+
space = ( key.match(assignment_pattern) ? '' : ' ' )
|
94
|
+
|
95
|
+
command_string << " #{dashes}#{key}#{space}\"#{value}\""
|
96
|
+
end
|
97
|
+
|
98
|
+
# Arguments
|
99
|
+
if overrides && overrides.has_key?(:args)
|
100
|
+
unless overrides[:args].empty?
|
101
|
+
if overrides[:args].is_a?(Hash)
|
102
|
+
if overrides[:args].has_key?(override_key)
|
103
|
+
args = array(overrides[:args][override_key])
|
104
|
+
end
|
105
|
+
else
|
106
|
+
args = array(overrides[:args])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
args.each do |arg|
|
111
|
+
arg = string(arg).sub(escape_characters, escape_replacement)
|
112
|
+
|
113
|
+
unless arg.empty?
|
114
|
+
command_string << " \"#{arg}\""
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Subcommand
|
119
|
+
subcommand_overrides = ( overrides ? overrides[:subcommand] : nil )
|
120
|
+
if subcommand && subcommand.is_a?(Hash) && ! subcommand.empty?
|
121
|
+
subcommand_string = build(subcommand, subcommand_overrides)
|
122
|
+
end
|
123
|
+
|
124
|
+
command_string = (command_string + ' ' + subcommand_string).strip
|
125
|
+
|
126
|
+
logger.debug("Rendered command: #{command_string}")
|
127
|
+
return command_string
|
128
|
+
end
|
129
|
+
|
130
|
+
#---
|
131
|
+
|
132
|
+
def exec(options = {}, overrides = nil)
|
133
|
+
config = Config.ensure(options)
|
134
|
+
|
135
|
+
logger.info("Executing command #{command}")
|
136
|
+
|
137
|
+
config[:ui] = @ui
|
138
|
+
result = Util::Shell.connection.exec(build(export, overrides), config) do |op, command, data|
|
139
|
+
block_given? ? yield(op, command, data) : true
|
140
|
+
end
|
141
|
+
|
142
|
+
logger.warn("Command #{command} failed to execute") unless result.status == CORL.code.success
|
143
|
+
return result
|
144
|
+
end
|
145
|
+
|
146
|
+
#-----------------------------------------------------------------------------
|
147
|
+
# Utilities
|
148
|
+
|
149
|
+
def executable(options)
|
150
|
+
config = Config.ensure(options)
|
151
|
+
|
152
|
+
if config.get(:corl, false)
|
153
|
+
return 'corl ' + config[:corl]
|
154
|
+
|
155
|
+
elsif config.get(:vagrant, false)
|
156
|
+
return 'vagrant ' + config[:vagrant]
|
157
|
+
|
158
|
+
elsif config.get(:command, false)
|
159
|
+
return config[:command]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
|
2
|
+
module CORL
|
3
|
+
module Configuration
|
4
|
+
class File < Plugin::Configuration
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Configuration plugin interface
|
8
|
+
|
9
|
+
def normalize
|
10
|
+
super
|
11
|
+
|
12
|
+
logger.info("Setting source configuration project")
|
13
|
+
@project = CORL.project(extended_config(:project, {
|
14
|
+
:directory => _delete(:directory, Dir.pwd),
|
15
|
+
:url => _delete(:url),
|
16
|
+
:revision => _delete(:revision)
|
17
|
+
}), _delete(:project_provider))
|
18
|
+
|
19
|
+
_set(:search, Config.new)
|
20
|
+
_set(:router, Config.new)
|
21
|
+
|
22
|
+
set_location(@project)
|
23
|
+
end
|
24
|
+
|
25
|
+
#---
|
26
|
+
|
27
|
+
def self.finalize(file_name)
|
28
|
+
proc do
|
29
|
+
logger.debug("Finalizing file: #{file_name}")
|
30
|
+
Util::Disk.close(file_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#-----------------------------------------------------------------------------
|
35
|
+
# Checks
|
36
|
+
|
37
|
+
def can_persist?
|
38
|
+
project.can_persist?
|
39
|
+
end
|
40
|
+
|
41
|
+
#-----------------------------------------------------------------------------
|
42
|
+
# Property accessors / modifiers
|
43
|
+
|
44
|
+
def project
|
45
|
+
@project
|
46
|
+
end
|
47
|
+
|
48
|
+
#---
|
49
|
+
|
50
|
+
def search
|
51
|
+
_get(:search)
|
52
|
+
end
|
53
|
+
|
54
|
+
#---
|
55
|
+
|
56
|
+
def router
|
57
|
+
_get(:router)
|
58
|
+
end
|
59
|
+
|
60
|
+
#-----------------------------------------------------------------------------
|
61
|
+
|
62
|
+
def set_location(directory)
|
63
|
+
if directory && directory.is_a?(CORL::Plugin::Project)
|
64
|
+
logger.debug("Setting source project directory from other project at #{directory.directory}")
|
65
|
+
project.set_location(directory.directory)
|
66
|
+
|
67
|
+
elsif directory && directory.is_a?(String) || directory.is_a?(Symbol)
|
68
|
+
logger.debug("Setting source project directory to #{directory}")
|
69
|
+
project.set_location(directory.to_s)
|
70
|
+
end
|
71
|
+
search_files if directory
|
72
|
+
end
|
73
|
+
|
74
|
+
#---
|
75
|
+
|
76
|
+
def remote(name)
|
77
|
+
project.remote(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
#---
|
81
|
+
|
82
|
+
def set_remote(name, location)
|
83
|
+
project.set_remote(name, location)
|
84
|
+
end
|
85
|
+
|
86
|
+
#-----------------------------------------------------------------------------
|
87
|
+
# Configuration loading / saving
|
88
|
+
|
89
|
+
def load(options = {})
|
90
|
+
super do |method_config, properties|
|
91
|
+
|
92
|
+
generate_routes = lambda do |config_name, file_properties, parents = []|
|
93
|
+
file_properties.each do |name, value|
|
94
|
+
keys = [ parents, name ].flatten
|
95
|
+
|
96
|
+
if value.is_a?(Hash) && ! value.empty?
|
97
|
+
generate_routes.call(config_name, value, keys)
|
98
|
+
else
|
99
|
+
router.set(keys, config_name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if fetch_project(method_config)
|
105
|
+
search.export.each do |config_name, info|
|
106
|
+
provider = info[:provider]
|
107
|
+
file = info[:file]
|
108
|
+
|
109
|
+
logger.info("Loading #{provider} translated source configuration from #{file}")
|
110
|
+
|
111
|
+
parser = CORL.translator(method_config, provider)
|
112
|
+
raw = Util::Disk.read(file)
|
113
|
+
|
114
|
+
if parser && raw && ! raw.empty?
|
115
|
+
logger.debug("Source configuration file contents: #{raw}")
|
116
|
+
file_properties = parser.parse(raw)
|
117
|
+
|
118
|
+
generate_routes.call(config_name, file_properties)
|
119
|
+
properties.import(file_properties)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
#---
|
127
|
+
|
128
|
+
# properties[key...] = values
|
129
|
+
#
|
130
|
+
# to
|
131
|
+
#
|
132
|
+
# file_data[config_name][key...] = config
|
133
|
+
|
134
|
+
def separate
|
135
|
+
file_data = Config.new
|
136
|
+
|
137
|
+
split_config = lambda do |properties, local_router, parents = []|
|
138
|
+
properties.each do |name, value|
|
139
|
+
keys = [ parents, name ].flatten
|
140
|
+
|
141
|
+
if value.is_a?(Hash) && ! value.empty?
|
142
|
+
# Nested configurations
|
143
|
+
if local_router.is_a?(Hash) && local_router.has_key?(name)
|
144
|
+
# Router and configuration values are nested
|
145
|
+
split_config.call(value, local_router[name], keys)
|
146
|
+
else
|
147
|
+
# Just configuration values are nested
|
148
|
+
if local_router.is_a?(String)
|
149
|
+
# We are down to a config_name router. Inherit on down the line
|
150
|
+
split_config.call(value, local_router, keys)
|
151
|
+
else
|
152
|
+
# Never encountered before
|
153
|
+
config_name = nil
|
154
|
+
config_name = select_largest(router.get(parents)) unless parents.empty?
|
155
|
+
split_config.call(value, config_name, keys)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
else
|
159
|
+
if local_router.is_a?(String)
|
160
|
+
# Router is a config_name string
|
161
|
+
file_data.set([ local_router, keys ].flatten, value)
|
162
|
+
elsif router.is_a?(Hash)
|
163
|
+
# Router is a hash with sub options we have to pick from
|
164
|
+
config_name = select_largest(local_router)
|
165
|
+
file_data.set([ config_name, keys ].flatten, value)
|
166
|
+
else
|
167
|
+
# Router is non existent
|
168
|
+
if config_name = select_largest(router)
|
169
|
+
# Pick largest router from top level
|
170
|
+
file_data.set([ config_name, keys ].flatten, value)
|
171
|
+
else
|
172
|
+
# Resort to sane defaults
|
173
|
+
default_provider = Manager.connection.type_default(:translator)
|
174
|
+
config_name = "corl.#{default_provider}"
|
175
|
+
file_data.set([ config_name, keys ].flatten, value)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Whew! Glad that's over...
|
183
|
+
|
184
|
+
split_config.call(config.export, router.export)
|
185
|
+
file_data
|
186
|
+
end
|
187
|
+
protected :separate
|
188
|
+
|
189
|
+
#---
|
190
|
+
|
191
|
+
def save(options = {})
|
192
|
+
super do |method_config|
|
193
|
+
config_files = []
|
194
|
+
success = true
|
195
|
+
|
196
|
+
separate.export.each do |config_name, router_data|
|
197
|
+
info = search[config_name]
|
198
|
+
provider = info[:provider]
|
199
|
+
file = info[:file]
|
200
|
+
|
201
|
+
if renderer = CORL.translator(method_config, provider)
|
202
|
+
rendering = renderer.generate(router_data)
|
203
|
+
|
204
|
+
if Util::Disk.write(file, rendering)
|
205
|
+
config_files << config_name
|
206
|
+
else
|
207
|
+
success = false
|
208
|
+
end
|
209
|
+
else
|
210
|
+
success = false
|
211
|
+
end
|
212
|
+
break unless success
|
213
|
+
end
|
214
|
+
if success && ! config_files.empty?
|
215
|
+
commit_files = [ config_files, method_config.get_array(:files) ].flatten
|
216
|
+
|
217
|
+
logger.debug("Source configuration rendering: #{rendering}")
|
218
|
+
success = update_project(commit_files, method_config)
|
219
|
+
end
|
220
|
+
success
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
#---
|
225
|
+
|
226
|
+
def remove(options = {})
|
227
|
+
super do |method_config|
|
228
|
+
success = true
|
229
|
+
config_files = []
|
230
|
+
search.each do |config_name, info|
|
231
|
+
config_files << info[:file]
|
232
|
+
success = false unless Util::Disk.delete(info[:file])
|
233
|
+
end
|
234
|
+
success = update_project(config_files, method_config) if success
|
235
|
+
success
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
#---
|
240
|
+
|
241
|
+
def attach(type, name, data, options = {})
|
242
|
+
super do |method_config|
|
243
|
+
attach_path = Util::Disk.filename([ project.directory, type.to_s ])
|
244
|
+
success = true
|
245
|
+
|
246
|
+
begin
|
247
|
+
FileUtils.mkdir_p(attach_path) unless Dir.exists?(attach_path)
|
248
|
+
|
249
|
+
rescue Exception => error
|
250
|
+
alert(error.message)
|
251
|
+
success = false
|
252
|
+
end
|
253
|
+
|
254
|
+
if success
|
255
|
+
case method_config.get(:type, :source)
|
256
|
+
when :source
|
257
|
+
new_file = project.local_path(Util::Disk.filename([ attach_path, name ]))
|
258
|
+
|
259
|
+
logger.debug("Attaching source data (length: #{data.length}) to configuration at #{attach_path}")
|
260
|
+
success = Util::Disk.write(new_file, data)
|
261
|
+
|
262
|
+
when :file
|
263
|
+
file = ::File.expand_path(data)
|
264
|
+
attach_ext = ::File.basename(file)
|
265
|
+
new_file = project.local_path(Util::Disk.filename([ attach_path, "#{name}-#{attach_ext}" ]))
|
266
|
+
|
267
|
+
logger.debug("Attaching file #{file} to configuration at #{attach_path}")
|
268
|
+
|
269
|
+
begin
|
270
|
+
FileUtils.mkdir_p(attach_path) unless Dir.exists?(attach_path)
|
271
|
+
FileUtils.cp(file, new_file)
|
272
|
+
|
273
|
+
rescue Exception => error
|
274
|
+
alert(error.message)
|
275
|
+
success = false
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
if success
|
280
|
+
logger.debug("Attaching data to project as #{new_file}")
|
281
|
+
success = update_project(new_file, method_config)
|
282
|
+
end
|
283
|
+
success ? new_file : nil
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
#-----------------------------------------------------------------------------
|
288
|
+
# Utilities
|
289
|
+
|
290
|
+
def search_files
|
291
|
+
if Util::Data.empty?(project.directory)
|
292
|
+
logger.debug("Clearing configuration file information")
|
293
|
+
search.clear
|
294
|
+
else
|
295
|
+
file_bases = [ "corl", extension_collect(:base) ].flatten
|
296
|
+
|
297
|
+
Manager.connection.loaded_plugins(:translator).each do |provider, info|
|
298
|
+
file_bases.each do |file_base|
|
299
|
+
config_name = "#{file_base}.#{provider}"
|
300
|
+
file = Util::Disk.filename([ project.directory, config_name ])
|
301
|
+
|
302
|
+
if Util::Disk.exists?(file)
|
303
|
+
search[config_name] = {
|
304
|
+
:provider => provider,
|
305
|
+
:info => info,
|
306
|
+
:file => file
|
307
|
+
}
|
308
|
+
ObjectSpace.define_finalizer(myself, myself.class.finalize(file))
|
309
|
+
else
|
310
|
+
logger.info("Configuration file #{file} does not exist")
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
logger.debug("Setting configuration file information to #{search.inspect}")
|
315
|
+
end
|
316
|
+
load(_export) if autoload
|
317
|
+
end
|
318
|
+
protected :search_files
|
319
|
+
|
320
|
+
#---
|
321
|
+
|
322
|
+
def fetch_project(options = {})
|
323
|
+
config = Config.ensure(options)
|
324
|
+
success = true
|
325
|
+
if remote = config.get(:remote, nil)
|
326
|
+
logger.info("Pulling configuration updates from remote #{remote}")
|
327
|
+
success = project.pull(remote, config) if config.get(:pull, true)
|
328
|
+
end
|
329
|
+
success
|
330
|
+
end
|
331
|
+
protected :fetch_project
|
332
|
+
|
333
|
+
#---
|
334
|
+
|
335
|
+
def update_project(files = [], options = {})
|
336
|
+
config = Config.ensure(options)
|
337
|
+
success = true
|
338
|
+
|
339
|
+
commit_files = '.'
|
340
|
+
commit_files = array(files).flatten unless files.empty?
|
341
|
+
|
342
|
+
logger.info("Committing changes to configuration files")
|
343
|
+
success = project.commit(commit_files, config)
|
344
|
+
|
345
|
+
if success && remote = config.get(:remote, nil)
|
346
|
+
logger.info("Pushing configuration updates to remote #{remote}")
|
347
|
+
success = project.pull(remote, config) if config.get(:pull, true)
|
348
|
+
success = project.push(remote, config) if success && config.get(:push, true)
|
349
|
+
end
|
350
|
+
success
|
351
|
+
end
|
352
|
+
protected :update_project
|
353
|
+
|
354
|
+
#---
|
355
|
+
|
356
|
+
def select_largest(router)
|
357
|
+
config_map = {}
|
358
|
+
|
359
|
+
count_config_names = lambda do |data|
|
360
|
+
data = data.export if data.is_a?(CORL::Config)
|
361
|
+
data.each do |name, value|
|
362
|
+
if value.is_a?(Hash)
|
363
|
+
count_config_names.call(value)
|
364
|
+
else
|
365
|
+
config_map[value] = 0 unless config_map.has_key?(value)
|
366
|
+
config_map[value] = config_map[value] + 1
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
config_name = nil
|
372
|
+
config_weight = nil
|
373
|
+
|
374
|
+
count_config_names.call(router)
|
375
|
+
config_map.each do |name, weight|
|
376
|
+
if config_name.nil? || weight > config_weight
|
377
|
+
config_name = name
|
378
|
+
config_weight = weight
|
379
|
+
end
|
380
|
+
end
|
381
|
+
config_name
|
382
|
+
end
|
383
|
+
protected :select_largest
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
module CORL
|
3
|
+
module Event
|
4
|
+
class Puppet < Plugin::Event
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Puppet event interface
|
8
|
+
|
9
|
+
def normalize
|
10
|
+
super
|
11
|
+
|
12
|
+
if get(:string)
|
13
|
+
items = string(delete(:string)).split(':')
|
14
|
+
myself.element = items[0]
|
15
|
+
myself.operation = items[1]
|
16
|
+
myself.message = items[2]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#-----------------------------------------------------------------------------
|
21
|
+
# Property accessors / modifiers
|
22
|
+
|
23
|
+
def element(default = '')
|
24
|
+
return get(:element, default, :string)
|
25
|
+
end
|
26
|
+
|
27
|
+
#---
|
28
|
+
|
29
|
+
def element=element
|
30
|
+
set(:element, string(element))
|
31
|
+
end
|
32
|
+
|
33
|
+
#---
|
34
|
+
|
35
|
+
def operation(default = '')
|
36
|
+
return get(:operation, default, :string)
|
37
|
+
end
|
38
|
+
|
39
|
+
#---
|
40
|
+
|
41
|
+
def operation=operation
|
42
|
+
set(:operation, string(operation))
|
43
|
+
end
|
44
|
+
|
45
|
+
#--
|
46
|
+
|
47
|
+
def message(default = '')
|
48
|
+
return get(:message, default, :string)
|
49
|
+
end
|
50
|
+
|
51
|
+
#---
|
52
|
+
|
53
|
+
def message=message
|
54
|
+
set(:message, string(message))
|
55
|
+
end
|
56
|
+
|
57
|
+
#-----------------------------------------------------------------------------
|
58
|
+
# Operations
|
59
|
+
|
60
|
+
def render
|
61
|
+
return "#{name}:#{element}:#{operation}:#{message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
#---
|
65
|
+
|
66
|
+
def check(source)
|
67
|
+
if source.match(/notice:\s+(.+?):\s+(.+)\s*/i)
|
68
|
+
source_element = $1
|
69
|
+
source_operation = ''
|
70
|
+
source_message = $2
|
71
|
+
|
72
|
+
source_elements = source_element.split('/')
|
73
|
+
source_operation = source_elements.pop.strip unless source_elements.last.match(/[\[\]]/)
|
74
|
+
|
75
|
+
if source_operation
|
76
|
+
source_element = source_elements.join('/').strip
|
77
|
+
success = ( source_element.include?(element) && source_operation == operation && source_message.include?(message) )
|
78
|
+
|
79
|
+
logger.debug("Checking puppet event with source #{source_element} #{source_operation} #{source_message}: #{success.inspect}")
|
80
|
+
|
81
|
+
return success
|
82
|
+
else
|
83
|
+
logger.warn("Can not check puppet event because it is missing an operation")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module CORL
|
3
|
+
module Event
|
4
|
+
class Regex < Plugin::Event
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Regular expression event interface
|
8
|
+
|
9
|
+
def normalize
|
10
|
+
super
|
11
|
+
|
12
|
+
if get(:string)
|
13
|
+
myself.pattern = delete(:string)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#-----------------------------------------------------------------------------
|
18
|
+
# Property accessors / modifiers
|
19
|
+
|
20
|
+
def pattern(default = '')
|
21
|
+
return get(:pattern, default)
|
22
|
+
end
|
23
|
+
|
24
|
+
#---
|
25
|
+
|
26
|
+
def pattern=pattern
|
27
|
+
set(:pattern, string(pattern))
|
28
|
+
end
|
29
|
+
|
30
|
+
#-----------------------------------------------------------------------------
|
31
|
+
# Operations
|
32
|
+
|
33
|
+
def render
|
34
|
+
return "#{name}:#{pattern}"
|
35
|
+
end
|
36
|
+
|
37
|
+
#---
|
38
|
+
|
39
|
+
def check(source)
|
40
|
+
if pattern.empty?
|
41
|
+
logger.warn("Can not check regex pattern because it is empty")
|
42
|
+
else
|
43
|
+
success = source.match(/#{pattern}/)
|
44
|
+
|
45
|
+
logger.debug("Checking regex event with pattern #{pattern}: #{success.inspect}")
|
46
|
+
return success
|
47
|
+
end
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module CORL
|
3
|
+
module Extension
|
4
|
+
class Puppetloader < Plugin::Extension
|
5
|
+
|
6
|
+
def register_plugins(config)
|
7
|
+
connection = Manager.connection
|
8
|
+
provisioners = connection.plugins(:provisioner, :puppetnode)
|
9
|
+
provisioner = provisioners.empty? ? nil : provisioners[provisioners.keys.first]
|
10
|
+
|
11
|
+
if provisioner
|
12
|
+
# Register Puppet CORL extensions
|
13
|
+
provisioner.env.modules.each do |mod|
|
14
|
+
lib_dir = File.join(mod.path, 'lib', 'corl')
|
15
|
+
if File.directory?(lib_dir)
|
16
|
+
logger.debug("Registering Puppet module at #{lib_dir}")
|
17
|
+
connection.register(lib_dir)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|