animal 0.1.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -0
- data/.travis.yml +10 -2
- data/README.md +51 -5
- data/animal.gemspec +2 -0
- data/exe/animal_enc +13 -0
- data/exe/animal_import +32 -0
- data/lib/animal.rb +17 -5
- data/lib/animal/classifier.rb +35 -0
- data/lib/animal/enc.rb +23 -0
- data/lib/animal/inventory_plugin.rb +9 -0
- data/lib/animal/plugins/inventory/fact.rb +25 -0
- data/lib/animal/plugins/storage/yaml.rb +19 -0
- data/lib/animal/rule.rb +99 -0
- data/lib/animal/rules.treetop +147 -0
- data/lib/animal/storage_plugin.rb +14 -0
- data/lib/animal/version.rb +1 -1
- metadata +31 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1140c1f29b1f085aa857b0d482ca652b35d7a163
|
4
|
+
data.tar.gz: 6db2af85595e560a055383d53f7d155298b40aea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f840514c53598913fe773fbd50db710ae76f5b0b481ae3da7b4f732fbec98d79040202c4b20f6c87cd853530c40d16bc7ceb0ee7ad83d98e1d1b580247fd0af4
|
7
|
+
data.tar.gz: fb70b089488a2081366c169ff5678e6c36d068c693db6efd9384d7e1944f73f762c0ce36040bd19b90db0032409408fb93b01b06cf3a4041f36c649402ddd4cb
|
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
|
5
|
-
|
4
|
+
- 2.2.5
|
5
|
+
- 2.3.1
|
6
6
|
before_install: gem install bundler -v 1.12.5
|
7
|
+
deploy:
|
8
|
+
provider: rubygems
|
9
|
+
api_key:
|
10
|
+
secure: Bvix9+hJrZhd9GTYZQ7yN+htm+iWpBigVdVybAu6NHx1+YwJbelCQ68hN1gpFI/bSTdUlaQup9M1SW2Nb4fzwGB2byya9bIgjrez6vDuZ6SbwrXnTVZ/w1lpDG2ZaPRDVYet7+Xn1WTEwDm/ANeL7Gi5CDB87w6vu/vBfoWcKU4jLZcAgVtZ1TlfBnM1rKKC896/Dt4wVh1PLDuKfx8XuLNFR4VCLjIM1S3vKD9vl/8VzuxJcZLCgRbNs5CmidQNPe3zEkTO9hvg1/p9UY6OardNeEPbkKNDNITJ5gggX6chZtni+1qYIWmeUHuo80PwrB/J1gODDkl4kmNtRdpf6UGbi/hJbXM7vDWr5VQzKmVVbHoNYaLWmnWCcmtRD0zk0BTEfemwFzqANKXpRFvQRvfwhLjwpg/agaKUwVzWoLHo3QBEbrMSsamY2uQcIlHxMgofrPVfDD+puLFOANKJB/M2Vrr6cVdGziavizYHPhRxXxr1/23oiOLk0B61PzfOZLKdk1v2/uPF44WkGSiqvvNJIJjw80EhNIFNGhDxlyZsM2z+1+CrW5FkaVlPS9mnVS6H21xHKLVWYwGLpAdG80YasVmGGpDXxEdHPpsn2qmFqSJWOPSPqsbb4FYKDnrCqYIYwESg6hNI7XDN65Bet3g/ve61D0K9EKeKAfdaNo4=
|
11
|
+
gem: animal
|
12
|
+
on:
|
13
|
+
tags: true
|
14
|
+
repo: knuedge/animal
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Animal
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Animal is a work-in-progress toward developing a flexible, modular, and powerful rule-based [Puppet](https://puppet.com/) [ENC](https://docs.puppet.com/guides/external_nodes.html) written in Ruby.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -22,7 +20,55 @@ Or install it yourself as:
|
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
|
-
|
23
|
+
### Rules
|
24
|
+
|
25
|
+
#### Rule Statement Syntax
|
26
|
+
|
27
|
+
Animal uses a rules-based approach to classifying nodes, and its rules engine supports a simple yet powerful syntax for building conditions based on installed plugins. It utilizes a delayed merging approach for building a list of Puppet classes to apply to a node, meaning that _subtracting_ a class from a list of classes happens _after_ all the _add_ operations are complete, allowing a _subtract_ to be performed at any point in the rules system. The benefit is that rules need not be evaluated in any particular order.
|
28
|
+
|
29
|
+
The actual syntax should be familiar enough for people used to writing either SQL or Puppet code. Here is an example of a simple rule statement:
|
30
|
+
|
31
|
+
```
|
32
|
+
Fact["certname"] = "machine.domain.tld"
|
33
|
+
```
|
34
|
+
|
35
|
+
This rule will use the `Fact` plugin (which is built-in to the core `Animal` library) to lookup the `certname` key and determines if it is equivalent to `"machine.domain.tld"`.
|
36
|
+
|
37
|
+
A slightly more complicated rule might look like:
|
38
|
+
|
39
|
+
```
|
40
|
+
(Fact["machine_class"] = "server" AND Fact["os"] = "ubuntu") OR Fact["awesome"] = true
|
41
|
+
```
|
42
|
+
|
43
|
+
This rule will again use the `Fact` plugin (several times, in fact) to first check if both the `machine_class` fact is set to `"server"` _and_ the `os` fact is set to `"ubuntu"`, and only if either of those are `false`, the rule determines if the `awesome` fact is set to the literal `true` value.
|
44
|
+
|
45
|
+
There are currently several limitations to the rules syntax, such as:
|
46
|
+
|
47
|
+
* Parenthesis are required to force the order of operations for cojunctions (`AND` and `OR`), but is not used to determing which is actually applied first. Parenthesis are, in fact, collapsed before any preceeding conjunction is used, but in `A OR (B AND C)`, if `A` is `true` then `(B AND C)` is never evaluated.
|
48
|
+
* Rules are recursively evaluated with an arity of 2, meaning they are always evaluated as `A then B` where `B` is one or more subrules. This means that `A AND B OR C` is equivalent to `A AND (B OR C)`.
|
49
|
+
* Keys sent to plugins, such as `foo` in `Fact["foo"]`, must be double-quoted and can not contain `[`, `]`, or `"`.
|
50
|
+
* Only these comparison operators are allowed for rules: `=`, `!=`, `>`, `>=`, `<`, `<=`, and `LIKE`. The `LIKE` comparison operator treats the provided value as a regular expression. Do not include the `/` before or after the regular expression.
|
51
|
+
* Values used in comparisons must be either literal booleans (`true` or `false`), a double-quoted string (`"foo"`), or an Integer (`1`, `2`, etc.). Decimals must currently be treated as strings.
|
52
|
+
|
53
|
+
#### Other Rule Components
|
54
|
+
|
55
|
+
Besides the rule statement described above, rules also support two additional components, each with two subcomponents. When a rule evaluates to `true`, it is said to be applied successfully, so rules have a `success` component. Otherwise, rules provide a `failure` component for determining what to do when the rule evaluates to `false`. Both of these components are considered optional by the rules engine, though a rule that does nothing should be suspect.
|
56
|
+
|
57
|
+
Each of these components support adding and subtracting Puppet classes from the final compiled list of classes returned by the ENC. These addition and subtraction operations are gathered then applied after all such operations are determined -- providing the delayed-merging capability of the tool. To add classes based on the outcome of a rule, define an Array of class names (usually roles or profiles) to return in an `add` section, either under `success` or `failure`. Likewise, define a `subtract` Array as needed.
|
58
|
+
|
59
|
+
When using the YAML storage provider (currently the only supported storage provider for Animal), this could be an example rule:
|
60
|
+
|
61
|
+
```
|
62
|
+
- :statement: (Fact["machine_class"] = "server" AND Fact["os"] = "ubuntu") OR Fact["awesome"] = true
|
63
|
+
:success:
|
64
|
+
:add:
|
65
|
+
- roles::linux::server
|
66
|
+
- roles::awesome
|
67
|
+
:subtract:
|
68
|
+
- roles::linux::desktop
|
69
|
+
```
|
70
|
+
|
71
|
+
This rule will add `roles::linux::server` and `roles::awesome`, and will guarantee that `roles::linux::desktop` will not be present in the returned list of Puppet classes if the rule evaluates to `true` for a given Puppet node.
|
26
72
|
|
27
73
|
## Development
|
28
74
|
|
@@ -32,7 +78,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
78
|
|
33
79
|
## Contributing
|
34
80
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
81
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/knuedge/animal.
|
36
82
|
|
37
83
|
|
38
84
|
## License
|
data/animal.gemspec
CHANGED
@@ -26,6 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.required_ruby_version = '~> 2.2'
|
27
27
|
spec.post_install_message = 'Thanks for installing Animal!'
|
28
28
|
|
29
|
+
spec.add_runtime_dependency 'treetop', '~> 1.6'
|
30
|
+
|
29
31
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
30
32
|
spec.add_development_dependency 'rake', '~> 10.0'
|
31
33
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
data/exe/animal_enc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'animal'
|
4
|
+
|
5
|
+
node_name = ARGV[0]
|
6
|
+
|
7
|
+
# Must pass a node name
|
8
|
+
raise 'Missing Node Name' unless node_name
|
9
|
+
|
10
|
+
results = Animal::ENC.query(node_name, debug: true)
|
11
|
+
exit unless results # no output on empty results
|
12
|
+
|
13
|
+
puts results
|
data/exe/animal_import
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
path_to_nodes_pp = ARGV[0]
|
6
|
+
|
7
|
+
file_content = File.read(File.expand_path(path_to_nodes_pp))
|
8
|
+
|
9
|
+
nodes = {}
|
10
|
+
|
11
|
+
file_content.scan(/(^|\n)node ([^\s]+) ?\{([^}]+)\n(\s+)?\}/).each do |node|
|
12
|
+
name = node[1]
|
13
|
+
includes = node[2].delete("\n").split(/\s+include\s+/).select { |x| !x.empty? }.compact
|
14
|
+
nodes[name] = includes
|
15
|
+
end
|
16
|
+
|
17
|
+
# nodes.each { |k, v| puts "#{k} => [#{v.join(', ')}]" }
|
18
|
+
|
19
|
+
rules = []
|
20
|
+
nodes.each do |name, roles_and_profiles|
|
21
|
+
rule = {}
|
22
|
+
if name =~ %r{^/.+/$}
|
23
|
+
rule[:statement] = "Fact[\"certname\"] LIKE \"#{name}\""
|
24
|
+
else
|
25
|
+
rule[:statement] = "Fact[\"certname\"] = \"#{name.gsub(/(^['"]|['"]$)/, '')}\""
|
26
|
+
end
|
27
|
+
|
28
|
+
rule[:success] = { add: roles_and_profiles }
|
29
|
+
rules << rule
|
30
|
+
end
|
31
|
+
|
32
|
+
puts rules.to_yaml
|
data/lib/animal.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
|
-
|
1
|
+
ANIMAL_HOME = ENV['ANIMAL_HOME'] ? ENV['ANIMAL_HOME'] : File.expand_path(File.join('~', '.animal'))
|
2
|
+
FileUtils.mkdir_p(ANIMAL_HOME) unless File.exist?(ANIMAL_HOME)
|
3
|
+
|
4
|
+
# Standard Library requirements
|
5
|
+
require 'yaml'
|
2
6
|
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
+
# External requirements
|
8
|
+
require 'treetop'
|
9
|
+
|
10
|
+
# Internal requirements
|
11
|
+
require 'animal/version'
|
12
|
+
require 'animal/classifier'
|
13
|
+
require 'animal/inventory_plugin'
|
14
|
+
require 'animal/storage_plugin'
|
15
|
+
require 'animal/plugins/inventory/fact'
|
16
|
+
require 'animal/plugins/storage/yaml'
|
17
|
+
require 'animal/rule'
|
18
|
+
require 'animal/enc'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Animal
|
2
|
+
# The class responsible for actually classifying a node
|
3
|
+
# The Classifier pulls together required plugins and config
|
4
|
+
class Classifier
|
5
|
+
def initialize(node_name)
|
6
|
+
@node_name = node_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def classes
|
10
|
+
classify('classes')
|
11
|
+
end
|
12
|
+
|
13
|
+
def parameters
|
14
|
+
classify('parameters')
|
15
|
+
end
|
16
|
+
|
17
|
+
def environment
|
18
|
+
classify('environment')
|
19
|
+
end
|
20
|
+
|
21
|
+
def classify(type)
|
22
|
+
case type
|
23
|
+
when 'environment'
|
24
|
+
# TODO: look this up in a configuration somewhere
|
25
|
+
'production'
|
26
|
+
when 'classes'
|
27
|
+
Rule.apply_all_for(@node_name)
|
28
|
+
when 'parameters'
|
29
|
+
nil
|
30
|
+
else
|
31
|
+
raise 'Not Implemented'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/animal/enc.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Animal
|
2
|
+
# As Animal is an ENC, this is the main class and entry point for Animal.
|
3
|
+
class ENC
|
4
|
+
def self.query(node_name, _opts = {})
|
5
|
+
classifier = Classifier.new(node_name)
|
6
|
+
classes = classifier.classes
|
7
|
+
parameters = classifier.parameters
|
8
|
+
environment = classifier.environment
|
9
|
+
results = {}
|
10
|
+
|
11
|
+
results['classes'] = classes if classes
|
12
|
+
results['parameters'] = parameters if parameters
|
13
|
+
results['environment'] = environment ? environment : 'production'
|
14
|
+
|
15
|
+
to_enc_output results
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.to_enc_output(data = {})
|
19
|
+
return nil if data.empty? || (!data.key?('classes') && !data.key?('parameters'))
|
20
|
+
data.to_yaml
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Animal
|
2
|
+
module Plugins
|
3
|
+
module Inventory
|
4
|
+
# The Facter integration inventory plugin mock-up
|
5
|
+
class Fact < InventoryPlugin
|
6
|
+
def self.get(node, key)
|
7
|
+
data = {
|
8
|
+
'dschaaff' => {
|
9
|
+
'certname' => 'dschaaff.local',
|
10
|
+
'machine_class' => 'server',
|
11
|
+
'os' => 'ubuntu'
|
12
|
+
},
|
13
|
+
'jgnagy' => {
|
14
|
+
'certname' => 'jgnagy.local',
|
15
|
+
'machine_class' => 'server',
|
16
|
+
'os' => 'darwin',
|
17
|
+
'awesome' => true
|
18
|
+
}
|
19
|
+
}
|
20
|
+
data.key?(node) && data[node].key?(key) ? data[node][key] : nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Animal
|
2
|
+
module Plugins
|
3
|
+
module Storage
|
4
|
+
# The basic, YAML storage plugin
|
5
|
+
class Yaml < StoragePlugin
|
6
|
+
def self.all(type)
|
7
|
+
# TODO: add caching in here...
|
8
|
+
results = []
|
9
|
+
Dir.chdir File.expand_path(File.join(ANIMAL_HOME, "#{type}.d")) do
|
10
|
+
Dir.glob('*.yml').each do |file|
|
11
|
+
results.concat ::YAML.load_file(file)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
results
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/animal/rule.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# The Animal namespace module
|
2
|
+
module Animal
|
3
|
+
## Treetop Rules Parsing
|
4
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
5
|
+
Treetop.load File.expand_path(File.join(dir, 'rules'))
|
6
|
+
|
7
|
+
# The basis for the rules engine used for classifying nodes
|
8
|
+
class Rule
|
9
|
+
attr_reader :when_true, :when_false
|
10
|
+
|
11
|
+
def self.all
|
12
|
+
rules = []
|
13
|
+
Animal::Plugins::Storage::Yaml.all('rules').each do |data|
|
14
|
+
rules << if data.key?(:failure)
|
15
|
+
Rule.new(data[:statement], data[:success], data[:failure])
|
16
|
+
else
|
17
|
+
Rule.new(data[:statement], data[:success])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
rules
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.apply_all_for(node)
|
24
|
+
operations = { add: [], subtract: [] }
|
25
|
+
all.each do |rule|
|
26
|
+
result = rule.apply_for(node)
|
27
|
+
operations[:add].concat result[:add] if result.key?(:add)
|
28
|
+
operations[:subtract].concat result[:subtract] if result.key?(:subtract)
|
29
|
+
end
|
30
|
+
operations[:add].uniq - operations[:subtract]
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(statement, when_true, when_false = {})
|
34
|
+
@statement = statement
|
35
|
+
@when_true = when_true
|
36
|
+
@when_false = when_false
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse
|
40
|
+
parser = RulesParser.new
|
41
|
+
result = parser.parse(@statement)
|
42
|
+
result.conditions
|
43
|
+
end
|
44
|
+
|
45
|
+
# Used to evaluate the conditions provided by parsing a rule statement
|
46
|
+
# rubocop:disable Metrics/AbcSize
|
47
|
+
def evaluate(node, condition)
|
48
|
+
plugin = get_plugin_class(condition[:plugin]) if condition.key?(:plugin)
|
49
|
+
if [:and, :or].include?(condition[:conjunction])
|
50
|
+
recurse_on_conjunction(node, condition[:conditions], condition[:conjunction])
|
51
|
+
elsif condition[:operator] == :like
|
52
|
+
# Use the plugin to lookup a key and match it against the condition's value
|
53
|
+
plugin.get(node, condition[:key]).match(sanitize_regexp(condition[:value])) ? true : false
|
54
|
+
elsif condition[:operator] == '='.to_sym
|
55
|
+
plugin.get(node, condition[:key]) == condition[:value]
|
56
|
+
elsif ['!=', '>=', '<=', '>', '<'].include?(condition[:operator].to_s)
|
57
|
+
plugin.get(node, condition[:key]).send(condition[:operator], condition[:value])
|
58
|
+
else
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def recurse_on_conjunction(node, conditions, conjunction)
|
64
|
+
subresult = nil
|
65
|
+
if conjunction == :and
|
66
|
+
conditions.each do |subcondition|
|
67
|
+
subresult = evaluate(node, subcondition)
|
68
|
+
break if subresult.is_a? FalseClass
|
69
|
+
end
|
70
|
+
elsif conjunction == :or
|
71
|
+
subresult = nil
|
72
|
+
conditions.each do |subcondition|
|
73
|
+
subresult = evaluate(node, subcondition)
|
74
|
+
break if subresult.is_a? TrueClass
|
75
|
+
end
|
76
|
+
end
|
77
|
+
subresult ? true : false
|
78
|
+
end
|
79
|
+
|
80
|
+
def sanitize_regexp(value)
|
81
|
+
value.gsub(%r{(^/|/$)}, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
def apply_for(node)
|
85
|
+
evaluate(node, parse) ? @when_true : @when_false
|
86
|
+
rescue => e
|
87
|
+
# TODO: output something for debugging here since evaluate failed to run
|
88
|
+
STDERR.puts "Exception occurred on Rule#apply_for(#{node}) for `#{@statement}`: #{e.message}"
|
89
|
+
{}
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Constantize the plugin based on the class name
|
95
|
+
def get_plugin_class(name)
|
96
|
+
Class.const_get("Animal::Plugins::Inventory::#{name}")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Animal
|
2
|
+
grammar Rules
|
3
|
+
rule parenthesized_conditionals
|
4
|
+
parenthesized_conditional required_space boolean_join required_space parenthesized_conditionals {
|
5
|
+
def conditions
|
6
|
+
all_nodes = {}
|
7
|
+
all_nodes[:conditions] = []
|
8
|
+
all_nodes[:conjunction] = boolean_join.conjunction
|
9
|
+
all_nodes[:conditions] << parenthesized_conditional.conditions
|
10
|
+
all_nodes[:conditions] << parenthesized_conditionals.conditions
|
11
|
+
all_nodes
|
12
|
+
end
|
13
|
+
}
|
14
|
+
/ '(' parenthesized_conditionals ')' {
|
15
|
+
def conditions
|
16
|
+
parenthesized_conditionals.conditions
|
17
|
+
end
|
18
|
+
}
|
19
|
+
/ parenthesized_conditional
|
20
|
+
end
|
21
|
+
|
22
|
+
rule parenthesized_conditional
|
23
|
+
'(' parenthesized_conditional ')' {
|
24
|
+
def conditions
|
25
|
+
parenthesized_conditional.conditions
|
26
|
+
end
|
27
|
+
}
|
28
|
+
/ conditional_items
|
29
|
+
end
|
30
|
+
|
31
|
+
rule conditional_items
|
32
|
+
conditional_item required_space boolean_join required_space conditional_items {
|
33
|
+
def conditions
|
34
|
+
all_nodes = {}
|
35
|
+
all_nodes[:conditions] = []
|
36
|
+
all_nodes[:conjunction] = boolean_join.conjunction
|
37
|
+
all_nodes[:conditions] << conditional_item.conditions
|
38
|
+
all_nodes[:conditions] << conditional_items.conditions
|
39
|
+
all_nodes
|
40
|
+
end
|
41
|
+
}
|
42
|
+
/
|
43
|
+
conditional_item
|
44
|
+
end
|
45
|
+
|
46
|
+
rule boolean_join
|
47
|
+
( and_keyword / or_keyword ) {
|
48
|
+
def conjunction
|
49
|
+
text_value.downcase.to_sym
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
rule conditional_item
|
55
|
+
plugin_class quoted_text close_bracket space conditional_operator space compared_value {
|
56
|
+
def conditions
|
57
|
+
{
|
58
|
+
:operator => conditional_operator.value,
|
59
|
+
:plugin => plugin_class.name,
|
60
|
+
:key => quoted_text.content,
|
61
|
+
:value => compared_value.content
|
62
|
+
}
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
rule plugin_class
|
68
|
+
([A-Z] [a-zA-Z0-9]+) open_bracket {
|
69
|
+
def name
|
70
|
+
elements[0].text_value
|
71
|
+
end
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
rule compared_value
|
76
|
+
(number / boolean / quoted_text)
|
77
|
+
end
|
78
|
+
|
79
|
+
rule open_bracket
|
80
|
+
'['
|
81
|
+
end
|
82
|
+
|
83
|
+
rule close_bracket
|
84
|
+
']'
|
85
|
+
end
|
86
|
+
|
87
|
+
rule required_space
|
88
|
+
[\s]+
|
89
|
+
end
|
90
|
+
|
91
|
+
rule space
|
92
|
+
[\s]*
|
93
|
+
end
|
94
|
+
|
95
|
+
rule quoted_text
|
96
|
+
'"' text '"' {
|
97
|
+
def content
|
98
|
+
elements[1].content
|
99
|
+
end
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
rule conditional_operator
|
104
|
+
('!=' / '>=' / '<=' / '=' / '>' / '<' / like_keyword) {
|
105
|
+
def value
|
106
|
+
text_value.downcase.to_sym
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
rule like_keyword
|
112
|
+
[lL] [iI] [kK] [eE]
|
113
|
+
end
|
114
|
+
|
115
|
+
rule and_keyword
|
116
|
+
[aA] [nN] [dD]
|
117
|
+
end
|
118
|
+
|
119
|
+
rule or_keyword
|
120
|
+
[oO] [rR]
|
121
|
+
end
|
122
|
+
|
123
|
+
rule number
|
124
|
+
('-'? [1-9] [0-9]* / '0') {
|
125
|
+
def content
|
126
|
+
text_value.to_i
|
127
|
+
end
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
rule boolean
|
132
|
+
('true' / 'false') {
|
133
|
+
def content
|
134
|
+
text_value == 'true'
|
135
|
+
end
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
rule text
|
140
|
+
[^"]* {
|
141
|
+
def content
|
142
|
+
text_value
|
143
|
+
end
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/lib/animal/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: animal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Schaaff
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-01-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: treetop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.6'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.6'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: bundler
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,12 +126,15 @@ dependencies:
|
|
112
126
|
description: Animal Puppet External Node Classifier
|
113
127
|
email:
|
114
128
|
- jgnagy@knuedge.com
|
115
|
-
executables:
|
129
|
+
executables:
|
130
|
+
- animal_enc
|
131
|
+
- animal_import
|
116
132
|
extensions: []
|
117
133
|
extra_rdoc_files: []
|
118
134
|
files:
|
119
135
|
- ".gitignore"
|
120
136
|
- ".rspec"
|
137
|
+
- ".rubocop.yml"
|
121
138
|
- ".travis.yml"
|
122
139
|
- CONTRIBUTING.md
|
123
140
|
- Gemfile
|
@@ -127,7 +144,17 @@ files:
|
|
127
144
|
- animal.gemspec
|
128
145
|
- bin/console
|
129
146
|
- bin/setup
|
147
|
+
- exe/animal_enc
|
148
|
+
- exe/animal_import
|
130
149
|
- lib/animal.rb
|
150
|
+
- lib/animal/classifier.rb
|
151
|
+
- lib/animal/enc.rb
|
152
|
+
- lib/animal/inventory_plugin.rb
|
153
|
+
- lib/animal/plugins/inventory/fact.rb
|
154
|
+
- lib/animal/plugins/storage/yaml.rb
|
155
|
+
- lib/animal/rule.rb
|
156
|
+
- lib/animal/rules.treetop
|
157
|
+
- lib/animal/storage_plugin.rb
|
131
158
|
- lib/animal/version.rb
|
132
159
|
homepage: https://github.com/knuedge/animal
|
133
160
|
licenses:
|
@@ -150,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
177
|
version: '0'
|
151
178
|
requirements: []
|
152
179
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.4.8
|
154
181
|
signing_key:
|
155
182
|
specification_version: 4
|
156
183
|
summary: Animal Puppet ENC
|