ncedit 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 326ad90c579b6ab122bc1aca4e92f2ba9409f556
4
- data.tar.gz: 58fb80c7453318166436e8fac0d84a3d57b52c56
2
+ SHA256:
3
+ metadata.gz: e96cfedf083f77d881e84689e8126fcb2eacd5e965a1c78a8bfbbb3957468ccd
4
+ data.tar.gz: b2f81404318ea89f27d49bf7f2275c570aacb89816857ad76802479ba93e1fad
5
5
  SHA512:
6
- metadata.gz: a3053204bc285ae301a4848391e7bf52d46baf3feb4c40c8beac48998710df92888927e4b1fe4072affc4415823b28874bb9cdac81f8631765de60a44567a9ef
7
- data.tar.gz: 0d0c2c813e97aad9b2d41a1bf3ae8c9cce8b34ac310c3b8f3ab0b1e98b2ac4a1f8148ac45f8394e21e46e6fdbac4c85d0f17beb24accb7ddd25db3792dd388cb
6
+ metadata.gz: 47c9753e923f1c6410093a8cc55506b6344bc8c13b0ce89d6a1f295fdfd4b3a2b3d0f0ac82b9cce6566c754300954a9dd58c2b599c0b97237e470be5d4e144f1
7
+ data.tar.gz: a8d646edffb771c405fccc8726769612f66126868e07c05cafb852df35d14f6b6ebfca44f9ff02cbc255cea59d49503b6e7c7081537c1e6a50cd775d2f45156d
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  *.gem
13
+ /.idea
@@ -1,6 +1,6 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.3
5
- before_install: gem install bundler -v 1.12.5
4
+ - 2.6.6
5
+ before_install: gem install bundler -v 2.1.4
6
6
 
