pagerduty-pd_sync 0.1.1
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 +7 -0
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +220 -0
- data/Rakefile +6 -0
- data/lib/chef/knife/pd_sync.rb +198 -0
- data/lib/pagerduty/chef_server/sync.rb +208 -0
- data/lib/pagerduty/chef_server/sync_helper.rb +163 -0
- data/lib/pagerduty/chef_server/synclock.rb +111 -0
- data/pagerduty-pd_sync.gemspec +26 -0
- metadata +151 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 6fac563e7255e747b0ffff23e56056ef7477e945
|
|
4
|
+
data.tar.gz: a8359337b1b4558df37e79b1a1f826f0521a6b42
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b24f4216c8be7d2cccb2d53c37c1fb0641fb6cf34cd211796f7e6fc2affed2461c0c7852d3edd4c0135eef7af04118458c1a1574049691368cd95622fdc84c60
|
|
7
|
+
data.tar.gz: 13537752201b76d4922da5c507af0cc2d4818653904c2a0f67fa0eedba203517f0047cd851c206c863599ad5733b78c0ca85ab49da2924bdfad70514ac39666f
|
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.bundle
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
pd_sync (0.1.0)
|
|
5
|
+
berkshelf
|
|
6
|
+
chef
|
|
7
|
+
json
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
addressable (2.4.0)
|
|
13
|
+
berkshelf (4.3.2)
|
|
14
|
+
addressable (~> 2.3, >= 2.3.4)
|
|
15
|
+
berkshelf-api-client (~> 2.0, >= 2.0.2)
|
|
16
|
+
buff-config (~> 1.0)
|
|
17
|
+
buff-extensions (~> 1.0)
|
|
18
|
+
buff-shell_out (~> 0.1)
|
|
19
|
+
celluloid (= 0.16.0)
|
|
20
|
+
celluloid-io (~> 0.16.1)
|
|
21
|
+
cleanroom (~> 1.0)
|
|
22
|
+
faraday (~> 0.9)
|
|
23
|
+
httpclient (~> 2.7)
|
|
24
|
+
minitar (~> 0.5, >= 0.5.4)
|
|
25
|
+
octokit (~> 4.0)
|
|
26
|
+
retryable (~> 2.0)
|
|
27
|
+
ridley (~> 4.5)
|
|
28
|
+
solve (~> 2.0)
|
|
29
|
+
thor (~> 0.19)
|
|
30
|
+
berkshelf-api-client (2.0.2)
|
|
31
|
+
faraday (~> 0.9.1)
|
|
32
|
+
httpclient (~> 2.7.0)
|
|
33
|
+
ridley (~> 4.5)
|
|
34
|
+
buff-config (1.0.1)
|
|
35
|
+
buff-extensions (~> 1.0)
|
|
36
|
+
varia_model (~> 0.4)
|
|
37
|
+
buff-extensions (1.0.0)
|
|
38
|
+
buff-ignore (1.1.1)
|
|
39
|
+
buff-ruby_engine (0.1.0)
|
|
40
|
+
buff-shell_out (0.2.0)
|
|
41
|
+
buff-ruby_engine (~> 0.1.0)
|
|
42
|
+
builder (3.2.2)
|
|
43
|
+
celluloid (0.16.0)
|
|
44
|
+
timers (~> 4.0.0)
|
|
45
|
+
celluloid-io (0.16.2)
|
|
46
|
+
celluloid (>= 0.16.0)
|
|
47
|
+
nio4r (>= 1.1.0)
|
|
48
|
+
chef (12.5.1)
|
|
49
|
+
chef-config (= 12.5.1)
|
|
50
|
+
chef-zero (~> 4.2, >= 4.2.2)
|
|
51
|
+
diff-lcs (~> 1.2, >= 1.2.4)
|
|
52
|
+
erubis (~> 2.7)
|
|
53
|
+
ffi-yajl (~> 2.2)
|
|
54
|
+
highline (~> 1.6, >= 1.6.9)
|
|
55
|
+
mixlib-authentication (~> 1.3)
|
|
56
|
+
mixlib-cli (~> 1.4)
|
|
57
|
+
mixlib-log (~> 1.3)
|
|
58
|
+
mixlib-shellout (~> 2.0)
|
|
59
|
+
net-ssh (~> 2.6)
|
|
60
|
+
net-ssh-multi (~> 1.1)
|
|
61
|
+
ohai (>= 8.6.0.alpha.1, < 9)
|
|
62
|
+
plist (~> 3.1.0)
|
|
63
|
+
pry (~> 0.9)
|
|
64
|
+
rspec-core (~> 3.2)
|
|
65
|
+
rspec-expectations (~> 3.2)
|
|
66
|
+
rspec-mocks (~> 3.2)
|
|
67
|
+
rspec_junit_formatter (~> 0.2.0)
|
|
68
|
+
serverspec (~> 2.7)
|
|
69
|
+
specinfra (~> 2.10)
|
|
70
|
+
syslog-logger (~> 1.6)
|
|
71
|
+
chef-config (12.5.1)
|
|
72
|
+
mixlib-config (~> 2.0)
|
|
73
|
+
mixlib-shellout (~> 2.0)
|
|
74
|
+
chef-zero (4.6.2)
|
|
75
|
+
ffi-yajl (~> 2.2)
|
|
76
|
+
hashie (>= 2.0, < 4.0)
|
|
77
|
+
mixlib-log (~> 1.3)
|
|
78
|
+
rack
|
|
79
|
+
uuidtools (~> 2.1)
|
|
80
|
+
cleanroom (1.0.0)
|
|
81
|
+
coderay (1.1.0)
|
|
82
|
+
diff-lcs (1.2.5)
|
|
83
|
+
erubis (2.7.0)
|
|
84
|
+
faraday (0.9.2)
|
|
85
|
+
multipart-post (>= 1.2, < 3)
|
|
86
|
+
ffi (1.9.10)
|
|
87
|
+
ffi-yajl (2.2.3)
|
|
88
|
+
libyajl2 (~> 1.2)
|
|
89
|
+
hashie (3.4.4)
|
|
90
|
+
highline (1.7.8)
|
|
91
|
+
hitimes (1.2.3)
|
|
92
|
+
httpclient (2.7.2)
|
|
93
|
+
ipaddress (0.8.3)
|
|
94
|
+
json (1.8.3)
|
|
95
|
+
libyajl2 (1.2.0)
|
|
96
|
+
method_source (0.8.2)
|
|
97
|
+
minitar (0.5.4)
|
|
98
|
+
mixlib-authentication (1.4.0)
|
|
99
|
+
mixlib-log
|
|
100
|
+
rspec-core (~> 3.2)
|
|
101
|
+
rspec-expectations (~> 3.2)
|
|
102
|
+
rspec-mocks (~> 3.2)
|
|
103
|
+
mixlib-cli (1.5.0)
|
|
104
|
+
mixlib-config (2.2.1)
|
|
105
|
+
mixlib-log (1.6.0)
|
|
106
|
+
mixlib-shellout (2.2.6)
|
|
107
|
+
molinillo (0.4.4)
|
|
108
|
+
multi_json (1.11.3)
|
|
109
|
+
multipart-post (2.0.0)
|
|
110
|
+
net-scp (1.2.1)
|
|
111
|
+
net-ssh (>= 2.6.5)
|
|
112
|
+
net-ssh (2.9.4)
|
|
113
|
+
net-ssh-gateway (1.2.0)
|
|
114
|
+
net-ssh (>= 2.6.5)
|
|
115
|
+
net-ssh-multi (1.2.1)
|
|
116
|
+
net-ssh (>= 2.6.5)
|
|
117
|
+
net-ssh-gateway (>= 1.2.0)
|
|
118
|
+
net-telnet (0.1.1)
|
|
119
|
+
nio4r (1.2.1)
|
|
120
|
+
octokit (4.3.0)
|
|
121
|
+
sawyer (~> 0.7.0, >= 0.5.3)
|
|
122
|
+
ohai (8.15.1)
|
|
123
|
+
chef-config (>= 12.5.0.alpha.1, < 13)
|
|
124
|
+
ffi (~> 1.9)
|
|
125
|
+
ffi-yajl (~> 2.2)
|
|
126
|
+
ipaddress
|
|
127
|
+
mixlib-cli
|
|
128
|
+
mixlib-config (~> 2.0)
|
|
129
|
+
mixlib-log
|
|
130
|
+
mixlib-shellout (~> 2.0)
|
|
131
|
+
plist (~> 3.1)
|
|
132
|
+
systemu (~> 2.6.4)
|
|
133
|
+
wmi-lite (~> 1.0)
|
|
134
|
+
plist (3.1.0)
|
|
135
|
+
pry (0.10.1)
|
|
136
|
+
coderay (~> 1.1.0)
|
|
137
|
+
method_source (~> 0.8.1)
|
|
138
|
+
slop (~> 3.4)
|
|
139
|
+
rack (1.6.4)
|
|
140
|
+
rake (10.3.2)
|
|
141
|
+
retryable (2.0.3)
|
|
142
|
+
ridley (4.5.0)
|
|
143
|
+
addressable
|
|
144
|
+
buff-config (~> 1.0)
|
|
145
|
+
buff-extensions (~> 1.0)
|
|
146
|
+
buff-ignore (~> 1.1)
|
|
147
|
+
buff-shell_out (~> 0.1)
|
|
148
|
+
celluloid (~> 0.16.0)
|
|
149
|
+
celluloid-io (~> 0.16.1)
|
|
150
|
+
chef-config (>= 12.5.0)
|
|
151
|
+
erubis
|
|
152
|
+
faraday (~> 0.9.0)
|
|
153
|
+
hashie (>= 2.0.2, < 4.0.0)
|
|
154
|
+
httpclient (~> 2.7)
|
|
155
|
+
json (>= 1.7.7)
|
|
156
|
+
mixlib-authentication (>= 1.3.0)
|
|
157
|
+
retryable (~> 2.0)
|
|
158
|
+
semverse (~> 1.1)
|
|
159
|
+
varia_model (~> 0.4.0)
|
|
160
|
+
rspec (3.2.0)
|
|
161
|
+
rspec-core (~> 3.2.0)
|
|
162
|
+
rspec-expectations (~> 3.2.0)
|
|
163
|
+
rspec-mocks (~> 3.2.0)
|
|
164
|
+
rspec-core (3.2.2)
|
|
165
|
+
rspec-support (~> 3.2.0)
|
|
166
|
+
rspec-expectations (3.2.0)
|
|
167
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
168
|
+
rspec-support (~> 3.2.0)
|
|
169
|
+
rspec-its (1.2.0)
|
|
170
|
+
rspec-core (>= 3.0.0)
|
|
171
|
+
rspec-expectations (>= 3.0.0)
|
|
172
|
+
rspec-mocks (3.2.1)
|
|
173
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
174
|
+
rspec-support (~> 3.2.0)
|
|
175
|
+
rspec-support (3.2.2)
|
|
176
|
+
rspec_junit_formatter (0.2.3)
|
|
177
|
+
builder (< 4)
|
|
178
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
|
179
|
+
sawyer (0.7.0)
|
|
180
|
+
addressable (>= 2.3.5, < 2.5)
|
|
181
|
+
faraday (~> 0.8, < 0.10)
|
|
182
|
+
semverse (1.2.1)
|
|
183
|
+
serverspec (2.33.0)
|
|
184
|
+
multi_json
|
|
185
|
+
rspec (~> 3.0)
|
|
186
|
+
rspec-its
|
|
187
|
+
specinfra (~> 2.53)
|
|
188
|
+
sfl (2.2)
|
|
189
|
+
slop (3.6.0)
|
|
190
|
+
solve (2.0.3)
|
|
191
|
+
molinillo (~> 0.4.2)
|
|
192
|
+
semverse (~> 1.1)
|
|
193
|
+
specinfra (2.57.1)
|
|
194
|
+
net-scp
|
|
195
|
+
net-ssh (>= 2.7, < 4.0)
|
|
196
|
+
net-telnet
|
|
197
|
+
sfl
|
|
198
|
+
syslog-logger (1.6.8)
|
|
199
|
+
systemu (2.6.5)
|
|
200
|
+
thor (0.19.1)
|
|
201
|
+
timers (4.0.4)
|
|
202
|
+
hitimes
|
|
203
|
+
uuidtools (2.1.5)
|
|
204
|
+
varia_model (0.4.1)
|
|
205
|
+
buff-extensions (~> 1.0)
|
|
206
|
+
hashie (>= 2.0.2, < 4.0.0)
|
|
207
|
+
wmi-lite (1.0.0)
|
|
208
|
+
|
|
209
|
+
PLATFORMS
|
|
210
|
+
ruby
|
|
211
|
+
|
|
212
|
+
DEPENDENCIES
|
|
213
|
+
bundler
|
|
214
|
+
pd_sync!
|
|
215
|
+
pry
|
|
216
|
+
rake
|
|
217
|
+
rspec
|
|
218
|
+
|
|
219
|
+
BUNDLED WITH
|
|
220
|
+
1.11.2
|
data/Rakefile
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Tim Heckman (<ops@pagerduty.com>)
|
|
3
|
+
# Copyright:: Copyright (c) 2016 PagerDuty, Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require 'berkshelf'
|
|
19
|
+
require 'chef/knife'
|
|
20
|
+
|
|
21
|
+
class Chef
|
|
22
|
+
class Knife
|
|
23
|
+
class PdSync < Knife
|
|
24
|
+
|
|
25
|
+
attr_reader :altered_cookbooks
|
|
26
|
+
|
|
27
|
+
banner 'knife pd sync [--restore --why-run]'
|
|
28
|
+
|
|
29
|
+
deps do
|
|
30
|
+
require 'uri'
|
|
31
|
+
require 'socket'
|
|
32
|
+
require 'timeout'
|
|
33
|
+
require 'chef/cookbook_version'
|
|
34
|
+
require 'chef/data_bag_item'
|
|
35
|
+
require 'chef/data_bag'
|
|
36
|
+
require 'chef/knife/cookbook_bulk_delete'
|
|
37
|
+
require 'chef/knife/data_bag_create'
|
|
38
|
+
require 'chef/knife/data_bag_delete'
|
|
39
|
+
require 'chef/knife/data_bag_from_file'
|
|
40
|
+
require 'chef/knife/environment_from_file'
|
|
41
|
+
require 'chef/knife/role_from_file'
|
|
42
|
+
require 'chef/knife/cookbook_upload'
|
|
43
|
+
require 'berkshelf'
|
|
44
|
+
require 'berkshelf/berksfile'
|
|
45
|
+
require 'mixlib/shellout'
|
|
46
|
+
|
|
47
|
+
require 'pagerduty/chef_server/synclock'
|
|
48
|
+
require 'pagerduty/chef_server/sync'
|
|
49
|
+
|
|
50
|
+
Chef::Knife::CookbookUpload.load_deps
|
|
51
|
+
Chef::Knife::CookbookBulkDelete.load_deps
|
|
52
|
+
Chef::Knife::DataBagCreate.load_deps
|
|
53
|
+
Chef::Knife::DataBagDelete.load_deps
|
|
54
|
+
Chef::Knife::DataBagFromFile.load_deps
|
|
55
|
+
Chef::Knife::EnvironmentFromFile.load_deps
|
|
56
|
+
Chef::Knife::RoleFromFile.load_deps
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
option :restore,
|
|
60
|
+
short: '-r',
|
|
61
|
+
long: '--restore',
|
|
62
|
+
description: 'Upload all cookbooks regardless of whether checksums have changed',
|
|
63
|
+
boolean: true,
|
|
64
|
+
default: false
|
|
65
|
+
|
|
66
|
+
option :why_run,
|
|
67
|
+
short: '-W',
|
|
68
|
+
long: '--why-run',
|
|
69
|
+
description: 'Show what operations will be made, without actually performing them (does not work with --restore)',
|
|
70
|
+
boolean: true,
|
|
71
|
+
default: false
|
|
72
|
+
|
|
73
|
+
def run
|
|
74
|
+
@altered_cookbooks = nil
|
|
75
|
+
if config[:restore]
|
|
76
|
+
ui.warn 'pd sync will delete and reupload all cookbooks!'
|
|
77
|
+
plugin = Chef::Knife::CookbookBulkDelete.new
|
|
78
|
+
plugin.name_args = Array('.')
|
|
79
|
+
plugin.config[:yes] = true
|
|
80
|
+
plugin.config[:purge] = true
|
|
81
|
+
converge_by "delete all existing cookbooks" do
|
|
82
|
+
plugin.run
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
lockfile = '/tmp/restore_chef.lock'
|
|
86
|
+
user = Chef::Config[:node_name] || 'unknown'
|
|
87
|
+
converge_by 'perform pre-syn checks' do
|
|
88
|
+
preflight_checks
|
|
89
|
+
end
|
|
90
|
+
lock = PagerDuty::ChefServer::SyncLock.new(
|
|
91
|
+
lockfile, chef_server, localhost, user, local_branch
|
|
92
|
+
)
|
|
93
|
+
converge_by 'acquire lock' do
|
|
94
|
+
lock.lock
|
|
95
|
+
end
|
|
96
|
+
sync = PagerDuty::ChefServer::Sync.new(
|
|
97
|
+
vendor_dir: vendor_dir,
|
|
98
|
+
why_run: config[:why_run]
|
|
99
|
+
)
|
|
100
|
+
begin
|
|
101
|
+
@altered_cookbooks = sync.run
|
|
102
|
+
update_commit
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
ui.warn(e.message)
|
|
105
|
+
ui.warn(e.backtrace)
|
|
106
|
+
ensure
|
|
107
|
+
converge_by 'release lock' do
|
|
108
|
+
lock.unlock
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def preflight_checks
|
|
114
|
+
vdir = File.join(Dir.pwd, 'vendor')
|
|
115
|
+
if vendor_dir != vdir
|
|
116
|
+
ui.confirm("vendor directory (#{vendor_dir}) is different than standard one(#{vdir}), continue?")
|
|
117
|
+
end
|
|
118
|
+
if local_branch != 'master'
|
|
119
|
+
ui.confirm("You are deploying a non-master branch(#{local_branch}), continue?")
|
|
120
|
+
end
|
|
121
|
+
check_commit
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def check_commit
|
|
125
|
+
if origin_commit.nil?
|
|
126
|
+
ui.confirm('failed to determine the origin/master. sync anyway?')
|
|
127
|
+
elsif local_branch == 'master' && local_commit != origin_commit
|
|
128
|
+
ui.confirm('local master branch is different than origin, sync anyway?')
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def vendor_dir
|
|
133
|
+
Chef::Config[:cookbook_path].first
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def local_branch
|
|
137
|
+
%x(git symbolic-ref --short HEAD).strip! || 'unknown'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def chef_server
|
|
141
|
+
URI(Chef::Config[:chef_server_url]).host
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def origin_commit
|
|
145
|
+
@origin_commit||= begin
|
|
146
|
+
Timeout::timeout(5) do
|
|
147
|
+
commit = Mixlib::ShellOut.new("git ls-remote origin master | awk '{ print $1 }'")
|
|
148
|
+
commit.run_command
|
|
149
|
+
commit.exitstatus == 0 ? commit.stdout.strip : nil
|
|
150
|
+
end
|
|
151
|
+
rescue Timeout::Error
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def local_commit
|
|
157
|
+
@local_commit ||= %x(git rev-parse master).strip! || 'unknown'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def localhost
|
|
161
|
+
@localhost ||= Socket.gethostname
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def converge_by(msg)
|
|
165
|
+
if config[:why_run]
|
|
166
|
+
ui.info('Will '+msg)
|
|
167
|
+
else
|
|
168
|
+
yield if block_given?
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def update_commit
|
|
173
|
+
ui.info("updating commit from #{origin_commit} => #{local_commit}")
|
|
174
|
+
file = Tempfile.new(['restorechef', '.json'])
|
|
175
|
+
|
|
176
|
+
unless Chef::DataBag.list.keys.include?('metadata')
|
|
177
|
+
plugin = Chef::Knife::DataBagCreate.new
|
|
178
|
+
plugin.name_args = Array('metadata')
|
|
179
|
+
converge_by 'create data bag metadata' do
|
|
180
|
+
plugin.run
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
begin
|
|
184
|
+
file.write(JSON.dump({ id: 'commit', commit: local_commit }))
|
|
185
|
+
file.flush
|
|
186
|
+
dbag = Chef::Knife::DataBagFromFile.new
|
|
187
|
+
dbag.name_args = ['metadata', file.path]
|
|
188
|
+
converge_by 'update commit' do
|
|
189
|
+
dbag.run
|
|
190
|
+
end
|
|
191
|
+
ensure
|
|
192
|
+
file.close
|
|
193
|
+
file.unlink
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Tim Heckman (<ops@pagerduty.com>)
|
|
3
|
+
# Copyright:: Copyright (c) 2016 PagerDuty, Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require 'pagerduty/chef_server/sync_helper'
|
|
19
|
+
|
|
20
|
+
module PagerDuty
|
|
21
|
+
module ChefServer
|
|
22
|
+
# rubocop:disable Metrics/ClassLength
|
|
23
|
+
class Sync
|
|
24
|
+
|
|
25
|
+
# require_relative 'sync_helper'
|
|
26
|
+
include PagerDuty::ChefServer::SyncHelper
|
|
27
|
+
|
|
28
|
+
attr_reader :ui, :why_run, :cookbook_dir, :ignore_patterns
|
|
29
|
+
|
|
30
|
+
def initialize(opts={})
|
|
31
|
+
require 'tempfile'
|
|
32
|
+
require 'json'
|
|
33
|
+
require 'mixlib/shellout'
|
|
34
|
+
require 'chef/cookbook_version'
|
|
35
|
+
require 'chef/data_bag_item'
|
|
36
|
+
require 'chef/data_bag'
|
|
37
|
+
require 'berkshelf'
|
|
38
|
+
require 'berkshelf/berksfile'
|
|
39
|
+
@cookbook_dir = opts[:vendor_dir]
|
|
40
|
+
@why_run = opts[:why_run]
|
|
41
|
+
@ui = opts[:ui] || Chef::Knife.ui
|
|
42
|
+
if File.exist?(ignore_file)
|
|
43
|
+
@ignore_patterns = File.read(ignore_file).lines.map{|l| File.join(chef_repo_dir, l).strip}
|
|
44
|
+
else
|
|
45
|
+
ui.info('.pd-ignore absent, nothing will be ignored')
|
|
46
|
+
@ignore_patterns = false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def run
|
|
51
|
+
berkshelf_install
|
|
52
|
+
sync_cookbooks
|
|
53
|
+
upload_databags
|
|
54
|
+
upload_environments
|
|
55
|
+
upload_roles
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def sync_cookbooks
|
|
59
|
+
altered_cookbooks = Hash.new{|h, k| h[k] = []}
|
|
60
|
+
|
|
61
|
+
if remote_cookbooks.empty?
|
|
62
|
+
upload_all_cookbooks
|
|
63
|
+
else
|
|
64
|
+
unless new_cookbooks.empty?
|
|
65
|
+
upload_cookbooks(new_cookbooks)
|
|
66
|
+
altered_cookbooks[:added] = new_cookbooks
|
|
67
|
+
end
|
|
68
|
+
stale_cookbooks.each do |cb|
|
|
69
|
+
delete_cookbook(cb)
|
|
70
|
+
altered_cookbooks[:deleted] << cb
|
|
71
|
+
end
|
|
72
|
+
updated_cookbooks.each do |cb|
|
|
73
|
+
replace_cookbook(cb)
|
|
74
|
+
altered_cookbooks[:updated] << cb
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def berkshelf_install
|
|
80
|
+
path = File.expand_path(File.join(chef_repo_dir, 'Berksfile'))
|
|
81
|
+
ui.info(ui.color("using Berksfile: #{path} for berkshelf install", :yellow))
|
|
82
|
+
berksfile = Berkshelf::Berksfile.from_file(path, { except: 'tests' } )
|
|
83
|
+
FileUtils.rm_rf(cookbook_dir)
|
|
84
|
+
berksfile.vendor(cookbook_dir)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def local_cookbooks
|
|
88
|
+
local_checksums.keys.sort
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def remote_cookbooks
|
|
92
|
+
@remote_cookbooks ||= Chef::CookbookVersion.list.keys.sort
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def remote_commit
|
|
96
|
+
@remote_commit ||= begin
|
|
97
|
+
if Chef::DataBag.list.keys.include?('metadata')
|
|
98
|
+
Chef::DataBagItem.load('metadata', 'commit').raw_data['commit']
|
|
99
|
+
else
|
|
100
|
+
{}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def cookbook_segments
|
|
106
|
+
Chef::CookbookVersion::COOKBOOK_SEGMENTS
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def remote_checksums
|
|
110
|
+
@remote_checksums ||= begin
|
|
111
|
+
c = {}
|
|
112
|
+
remote_cookbooks.each do |cb|
|
|
113
|
+
c[cb] = {}
|
|
114
|
+
cbm = Chef::CookbookVersion.load(cb).manifest
|
|
115
|
+
cookbook_segments.each do |m|
|
|
116
|
+
cbm_sort = cbm[m].sort { |x, y| x['name'] <=> y['name'] }
|
|
117
|
+
cbm_sort = cbm_sort.sort { |x, y| x['checksum'] <=> y['checksum'] }
|
|
118
|
+
cbm_sort.each do |file|
|
|
119
|
+
file.delete(:url)
|
|
120
|
+
file.delete(:path)
|
|
121
|
+
file.delete(:specificity)
|
|
122
|
+
end
|
|
123
|
+
c[cb][m] = cbm_sort
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
c
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def local_checksums
|
|
131
|
+
@local_checksums ||= begin
|
|
132
|
+
c = {}
|
|
133
|
+
cbl = Chef::CookbookLoader.new(Array(cookbook_dir))
|
|
134
|
+
cbl.load_cookbooks
|
|
135
|
+
cbl_sort = cbl.values.map(&:name).map(&:to_s).sort
|
|
136
|
+
|
|
137
|
+
cbl_sort.each do |cb|
|
|
138
|
+
print "#{cb} => "
|
|
139
|
+
c[cb] = {}
|
|
140
|
+
cookbook_segments.each do |m|
|
|
141
|
+
cbm_sort = cbl[cb].manifest[m].sort { |x, y| x['name'] <=> y['name'] }
|
|
142
|
+
cbm_sort = cbm_sort.sort { |x, y| x['checksum'] <=> y['checksum'] }
|
|
143
|
+
cbm_sort.each do |file|
|
|
144
|
+
file.delete(:path)
|
|
145
|
+
file.delete(:specificity)
|
|
146
|
+
end
|
|
147
|
+
c[cb][m] = cbm_sort
|
|
148
|
+
end
|
|
149
|
+
diff = diff(c[cb], remote_checksums[cb])
|
|
150
|
+
if diff.empty?
|
|
151
|
+
ui.info(ui.color( 'match', :green))
|
|
152
|
+
else
|
|
153
|
+
ui.info(ui.color( 'mismatch', :yellow))
|
|
154
|
+
ui.output(diff(c[cb], remote_checksums[cb]))
|
|
155
|
+
end
|
|
156
|
+
sleep 0.1 # was printing too fast to be useful :(
|
|
157
|
+
end
|
|
158
|
+
c
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def diff(mf1, mf2)
|
|
163
|
+
diffs = Hash.new{|h, k| h[k]= []}
|
|
164
|
+
mf2 = {} if mf2.nil?
|
|
165
|
+
mf1 = {} if mf1.nil?
|
|
166
|
+
segments = (mf1.keys + mf2.keys).sort.uniq
|
|
167
|
+
different_parts = segments.select{|segment| mf1[segment]!= mf2[segment]}
|
|
168
|
+
different_parts.each do |segment|
|
|
169
|
+
files = (Array(mf1[segment]) + Array(mf2[segment])).map{|f| f['name']}.uniq
|
|
170
|
+
files.each do |file|
|
|
171
|
+
f1 = Array(mf1[segment]).detect{|f|f['name'] == file} || {}
|
|
172
|
+
f2 = Array(mf2[segment]).detect{|f|f['name'] == file} || {}
|
|
173
|
+
unless f1['checksum'] == f2['checksum']
|
|
174
|
+
diffs[segment] << file #unless file =~ /metadata\.(rb|json)/
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
diffs
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def different_cookbook?(cb)
|
|
182
|
+
!diff(local_checksums[cb], remote_checksums[cb]).empty?
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def new_cookbooks
|
|
186
|
+
local_cookbooks - remote_cookbooks
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def stale_cookbooks
|
|
190
|
+
remote_cookbooks - local_cookbooks
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def updated_cookbooks
|
|
194
|
+
(local_cookbooks & remote_cookbooks).select do |cb|
|
|
195
|
+
different_cookbook?(cb)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def replace_cookbook(cb)
|
|
200
|
+
converge_by "Replace cookbook #{cb}" do
|
|
201
|
+
delete_cookbook(cb)
|
|
202
|
+
upload_cookbook(cb)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
# rubocop:enable Metrics/ClassLength
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Tim Heckman (<ops@pagerduty.com>)
|
|
3
|
+
# Copyright:: Copyright (c) 2016 PagerDuty, Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
module PagerDuty
|
|
19
|
+
module ChefServer
|
|
20
|
+
module SyncHelper
|
|
21
|
+
|
|
22
|
+
def ignored?(path)
|
|
23
|
+
ignore_patterns && ignore_patterns.any?{|pattern| File.fnmatch?(pattern, path)}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def converge_by(msg)
|
|
27
|
+
if why_run
|
|
28
|
+
ui.info(ui.color("Would ", :cyan)+ msg)
|
|
29
|
+
else
|
|
30
|
+
yield
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def chef_repo_dir
|
|
35
|
+
File.expand_path('..', cookbook_dir)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def role_dir
|
|
39
|
+
File.join(chef_repo_dir, 'roles')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def databag_dir
|
|
43
|
+
File.join(chef_repo_dir, 'data_bags')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def environment_dir
|
|
47
|
+
File.join(chef_repo_dir, 'environments')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def data_bag_from_file(name, path)
|
|
52
|
+
converge_by "Create data bag #{name} from #{path}" do
|
|
53
|
+
knife Chef::Knife::DataBagFromFile, name, path
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def upload_environments
|
|
58
|
+
Dir[environment_dir+'/*'].reject{|f| File.directory?(f)}.each do |path|
|
|
59
|
+
converge_by "Create environment from #{path}" do
|
|
60
|
+
knife Chef::Knife::EnvironmentFromFile, path
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def upload_roles
|
|
66
|
+
Dir[role_dir+'/*'].each do |path|
|
|
67
|
+
converge_by "Create role from #{path}" do
|
|
68
|
+
knife Chef::Knife::RoleFromFile, path
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def upload_all_cookbooks
|
|
74
|
+
converge_by 'Upload all cookbooks' do
|
|
75
|
+
knife(Chef::Knife::CookbookUpload) do |config|
|
|
76
|
+
config[:all] = true
|
|
77
|
+
config[:cookbook_path] = cookbook_dir
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def upload_cookbook(cb)
|
|
83
|
+
converge_by "Upload cookbook #{cb}" do
|
|
84
|
+
knife(Chef::Knife::CookbookUpload, cb) do |config|
|
|
85
|
+
config[:cookbook_path] = cookbook_dir
|
|
86
|
+
config[:depends] = false
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def upload_cookbooks(cbcb)
|
|
92
|
+
sorted_cookbooks = cbcb.sort # definite order + nice printout for why_run
|
|
93
|
+
converge_by "Upload cookbooks #{sorted_cookbooks.join(', ')}" do
|
|
94
|
+
knife Chef::Knife::CookbookUpload, *sorted_cookbooks do |config|
|
|
95
|
+
config[:cookbook_path] = cookbook_dir
|
|
96
|
+
config[:depends] = false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def delete_cookbook(cb)
|
|
102
|
+
converge_by "Delete cookbook #{cb}" do
|
|
103
|
+
knife Chef::Knife::CookbookDelete, cb do |config|
|
|
104
|
+
config[:yes] = true
|
|
105
|
+
config[:all] = true
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def upload_databags
|
|
111
|
+
ui.info(ui.color('updating data bags in batch mode', :yellow))
|
|
112
|
+
existing_databags = Chef::DataBag.list.keys
|
|
113
|
+
Dir[databag_dir+'/*'].each do |db_path|
|
|
114
|
+
if ignored?(db_path)
|
|
115
|
+
ui.info(ui.color("Ignored:", :magenta) + db_path)
|
|
116
|
+
next
|
|
117
|
+
end
|
|
118
|
+
db_name = File.basename(db_path)
|
|
119
|
+
unless existing_databags.include?(db_name)
|
|
120
|
+
create_databag(db_name)
|
|
121
|
+
end
|
|
122
|
+
Dir[db_path+'/*'].each do |path|
|
|
123
|
+
unless ignored?(path)
|
|
124
|
+
data_bag_from_file(File.basename(db_path), path)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create_databag(data_bag_name)
|
|
131
|
+
converge_by "Create data bag #{data_bag_name}" do
|
|
132
|
+
knife Chef::Knife::DataBagCreate, data_bag_name
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def data_bag_from_hash(databag_name, data)
|
|
137
|
+
tmp = Tempfile.new(['restorechef', '.json'])
|
|
138
|
+
begin
|
|
139
|
+
tmp.write(JSON.dump(data))
|
|
140
|
+
tmp.close
|
|
141
|
+
converge_by "create data bag #{databag_name}" do
|
|
142
|
+
data_bag_from_file(databag_name, tmp.path)
|
|
143
|
+
end
|
|
144
|
+
ensure
|
|
145
|
+
tmp.unlink
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def knife(klass, *name_args)
|
|
150
|
+
klass.load_deps
|
|
151
|
+
plugin = klass.new
|
|
152
|
+
yield plugin.config if Kernel.block_given?
|
|
153
|
+
plugin.name_args = name_args
|
|
154
|
+
plugin.run
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ignore_file
|
|
158
|
+
File.join(chef_repo_dir, '.pd-ignore')
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Tim Heckman (<ops@pagerduty.com>)
|
|
3
|
+
# Copyright:: Copyright (c) 2016 PagerDuty, Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require 'fileutils'
|
|
19
|
+
require 'chef/knife'
|
|
20
|
+
|
|
21
|
+
module PagerDuty
|
|
22
|
+
module ChefServer
|
|
23
|
+
class LockUnavailable < IOError; end
|
|
24
|
+
class ChefCronRunning < StandardError; end
|
|
25
|
+
|
|
26
|
+
class SyncLock
|
|
27
|
+
def initialize(lockfile, server_hostname, local_hostname, user, branch, force_lock = false)
|
|
28
|
+
@lockfile = lockfile
|
|
29
|
+
@server_hostname = server_hostname.include?('.') ? server_hostname.split('.')[0] : server_hostname
|
|
30
|
+
@local_hostname = local_hostname
|
|
31
|
+
@user = user
|
|
32
|
+
@branch = branch
|
|
33
|
+
@opts = parse_opts({ announce: true, lock: true, force: force_lock })
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# get lock
|
|
37
|
+
def lock(time = Time.now)
|
|
38
|
+
verify_lockable
|
|
39
|
+
|
|
40
|
+
@f_lock = procure_lock if @opts[:lock] || @opts[:force]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# remove lock
|
|
44
|
+
def unlock
|
|
45
|
+
if @opts[:lock]
|
|
46
|
+
Chef::Knife.ui.info 'removing lockfile'
|
|
47
|
+
@f_lock.flock(File::LOCK_UN)
|
|
48
|
+
@f_lock.close
|
|
49
|
+
FileUtils.rm(@f_lock.path)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def verify_lockable
|
|
56
|
+
unless local_chef_server? && @opts[:force]
|
|
57
|
+
@opts[:lock] = false
|
|
58
|
+
Chef::Knife.ui.warn(
|
|
59
|
+
'Please be careful, this looks to be running on a system other than a chef server. '\
|
|
60
|
+
'As such, there will be *no* locking. Hold on to your butts...'
|
|
61
|
+
)
|
|
62
|
+
sleep 5
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def parse_opts(options)
|
|
67
|
+
options[:announce] &&= false unless remote_chef_server?
|
|
68
|
+
options[:lock] &&= false unless local_chef_server?
|
|
69
|
+
options
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def local_chef_server?
|
|
73
|
+
@local_hostname.include? 'chef'
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def remote_chef_server?
|
|
77
|
+
@server_hostname.include? 'chef'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def procure_lock
|
|
81
|
+
Chef::Knife.ui.info 'trying to obtain exclusive lock...'
|
|
82
|
+
|
|
83
|
+
# create a file handle for the lockfile -- create if it doesn't exist and
|
|
84
|
+
# make it read/write
|
|
85
|
+
lf = File.open(@lockfile, File::CREAT|File::RDWR, 0644)
|
|
86
|
+
|
|
87
|
+
unless lf.flock(File::LOCK_NB|File::LOCK_EX)
|
|
88
|
+
# if we fail to obtain the lock figure out who has lock and for
|
|
89
|
+
# how long so we can display that information
|
|
90
|
+
ld = JSON.parse(lf.read.strip)
|
|
91
|
+
msg = if (ld['user'].strip == @user)
|
|
92
|
+
"according to lockfile you've had lock for" \
|
|
93
|
+
" #{Time.now.to_i - ld['ts']} second(s)."
|
|
94
|
+
else
|
|
95
|
+
"unable to get exclusive lock, currently held by" \
|
|
96
|
+
" #{ld['user']} for #{Time.now.to_i - ld['ts']} second(s)" \
|
|
97
|
+
end
|
|
98
|
+
# close the file handle
|
|
99
|
+
lf.close
|
|
100
|
+
Chef::Knife.ui.fatal msg
|
|
101
|
+
raise LockUnavailable, msg
|
|
102
|
+
end
|
|
103
|
+
# we could get lock, so write our information to the file
|
|
104
|
+
lf.write(JSON.dump({ user: @user, ts: Time.now.to_i }))
|
|
105
|
+
lf.flush
|
|
106
|
+
Chef::Knife.ui.info 'lock obtained'
|
|
107
|
+
lf
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
Gem::Specification.new do |spec|
|
|
3
|
+
spec.name = 'pagerduty-pd_sync'
|
|
4
|
+
spec.version = '0.1.1'
|
|
5
|
+
spec.authors = ['Tim Heckman']
|
|
6
|
+
spec.email = ['ops+pd_sync@pagerduty.com']
|
|
7
|
+
spec.licenses = ['Apache 2.0']
|
|
8
|
+
|
|
9
|
+
spec.summary = 'A knife plugin to support the PagerDuty Chef workflow'
|
|
10
|
+
spec.description = 'A knife plugin to support the PagerDuty Chef workflow'
|
|
11
|
+
spec.homepage = 'https://github.com/PagerDuty/pd-sync-chef'
|
|
12
|
+
|
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
14
|
+
spec.require_paths = ['lib']
|
|
15
|
+
|
|
16
|
+
spec.required_ruby_version = '>= 2.1.4'
|
|
17
|
+
|
|
18
|
+
spec.add_runtime_dependency 'chef', '~> 12'
|
|
19
|
+
spec.add_runtime_dependency 'berkshelf', '~> 0'
|
|
20
|
+
spec.add_runtime_dependency 'json', '~> 0'
|
|
21
|
+
|
|
22
|
+
spec.add_development_dependency 'bundler', '~> 0'
|
|
23
|
+
spec.add_development_dependency 'pry', '~> 0'
|
|
24
|
+
spec.add_development_dependency 'rake', '~> 0'
|
|
25
|
+
spec.add_development_dependency 'rspec', '~> 0'
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pagerduty-pd_sync
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tim Heckman
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: chef
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '12'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '12'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: berkshelf
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: json
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: bundler
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: pry
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rake
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
description: A knife plugin to support the PagerDuty Chef workflow
|
|
112
|
+
email:
|
|
113
|
+
- ops+pd_sync@pagerduty.com
|
|
114
|
+
executables: []
|
|
115
|
+
extensions: []
|
|
116
|
+
extra_rdoc_files: []
|
|
117
|
+
files:
|
|
118
|
+
- ".gitignore"
|
|
119
|
+
- Gemfile
|
|
120
|
+
- Gemfile.lock
|
|
121
|
+
- Rakefile
|
|
122
|
+
- lib/chef/knife/pd_sync.rb
|
|
123
|
+
- lib/pagerduty/chef_server/sync.rb
|
|
124
|
+
- lib/pagerduty/chef_server/sync_helper.rb
|
|
125
|
+
- lib/pagerduty/chef_server/synclock.rb
|
|
126
|
+
- pagerduty-pd_sync.gemspec
|
|
127
|
+
homepage: https://github.com/PagerDuty/pd-sync-chef
|
|
128
|
+
licenses:
|
|
129
|
+
- Apache 2.0
|
|
130
|
+
metadata: {}
|
|
131
|
+
post_install_message:
|
|
132
|
+
rdoc_options: []
|
|
133
|
+
require_paths:
|
|
134
|
+
- lib
|
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - ">="
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: 2.1.4
|
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '0'
|
|
145
|
+
requirements: []
|
|
146
|
+
rubyforge_project:
|
|
147
|
+
rubygems_version: 2.2.2
|
|
148
|
+
signing_key:
|
|
149
|
+
specification_version: 4
|
|
150
|
+
summary: A knife plugin to support the PagerDuty Chef workflow
|
|
151
|
+
test_files: []
|