corl 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|