ncedit 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -5
- data/doc/example/batch.json +9 -6
- data/doc/example/batch.yaml +7 -5
- data/exe/ncedit +54 -43
- data/lib/ncedit/cmd.rb +184 -69
- data/lib/ncedit/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af182264e160a6970386cf7c82f89d633562e83b
|
4
|
+
data.tar.gz: de7185420068f8de02cc2eb5eb1aafe57f52d939
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8f5623802fd951fc3da86d6613ded5c934af43fdd6fdf01697abe2a5f237d65092ebf4e0520edc7aeb5e6fe12439a16357332c564cea2547205d5db2058b8fb
|
7
|
+
data.tar.gz: 1a7e2ca2245765be503c10572da54a7b59e0d5e1b17857637cbda2df93aee58bc33b40d19cfe88560b5fdac681cba1d84f5a7b7cb66f057c8a29bf26bd719471
|
data/README.md
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
[![Build Status](https://travis-ci.org/GeoffWilliams/ncedit.svg?branch=master)](https://travis-ci.org/GeoffWilliams/ncedit)
|
2
2
|
# ncedit - Puppet Node Classifier CLI editor
|
3
3
|
|
4
|
-
ncedit is a small utility program that lets you edit the Puppet Enterprise Node Classifier rules from the
|
4
|
+
ncedit is a small utility program that lets you edit the Puppet Enterprise Node Classifier rules from the command line.
|
5
5
|
|
6
|
-
Why would you want to do this given that we have the excellent [node_manager]
|
6
|
+
Why would you want to do this given that we have the excellent [node_manager](https://forge.puppet.com/WhatsARanjit/node_manager) module already on the forge? Well... lots of reasons. First off, using puppet code to drive the Node Classifier means that you have to have the `node_manager` module alread installed, which means that you must already have your [classification rules](https://docs.puppet.com/pe/latest/console_classes_groups_getting_started.html) in to reference the module through [Code Manager](https://docs.puppet.com/pe/latest/code_mgr.html). You could in-theory use Puppet Enterprise's new idempotent installer (just reinstall puppet over the top of itself) to fix this exact issue but then you still have the problem of how to classify your master in order to activate any other new rules (eg node-ttl) you want to use, which are associated with a new [role](https://docs.puppet.com/pe/latest/r_n_p_intro.html) for the Puppet Master.
|
7
7
|
|
8
8
|
That's where this tool comes in since all you need is root shell on the Puppet Master and a YAML or JSON file with the changes you want to make...
|
9
9
|
|
10
10
|
## Features
|
11
|
+
You can:
|
11
12
|
* Create node groups
|
12
13
|
* Add or remove classes
|
13
14
|
* Add or remove class parameters
|
14
15
|
* Add or remove rules
|
15
16
|
|
16
|
-
All from the convenience of the CLI. This also allows this tool to be called from scripts and other systems in order to setup Puppet Enterprise the way you want and with the minimum of effort.
|
17
|
+
...All from the convenience of the CLI. This also allows this tool to be called from scripts and other systems in order to setup Puppet Enterprise the way you want and with the minimum of effort.
|
17
18
|
|
18
19
|
For the moment, the edits to be carried out need to be placed into either a JSON or YAML file for bulk processing. If there is interest, the tool will be enhanced to allow the above operations to be specified individually on the command line so to avoid the need to write YAML/JSON.
|
19
20
|
|
@@ -28,7 +29,7 @@ This will install the gem into the Puppet Master's vendored ruby. You could ins
|
|
28
29
|
## Usage
|
29
30
|
|
30
31
|
### Node Classifier API access
|
31
|
-
ncedit is intended to be run on the Puppet Master as root. Doing so avoids having to deal with networks, firewalls, whitelists and the Puppet Enterprise RBAC API. While it would be cool to expand the tool to deal with these issues, its just a whole lot simpler to just run from the Puppet Master so right now that's all thats supported.
|
32
|
+
ncedit is intended to be run on the Puppet Master as root. Doing so avoids having to deal with networks, firewalls, certificate whitelists and the Puppet Enterprise RBAC API. While it would be cool to expand the tool to deal with these issues, its just a whole lot simpler to just run from the Puppet Master so right now that's all thats supported.
|
32
33
|
|
33
34
|
### Making batch changes
|
34
35
|
To avoid the need to repeatedly invoke this tool using say, a bash script, ncedit natively supports reading a file of batch changes to make that is written in either YAML or JSON.
|
@@ -109,14 +110,65 @@ ncedit batch --json-file /path/to/batch.json
|
|
109
110
|
```
|
110
111
|
|
111
112
|
## Making per-item changes
|
112
|
-
|
113
|
+
If you don't want to go to the hassle of creating a batch file or you have small, dynamic edits you wish to perform, your able to perform individual edits on the command line:
|
114
|
+
|
115
|
+
### Add a class to group
|
116
|
+
```shell
|
117
|
+
ncedit --group-name FOO --class-name BAR
|
118
|
+
```
|
119
|
+
* Group will be created if it doesn't exist
|
120
|
+
* Class MUST exist AND puppet must be aware of it (defeat caching) for the request to be accepted
|
121
|
+
|
122
|
+
### Add a parameter to a class for a group
|
123
|
+
```shell
|
124
|
+
ncedit --group-name FOO --class-name BAR --param-name BAZ --param-value BAS
|
125
|
+
```
|
126
|
+
* Group will be created if it doesn't exist
|
127
|
+
* Class will be added if it isn't already
|
128
|
+
* Class MUST exist AND puppet must be aware of it (defeat caching) AND the parameter must exist on the class for the request to be accepted
|
129
|
+
|
130
|
+
### Delete a parameter from a class inside a group
|
131
|
+
```shell
|
132
|
+
ncedit --group-name FOO --class-name BAR --param-name BAZ --delete-param
|
133
|
+
```
|
134
|
+
* Group will be created if it doesn't exist
|
135
|
+
* Class will be added if it isn't already
|
136
|
+
* Ensures the parameter `BAZ` is not set
|
137
|
+
|
138
|
+
### Delete a class inside a group
|
139
|
+
```shell
|
140
|
+
ncedit --group-name FOO --class-name BAR --delete-class
|
141
|
+
```
|
142
|
+
* Group will be created if it doesn't exist
|
143
|
+
* Ensures the class `BAR` is not defined
|
144
|
+
|
145
|
+
### Replace all rules for group
|
146
|
+
```shell
|
147
|
+
ncedit --group-name FOO --rule 'JSON_FRAGMENT' --rule-mode replace
|
148
|
+
```
|
149
|
+
* Group will be created if it doesn't exist
|
150
|
+
* Completely replaces existing rules for this group
|
151
|
+
* Example JSON_FRAGMENT: `["and",["=",["fact","ipaddress"],"192.168.1.1"]]`
|
152
|
+
|
153
|
+
### Append a rule to group
|
154
|
+
```shell
|
155
|
+
ncedit --group-name FOO --rule 'JSON_FRAGMENT' --rule-mode append
|
156
|
+
```
|
157
|
+
* Group will be created if it doesn't exist
|
158
|
+
* Appends supplied JSON_FRAGMENT to the group's rules
|
159
|
+
* Example JSON_FRAGMENT: `["and",["=",["fact","osfamily"],"RedHat"]]`
|
160
|
+
* Notice in our example JSON_FRAGMENT that we have *kept* the outer `and` rule. If we supply a conjuctive different to the rule's current value we will change it for the whole rule
|
113
161
|
|
114
162
|
## Troubleshooting
|
163
|
+
* If you cannot install the `ncedit` gem and you are behind a corporate proxy, ensure that you have correctly set your `http_proxy` and `https_proxy` variables on the shell before running `gem install`.
|
164
|
+
* Some corporate proxies will attempt to eavesdrop on all SSL connections which will cause downloads to fail. This can be resolved by installing a CA bundle (be sure you understand the implications of doing so) or domain whitelisting on the proxy itself
|
115
165
|
* If the ncedit fails, it will swallow stack traces by default, pass the `--verbosity debug` argument if you need to obtain one. Note the position of the argument before the command name:
|
116
166
|
```
|
117
167
|
bundle exec ncedit --verbosity debug batch --yaml-file /path/to/batch.yaml
|
118
168
|
```
|
119
169
|
* Ensure you are running as `root` to avoid permission errors
|
170
|
+
* If your shell can't find `ncedit` after successful installation and you installed into Puppet Enterprise's vendored ruby, make sure that your `PATH` contains `/opt/puppetlabs/puppet/bin` or run ncedit directly: `/opt/puppetlabs/puppet/bin/ncedit`
|
171
|
+
* Don't attempt to debug the NC API through the PE console by capturing traffic, it uses a completely different API all of its own (In particular, there is another layer of boolean logic around rules). Instead, use [NCIO](https://github.com/jeffmccune/ncio) to dump the current state of the NC API or see [Puppet's NC API documentation](https://docs.puppet.com/pe/latest/nc_index.html)
|
120
172
|
|
121
173
|
## Testing
|
122
174
|
To run tests:
|
data/doc/example/batch.json
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
"classes": {
|
4
4
|
"puppet_enterprise::profile::master": {
|
5
5
|
"code_manager_auto_configure": true,
|
6
|
-
|
7
6
|
"r10k_remote": "https://github.com/GeoffWilliams/r10k-control",
|
8
7
|
"r10k_private_key": "/etc/puppetlabs/puppetserver/ssh/id-control_repo.rsa"
|
9
8
|
}
|
@@ -12,22 +11,26 @@
|
|
12
11
|
"puppet_enterprise::profile::masterbad"
|
13
12
|
],
|
14
13
|
"delete_params": {
|
15
|
-
"puppet_enterprise::profile::
|
16
|
-
"
|
14
|
+
"puppet_enterprise::profile::mcollective::agent": [
|
15
|
+
"stomp_user"
|
17
16
|
]
|
18
17
|
}
|
19
18
|
},
|
20
19
|
"Puppet Masters": {
|
21
20
|
"classes": {
|
22
|
-
"
|
21
|
+
"pe_r10k": {
|
22
|
+
"proxy": "proxy.megacorp.com:8080"
|
23
23
|
}
|
24
24
|
},
|
25
25
|
"append_rules": [
|
26
26
|
"or",
|
27
27
|
[
|
28
28
|
"=",
|
29
|
-
|
30
|
-
|
29
|
+
[
|
30
|
+
"fact",
|
31
|
+
"ipaddress"
|
32
|
+
],
|
33
|
+
"192.168.0.252"
|
31
34
|
]
|
32
35
|
]
|
33
36
|
}
|
data/doc/example/batch.yaml
CHANGED
@@ -14,14 +14,16 @@
|
|
14
14
|
- "puppet_enterprise::profile::masterbad"
|
15
15
|
|
16
16
|
"delete_params":
|
17
|
-
"puppet_enterprise::profile::
|
18
|
-
- "
|
17
|
+
"puppet_enterprise::profile::mcollective::agent":
|
18
|
+
- "stomp_user"
|
19
19
|
|
20
20
|
"Puppet Masters":
|
21
21
|
"classes":
|
22
|
-
"
|
22
|
+
"pe_r10k":
|
23
|
+
"proxy": "proxy.megacorp.com:8080"
|
23
24
|
"append_rules":
|
24
25
|
- "or"
|
25
26
|
- - "="
|
26
|
-
- "
|
27
|
-
|
27
|
+
- - "fact"
|
28
|
+
- "ipaddress"
|
29
|
+
- "192.168.0.252"
|
data/exe/ncedit
CHANGED
@@ -11,49 +11,60 @@ Escort::App.create do |app|
|
|
11
11
|
app.summary "ncedit"
|
12
12
|
app.description "Edit PE node classification groups"
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
14
|
+
app.command :classes do |command|
|
15
|
+
command.summary "Edit classes"
|
16
|
+
command.description "Create/edit/delete class in rule"
|
17
|
+
command.options do |opts|
|
18
|
+
opts.opt(:group_name,
|
19
|
+
'NC group name',
|
20
|
+
:long => '--group-name',
|
21
|
+
:type => :string,
|
22
|
+
)
|
23
|
+
opts.opt(:class_name,
|
24
|
+
'NC class name',
|
25
|
+
:long => '--class-name',
|
26
|
+
:type => :string,
|
27
|
+
)
|
28
|
+
opts.opt(:param_name,
|
29
|
+
'NC parameter name',
|
30
|
+
:long => '--param-name',
|
31
|
+
:type => :string,
|
32
|
+
)
|
33
|
+
opts.opt(:param_value,
|
34
|
+
'NC parameter value',
|
35
|
+
:long => '--param-value',
|
36
|
+
:type => :string,
|
37
|
+
)
|
38
|
+
opts.opt(:delete_class,
|
39
|
+
'Delete this class',
|
40
|
+
:long => '--delete-class',
|
41
|
+
:type => :boolean,
|
42
|
+
:default => false,
|
43
|
+
)
|
44
|
+
opts.opt(:delete_param,
|
45
|
+
'Delete this param',
|
46
|
+
:long => '--delete-param',
|
47
|
+
:type => :boolean,
|
48
|
+
:default => false,
|
49
|
+
)
|
50
|
+
opts.opt(:rule,
|
51
|
+
'Update the NC group with this rule (JSON fragment)',
|
52
|
+
:long => '--rule',
|
53
|
+
:type => :string,
|
54
|
+
)
|
55
|
+
opts.dependency :param_value, :on => :param_name
|
56
|
+
|
57
|
+
opts.opt(:rule_mode,
|
58
|
+
"Processing instruction for rule supplied with --rule (allowed: 'replace', 'append')",
|
59
|
+
:long => '--rule-mode',
|
60
|
+
:type => :string,
|
61
|
+
)
|
62
|
+
|
63
|
+
end
|
64
|
+
command.action do |options, arguments|
|
65
|
+
NCEdit::Cmd::classes(options[:global][:commands][:classes][:options])
|
66
|
+
end
|
67
|
+
end
|
57
68
|
|
58
69
|
app.command :batch do |command|
|
59
70
|
command.summary "Batch processing from YAML/JSON"
|
data/lib/ncedit/cmd.rb
CHANGED
@@ -99,6 +99,33 @@ module NCEdit
|
|
99
99
|
group
|
100
100
|
end
|
101
101
|
|
102
|
+
# to see if our changes were saved or not we need to remove all nillified
|
103
|
+
# keys from both levels (class, parameter) of the class_delta array, since
|
104
|
+
# when we re-read from the NC our nillified data will be completely gone. A
|
105
|
+
# naive comparison would then report a failure even though the operation
|
106
|
+
# succeeded. On a practical level we must convert:
|
107
|
+
# {"puppet_enterprise"=>{"proxy"=>nil, "keep"=>"keep"}, "b"=>nil}
|
108
|
+
# ...to...
|
109
|
+
# {"puppet_enterprise"=>{"keep"=>"keep"}}
|
110
|
+
#
|
111
|
+
# @param nc_class The class hash as re-read from the NC API
|
112
|
+
# @param class_delta The class delta we originally requested (with nils for deletes)
|
113
|
+
def self.delta_saved?(nc_class, class_delta)
|
114
|
+
class_delta_reformatted = class_delta.map { |class_name, params|
|
115
|
+
if params == nil
|
116
|
+
# skip classes that are requested to be deleted for the moment since
|
117
|
+
# we will catch them on the outer pass
|
118
|
+
params_fixed = params
|
119
|
+
else
|
120
|
+
# remove all individual nullified parameters
|
121
|
+
params_fixed = params.reject{|param_name, param_value| param_value == nil}
|
122
|
+
end
|
123
|
+
[class_name,params_fixed]
|
124
|
+
}.to_h.reject { |class_name,params| params == nil}
|
125
|
+
|
126
|
+
nc_class == class_delta_reformatted
|
127
|
+
end
|
128
|
+
|
102
129
|
def self.update_group(group_name, classes: nil, rule: nil)
|
103
130
|
# group_delta will actually replace all classes/rules with whatever is
|
104
131
|
# specified, so we need to merge this with any existing definition if
|
@@ -126,11 +153,11 @@ module NCEdit
|
|
126
153
|
# now present. If there was an error, then the user should have
|
127
154
|
# previously seen some output since puppetclassify prints some useful
|
128
155
|
# debug output
|
129
|
-
|
130
|
-
if
|
156
|
+
re_read_group = nc_group(group_name)
|
157
|
+
if delta_saved?(re_read_group["classes"], classes) and re_read_group["rule"] == rule
|
131
158
|
Escort::Logger.output.puts "changes saved"
|
132
159
|
else
|
133
|
-
Escort::Logger.error.error "re-read #{group_name} results in #{
|
160
|
+
Escort::Logger.error.error "re-read #{group_name} results in #{re_read_group} should have delta of #{group_delta}"
|
134
161
|
raise "Error saving #{group_name}"
|
135
162
|
end
|
136
163
|
end
|
@@ -190,55 +217,73 @@ module NCEdit
|
|
190
217
|
data.each { |group_name, data|
|
191
218
|
|
192
219
|
Escort::Logger.output.puts "Processing #{group_name}"
|
220
|
+
group = nc_group(group_name)
|
193
221
|
|
222
|
+
#
|
223
|
+
# delete classes
|
224
|
+
#
|
194
225
|
if data.has_key?("delete_classes")
|
195
|
-
|
196
|
-
|
226
|
+
changes = false
|
227
|
+
|
228
|
+
data["delete_classes"].each { |class_name|
|
229
|
+
changes |= ensure_class(group, class_name, delete:true)
|
230
|
+
}
|
231
|
+
if changes
|
232
|
+
update_group(group_name, classes: group["classes"])
|
197
233
|
end
|
198
234
|
end
|
199
235
|
|
236
|
+
#
|
237
|
+
# delete params
|
238
|
+
#
|
200
239
|
if data.has_key?("delete_params")
|
201
|
-
|
202
|
-
|
240
|
+
changes = false
|
241
|
+
data["delete_params"].each { |class_name, delete_params|
|
242
|
+
delete_params.each { | param_name|
|
243
|
+
changes |= ensure_class(group, class_name)
|
244
|
+
changes |= ensure_param(group, class_name, param_name, nil, delete:true)
|
245
|
+
}
|
246
|
+
}
|
247
|
+
if changes
|
248
|
+
update_group(group_name, classes: group["classes"])
|
203
249
|
end
|
204
250
|
end
|
205
251
|
|
252
|
+
#
|
253
|
+
# classes (and optionally params)
|
254
|
+
#
|
206
255
|
if data.has_key?("classes")
|
207
|
-
if ensure_classes_and_params(
|
208
|
-
update_group(group_name, classes:
|
256
|
+
if ensure_classes_and_params(group, data["classes"])
|
257
|
+
update_group(group_name, classes: group["classes"])
|
209
258
|
end
|
210
259
|
end
|
211
260
|
|
261
|
+
#
|
262
|
+
# append rules
|
263
|
+
#
|
212
264
|
if data.has_key?("append_rules")
|
213
|
-
if ensure_rules(
|
214
|
-
update_group(group_name, rule:
|
265
|
+
if ensure_rules(group, data["append_rules"])
|
266
|
+
update_group(group_name, rule: group["rule"])
|
215
267
|
end
|
216
268
|
end
|
217
269
|
}
|
218
270
|
end
|
219
271
|
|
220
|
-
def self.delete_class(group, class_name)
|
221
|
-
if group["classes"].delete(class_name)
|
222
|
-
changes = true
|
223
|
-
else
|
224
|
-
changes = false
|
225
|
-
end
|
226
272
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
273
|
+
# Classes are only removed when they have their parameters nilled so we must
|
274
|
+
# formulate special json to allow delete
|
275
|
+
# @see https://docs.puppet.com/pe/latest/nc_groups.html#post-v1groupsid
|
276
|
+
#
|
277
|
+
# Updates `group` to ensure that it now contains `class_name` (or marks it
|
278
|
+
# for deletion). To commit changes, need to pass the updated
|
279
|
+
# `group['class']` hash to `update_group`
|
280
|
+
def self.ensure_class(group, class_name, delete:false)
|
281
|
+
if group["classes"].has_key?(class_name) and delete
|
282
|
+
# delete class by nilling its parameters
|
283
|
+
group["classes"][class_name] = nil
|
233
284
|
changes = true
|
234
|
-
|
235
|
-
|
236
|
-
end
|
237
|
-
changes
|
238
|
-
end
|
239
|
-
|
240
|
-
def self.ensure_class(group, class_name)
|
241
|
-
if ! group["classes"].has_key?(class_name)
|
285
|
+
elsif ! group["classes"].has_key?(class_name) and ! delete
|
286
|
+
# create class because we are not deleting it and it doesn't exist yet
|
242
287
|
group["classes"][class_name] = {}
|
243
288
|
changes = true
|
244
289
|
else
|
@@ -248,12 +293,21 @@ module NCEdit
|
|
248
293
|
changes
|
249
294
|
end
|
250
295
|
|
251
|
-
|
296
|
+
# Updates `group` to ensure that it now contains `param_name` set to
|
297
|
+
# `param_value` (or marks the parameter it for deletion). To commit changes
|
298
|
+
# , need to pass the updated `group['class']` hash to `update_group`
|
299
|
+
def self.ensure_param(group, class_name, param_name, param_value, delete:false)
|
252
300
|
# ensure parameter set if specified
|
253
|
-
if !
|
254
|
-
|
301
|
+
if ! delete and (
|
302
|
+
! group["classes"][class_name].has_key?(param_name) or
|
303
|
+
group["classes"][class_name][param_name] != param_value
|
304
|
+
)
|
305
|
+
# update or add a new parameter
|
255
306
|
group["classes"][class_name][param_name] = param_value
|
256
307
|
changes = true
|
308
|
+
elsif delete and group["classes"][class_name].has_key?(param_name)
|
309
|
+
group["classes"][class_name][param_name] = nil
|
310
|
+
changes = true
|
257
311
|
else
|
258
312
|
changes = false
|
259
313
|
end
|
@@ -261,40 +315,19 @@ module NCEdit
|
|
261
315
|
changes
|
262
316
|
end
|
263
317
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
Escort::Logger.output.puts "Deleting class: #{group_name}->#{class_name}"
|
269
|
-
updated |= delete_class(nc_group(group_name), class_name)
|
270
|
-
}
|
271
|
-
end
|
272
|
-
updated
|
273
|
-
end
|
274
|
-
|
275
|
-
def self.delete_params(group_name, data)
|
276
|
-
updated = false
|
277
|
-
if data
|
278
|
-
data.each{ |class_name, param_names|
|
279
|
-
param_names.each { |param_name|
|
280
|
-
Escort::Logger.output.puts "Deleting param: #{group_name}->#{class_name}=>#{param_name}"
|
281
|
-
updated |= delete_param(nc_group(group_name), class_name, param_name)
|
282
|
-
}
|
283
|
-
}
|
284
|
-
end
|
285
|
-
updated
|
286
|
-
end
|
287
|
-
|
288
|
-
def self.ensure_classes_and_params(group_name, data)
|
318
|
+
# Updates `group` to ensure that it now contains classes and parameters as
|
319
|
+
# specified in the `data` paramater. To commit changes, need to pass the
|
320
|
+
# updated `group['class']` hash to `update_group`
|
321
|
+
def self.ensure_classes_and_params(group, data)
|
289
322
|
updated = false
|
290
323
|
if data
|
291
324
|
data.each{ |class_name, params|
|
292
|
-
Escort::Logger.output.puts "ensuring class: #{
|
293
|
-
updated |= ensure_class(
|
325
|
+
Escort::Logger.output.puts "ensuring class: #{group['name']}->#{class_name}"
|
326
|
+
updated |= ensure_class(group, class_name)
|
294
327
|
if params
|
295
328
|
params.each { |param_name, param_value|
|
296
|
-
Escort::Logger.output.puts "ensuring param: #{
|
297
|
-
updated |= ensure_param(
|
329
|
+
Escort::Logger.output.puts "ensuring param: #{group['name']}->#{class_name}->#{param_name}=#{param_value}"
|
330
|
+
updated |= ensure_param(group, class_name, param_name, param_value)
|
298
331
|
}
|
299
332
|
end
|
300
333
|
}
|
@@ -313,6 +346,8 @@ module NCEdit
|
|
313
346
|
#
|
314
347
|
# Only the rule to be added in should be passed as the rule parameter, eg:
|
315
348
|
# ["=", "name", "bob"]
|
349
|
+
#
|
350
|
+
# To commit changes, need to pass the updated `group['rule']` hash to `update_group`
|
316
351
|
def self.ensure_rule(group, rule)
|
317
352
|
updated = false
|
318
353
|
|
@@ -321,7 +356,7 @@ module NCEdit
|
|
321
356
|
|
322
357
|
# rules are nested like this, the "or" applies to the whole rule chain:
|
323
358
|
# "rule"=>["or", ["=", "name", "bob"], ["=", "name", "hello"]]
|
324
|
-
group["rule"]
|
359
|
+
group["rule"].drop(1).each {|system_rule|
|
325
360
|
if system_rule[0] == rule[0] and
|
326
361
|
system_rule[1] == rule[1] and
|
327
362
|
system_rule[2] == rule[2]
|
@@ -331,33 +366,43 @@ module NCEdit
|
|
331
366
|
}
|
332
367
|
if ! found
|
333
368
|
Escort::Logger.output.puts "Appending rule: #{rule}"
|
334
|
-
group["rule"]
|
369
|
+
group["rule"].push(rule)
|
335
370
|
updated = true
|
336
371
|
end
|
337
372
|
|
338
373
|
updated
|
339
374
|
end
|
340
375
|
|
376
|
+
# Modify `group` to ensure the passed in `rules` exist. To commit changes,
|
377
|
+
# need to pass the updated `group['rule']` hash to `update_group`
|
378
|
+
#
|
341
379
|
# rules need to arrive like this:
|
342
380
|
# ["or", ["=", "name", "pupper.megacorp.com"], ["=", "name", "pupper.megacorp.com"]]
|
343
381
|
# since the rule conjunction "or" can only be specified once per rule chain
|
344
382
|
# we will replace whatever already exists in the rule with what the user
|
345
383
|
# specified
|
346
|
-
def self.ensure_rules(
|
384
|
+
def self.ensure_rules(group, rules)
|
347
385
|
updated = false
|
348
|
-
|
386
|
+
|
349
387
|
if ! group["rule"] or group["rule"].empty?
|
350
388
|
# no rules yet - just add our new one
|
351
|
-
group["rule"] = [DEFAULT_RULE
|
389
|
+
group["rule"] = [DEFAULT_RULE]
|
352
390
|
end
|
353
391
|
updated |= ensure_rule_conjunction(group, rules[0])
|
354
|
-
rules
|
392
|
+
rules.drop(1).each { |rule|
|
355
393
|
updated |= ensure_rule(group, rule)
|
356
394
|
}
|
357
395
|
|
358
396
|
updated
|
359
397
|
end
|
360
398
|
|
399
|
+
# Ensure the correct boolean conjunction ('and'/'or' - 'not' is not allowed)
|
400
|
+
# is being used for a given rule chain. If user tried to append a rule with
|
401
|
+
# a different conjuction to the one currently in use we will change the
|
402
|
+
# conjuction used on the entire chain to match.
|
403
|
+
#
|
404
|
+
# Updates `group` in-place, To commit changes, need to pass the updated
|
405
|
+
# `group['rule']` hash to `update_group`
|
361
406
|
def self.ensure_rule_conjunction(group, op)
|
362
407
|
updated = false
|
363
408
|
if ["and", "or"].include?(op)
|
@@ -371,5 +416,75 @@ module NCEdit
|
|
371
416
|
|
372
417
|
updated
|
373
418
|
end
|
419
|
+
|
420
|
+
|
421
|
+
def self.classes(options)
|
422
|
+
group_name = options[:group_name]
|
423
|
+
class_name = options[:class_name]
|
424
|
+
param_name = options[:param_name]
|
425
|
+
param_value = options[:param_value]
|
426
|
+
delete_class = options[:delete_class]
|
427
|
+
delete_param = options[:delete_param]
|
428
|
+
rule = options[:rule]
|
429
|
+
rule_mode = options[:rule_mode]
|
430
|
+
|
431
|
+
rule_change = false
|
432
|
+
class_change = false
|
433
|
+
|
434
|
+
if group_name
|
435
|
+
group = nc_group(group_name)
|
436
|
+
else
|
437
|
+
raise "All operations require a valid group_name"
|
438
|
+
end
|
439
|
+
|
440
|
+
rule_modes = ['replace', 'append']
|
441
|
+
if rule and (! rule_modes.include?(rule_mode))
|
442
|
+
raise "Invalid rule mode '#{rule_mode}'. Allowed: #{rule_modes}"
|
443
|
+
end
|
444
|
+
|
445
|
+
if class_name and delete_class
|
446
|
+
# delete a class from a group
|
447
|
+
Escort::Logger.output.puts "Deleting class #{class_name} from #{group_name}"
|
448
|
+
class_change = ensure_class(group, class_name, delete:true)
|
449
|
+
elsif class_name and param_name and delete_param
|
450
|
+
# delete a parameter from a class
|
451
|
+
Escort::Logger.output.puts "Deleting parameter #{param_name} on #{class_name} from #{group_name}"
|
452
|
+
class_change = ensure_class(group, class_name)
|
453
|
+
class_change |= ensure_param(group, class_name, param_name, nil, delete:true)
|
454
|
+
elsif class_name and param_name and param_value
|
455
|
+
# set a value inside a class
|
456
|
+
Escort::Logger.output.puts "Setting parameter #{param_name} to #{param_value} on #{class_name} in #{group_name}"
|
457
|
+
class_change = ensure_class(group, class_name)
|
458
|
+
class_change |= ensure_param(group, class_name, param_name, param_value)
|
459
|
+
elsif class_name
|
460
|
+
Escort::Logger.output.puts "Adding #{class_name} to #{group_name}"
|
461
|
+
class_change = ensure_class(group, class_name)
|
462
|
+
end
|
463
|
+
|
464
|
+
# process any rule changes separately since they are valid for all actions
|
465
|
+
if rule
|
466
|
+
begin
|
467
|
+
rule_json = JSON.parse(rule)
|
468
|
+
rescue JSON::ParserError
|
469
|
+
raise "Syntax error in data supplied to --rule (must be valid JSON)"
|
470
|
+
end
|
471
|
+
|
472
|
+
if rule_mode == 'replace'
|
473
|
+
if group['rule'] != rule_json
|
474
|
+
group['rule'] = rule_json
|
475
|
+
rule_change = true
|
476
|
+
end
|
477
|
+
else
|
478
|
+
rule_change = ensure_rules(group, rule_json)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
# save changes
|
483
|
+
if class_change or rule_change
|
484
|
+
update_group(group_name, classes: group["classes"], rule: group["rule"])
|
485
|
+
else
|
486
|
+
Escort::Logger.output.puts "Already up-to-date"
|
487
|
+
end
|
488
|
+
end
|
374
489
|
end
|
375
490
|
end
|
data/lib/ncedit/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ncedit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geoff Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|