@@ -0,0 +1,3 @@
1
+ build:
2
+ bundle exec rake spec
3
+ gem build ncedit.gemspec
data/README.md CHANGED
@@ -1,21 +1,23 @@
1
- [![Build Status](https://travis-ci.org/GeoffWilliams/ncedit.svg?branch=master)](https://travis-ci.org/GeoffWilliams/ncedit)
1
+ [![Build Status](https://travis-ci.org/declarativesystems/ncedit.svg?branch=master)](https://travis-ci.org/declarativesystems/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 commandline.
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] (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.
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 already 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
- 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...
8
+ That's where this tool comes in since all you need is root shell on the Puppet Master.
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
16
+ * Add or edit environment groups
15
17
 
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.
18
+ ...All from the convenience of the CLI. This allows us 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
19
 
18
- 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.
20
+ You have a choice of running `ncedit` for each change you wish to make or collecting all of your edits into either a JSON or YAML file for bulk processing.
19
21
 
20
22
  ## Installation
21
23
  Install this tool on your Puppet Master (Master-of-Masters)
@@ -28,7 +30,7 @@ This will install the gem into the Puppet Master's vendored ruby. You could ins
28
30
  ## Usage
29
31
 
30
32
  ### 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.
33
+ 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
34
 
33
35
  ### Making batch changes
34
36
  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.
@@ -48,7 +50,7 @@ In each case the file needs to be ordered as follows:
48
50
  "OPTIONAL_PARAM_NAME": "VALUE_TO_SET"
49
51
  # Array of classes to delete
50
52
  "delete_classes":
51
- - "CLASS_TO_DELETE"
53
+ - "CLASS_TO_DELETE"
52
54
  # Hash classes + Array of parameter names to delete
53
55
  "delete_params":
54
56
  "CLASS_TO_PROCESS":
@@ -96,27 +98,159 @@ In each case the file needs to be ordered as follows:
96
98
  * [Worked example](doc/example/batch.json)
97
99
 
98
100
  #### Ensuring changes
99
- * ncedit is idempotent so you may run the command as often as you like
101
+ * `ncedit` is idempotent so you may run the command as often as you like
102
+ * Classes used in rules *must* already exist for classification to succeed, `--smart-update` will do a code redeploy for you if specified.
100
103
 
101
104
  ##### YAML
102
105
  ```shell
103
- ncedit  batch --yaml-file /path/to/batch.yaml
106
+ ncedit batch --smart-update --yaml-file /path/to/batch.yaml
104
107
  ```
105
108
 
106
109
  ##### JSON
107
110
  ```shell
108
- ncedit batch --json-file /path/to/batch.json
111
+ ncedit batch --smart-update --json-file /path/to/batch.json
109
112
  ```
110
113
 
111
114
  ## Making per-item changes
112
- * coming? (soon?) -- anyone want this?
115
+ 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:
116
+
117
+
118
+ ### Practical examples
119
+ One of the main uses of this tool is to configure Puppet Code Manager, so here are the exact commands you need (alternatively make a `batch.yaml` file to do it all in one hit):
120
+
121
+ #### Code Manager R10K checkout URL
122
+ ```shell
123
+ ncedit classes --smart-update --group-name 'PE Master' \
124
+ --class-name puppet_enterprise::profile::master \
125
+ --param-name r10k_remote \
126
+ --param-value https://github.com/puppetlabs/control-repo
127
+ ```
128
+
129
+ #### Code Manager SSH key
130
+ ```shell
131
+ ncedit classes --smart-update --group-name 'PE Master' \
132
+ --class-name puppet_enterprise::profile::master \
133
+ --param-name r10k_ \
134
+ --param-value /etc/puppetlabs/puppetserver/ssh/id_rsa
135
+ ```
136
+
137
+ #### Code Manager proxy server
138
+ ```shell
139
+ ncedit classes --smart-update --group-name 'PE Master' \
140
+ --class-name puppet_enterprise::profile::master \
141
+ --param-name r10k_proxy \
142
+ --param-value http://proxy.megacorp.com:3128
143
+ ```
144
+
145
+
146
+ #### Enable Code Manager
147
+ ```shell
148
+ ncedit classes --smart-update --group-name 'PE Master' \
149
+ --class-name puppet_enterprise::profile::master \
150
+ --param-name code_manager_auto_configure \
151
+ --param-value true
152
+
153
+ ncedit classes --smart-update --group-name 'PE Master' \
154
+ --class-name puppet_enterprise::profile::master \
155
+ --param-name file_sync_enabled \
156
+ --param-value automatic
157
+ ```
158
+
159
+
160
+ #### Add a rule to configure the puppet master with extra classes
161
+ ```shell
162
+ ncedit classes --smart-update --group-name "Puppet Masters" \
163
+ --class-name role::my_puppet_master \
164
+ --rule '["and", ["=",["fact","fqdn"],"'$(facter fqdn)'"]]' \
165
+ --rule-mode replace
166
+ ```
167
+
168
+ * Run puppet and then re-deploy puppet code
169
+ * Create a new group called `Puppet Masters`
170
+ * Make it load the role `role::my_puppet_master`
171
+ * Have it match any host matching the FQDN of the host the command was run from and replace any existing rules for the group
172
+
173
+ #### Refresh the list of classes in the console
174
+ ```shell
175
+ ncedit update_classes
176
+ ```
177
+
178
+ ### Add a class to group
179
+ ```shell
180
+ ncedit classes --group-name FOO --class-name BAR
181
+ ```
182
+ * Group will be created if it doesn't exist
183
+ * Class MUST exist AND puppet must be aware of it (defeat caching) for the request to be accepted
184
+ * Pass `--smart-update` to run puppet and re-deploy classes if desired
185
+
186
+ ### Add a parameter to a class for a group
187
+ ```shell
188
+ ncedit classes --group-name FOO --class-name BAR --param-name BAZ --param-value BAS
189
+ ```
190
+ * Group will be created if it doesn't exist
191
+ * Class will be added if it isn't already
192
+ * 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
193
+ * Pass `--smart-update` to run puppet and re-deploy classes if desired
194
+
195
+ ### Delete a parameter from a class inside a group
196
+ ```shell
197
+ ncedit classes --group-name FOO --class-name BAR --param-name BAZ --delete-param
198
+ ```
199
+ * Group will be created if it doesn't exist
200
+ * Class will be added if it isn't already
201
+ * Ensures the parameter `BAZ` is not set
202
+
203
+ ### Delete a class inside a group
204
+ ```shell
205
+ ncedit classes --group-name FOO --class-name BAR --delete-class
206
+ ```
207
+ * Group will be created if it doesn't exist
208
+ * Ensures the class `BAR` is not defined
209
+
210
+ ### Replace all rules for group
211
+ ```shell
212
+ ncedit classes --group-name FOO --rule 'JSON_FRAGMENT' --rule-mode replace
213
+ ```
214
+ * Group will be created if it doesn't exist
215
+ * Completely replaces existing rules for this group
216
+ * Example JSON_FRAGMENT: `["and",["=",["fact","ipaddress"],"192.168.1.1"]]`
217
+
218
+ ### Append a rule to group
219
+ ```shell
220
+ ncedit classes --group-name FOO --rule 'JSON_FRAGMENT' --rule-mode append
221
+ ```
222
+ * Group will be created if it doesn't exist
223
+ * Appends supplied JSON_FRAGMENT to the group's rules
224
+ * Example JSON_FRAGMENT: `["and",["=",["fact","osfamily"],"RedHat"]]`
225
+ * 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
226
+
227
+ ### Add/edit an environment group (experimental)
228
+
229
+ ```shell
230
+ ncedit groups --group-name "Agent-specified environment" --environment agent-specified --environment-trumps --rule '["~",["fact","fqdn"],".*"]' --rule-mode replace
231
+ ```
232
+ * Group will be created if it doesn't exit
233
+ * Will be nested under `All Environments`
234
+
235
+ ## Smart updates
236
+ The NC API will only accept rules for classes that currently exist on the system, so its likely that your rules will be rejected if they have not yet been deployed to the master. To make this process as seamless as possible, the `--smart-update` option will perform this task for you as-and-when required. This assumes you have already setup RBAC to grant access to Code Manager, this can be done in a single command using the [pe_rbac gem](https://github.com/declarativesystems/pe_rbac#setting-up-code-manager-on-the-command-line)
237
+
238
+ Smart updates work as follows:
239
+
240
+ * If any of the `r10k_*` or `code_manager_auto_configure` parameters are set, update them immediately
241
+ * Run `puppet agent -t` then `puppet-code deploy --all --wait`
242
+ * Process any remaining directives
113
243
 
114
244
  ## Troubleshooting
245
+ * 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`.
246
+ * 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
247
  * 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
248
  ```
117
249
  bundle exec ncedit --verbosity debug  batch --yaml-file /path/to/batch.yaml
118
250
  ```
119
251
  * Ensure you are running as `root` to avoid permission errors
252
+ * 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`
253
+ * 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
254
 
121
255
  ## Testing
122
256
  To run tests:
@@ -128,4 +262,4 @@ bundle exec rake spec
128
262
 
129
263
  ## Contributing
130
264
 
131
- Bug reports and pull requests are welcome on GitHub at https://github.com/GeoffWilliams/ncedit.
265
+ Bug reports and pull requests are welcome on GitHub at https://github.com/declarativesystems/ncedit.
@@ -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::redo:": [
16
- "badparam"
14
+ "puppet_enterprise::profile::mcollective::agent": [
15
+ "stomp_user"
17
16
  ]
18
17
  }
19
18
  },
20
19
  "Puppet Masters": {
21
20
  "classes": {
22
- "r_role::puppet::master_minimal": {
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
- "name",
30
- "pupper.puppet.com"
29
+ [
30
+ "fact",
31
+ "ipaddress"
32
+ ],
33
+ "192.168.0.252"
31
34
  ]
32
35
  ]
33
36
  }
@@ -14,14 +14,16 @@
14
14
  - "puppet_enterprise::profile::masterbad"
15
15
 
16
16
  "delete_params":
17
- "puppet_enterprise::profile::redo:":
18
- - "badparam"
17
+ "puppet_enterprise::profile::mcollective::agent":
18
+ - "stomp_user"
19
19
 
20
20
  "Puppet Masters":
21
21
  "classes":
22
- "r_role::puppet::master_minimal": {}
22
+ "pe_r10k":
23
+ "proxy": "proxy.megacorp.com:8080"
23
24
  "append_rules":
24
25
  - "or"
25
26
  - - "="
26
- - "name"
27
- - "pupper.puppet.com"
27
+ - - "fact"
28
+ - "ipaddress"
29
+ - "192.168.0.252"
data/exe/ncedit CHANGED
@@ -6,54 +6,74 @@ require 'ncedit/cmd'
6
6
  # display help if nothing specified
7
7
  ARGV.push('-h') if ARGV.empty?
8
8
 
9
+ # Add the path to the puppet-code command as a fallback. It's last to
10
+ # allow user to override via the real PATH if necessary
11
+ ENV['PATH'] = "#{ENV['PATH']}:/opt/puppetlabs/puppet/bin/:/opt/puppetlabs/client-tools/bin/"
12
+
13
+
9
14
  Escort::App.create do |app|
10
15
  app.version NCEdit::VERSION
11
16
  app.summary "ncedit"
12
17
  app.description "Edit PE node classification groups"
13
18
 
14
- # not currently working...
15
- # app.command :classes do |command|
16
- # command.summary "Install all known nodes"
17
- # command.description "Install Puppet Enterprise master and agents on all known nodes"
18
- # command.options do |opts|
19
- # opts.opt(:group_name,
20
- # 'NC group name',
21
- # :long => '--group-name',
22
- # :type => :string,
23
- # )
24
- # opts.opt(:class_name,
25
- # 'NC class name',
26
- # :long => '--class-name',
27
- # :type => :string,
28
- # )
29
- # opts.opt(:param_name,
30
- # 'NC parameter name',
31
- # :long => '--param-name',
32
- # :type => :string,
33
- # )
34
- # opts.opt(:param_value,
35
- # 'NC parameter value',
36
- # :long => '--param-value',
37
- # :type => :string,
38
- # )
39
- # opts.opt(:delete_class,
40
- # 'delete this rule',
41
- # :long => '--delete-class',
42
- # :type => :boolean,
43
- # :default => false,
44
- # )
45
- # opts.opt(:delete_param,
46
- # 'delete this rule',
47
- # :long => '--delete-param',
48
- # :type => :boolean,
49
- # :default => false,
50
- # )
51
- # opts.dependency :param_value, :on => :param_name
52
- # end
53
- # command.action do |options, arguments|
54
- # NCEdit::Cmd::classes(options, arguments)
55
- # end
56
- # end
19
+ app.command :classes do |command|
20
+ command.summary "Edit classes"
21
+ command.description "Create/edit/delete class in rule"
22
+ command.options do |opts|
23
+ opts.opt(:group_name,
24
+ 'NC group name',
25
+ :long => '--group-name',
26
+ :type => :string,
27
+ )
28
+ opts.opt(:class_name,
29
+ 'NC class name',
30
+ :long => '--class-name',
31
+ :type => :string,
32
+ )
33
+ opts.opt(:param_name,
34
+ 'NC parameter name',
35
+ :long => '--param-name',
36
+ :type => :string,
37
+ )
38
+ opts.opt(:param_value,
39
+ 'NC parameter value',
40
+ :long => '--param-value',
41
+ :type => :string,
42
+ )
43
+ opts.opt(:delete_class,
44
+ 'Delete this class',
45
+ :long => '--delete-class',
46
+ :type => :boolean,
47
+ :default => false,
48
+ )
49
+ opts.opt(:delete_param,
50
+ 'Delete this param',
51
+ :long => '--delete-param',
52
+ :type => :boolean,
53
+ :default => false,
54
+ )
55
+ opts.opt(:rule,
56
+ 'Update the NC group with this rule (JSON fragment)',
57
+ :long => '--rule',
58
+ :type => :string,
59
+ )
60
+ opts.dependency :param_value, :on => :param_name
61
+
62
+ opts.opt(:rule_mode,
63
+ "Processing instruction for rule supplied with --rule (allowed: 'replace', 'append')",
64
+ :long => '--rule-mode',
65
+ :type => :string,
66
+ )
67
+ opts.opt(:smart_update,
68
+ 'Smart update',
69
+ :long => '--smart-update',
70
+ :type => :boolean,
71
+ )
72
+ end
73
+ command.action do |options, arguments|
74
+ NCEdit::Cmd::classes(options[:global][:commands][:classes][:options])
75
+ end
76
+ end
57
77
 
58
78
  app.command :batch do |command|
59
79
  command.summary "Batch processing from YAML/JSON"
@@ -69,12 +89,63 @@ Escort::App.create do |app|
69
89
  :long => '--json-file',
70
90
  :type => :string,
71
91
  )
92
+ opts.opt(:smart_update,
93
+ 'Smart update',
94
+ :long => '--smart-update',
95
+ :type => :boolean,
96
+ )
72
97
  end
73
98
  command.action do |options, arguments|
74
99
  yaml_file = options[:global][:commands][:batch][:options][:yaml_file]
75
100
  json_file = options[:global][:commands][:batch][:options][:json_file]
101
+ smart_update = options[:global][:commands][:batch][:options][:smart_update]
76
102
 
77
- NCEdit::Cmd::batch(yaml_file: yaml_file, json_file: json_file)
103
+ NCEdit::Cmd::batch(yaml_file: yaml_file, json_file: json_file, smart_update: smart_update)
104
+ end
105
+ end
106
+
107
+ app.command :groups do |command|
108
+ command.summary "Create/Edit groups"
109
+ command.description "Create or edit groups (and set environment)"
110
+ command.options do |opts|
111
+ opts.opt(:group_name,
112
+ 'NC group name',
113
+ :long => '--group-name',
114
+ :type => :string,
115
+ )
116
+ opts.opt(:environment,
117
+ 'Group should use this environment',
118
+ :long => '--environment',
119
+ :type => :string,
120
+ )
121
+ opts.opt(:environment_trumps,
122
+ 'Group environment overrides all others',
123
+ :long => '--environment-trumps',
124
+ :type => :boolean,
125
+ )
126
+ opts.opt(:rule,
127
+ 'Update the NC group with this rule (JSON fragment)',
128
+ :long => '--rule',
129
+ :type => :string,
130
+ )
131
+
132
+ opts.opt(:rule_mode,
133
+ "Processing instruction for rule supplied with --rule (allowed: 'replace', 'append')",
134
+ :long => '--rule-mode',
135
+ :type => :string,
136
+ )
137
+ end
138
+ command.action do |options, arguments|
139
+ NCEdit::Cmd::groups(options[:global][:commands][:groups][:options])
140
+ end
141
+ end
142
+
143
+
144
+ app.command :update_classes do |command|
145
+ command.summary "Refresh the classes available in the console"
146
+ command.description "Invalidate class cache and ask puppet to re-scan classes"
147
+ command.action do |options, arguments|
148
+ NCEdit::Cmd::update_classes()
78
149
  end
79
150
  end
80
151
  end
@@ -2,11 +2,21 @@ require 'puppetclassify'
2
2
  require 'yaml'
3
3
  require 'json'
4
4
  require 'escort'
5
+ require 'puppet_https'
5
6
 
6
7
  module NCEdit
7
8
  module Cmd
8
9
  DEFAULT_RULE = "or"
9
10
 
11
+ R10K_SETTINGS_CLASS = "puppet_enterprise::profile::master"
12
+ R10K_SETTINGS_PARAMS = [
13
+ "code_manager_auto_configure",
14
+ "r10k_remote",
15
+ "r10k_private_key",
16
+ "r10k_proxy",
17
+ "r10k_postrun",
18
+ ]
19
+
10
20
  def self.init(puppetclassify = nil)
11
21
  if puppetclassify
12
22
  # use passed in puppetclassify if present - allows injection for easy
@@ -16,9 +26,12 @@ module NCEdit
16
26
  hostname = %x(facter fqdn).strip.downcase
17
27
  port = 4433
18
28
 
29
+
19
30
  # Define the url to the classifier API - we can't just do localhost because
20
31
  # the name has to match the SSL certificate
21
- rest_api_url = "https://#{hostname}:#{port}/classifier-api"
32
+ base_url = "https://#{hostname}:"
33
+ @puppet_url = "#{base_url}8140"
34
+ @rest_api_url = "#{base_url}#{port}/classifier-api"
22
35
 
23
36
  # We need to authenticate against the REST API using a certificate
24
37
  # that is whitelisted in /etc/puppetlabs/console-services/rbac-certificate-whitelist.
@@ -54,12 +67,15 @@ module NCEdit
54
67
  end
55
68
  end
56
69
 
57
- @puppetclassify = PuppetClassify.new(rest_api_url, auth_info)
70
+ @puppetclassify = PuppetClassify.new(@rest_api_url, auth_info)
71
+
72
+ # borrow the cool HTTPS requester built into puppetclassify
73
+ @puppet_https = PuppetHttps.new(auth_info)
58
74
  end
59
75
  end
60
76
 
61
77
  # Fetch a group by ID, make the group if it doesn't already exist
62
- def self.nc_group_id(group_name)
78
+ def self.nc_group_id(group_name, parent_name: "All Nodes")
63
79
  if ! @puppetclassify
64
80
  init
65
81
  end
@@ -70,7 +86,7 @@ module NCEdit
70
86
  res = @puppetclassify.groups.create_group(
71
87
  {
72
88
  "name" => group_name,
73
- "parent" => @puppetclassify.groups.get_group_id("All Nodes"),
89
+ "parent" => @puppetclassify.groups.get_group_id(parent_name),
74
90
  "classes" => {},
75
91
  }
76
92
  )
@@ -85,21 +101,48 @@ module NCEdit
85
101
  group_id
86
102
  end
87
103
 
88
- def self.nc_group(group_name)
104
+ def self.nc_group(group_name, parent_name:nil)
89
105
  if ! @puppetclassify
90
106
  init
91
107
  end
92
108
  # Get the wanted group from the API
93
109
  # 1. Get the id of the wanted group
94
110
  # 2. Use the id to fetch the group
95
- group_id = nc_group_id(group_name)
111
+ group_id = nc_group_id(group_name, parent_name: parent_name)
96
112
  Escort::Logger.output.puts "Group #{group_name} found, getting definition"
97
113
  group = @puppetclassify.groups.get_group(group_id)
98
114
 
99
115
  group
100
116
  end
101
117
 
102
- def self.update_group(group_name, classes: nil, rule: nil)
118
+ # to see if our changes were saved or not we need to remove all nillified
119
+ # keys from both levels (class, parameter) of the class_delta array, since
120
+ # when we re-read from the NC our nillified data will be completely gone. A
121
+ # naive comparison would then report a failure even though the operation
122
+ # succeeded. On a practical level we must convert:
123
+ # {"puppet_enterprise"=>{"proxy"=>nil, "keep"=>"keep"}, "b"=>nil}
124
+ # ...to...
125
+ # {"puppet_enterprise"=>{"keep"=>"keep"}}
126
+ #
127
+ # @param nc_class The class hash as re-read from the NC API
128
+ # @param class_delta The class delta we originally requested (with nils for deletes)
129
+ def self.delta_saved?(nc_class, class_delta)
130
+ class_delta_reformatted = class_delta.map { |class_name, params|
131
+ if params == nil
132
+ # skip classes that are requested to be deleted for the moment since
133
+ # we will catch them on the outer pass
134
+ params_fixed = params
135
+ else
136
+ # remove all individual nullified parameters
137
+ params_fixed = params.reject{|param_name, param_value| param_value == nil}
138
+ end
139
+ [class_name,params_fixed]
140
+ }.to_h.reject { |class_name,params| params == nil}
141
+
142
+ nc_class == class_delta_reformatted
143
+ end
144
+
145
+ def self.update_group(group_name, classes: nil, rule: nil, environment: nil, environment_trumps: nil)
103
146
  # group_delta will actually replace all classes/rules with whatever is
104
147
  # specified, so we need to merge this with any existing definition if
105
148
  # one of these fields is not needed for a particular update otherwise
@@ -112,10 +155,20 @@ module NCEdit
112
155
  rule = nc_group(group_name)["rule"]
113
156
  end
114
157
 
158
+ if environment == nil
159
+ environment = nc_group(group_name)["environment"]
160
+ end
161
+
162
+ if ! environment_trumps
163
+ environment_trumps = nc_group(group_name)["environment_trumps"]
164
+ end
165
+
115
166
  group_delta = {
116
- 'id' => nc_group_id(group_name),
117
- 'rule' => rule,
118
- 'classes' => classes,
167
+ 'id' => nc_group_id(group_name),
168
+ 'rule' => rule,
169
+ 'classes' => classes,
170
+ 'environment' => environment,
171
+ 'environment_trumps' => environment_trumps,
119
172
  }
120
173
  res = @puppetclassify.groups.update_group(group_delta)
121
174
 
@@ -126,11 +179,14 @@ module NCEdit
126
179
  # now present. If there was an error, then the user should have
127
180
  # previously seen some output since puppetclassify prints some useful
128
181
  # debug output
129
- saved_group = nc_group(group_name)
130
- if saved_group["classes"] == classes and saved_group["rule"] == rule
182
+ re_read_group = nc_group(group_name)
183
+ if delta_saved?(re_read_group["classes"], classes) &&
184
+ re_read_group["rule"] == rule &&
185
+ re_read_group["environment"] == environment &&
186
+ re_read_group["environment_trumps"] == environment_trumps
131
187
  Escort::Logger.output.puts "changes saved"
132
188
  else
133
- Escort::Logger.error.error "re-read #{group_name} results in #{saved_group} should have delta of #{group_delta}"
189
+ Escort::Logger.error.error "re-read #{group_name} results in #{re_read_group} should have delta of #{group_delta}"
134
190
  raise "Error saving #{group_name}"
135
191
  end
136
192
  end
@@ -179,66 +235,96 @@ module NCEdit
179
235
  # 'badparam'
180
236
  #
181
237
  # 'Puppet Masters':
182
- # 'clases':
238
+ # 'classes':
183
239
  # 'role::puppet::master':
184
240
  # 'append_rules':
185
241
  # - - "="
186
242
  # - "name"
187
243
  # - "vmpump02.puppet.com"
188
- def self.batch(yaml_file: nil, json_file: nil)
244
+ def self.batch(yaml_file: nil, json_file: nil, smart_update: false)
189
245
  data = read_batch_data(yaml_file: yaml_file, json_file: json_file)
246
+
247
+ if smart_update
248
+ needs_reclassify = contains_r10k_settings(data)
249
+ if needs_reclassify
250
+ apply_r10k_settings_now(needs_reclassify)
251
+ end
252
+ puppet_code_deploy
253
+
254
+ Escort::Logger.output.puts "Sleep for 60 seconds to let classes finish their refresh..."
255
+ sleep(60)
256
+ end
257
+
190
258
  data.each { |group_name, data|
191
259
 
192
260
  Escort::Logger.output.puts "Processing #{group_name}"
261
+ group = nc_group(group_name)
193
262
 
263
+ #
264
+ # delete classes
265
+ #
194
266
  if data.has_key?("delete_classes")
195
- if delete_classes(group_name, data["delete_classes"])
196
- update_group(group_name, classes: data["delete_classes"])
267
+ changes = false
268
+
269
+ data["delete_classes"].each { |class_name|
270
+ changes |= ensure_class(group, class_name, delete:true)
271
+ }
272
+ if changes
273
+ update_group(group_name, classes: group["classes"])
197
274
  end
198
275
  end
199
276
 
277
+ #
278
+ # delete params
279
+ #
200
280
  if data.has_key?("delete_params")
201
- if delete_params(group_name, data["delete_params"])
202
- update_group(group_name, classes: data["delete_params"])
281
+ changes = false
282
+ data["delete_params"].each { |class_name, delete_params|
283
+ delete_params.each { | param_name|
284
+ changes |= ensure_class(group, class_name)
285
+ changes |= ensure_param(group, class_name, param_name, nil, delete:true)
286
+ }
287
+ }
288
+ if changes
289
+ update_group(group_name, classes: group["classes"])
203
290
  end
204
291
  end
205
292
 
293
+ #
294
+ # classes (and optionally params)
295
+ #
206
296
  if data.has_key?("classes")
207
- if ensure_classes_and_params(group_name, data["classes"])
208
- update_group(group_name, classes: data["classes"])
297
+ if ensure_classes_and_params(group, data["classes"])
298
+ update_group(group_name, classes: group["classes"])
209
299
  end
210
300
  end
211
301
 
302
+ #
303
+ # append rules
304
+ #
212
305
  if data.has_key?("append_rules")
213
- if ensure_rules(group_name, data["append_rules"])
214
- update_group(group_name, rule: data["append_rules"])
306
+ if ensure_rules(group, data["append_rules"])
307
+ update_group(group_name, rule: group["rule"])
215
308
  end
216
309
  end
217
310
  }
218
311
  end
219
312
 
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
-
227
- changes
228
- end
229
313
 
230
- def self.delete_param(group, class_name, param_name)
231
- if group["classes"].has_key?(class_name) and
232
- group["classes"][class_name].delete(param_name)
314
+ # Classes are only removed when they have their parameters nilled so we must
315
+ # formulate special json to allow delete
316
+ # @see https://docs.puppet.com/pe/latest/nc_groups.html#post-v1groupsid
317
+ #
318
+ # Updates `group` to ensure that it now contains `class_name` (or marks it
319
+ # for deletion). To commit changes, need to pass the updated
320
+ # `group['class']` hash to `update_group`
321
+ def self.ensure_class(group, class_name, delete:false)
322
+ if group["classes"].has_key?(class_name) and delete
323
+ # delete class by nilling its parameters
324
+ group["classes"][class_name] = nil
233
325
  changes = true
234
- else
235
- changes = false
236
- end
237
- changes
238
- end
239
-
240
- def self.ensure_class(group, class_name)
241
- if ! group["classes"].has_key?(class_name)
326
+ elsif ! group["classes"].has_key?(class_name) and ! delete
327
+ # create class because we are not deleting it and it doesn't exist yet
242
328
  group["classes"][class_name] = {}
243
329
  changes = true
244
330
  else
@@ -248,12 +334,21 @@ module NCEdit
248
334
  changes
249
335
  end
250
336
 
251
- def self.ensure_param(group, class_name, param_name, param_value)
337
+ # Updates `group` to ensure that it now contains `param_name` set to
338
+ # `param_value` (or marks the parameter it for deletion). To commit changes
339
+ # , need to pass the updated `group['class']` hash to `update_group`
340
+ def self.ensure_param(group, class_name, param_name, param_value, delete:false)
252
341
  # ensure parameter set if specified
253
- if ! group["classes"][class_name].has_key?(param_name) or
254
- group["classes"][class_name][param_name] != param_value
342
+ if ! delete and (
343
+ ! group["classes"][class_name].has_key?(param_name) or
344
+ group["classes"][class_name][param_name] != param_value
345
+ )
346
+ # update or add a new parameter
255
347
  group["classes"][class_name][param_name] = param_value
256
348
  changes = true
349
+ elsif delete and group["classes"][class_name].has_key?(param_name)
350
+ group["classes"][class_name][param_name] = nil
351
+ changes = true
257
352
  else
258
353
  changes = false
259
354
  end
@@ -261,40 +356,19 @@ module NCEdit
261
356
  changes
262
357
  end
263
358
 
264
- def self.delete_classes(group_name, data)
265
- updated = false
266
- if data
267
- data.each{ |class_name|
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)
359
+ # Updates `group` to ensure that it now contains classes and parameters as
360
+ # specified in the `data` paramater. To commit changes, need to pass the
361
+ # updated `group['class']` hash to `update_group`
362
+ def self.ensure_classes_and_params(group, data)
289
363
  updated = false
290
364
  if data
291
365
  data.each{ |class_name, params|
292
- Escort::Logger.output.puts "ensuring class: #{group_name}->#{class_name}"
293
- updated |= ensure_class(nc_group(group_name), class_name)
366
+ Escort::Logger.output.puts "ensuring class: #{group['name']}->#{class_name}"
367
+ updated |= ensure_class(group, class_name)
294
368
  if params
295
369
  params.each { |param_name, param_value|
296
- Escort::Logger.output.puts "ensuring param: #{group_name}->#{class_name}->#{param_name}=#{param_value}"
297
- updated |= ensure_param(nc_group(group_name), class_name, param_name, param_value)
370
+ Escort::Logger.output.puts "ensuring param: #{group['name']}->#{class_name}->#{param_name}=#{param_value}"
371
+ updated |= ensure_param(group, class_name, param_name, param_value)
298
372
  }
299
373
  end
300
374
  }
@@ -302,7 +376,7 @@ module NCEdit
302
376
  updated
303
377
  end
304
378
 
305
- # Ensure a partualar rule exists in the group["rule"] array
379
+ # Ensure a particular rule exists in the group["rule"] array
306
380
  # This affects only the items in the chain, eg:
307
381
  # [
308
382
  # "or",
@@ -313,6 +387,8 @@ module NCEdit
313
387
  #
314
388
  # Only the rule to be added in should be passed as the rule parameter, eg:
315
389
  # ["=", "name", "bob"]
390
+ #
391
+ # To commit changes, need to pass the updated `group['rule']` hash to `update_group`
316
392
  def self.ensure_rule(group, rule)
317
393
  updated = false
318
394
 
@@ -321,7 +397,7 @@ module NCEdit
321
397
 
322
398
  # rules are nested like this, the "or" applies to the whole rule chain:
323
399
  # "rule"=>["or", ["=", "name", "bob"], ["=", "name", "hello"]]
324
- group["rule"][1].each {|system_rule|
400
+ group["rule"].drop(1).each {|system_rule|
325
401
  if system_rule[0] == rule[0] and
326
402
  system_rule[1] == rule[1] and
327
403
  system_rule[2] == rule[2]
@@ -331,33 +407,43 @@ module NCEdit
331
407
  }
332
408
  if ! found
333
409
  Escort::Logger.output.puts "Appending rule: #{rule}"
334
- group["rule"][1] << rule
410
+ group["rule"].push(rule)
335
411
  updated = true
336
412
  end
337
413
 
338
414
  updated
339
415
  end
340
416
 
417
+ # Modify `group` to ensure the passed in `rules` exist. To commit changes,
418
+ # need to pass the updated `group['rule']` hash to `update_group`
419
+ #
341
420
  # rules need to arrive like this:
342
421
  # ["or", ["=", "name", "pupper.megacorp.com"], ["=", "name", "pupper.megacorp.com"]]
343
422
  # since the rule conjunction "or" can only be specified once per rule chain
344
423
  # we will replace whatever already exists in the rule with what the user
345
424
  # specified
346
- def self.ensure_rules(group_name, rules)
425
+ def self.ensure_rules(group, rules)
347
426
  updated = false
348
- group = nc_group(group_name)
427
+
349
428
  if ! group["rule"] or group["rule"].empty?
350
429
  # no rules yet - just add our new one
351
- group["rule"] = [DEFAULT_RULE,[]]
430
+ group["rule"] = [DEFAULT_RULE]
352
431
  end
353
432
  updated |= ensure_rule_conjunction(group, rules[0])
354
- rules[1].each { |rule|
433
+ rules.drop(1).each { |rule|
355
434
  updated |= ensure_rule(group, rule)
356
435
  }
357
436
 
358
437
  updated
359
438
  end
360
439
 
440
+ # Ensure the correct boolean conjunction ('and'/'or' - 'not' is not allowed)
441
+ # is being used for a given rule chain. If user tried to append a rule with
442
+ # a different conjuction to the one currently in use we will change the
443
+ # conjuction used on the entire chain to match.
444
+ #
445
+ # Updates `group` in-place, To commit changes, need to pass the updated
446
+ # `group['rule']` hash to `update_group`
361
447
  def self.ensure_rule_conjunction(group, op)
362
448
  updated = false
363
449
  if ["and", "or"].include?(op)
@@ -371,5 +457,194 @@ module NCEdit
371
457
 
372
458
  updated
373
459
  end
460
+
461
+ # process any rule changes separately since they are valid for all actions
462
+ # returns true if changes were made
463
+ def self.rule_change(group, rule, rule_mode)
464
+ rule_change = false
465
+
466
+ rule_modes = ['replace', 'append']
467
+ if rule and (! rule_modes.include?(rule_mode))
468
+ raise "Invalid rule mode '#{rule_mode}'. Allowed: #{rule_modes}"
469
+ end
470
+
471
+ if rule
472
+ begin
473
+ rule_json = JSON.parse(rule)
474
+ rescue JSON::ParserError
475
+ raise "Syntax error in data supplied to --rule (must be valid JSON)"
476
+ end
477
+
478
+ if rule_mode == 'replace'
479
+ if group['rule'] != rule_json
480
+ group['rule'] = rule_json
481
+ rule_change = true
482
+ end
483
+ else
484
+ rule_change = ensure_rules(group, rule_json)
485
+ end
486
+ end
487
+
488
+ rule_change
489
+ end
490
+
491
+ def self.classes(options)
492
+ group_name = options[:group_name]
493
+ class_name = options[:class_name]
494
+ param_name = options[:param_name]
495
+ param_value = options[:param_value]
496
+ delete_class = options[:delete_class]
497
+ delete_param = options[:delete_param]
498
+ rule = options[:rule]
499
+ rule_mode = options[:rule_mode]
500
+ smart_update = options[:smart_update]
501
+
502
+ rule_change = false
503
+ class_change = false
504
+
505
+ if group_name
506
+ group = nc_group(group_name)
507
+ else
508
+ raise "All operations require a valid group_name"
509
+ end
510
+
511
+ if class_name and delete_class
512
+ # delete a class from a group
513
+ Escort::Logger.output.puts "Deleting class #{class_name} from #{group_name}"
514
+ class_change = ensure_class(group, class_name, delete:true)
515
+ elsif class_name and param_name and delete_param
516
+ # delete a parameter from a class
517
+ Escort::Logger.output.puts "Deleting parameter #{param_name} on #{class_name} from #{group_name}"
518
+ class_change = ensure_class(group, class_name)
519
+ class_change |= ensure_param(group, class_name, param_name, nil, delete:true)
520
+ elsif class_name and param_name and param_value
521
+ # set a value inside a class
522
+ if smart_update
523
+ if ! is_r10k_param(class_name, param_name)
524
+
525
+ # not an R10K parameter, do an immediate update to make sure any classes
526
+ # we need are in-place
527
+ puppet_code_deploy
528
+ end
529
+ end
530
+ Escort::Logger.output.puts "Setting parameter #{param_name} to #{param_value} on #{class_name} in #{group_name}"
531
+ class_change = ensure_class(group, class_name)
532
+ class_change |= ensure_param(group, class_name, param_name, param_value)
533
+ elsif class_name
534
+ if smart_update
535
+ puppet_code_deploy
536
+ end
537
+ Escort::Logger.output.puts "Adding #{class_name} to #{group_name}"
538
+ class_change = ensure_class(group, class_name)
539
+ end
540
+
541
+ # process any rule changes separately since they are valid for all actions
542
+ rule_change = rule_change(group, rule, rule_mode)
543
+
544
+ # save changes
545
+ if class_change or rule_change
546
+ update_group(group_name, classes: group["classes"], rule: group["rule"])
547
+ else
548
+ Escort::Logger.output.puts "Already up-to-date"
549
+ end
550
+ end
551
+
552
+ def self.update_classes
553
+ if ! @puppetclassify
554
+ init
555
+ end
556
+ @puppet_https.delete("#{@puppet_url}/puppet-admin-api/v1/environment-cache")
557
+ @puppet_https.post("#{@rest_api_url}/v1/update-classes")
558
+ end
559
+
560
+ def self.puppet_code_deploy
561
+ Escort::Logger.output.puts "Running puppet and deploying code..."
562
+
563
+ # if puppet run fails, just deploy the code anyway as the fix needed might
564
+ # be in the update...
565
+ system("puppet agent -t ; puppet-code deploy --all --wait")
566
+ end
567
+
568
+ # Extract the r10k settings ONLY from the passed in data has and update
569
+ # NCAPI with them immediately
570
+ def self.apply_r10k_settings_now(data)
571
+ data.each { |group_name,opts|
572
+ group = nc_group(group_name)
573
+
574
+ if opts.key?("classes")
575
+ Escort::Logger.output.puts "Setting up rules for #{group_name} immediately"
576
+ if ensure_classes_and_params(group, opts["classes"])
577
+ update_group(group_name, classes: group["classes"])
578
+ end
579
+ end
580
+ }
581
+ end
582
+
583
+ # Check if this is an r10k parameter or not
584
+ #
585
+ # @return true if this is to do with R10K otherwise false
586
+ def self.is_r10k_param(class_name, param_name)
587
+ class_name == R10K_SETTINGS_CLASS and R10K_SETTINGS_PARAMS.include?(param_name)
588
+ end
589
+
590
+ # Evaluate whether change instructions contain R10K settings or not
591
+ #
592
+ # @param data Hash of data settings to look at
593
+ # @return false if not found otherwise hash of with just the settings that
594
+ # need to be applied immediately
595
+ def self.contains_r10k_settings(data)
596
+ found = {}
597
+ data.each { |group_name, opts|
598
+ if opts.key?("classes") and opts["classes"].key?(R10K_SETTINGS_CLASS)
599
+ opts["classes"][R10K_SETTINGS_CLASS].each { |param_name,param_value|
600
+ if is_r10k_param(R10K_SETTINGS_CLASS, param_name)
601
+ # make the hash structure we need
602
+ if ! found.key?(group_name)
603
+ found[group_name] = {}
604
+ end
605
+
606
+ if ! found[group_name].key?("classes")
607
+ found[group_name]["classes"] = {}
608
+ end
609
+
610
+ if ! found[group_name]["classes"].key?(R10K_SETTINGS_CLASS)
611
+ found[group_name]["classes"][R10K_SETTINGS_CLASS] = {}
612
+ end
613
+
614
+ found[group_name]["classes"][R10K_SETTINGS_CLASS][param_name] = param_value
615
+ end
616
+ }
617
+ end
618
+ }
619
+
620
+ # Return the found elements if there were any, otherwise simplify to false
621
+ ! found.empty? ? found : false
622
+ end
623
+
624
+ def self.groups(options)
625
+ group_name = options[:group_name]
626
+ environment = options[:environment]
627
+ environment_trumps = options[:environment_trumps]
628
+ rule = options[:rule]
629
+ rule_mode = options[:rule_mode]
630
+
631
+ # step 1: create the group with the parent "All Environments"
632
+ nc_group(group_name, parent_name: "All Environments")
633
+
634
+ # step 2: set the environment + environment trumps
635
+ update_group(
636
+ group_name,
637
+ environment: environment,
638
+ environment_trumps: environment_trumps,
639
+ )
640
+
641
+ # step 3: set the rules - separate step because rule_mode needs special
642
+ # handling
643
+ group = nc_group(group_name)
644
+ rule_change = rule_change(group, rule, rule_mode)
645
+ if rule_change
646
+ update_group(group_name, rule: group["rule"])
647
+ end
648
+ end
374
649
  end
375
650
  end
@@ -1,3 +1,3 @@
1
1
  module NCEdit
2
- VERSION = "0.1.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -6,12 +6,13 @@ require 'ncedit/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ncedit"
8
8
  spec.version = NCEdit::VERSION
9
- spec.authors = ["Geoff Williams"]
10
- spec.email = ["geoff@geoffwilliams.me.uk"]
9
+ spec.authors = ["Declarative Systems"]
10
+ spec.email = ["sales@declarativesystems.com"]
11
+ spec.license = "Apache-2.0"
11
12
 
12
13
  spec.summary = %q{Edit Puppet Enterprise Node Classifier rules}
13
14
  spec.description = %q{Use the puppet-classify gem to create/edit NC rules}
14
- spec.homepage = "https://github.com/GeoffWilliams/ncedit"
15
+ spec.homepage = "https://github.com/declarativesystems/ncedit"
15
16
 
16
17
 
17
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -21,11 +22,11 @@ Gem::Specification.new do |spec|
21
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
23
  spec.require_paths = ["lib"]
23
24
 
24
- spec.add_development_dependency "bundler", "~> 1.14"
25
- spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "bundler", "~> 2.1"
26
+ spec.add_development_dependency "rake", "~> 13.0"
27
+ spec.add_development_dependency "rspec", "~> 3.9"
27
28
 
28
29
  spec.add_runtime_dependency "escort", "0.4.0"
29
- spec.add_runtime_dependency "json", "2.0.3"
30
- spec.add_runtime_dependency "puppetclassify", "0.1.5"
30
+ spec.add_runtime_dependency "json_pure", "2.3.0"
31
+ spec.add_runtime_dependency "puppetclassify", "0.1.8"
31
32
  end
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.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
- - Geoff Williams
7
+ - Declarative Systems
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-15 00:00:00.000000000 Z
11
+ date: 2020-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.14'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.14'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.0'
47
+ version: '3.9'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.9'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: escort
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -67,36 +67,36 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.4.0
69
69
  - !ruby/object:Gem::Dependency
70
- name: json
70
+ name: json_pure
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 2.0.3
75
+ version: 2.3.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 2.0.3
82
+ version: 2.3.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: puppetclassify
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 0.1.5
89
+ version: 0.1.8
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 0.1.5
96
+ version: 0.1.8
97
97
  description: Use the puppet-classify gem to create/edit NC rules
98
98
  email:
99
- - geoff@geoffwilliams.me.uk
99
+ - sales@declarativesystems.com
100
100
  executables:
101
101
  - ncedit
102
102
  extensions: []
@@ -107,6 +107,7 @@ files:
107
107
  - ".travis.yml"
108
108
  - Gemfile
109
109
  - LICENSE
110
+ - Makefile
110
111
  - README.md
111
112
  - Rakefile
112
113
  - bin/console
@@ -118,8 +119,9 @@ files:
118
119
  - lib/ncedit/cmd.rb
119
120
  - lib/ncedit/version.rb
120
121
  - ncedit.gemspec
121
- homepage: https://github.com/GeoffWilliams/ncedit
122
- licenses: []
122
+ homepage: https://github.com/declarativesystems/ncedit
123
+ licenses:
124
+ - Apache-2.0
123
125
  metadata: {}
124
126
  post_install_message:
125
127
  rdoc_options: []
@@ -136,8 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
138
  - !ruby/object:Gem::Version
137
139
  version: '0'
138
140
  requirements: []
139
- rubyforge_project:
140
- rubygems_version: 2.5.2
141
+ rubygems_version: 3.0.3
141
142
  signing_key:
142
143
  specification_version: 4
143
144
  summary: Edit Puppet Enterprise Node Classifier rules