ncio 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +64 -0
- data/ext/ncio-replicate +41 -0
- data/lib/ncio/api/v1.rb +57 -7
- data/lib/ncio/app.rb +8 -0
- data/lib/ncio/support.rb +50 -3
- data/lib/ncio/support/option_parsing.rb +9 -0
- data/lib/ncio/support/retry_action.rb +79 -0
- data/lib/ncio/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3a023e01e8f30ad099628a652e23d8432a96e29
|
4
|
+
data.tar.gz: 26a22f56c26aa09821e7cc5af6b11ee92f2e9748
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbd161b5b74263feccfe972c9f0be4b1a12bd5e5e650d3e80a683177cd25615d9510974843c58689494442961ae712e09840f30a300336047d0017a1423d9bc5
|
7
|
+
data.tar.gz: 219f253cf24cbc5038160884ef0f55eecff340e3a30c92c9690b758b2e9d0885a23639108b7b76376f1f7c72d8f6d0fbf47ee0005e01b362611fada80928249c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Version 1.1.0
|
2
|
+
===
|
3
|
+
|
4
|
+
* Add `--retry-connections` [Issue 6](https://github.com/jeffmccune/ncio/issues/6)
|
5
|
+
* Add better error handling [Issue 7](https://github.com/jeffmccune/ncio/issues/7)
|
6
|
+
|
7
|
+
Version 1.0.1
|
8
|
+
===
|
9
|
+
|
10
|
+
* Initial release. Backup / Transform / Restore
|
data/README.md
CHANGED
@@ -111,6 +111,70 @@ Log to the console using the `--no-syslog` command line option.
|
|
111
111
|
The tool can only log to either syslog or the console at this time. Multiple
|
112
112
|
log destinations are not currently supported.
|
113
113
|
|
114
|
+
## Retrying Connections
|
115
|
+
|
116
|
+
It can take some time for the `pe-console-services` service to come online. In
|
117
|
+
an effort to make things are robust as possible consider using the
|
118
|
+
`--retry-connections` global option. This allows ncio to retry API connections
|
119
|
+
while the service comes online. This option has been added to address the
|
120
|
+
following use case:
|
121
|
+
|
122
|
+
service start pe-console-services.service
|
123
|
+
ncio --retry-connections backup
|
124
|
+
|
125
|
+
In this scenario ncio will retry API connections, eventually succeeding or
|
126
|
+
timing out. Ideally the service will come online before the timeout expires.
|
127
|
+
|
128
|
+
## Replication
|
129
|
+
|
130
|
+
A simple way to replicate node classification data between a primary and a
|
131
|
+
secondary can be achieved with the following shell script. Call this from cron
|
132
|
+
on a periodic basis:
|
133
|
+
|
134
|
+
```bash
|
135
|
+
#! /bin/bash
|
136
|
+
#
|
137
|
+
# This shell script is intended to be executed from cron on a periodic basis.
|
138
|
+
# The goal is to keep a Standby PE Monolithic master in sync with an active
|
139
|
+
# Primary. Pass the FQDN of the primary as ARG 1 and the FQDN of the secondary
|
140
|
+
# as ARG 2
|
141
|
+
#
|
142
|
+
# In a DR situation when the secondary becomes active, block replication by
|
143
|
+
# touching the lockfile. This will prevent any changes made to the standby from
|
144
|
+
# being clobbered as soon as the primary comes back online.
|
145
|
+
#
|
146
|
+
# Prior to re-enabling replication after a DR situation, replicate back to the
|
147
|
+
# primary by reversing the direction of this script.
|
148
|
+
|
149
|
+
set -euo pipefail
|
150
|
+
|
151
|
+
PRIMARY="$1"
|
152
|
+
STANDBY="$2"
|
153
|
+
|
154
|
+
SOURCE="https://${PRIMARY}:4433/classification-api/v1"
|
155
|
+
PATH="/opt/puppetlabs/puppet/bin:$PATH"
|
156
|
+
lockfile='/etc/ncio_do_not_replicate'
|
157
|
+
|
158
|
+
log() {
|
159
|
+
logger -t ncio-replicate -p daemon.warn -s "$1"
|
160
|
+
}
|
161
|
+
|
162
|
+
if [[ -e "$lockfile" ]]; then
|
163
|
+
log "WARN: Replication aborted, $lockfile exists!"
|
164
|
+
exit 1
|
165
|
+
fi
|
166
|
+
|
167
|
+
ncio --uri "$SOURCE" --retry-connections backup \
|
168
|
+
| ncio transform --hostname "${PRIMARY}:${STANDBY}" \
|
169
|
+
| ncio --retry-connections restore
|
170
|
+
rval=$?
|
171
|
+
|
172
|
+
[[ $rval -eq 0 ]] && STATUS='OK' || STATUS='ERROR'
|
173
|
+
msg="INFO: Finished replicating puppet classification groups."
|
174
|
+
log "$msg STATUS=${STATUS} EXITCODE=${rval} (touch $lockfile to disable)"
|
175
|
+
exit $rval
|
176
|
+
```
|
177
|
+
|
114
178
|
## Contributing
|
115
179
|
|
116
180
|
Bug reports and pull requests are welcome on GitHub at
|
data/ext/ncio-replicate
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
#
|
3
|
+
# This shell script is intended to be executed from cron on a periodic basis.
|
4
|
+
# The goal is to keep a Standby PE Monolithic master in sync with an active
|
5
|
+
# Primary. Pass the FQDN of the primary as ARG 1 and the FQDN of the secondary
|
6
|
+
# as ARG 2
|
7
|
+
#
|
8
|
+
# In a DR situation when the secondary becomes active, block replication by
|
9
|
+
# touching the lockfile. This will prevent any changes made to the standby from
|
10
|
+
# being clobbered as soon as the primary comes back online.
|
11
|
+
#
|
12
|
+
# Prior to re-enabling replication after a DR situation, replicate back to the
|
13
|
+
# primary by reversing the direction of this script.
|
14
|
+
|
15
|
+
set -euo pipefail
|
16
|
+
|
17
|
+
PRIMARY="$1"
|
18
|
+
STANDBY="$2"
|
19
|
+
|
20
|
+
SOURCE="https://${PRIMARY}:4433/classification-api/v1"
|
21
|
+
PATH="/opt/puppetlabs/puppet/bin:$PATH"
|
22
|
+
lockfile='/etc/ncio_do_not_replicate'
|
23
|
+
|
24
|
+
log() {
|
25
|
+
logger -t ncio-replicate -p daemon.warn -s "$1"
|
26
|
+
}
|
27
|
+
|
28
|
+
if [[ -e "$lockfile" ]]; then
|
29
|
+
log "WARN: Replication aborted, $lockfile exists!"
|
30
|
+
exit 1
|
31
|
+
fi
|
32
|
+
|
33
|
+
ncio --uri "$SOURCE" backup \
|
34
|
+
| ncio transform --hostname "${PRIMARY}:${STANDBY}" \
|
35
|
+
| ncio restore
|
36
|
+
rval=$?
|
37
|
+
|
38
|
+
[[ $rval -eq 0 ]] && STATUS='OK' || STATUS='ERROR'
|
39
|
+
msg="INFO: Finished replicating puppet classification groups."
|
40
|
+
log "$msg STATUS=${STATUS} EXITCODE=${rval} (touch $lockfile to disable)"
|
41
|
+
exit $rval
|
data/lib/ncio/api/v1.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'ncio/api'
|
2
2
|
require 'ncio/http_client'
|
3
|
+
require 'ncio/support'
|
4
|
+
require 'ncio/support/retry_action'
|
3
5
|
require 'uri'
|
4
6
|
require 'socket'
|
5
7
|
require 'json'
|
@@ -17,6 +19,7 @@ module Ncio
|
|
17
19
|
attr_reader :opts
|
18
20
|
|
19
21
|
class ApiError < RuntimeError; end
|
22
|
+
class ApiAuthenticationError < RuntimeError; end
|
20
23
|
|
21
24
|
DEFAULT_HEADERS = {
|
22
25
|
'Content-Type' => 'application/json',
|
@@ -35,6 +38,10 @@ module Ncio
|
|
35
38
|
@port = uri.port
|
36
39
|
end
|
37
40
|
|
41
|
+
def log
|
42
|
+
Ncio::Support.log
|
43
|
+
end
|
44
|
+
|
38
45
|
##
|
39
46
|
# Return a memoized HTTP connection
|
40
47
|
def connection
|
@@ -49,6 +56,37 @@ module Ncio
|
|
49
56
|
@connection = Ncio::HttpClient.new(conn_opts)
|
50
57
|
end
|
51
58
|
|
59
|
+
##
|
60
|
+
# Make a request respecting the timeout global option
|
61
|
+
#
|
62
|
+
# Assumes the timeout value is available in opts[:connect_timeout]
|
63
|
+
def request_with_timeout(req)
|
64
|
+
params = {
|
65
|
+
timeout: opts[:connect_timeout],
|
66
|
+
retry_exceptions: [Errno::ECONNREFUSED],
|
67
|
+
log: self.log,
|
68
|
+
}
|
69
|
+
Ncio::Support::RetryAction.retry_action(params) do
|
70
|
+
connection.request(req)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Make a request without a timeout
|
76
|
+
def request_without_timeout(req)
|
77
|
+
connection.request(req)
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Make a request, return a response
|
82
|
+
def request(req)
|
83
|
+
if opts[:retry_connections]
|
84
|
+
request_with_timeout(req)
|
85
|
+
else
|
86
|
+
request_without_timeout(req)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
52
90
|
##
|
53
91
|
# Return all of the groups currently defined in the node classifier API.
|
54
92
|
#
|
@@ -60,14 +98,27 @@ module Ncio
|
|
60
98
|
def groups(inherited = false)
|
61
99
|
uri = build_uri('groups', inherited: inherited.to_s)
|
62
100
|
req = Net::HTTP::Get.new(uri, DEFAULT_HEADERS)
|
63
|
-
resp =
|
64
|
-
if resp.code == '200'
|
101
|
+
resp = request(req)
|
102
|
+
obj = if resp.code == '200'
|
103
|
+
JSON.parse(resp.body)
|
104
|
+
else
|
105
|
+
raise_on_non_200(resp, 200)
|
106
|
+
end
|
107
|
+
obj
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Handle a non 200 response.
|
112
|
+
def raise_on_non_200(resp, expected_code=200)
|
113
|
+
if resp.code == '401' && %r{rbac/user-unauthenticated}.match(resp.body)
|
65
114
|
obj = JSON.parse(resp.body)
|
115
|
+
msg = obj['msg'] || '401 User Unauthenticated Error'
|
116
|
+
raise ApiAuthenticationError, msg
|
66
117
|
else
|
67
|
-
msg = "Expected
|
118
|
+
msg = "Expected #{expected_code} response, got #{resp.code} "\
|
119
|
+
"body: #{resp.body}"
|
68
120
|
raise ApiError, msg
|
69
121
|
end
|
70
|
-
obj
|
71
122
|
end
|
72
123
|
|
73
124
|
##
|
@@ -80,10 +131,9 @@ module Ncio
|
|
80
131
|
uri = build_uri('import-hierarchy')
|
81
132
|
req = Net::HTTP::Post.new(uri, DEFAULT_HEADERS)
|
82
133
|
req.body_stream = stream
|
83
|
-
resp =
|
134
|
+
resp = request(req)
|
84
135
|
return true if resp.code == '204'
|
85
|
-
|
86
|
-
raise ApiError, msg
|
136
|
+
raise_on_non_200(resp, 204)
|
87
137
|
end
|
88
138
|
|
89
139
|
##
|
data/lib/ncio/app.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'ncio'
|
3
3
|
require 'ncio/support'
|
4
4
|
require 'ncio/support/option_parsing'
|
5
|
+
require 'ncio/support/retry_action'
|
5
6
|
require 'ncio/support/transform'
|
6
7
|
require 'ncio/trollop'
|
7
8
|
require 'ncio/version'
|
@@ -62,6 +63,11 @@ class App
|
|
62
63
|
transform_groups
|
63
64
|
return 0
|
64
65
|
end
|
66
|
+
rescue Exception => e
|
67
|
+
msg = "ERROR: #{friendly_error(e)}"
|
68
|
+
fatal msg
|
69
|
+
$stderr.puts msg
|
70
|
+
return 1
|
65
71
|
end
|
66
72
|
# rubocop:enable Metrics/MethodLength
|
67
73
|
|
@@ -90,6 +96,7 @@ class App
|
|
90
96
|
# Restore all groups in a manner suitable for the node classification
|
91
97
|
# hierarchy import. See: [NC Import
|
92
98
|
# Hierarchy](https://docs.puppet.com/pe/2016.1/nc_import-hierarchy.html)
|
99
|
+
# rubocop:disable Lint/RescueException
|
93
100
|
def restore_groups
|
94
101
|
warn 'Starting Node Classification Restore using '\
|
95
102
|
"POST #{uri}/import-hierarchy"
|
@@ -105,6 +112,7 @@ class App
|
|
105
112
|
fatal "ERROR Restoring backup: #{format_error e}"
|
106
113
|
raise e
|
107
114
|
end
|
115
|
+
# rubocop:enable Lint/RescueException
|
108
116
|
|
109
117
|
##
|
110
118
|
# Transform a backup produced with backup_groups. The transformation is
|
data/lib/ncio/support.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'json'
|
1
2
|
require 'logger'
|
3
|
+
require 'stringio'
|
2
4
|
require 'syslog/logger'
|
3
|
-
require 'json'
|
4
5
|
|
5
6
|
module Ncio
|
6
7
|
##
|
@@ -11,6 +12,10 @@ module Ncio
|
|
11
12
|
module Support
|
12
13
|
attr_reader :opts
|
13
14
|
|
15
|
+
##
|
16
|
+
# Reset the global logger instance and return it as an object.
|
17
|
+
#
|
18
|
+
# @return [Logger] initialized logging instance
|
14
19
|
def self.reset_logging!(opts)
|
15
20
|
logger = opts[:syslog] ? syslog_logger : stream_logger(opts)
|
16
21
|
@log = logger
|
@@ -38,7 +43,7 @@ module Ncio
|
|
38
43
|
# Logging is handled centrally, the helper methods will delegate to the
|
39
44
|
# centrally configured logging instance.
|
40
45
|
def self.log
|
41
|
-
@log
|
46
|
+
@log || reset_logging!
|
42
47
|
end
|
43
48
|
|
44
49
|
##
|
@@ -53,6 +58,7 @@ module Ncio
|
|
53
58
|
when 'STDOUT' then $stdout
|
54
59
|
when 'STDERR' then $stderr
|
55
60
|
when 'STDIN' then $stdin
|
61
|
+
when 'STRING' then StringIO.new
|
56
62
|
else File.expand_path(filepath)
|
57
63
|
end
|
58
64
|
end
|
@@ -155,10 +161,51 @@ module Ncio
|
|
155
161
|
#
|
156
162
|
# @param [Exception] e the exception to format
|
157
163
|
def format_error(e)
|
158
|
-
data = { error:
|
164
|
+
data = { error: e.class.to_s, message: e.message, backtrace: e.backtrace }
|
159
165
|
JSON.pretty_generate(data)
|
160
166
|
end
|
161
167
|
|
168
|
+
##
|
169
|
+
# Top level exception handler and friendly error message handler.
|
170
|
+
def friendly_error(e)
|
171
|
+
case e
|
172
|
+
when Ncio::Support::RetryAction::RetryException::Timeout
|
173
|
+
'Timeout expired connecting to the console service. Verify it is up and running.'
|
174
|
+
when OpenSSL::SSL::SSLError
|
175
|
+
friendly_ssl_error(e)
|
176
|
+
when Ncio::Api::V1::ApiAuthenticationError
|
177
|
+
'Make sure the --cert option value is listed in the certificate whitelist, '\
|
178
|
+
'and you are able to run puppet agent --test on the master. '\
|
179
|
+
'The certificate whitelist on the master is located at '\
|
180
|
+
'/etc/puppetlabs/console-services/rbac-certificate-whitelist'
|
181
|
+
else
|
182
|
+
e.message
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Handle SSL errors as a special case
|
188
|
+
def friendly_ssl_error(e)
|
189
|
+
case e.message
|
190
|
+
when %r{read server hello A}
|
191
|
+
'The socket connected, but there is no SSL service on the other side. '\
|
192
|
+
'This is often the case with TCP forwarding, e.g. in Vagrant '\
|
193
|
+
'or with SSH tunnels.'
|
194
|
+
when %r{state=error: certificate verify failed}
|
195
|
+
'The socket connected, but the certificate presented by the service could not '\
|
196
|
+
'be verified. Make sure the value of the --cacert option points to an identical '\
|
197
|
+
'copy of the /etc/puppetlabs/puppet/ssl/certs/ca.pem file from the master.'
|
198
|
+
when %r{returned=5 errno=0 state=SSLv3 read finished A}
|
199
|
+
"The socket connected, but got back SSL error: #{e.message} "\
|
200
|
+
'This usually means the value of the --cert and --key options are certificates '\
|
201
|
+
'which are not signed by the same CA the service trusts. This can often happen '\
|
202
|
+
'if the service has recently been re-installed. Please obtain a valid cert and key '\
|
203
|
+
'and try again.'
|
204
|
+
else
|
205
|
+
"SSL Error: The socket is listening but something went wrong: #{e.message}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
162
209
|
##
|
163
210
|
# Return the application version as a Semantic Version encoded string
|
164
211
|
#
|
@@ -75,6 +75,13 @@ module Ncio
|
|
75
75
|
opt :syslog, 'Log to syslog', default: true, conflicts: :logto
|
76
76
|
opt :verbose, 'Set log level to INFO'
|
77
77
|
opt :debug, 'Set log level to DEBUG'
|
78
|
+
opt :retry_connections, 'Retry API connections, '\
|
79
|
+
'e.g. waiting for the service to come online. '\
|
80
|
+
'{NCIO_RETRY_CONNECTIONS}',
|
81
|
+
default: (env['NCIO_RETRY_CONNECTIONS'] == 'true') || false
|
82
|
+
opt :connect_timeout, 'Retry <i> seconds if --retry-connections=true '\
|
83
|
+
'{NCIO_CONNECT_TIMEOUT}',
|
84
|
+
default: env['NCIO_CONNECT_TIMEOUT'] || CONNECT_TIMEOUT_DEFAULT
|
78
85
|
end
|
79
86
|
end
|
80
87
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
@@ -198,6 +205,8 @@ Global options: (Note, command line arguments supersede ENV vars in {}'s)
|
|
198
205
|
|
199
206
|
# Map is indexed by the subcommand
|
200
207
|
FILE_DEFAULT_MAP = { 'backup' => 'STDOUT', 'restore' => 'STDIN' }.freeze
|
208
|
+
|
209
|
+
CONNECT_TIMEOUT_DEFAULT = 120
|
201
210
|
end
|
202
211
|
end
|
203
212
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'ncio/support'
|
2
|
+
module Ncio
|
3
|
+
module Support
|
4
|
+
##
|
5
|
+
# Provide a method to retry arbitrary code blocks with the ability to rescue
|
6
|
+
# certain exceptions and retry rather than failing hard on the exception.
|
7
|
+
#
|
8
|
+
# Copied from:
|
9
|
+
# https://github.com/puppetlabs/puppetlabs-cloud_provisioner/blob/f6cbac3/lib/puppet/cloudpack/utils.rb
|
10
|
+
module RetryAction
|
11
|
+
class RetryException < RuntimeError
|
12
|
+
class NoBlockGiven < RetryException; end
|
13
|
+
class NoTimeoutGiven < RetryException; end
|
14
|
+
class Timeout < RetryException; end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.timedout?(start, timeout)
|
18
|
+
return true if timeout.nil?
|
19
|
+
(Time.now - start) >= timeout
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Retry an action, catching exceptions and retrying if the exception has
|
24
|
+
# been specified.
|
25
|
+
#
|
26
|
+
# rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength
|
27
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
28
|
+
def self.retry_action(params = { retry_exceptions: nil, timeout: nil, log: nil })
|
29
|
+
# Retry actions for a specified amount of time. This method will allow
|
30
|
+
# the final retry to complete even if that extends beyond the timeout
|
31
|
+
# period.
|
32
|
+
raise RetryException::NoBlockGiven unless block_given?
|
33
|
+
|
34
|
+
raise RetryException::NoTimeoutGiven if params[:timeout].nil?
|
35
|
+
params[:retry_exceptions] ||= []
|
36
|
+
|
37
|
+
# Assumes reset_logging! has been called. This happens in the Ncio::App
|
38
|
+
# initialization.
|
39
|
+
log = params[:log] || Ncio::Support.log
|
40
|
+
|
41
|
+
start = Time.now
|
42
|
+
failures = 0
|
43
|
+
|
44
|
+
# rubocop:disable Lint/RescueException
|
45
|
+
begin
|
46
|
+
yield
|
47
|
+
|
48
|
+
rescue Exception => e
|
49
|
+
# If we were giving exceptions to catch,
|
50
|
+
# catch the exceptions we care about and retry.
|
51
|
+
# All others fail hard
|
52
|
+
|
53
|
+
raise RetryException::Timeout if timedout?(start, params[:timeout])
|
54
|
+
|
55
|
+
retry_exceptions = params[:retry_exceptions]
|
56
|
+
|
57
|
+
unless retry_exceptions.empty?
|
58
|
+
if retry_exceptions.include?(e.class)
|
59
|
+
log.warn("Retrying: #{e.class}: #{e}")
|
60
|
+
else
|
61
|
+
# If the exceptions is not in the list of retry_exceptions
|
62
|
+
# re-raise.
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
# rubocop:enable Lint/RescueException
|
67
|
+
|
68
|
+
failures += 1
|
69
|
+
# Increase the amount of time that we sleep after every
|
70
|
+
# failed retry attempt.
|
71
|
+
sleep(((2**failures) - 1) * 0.1)
|
72
|
+
|
73
|
+
retry
|
74
|
+
end
|
75
|
+
# rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/ncio/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ncio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff McCune
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- ".rubocop.yml"
|
137
137
|
- ".travis.yml"
|
138
138
|
- ".yardopts"
|
139
|
+
- CHANGELOG.md
|
139
140
|
- Gemfile
|
140
141
|
- LICENSE.txt
|
141
142
|
- README.md
|
@@ -143,6 +144,7 @@ files:
|
|
143
144
|
- bin/console
|
144
145
|
- bin/setup
|
145
146
|
- exe/ncio
|
147
|
+
- ext/ncio-replicate
|
146
148
|
- lib/ncio.rb
|
147
149
|
- lib/ncio/api.rb
|
148
150
|
- lib/ncio/api/v1.rb
|
@@ -150,6 +152,7 @@ files:
|
|
150
152
|
- lib/ncio/http_client.rb
|
151
153
|
- lib/ncio/support.rb
|
152
154
|
- lib/ncio/support/option_parsing.rb
|
155
|
+
- lib/ncio/support/retry_action.rb
|
153
156
|
- lib/ncio/support/transform.rb
|
154
157
|
- lib/ncio/trollop.rb
|
155
158
|
- lib/ncio/version.rb
|
@@ -174,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
177
|
version: '0'
|
175
178
|
requirements: []
|
176
179
|
rubyforge_project:
|
177
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.2.5
|
178
181
|
signing_key:
|
179
182
|
specification_version: 4
|
180
183
|
summary: Puppet Node Classifier backup / restore / transform
|