choria-mcorpc-support 2.20.8 → 2.23.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mcollective.rb +1 -1
- data/lib/mcollective/agent/bolt_tasks.ddl +235 -0
- data/lib/mcollective/agent/bolt_tasks.json +347 -0
- data/lib/mcollective/agent/bolt_tasks.rb +176 -0
- data/lib/mcollective/agent/choria_util.ddl +152 -0
- data/lib/mcollective/agent/choria_util.json +244 -0
- data/lib/mcollective/agent/rpcutil.ddl +7 -3
- data/lib/mcollective/agent/rpcutil.json +333 -0
- data/lib/mcollective/agent/scout.ddl +169 -0
- data/lib/mcollective/agent/scout.json +224 -0
- data/lib/mcollective/agents.rb +7 -6
- data/lib/mcollective/aggregate.rb +4 -4
- data/lib/mcollective/aggregate/average.rb +2 -2
- data/lib/mcollective/aggregate/base.rb +2 -2
- data/lib/mcollective/aggregate/result.rb +3 -3
- data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
- data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
- data/lib/mcollective/aggregate/sum.rb +2 -2
- data/lib/mcollective/aggregate/summary.rb +3 -4
- data/lib/mcollective/application.rb +57 -21
- data/lib/mcollective/application/choria.rb +249 -0
- data/lib/mcollective/application/completion.rb +6 -6
- data/lib/mcollective/application/describe_filter.rb +20 -20
- data/lib/mcollective/application/facts.rb +19 -11
- data/lib/mcollective/application/federation.rb +239 -0
- data/lib/mcollective/application/find.rb +4 -4
- data/lib/mcollective/application/help.rb +3 -3
- data/lib/mcollective/application/inventory.rb +3 -341
- data/lib/mcollective/application/ping.rb +3 -77
- data/lib/mcollective/application/playbook.rb +207 -0
- data/lib/mcollective/application/plugin.rb +106 -106
- data/lib/mcollective/application/rpc.rb +3 -108
- data/lib/mcollective/application/tasks.rb +416 -0
- data/lib/mcollective/applications.rb +11 -10
- data/lib/mcollective/audit/choria.rb +33 -0
- data/lib/mcollective/cache.rb +2 -4
- data/lib/mcollective/client.rb +11 -10
- data/lib/mcollective/config.rb +21 -34
- data/lib/mcollective/connector/base.rb +2 -1
- data/lib/mcollective/connector/nats.ddl +9 -0
- data/lib/mcollective/connector/nats.rb +450 -0
- data/lib/mcollective/data.rb +8 -3
- data/lib/mcollective/data/agent_data.rb +1 -1
- data/lib/mcollective/data/base.rb +6 -5
- data/lib/mcollective/data/bolt_task_data.ddl +90 -0
- data/lib/mcollective/data/bolt_task_data.rb +32 -0
- data/lib/mcollective/data/collective_data.rb +1 -1
- data/lib/mcollective/data/fact_data.rb +6 -6
- data/lib/mcollective/data/fstat_data.rb +2 -4
- data/lib/mcollective/data/result.rb +7 -2
- data/lib/mcollective/ddl/agentddl.rb +5 -17
- data/lib/mcollective/ddl/base.rb +11 -14
- data/lib/mcollective/discovery.rb +12 -26
- data/lib/mcollective/discovery/choria.ddl +11 -0
- data/lib/mcollective/discovery/choria.rb +223 -0
- data/lib/mcollective/discovery/flatfile.rb +7 -8
- data/lib/mcollective/discovery/mc.rb +2 -2
- data/lib/mcollective/discovery/stdin.rb +17 -18
- data/lib/mcollective/exceptions.rb +13 -0
- data/lib/mcollective/facts/base.rb +9 -9
- data/lib/mcollective/facts/yaml_facts.rb +12 -12
- data/lib/mcollective/generators.rb +3 -3
- data/lib/mcollective/generators/agent_generator.rb +3 -4
- data/lib/mcollective/generators/base.rb +14 -15
- data/lib/mcollective/generators/data_generator.rb +5 -6
- data/lib/mcollective/log.rb +2 -2
- data/lib/mcollective/logger/base.rb +3 -2
- data/lib/mcollective/logger/console_logger.rb +10 -10
- data/lib/mcollective/logger/file_logger.rb +7 -7
- data/lib/mcollective/logger/syslog_logger.rb +11 -15
- data/lib/mcollective/matcher.rb +14 -14
- data/lib/mcollective/matcher/parser.rb +31 -41
- data/lib/mcollective/matcher/scanner.rb +69 -74
- data/lib/mcollective/message.rb +10 -17
- data/lib/mcollective/monkey_patches.rb +2 -4
- data/lib/mcollective/optionparser.rb +1 -0
- data/lib/mcollective/pluginmanager.rb +3 -5
- data/lib/mcollective/pluginpackager.rb +1 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +10 -11
- data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
- data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
- data/lib/mcollective/registration/base.rb +18 -16
- data/lib/mcollective/rpc.rb +2 -4
- data/lib/mcollective/rpc/actionrunner.rb +16 -18
- data/lib/mcollective/rpc/agent.rb +26 -43
- data/lib/mcollective/rpc/audit.rb +1 -0
- data/lib/mcollective/rpc/client.rb +67 -85
- data/lib/mcollective/rpc/helpers.rb +55 -62
- data/lib/mcollective/rpc/progress.rb +2 -2
- data/lib/mcollective/rpc/reply.rb +17 -19
- data/lib/mcollective/rpc/request.rb +7 -5
- data/lib/mcollective/rpc/result.rb +6 -8
- data/lib/mcollective/rpc/stats.rb +49 -58
- data/lib/mcollective/security/base.rb +29 -36
- data/lib/mcollective/security/choria.rb +765 -0
- data/lib/mcollective/shell.rb +9 -4
- data/lib/mcollective/signer/base.rb +28 -0
- data/lib/mcollective/signer/choria.rb +185 -0
- data/lib/mcollective/ssl.rb +8 -6
- data/lib/mcollective/util.rb +58 -55
- data/lib/mcollective/util/bolt_support.rb +176 -0
- data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
- data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
- data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
- data/lib/mcollective/util/choria.rb +1103 -0
- data/lib/mcollective/util/indifferent_hash.rb +12 -0
- data/lib/mcollective/util/natswrapper.rb +242 -0
- data/lib/mcollective/util/playbook.rb +435 -0
- data/lib/mcollective/util/playbook/data_stores.rb +201 -0
- data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
- data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
- data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
- data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
- data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
- data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
- data/lib/mcollective/util/playbook/inputs.rb +265 -0
- data/lib/mcollective/util/playbook/nodes.rb +207 -0
- data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
- data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
- data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
- data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
- data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
- data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
- data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
- data/lib/mcollective/util/playbook/report.rb +152 -0
- data/lib/mcollective/util/playbook/task_result.rb +55 -0
- data/lib/mcollective/util/playbook/tasks.rb +196 -0
- data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
- data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
- data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
- data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
- data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
- data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
- data/lib/mcollective/util/playbook/template_util.rb +98 -0
- data/lib/mcollective/util/playbook/uses.rb +169 -0
- data/lib/mcollective/util/tasks_support.rb +733 -0
- data/lib/mcollective/util/tasks_support/cli.rb +260 -0
- data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
- data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
- data/lib/mcollective/validator.rb +8 -3
- data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
- data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
- data/lib/mcollective/validator/length_validator.rb +1 -3
- data/lib/mcollective/validator/typecheck_validator.rb +4 -0
- metadata +67 -4
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "yaml"
|
5
|
+
|
6
|
+
module MCollective
|
7
|
+
module Util
|
8
|
+
class Playbook
|
9
|
+
class DataStores
|
10
|
+
class FileDataStore < Base
|
11
|
+
attr_accessor :file, :format, :create
|
12
|
+
|
13
|
+
def startup_hook
|
14
|
+
@file_mutex = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def from_hash(properties)
|
18
|
+
@file = properties["file"]
|
19
|
+
@format = properties["format"]
|
20
|
+
@create = !!properties["create"]
|
21
|
+
|
22
|
+
validate_configuration!
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_configuration!
|
28
|
+
raise("No file given to use as data source") unless @file
|
29
|
+
raise("No file format given") unless @format
|
30
|
+
raise("File format has to be one of 'json' or 'yaml'") unless ["json", "yaml"].include?(@format)
|
31
|
+
|
32
|
+
@file = File.expand_path(@file)
|
33
|
+
|
34
|
+
FileUtils.touch(@file) if @create && !File.exist?(@file)
|
35
|
+
|
36
|
+
raise("Cannot find data file %s" % @file) unless File.exist?(@file)
|
37
|
+
raise("Cannot read data file %s" % @file) unless File.readable?(@file)
|
38
|
+
raise("Cannot write data file %s" % @file) unless File.writable?(@file)
|
39
|
+
|
40
|
+
raise("The data file must contain a Hash or be empty") unless data.is_a?(Hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
def data
|
44
|
+
@file_mutex.synchronize do
|
45
|
+
parse_data
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_data
|
50
|
+
return({}) if File.size(@file) == 0
|
51
|
+
|
52
|
+
case @format
|
53
|
+
when "json"
|
54
|
+
JSON.parse(File.read(@file))
|
55
|
+
when "yaml"
|
56
|
+
YAML.load(File.read(@file))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def save_data(raw_data)
|
61
|
+
File.open(@file, "w") do |f|
|
62
|
+
case @format
|
63
|
+
when "json"
|
64
|
+
f.print(JSON.dump(raw_data))
|
65
|
+
when "yaml"
|
66
|
+
f.print(YAML.dump(raw_data))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def read(key)
|
72
|
+
raise("No such key %s" % [key]) unless include?(key)
|
73
|
+
|
74
|
+
data[key]
|
75
|
+
end
|
76
|
+
|
77
|
+
def write(key, value)
|
78
|
+
@file_mutex.synchronize do
|
79
|
+
raw_data = parse_data
|
80
|
+
|
81
|
+
raw_data[key] = value
|
82
|
+
|
83
|
+
save_data(raw_data)
|
84
|
+
end
|
85
|
+
|
86
|
+
read(key)
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete(key)
|
90
|
+
@file_mutex.synchronize do
|
91
|
+
raw_data = parse_data
|
92
|
+
|
93
|
+
raw_data.delete(key)
|
94
|
+
|
95
|
+
save_data(raw_data)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def include?(key)
|
100
|
+
data.include?(key)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module MCollective
|
4
|
+
module Util
|
5
|
+
class Playbook
|
6
|
+
class DataStores
|
7
|
+
class ShellDataStore < Base
|
8
|
+
attr_reader :command, :timeout, :environment, :cwd
|
9
|
+
|
10
|
+
def write(key, value)
|
11
|
+
run("write", key, "CHORIA_DATA_VALUE" => value)
|
12
|
+
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete(key)
|
17
|
+
run("delete", key)
|
18
|
+
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def read(key)
|
23
|
+
run("read", key).stdout.chomp
|
24
|
+
end
|
25
|
+
|
26
|
+
def run(action, key, environment={})
|
27
|
+
validate_key(key)
|
28
|
+
|
29
|
+
command = "%s --%s" % [@command, action]
|
30
|
+
options = shell_options
|
31
|
+
|
32
|
+
options["environment"].merge!(
|
33
|
+
environment.merge(
|
34
|
+
"CHORIA_DATA_KEY" => key,
|
35
|
+
"CHORIA_DATA_ACTION" => action
|
36
|
+
)
|
37
|
+
)
|
38
|
+
|
39
|
+
shell = run_command(command, options)
|
40
|
+
|
41
|
+
unless shell.status.exitstatus == 0
|
42
|
+
Log.warn("While running command %s: %s" % [command, shell.stderr])
|
43
|
+
raise("Could not %s key %s, got exitcode %d" % [action, key, shell.status.exitstatus])
|
44
|
+
end
|
45
|
+
|
46
|
+
shell
|
47
|
+
end
|
48
|
+
|
49
|
+
def run_command(command, options)
|
50
|
+
shell = Shell.new(command, options)
|
51
|
+
shell.runcommand
|
52
|
+
shell
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_key(key)
|
56
|
+
raise("Valid keys must match ^[a-zA-Z0-9_-]+$") unless key =~ /^[a-zA-Z0-9_-]+$/
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def from_hash(properties)
|
62
|
+
@command = properties["command"]
|
63
|
+
@timeout = properties.fetch("timeout", 10)
|
64
|
+
@environment = properties.fetch("environment", {})
|
65
|
+
@cwd = properties["cwd"]
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_configuration!
|
71
|
+
raise("A command is required") unless @command
|
72
|
+
raise("Command %s is not executable" % @command) unless File.executable?(@command)
|
73
|
+
raise("Timeout should be an integer") unless @timeout.to_i.to_s == @timeout.to_s
|
74
|
+
|
75
|
+
if @environment
|
76
|
+
raise("Environment should be a hash") unless @environment.is_a?(Hash)
|
77
|
+
|
78
|
+
all_strings = @environment.map {|k, v| k.is_a?(String) && v.is_a?(String)}.all?
|
79
|
+
raise("All keys and values in the environment must be strings") unless all_strings
|
80
|
+
end
|
81
|
+
|
82
|
+
if @cwd
|
83
|
+
raise("cwd %s does not exist" % @cwd) unless File.exist?(@cwd)
|
84
|
+
raise("cwd %s is not a directory" % @cwd) unless File.directory?(@cwd)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def shell_options
|
89
|
+
unless @__options
|
90
|
+
@__options = {}
|
91
|
+
@__options["cwd"] = @cwd if @cwd
|
92
|
+
@__options["environment"] = @environment
|
93
|
+
@__options["timeout"] = Integer(@timeout)
|
94
|
+
end
|
95
|
+
|
96
|
+
# bacause environment is being edited
|
97
|
+
Marshal.load(Marshal.dump(@__options))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Util
|
3
|
+
class Playbook
|
4
|
+
class Inputs
|
5
|
+
def initialize(playbook)
|
6
|
+
@playbook = playbook
|
7
|
+
@inputs = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
# List of known input names
|
11
|
+
#
|
12
|
+
# @return [Array<String>]
|
13
|
+
def keys
|
14
|
+
@inputs.keys
|
15
|
+
end
|
16
|
+
|
17
|
+
# List of known input names that have static values
|
18
|
+
#
|
19
|
+
# @return [Array<String>]
|
20
|
+
def static_keys
|
21
|
+
keys - dynamic_keys
|
22
|
+
end
|
23
|
+
|
24
|
+
# List of known input names that have dynamic values
|
25
|
+
#
|
26
|
+
# @return [Array<String>]
|
27
|
+
def dynamic_keys
|
28
|
+
@inputs.select do |_, props|
|
29
|
+
props[:dynamic]
|
30
|
+
end.keys
|
31
|
+
end
|
32
|
+
|
33
|
+
# Creates options for each input in the application
|
34
|
+
#
|
35
|
+
# @param application [MCollective::Application]
|
36
|
+
# @param set_required [Boolean] when true required inputs will be required on the CLI
|
37
|
+
# @raise [StandardError] for invalidly defined inputs
|
38
|
+
def add_cli_options(application, set_required)
|
39
|
+
@inputs.each do |input, props|
|
40
|
+
i_props = props[:properties]
|
41
|
+
|
42
|
+
next if i_props["dynamic"]
|
43
|
+
|
44
|
+
type = case i_props["type"]
|
45
|
+
when :string, "String"
|
46
|
+
String
|
47
|
+
when :fixnum, "Fixnum", "Integer"
|
48
|
+
Integer
|
49
|
+
when :float, "Float"
|
50
|
+
Float
|
51
|
+
when :numeric, "Numeric"
|
52
|
+
Numeric
|
53
|
+
when :array, ":array", "Array"
|
54
|
+
:array
|
55
|
+
when :bool, ":bool", ":boolean", "Boolean"
|
56
|
+
:boolean
|
57
|
+
else
|
58
|
+
raise("Invalid input type %s given for input %s" % [i_props["type"], input])
|
59
|
+
end
|
60
|
+
|
61
|
+
description = "%s (%s) %s" % [i_props["description"], type, i_props["default"] ? ("default: %s" % i_props["default"]) : ""]
|
62
|
+
|
63
|
+
option_params = {
|
64
|
+
:description => description,
|
65
|
+
:arguments => ["--%s %s" % [input.downcase, input.upcase]],
|
66
|
+
:type => type
|
67
|
+
}
|
68
|
+
|
69
|
+
option_params[:arguments] = ["--%s" % input.downcase] if type == :boolean
|
70
|
+
|
71
|
+
option_params[:required] = i_props["required"] if set_required && !i_props.include?("data")
|
72
|
+
|
73
|
+
application.class.option(input, option_params)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Attempts to find values for all declared inputs
|
78
|
+
#
|
79
|
+
# During tests saving to the ds can be skipped by setting
|
80
|
+
# @save_during_prepare to false
|
81
|
+
#
|
82
|
+
# @param data [Hash] input data from CLI etc
|
83
|
+
# @return [void]
|
84
|
+
# @raise [StandardError] when required data could not be found
|
85
|
+
# @raise [StandardError] when validation fails for any data
|
86
|
+
def prepare(data={})
|
87
|
+
@inputs.each do |input, props|
|
88
|
+
next unless data.include?(input)
|
89
|
+
next if data[input].nil?
|
90
|
+
next if props[:properties]["dynamic"]
|
91
|
+
|
92
|
+
validate_data(input, data[input])
|
93
|
+
|
94
|
+
props[:value] = data[input]
|
95
|
+
props[:dynamic] = false
|
96
|
+
end
|
97
|
+
|
98
|
+
validate_requirements
|
99
|
+
end
|
100
|
+
|
101
|
+
# Checks if a input is dynamic
|
102
|
+
#
|
103
|
+
# Dynaic inputs are those where the data is sourced from
|
104
|
+
# a data source, an input that has a data source defined
|
105
|
+
# and had a specific input given will not be dynamic
|
106
|
+
#
|
107
|
+
# @return [Boolean]
|
108
|
+
def dynamic?(input)
|
109
|
+
@inputs[input][:dynamic]
|
110
|
+
end
|
111
|
+
|
112
|
+
def include?(input)
|
113
|
+
@inputs.include?(input)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Looks up data from a datastore, returns default when not found
|
117
|
+
#
|
118
|
+
# @param input [String] input name
|
119
|
+
# @return [Object] value from the ds
|
120
|
+
# @raise [StandardError] for invalid inputs and ds errors
|
121
|
+
def lookup_from_datastore(input)
|
122
|
+
raise("Unknown input %s" % input) unless include?(input)
|
123
|
+
|
124
|
+
properties = @inputs[input][:properties]
|
125
|
+
|
126
|
+
value = @playbook.data_stores.read(properties["data"])
|
127
|
+
validate_data(input, value)
|
128
|
+
|
129
|
+
value
|
130
|
+
rescue
|
131
|
+
raise("Could not resolve %s for input %s: %s: %s" % [properties["data"], input, $!.class, $!.to_s]) unless properties.include?("default")
|
132
|
+
|
133
|
+
Log.warn("Could not find %s, returning default value" % properties["data"])
|
134
|
+
|
135
|
+
properties["default"]
|
136
|
+
end
|
137
|
+
|
138
|
+
# Saves static property values in their associated data stores for any keys with save set
|
139
|
+
def save_input_data
|
140
|
+
@inputs.each do |input, props|
|
141
|
+
next unless props[:properties]["save"]
|
142
|
+
next unless props[:properties]["data"]
|
143
|
+
next unless props[:value]
|
144
|
+
next if props[:dynamic]
|
145
|
+
|
146
|
+
save_to_datastore(input)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Saves the value of a input to the data entry associated with it
|
151
|
+
#
|
152
|
+
# @see #save_input_data
|
153
|
+
# @param input [String] input name
|
154
|
+
# @raise [StandardError] for invalid inputs and ds errors
|
155
|
+
def save_to_datastore(input)
|
156
|
+
raise("Unknown input %s" % input) unless include?(input)
|
157
|
+
|
158
|
+
i_data = @inputs[input]
|
159
|
+
|
160
|
+
raise("Input %s has no value, cannot store it" % input) unless i_data.include?(:value)
|
161
|
+
|
162
|
+
Log.debug("Saving value for input %s to data item %s" % [input, i_data[:properties]["data"]])
|
163
|
+
|
164
|
+
@playbook.data_stores.write(i_data[:properties]["data"], i_data[:value])
|
165
|
+
end
|
166
|
+
|
167
|
+
# Retrieves the value for a specific input
|
168
|
+
#
|
169
|
+
# @param input [String] input name
|
170
|
+
# @return [Object]
|
171
|
+
# @raise [StandardError] for unknown inputs
|
172
|
+
def [](input)
|
173
|
+
raise("Unknown input %s" % input) unless include?(input)
|
174
|
+
|
175
|
+
props = @inputs[input][:properties]
|
176
|
+
|
177
|
+
if @inputs[input].include?(:value)
|
178
|
+
Log.debug("Resolving %s as static" % [input])
|
179
|
+
@inputs[input][:value]
|
180
|
+
elsif props.include?("data")
|
181
|
+
Log.debug("Resolving %s as dynamic" % [input])
|
182
|
+
lookup_from_datastore(input)
|
183
|
+
elsif props.include?("default")
|
184
|
+
Log.debug("Resolving %s as default" % [input])
|
185
|
+
props["default"]
|
186
|
+
else
|
187
|
+
raise("Input %s has no value, data source or default" % [input])
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Retrieves the properties for a specific input
|
192
|
+
#
|
193
|
+
# @param input [String] input name
|
194
|
+
# @return [Hash]
|
195
|
+
# @raise [StandardError] for unknown inputs
|
196
|
+
def input_properties(input)
|
197
|
+
if include?(input)
|
198
|
+
@inputs[input][:properties]
|
199
|
+
else
|
200
|
+
raise("Unknown input %s" % input)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Checks all required inputs have values
|
205
|
+
#
|
206
|
+
# @raise [StandardError] when not
|
207
|
+
def validate_requirements
|
208
|
+
invalid = @inputs.map do |input, props|
|
209
|
+
next unless props[:properties]["required"]
|
210
|
+
next if props[:properties].include?("data")
|
211
|
+
|
212
|
+
unless props[:value]
|
213
|
+
Log.warn("Input %s requires a value but has none or nil" % input)
|
214
|
+
input
|
215
|
+
end
|
216
|
+
end.compact
|
217
|
+
|
218
|
+
raise("Values were required but not given for inputs: %s" % invalid.join(", ")) unless invalid.empty?
|
219
|
+
end
|
220
|
+
|
221
|
+
# Validates a piece of data against an input
|
222
|
+
#
|
223
|
+
# @todo this seems quite limited, we have to expand with real needs
|
224
|
+
# @param input [String] a valid input name
|
225
|
+
# @param value [Object] a value to validate
|
226
|
+
# @raise [StandardError] on validation failure
|
227
|
+
def validate_data(input, value)
|
228
|
+
return unless @inputs[input][:properties].include?("validation")
|
229
|
+
|
230
|
+
validator = @inputs[input][:properties]["validation"]
|
231
|
+
|
232
|
+
case validator
|
233
|
+
when /^:(.+)/
|
234
|
+
validator = $1.intern
|
235
|
+
when /^\/(.+)\/$/
|
236
|
+
validator = Regexp.new($1)
|
237
|
+
end
|
238
|
+
|
239
|
+
Log.debug("Validating input %s using %s validator" % [input, validator])
|
240
|
+
|
241
|
+
Validator.validate(value, validator)
|
242
|
+
rescue
|
243
|
+
Log.warn("Attempt to validate input %s with validator %s failed: %s" % [input, validator, $!.to_s]) if validator
|
244
|
+
|
245
|
+
raise("Failed to validate value for input %s: %s" % [input, $!.to_s])
|
246
|
+
end
|
247
|
+
|
248
|
+
def from_hash(data)
|
249
|
+
data.each do |input, props|
|
250
|
+
props["required"] = true unless props.include?("required")
|
251
|
+
|
252
|
+
Log.debug("Loading input %s" % [input])
|
253
|
+
|
254
|
+
@inputs[input] = {
|
255
|
+
:properties => props,
|
256
|
+
:dynamic => props.include?("data")
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
self
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|