puppet_webhook 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -2
- data/README.md +107 -57
- data/bin/puppet_webhook +95 -27
- data/config/app.yml +10 -9
- data/lib/helpers/data_parsers.rb +4 -0
- data/lib/helpers/deployments.rb +4 -4
- data/lib/helpers/tasks.rb +16 -25
- data/lib/parsers/webhook_json_parser.rb +7 -19
- data/lib/puppet_webhook.rb +30 -130
- data/lib/routes/default.rb +18 -0
- data/lib/routes/module.rb +28 -0
- data/lib/routes/payload.rb +70 -0
- metadata +21 -5
- data/config/server.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a2bedbab06ccd3b043abda7e4e3c4711f90bae1fcc6cc102c283c63c517f783
|
4
|
+
data.tar.gz: b609d99c486ef605836756939f1ff33ae40056b38641d13c2665b33ecbd56093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cd5c13d66c1fef5b8eda9c5768e5ecc216cb24617cdd04ec07e0655213b543561074aec522790b394879e3906cd8835896d8bdf7abaffb265ade893cb2496ff
|
7
|
+
data.tar.gz: d3870a2daffca879005cac928fa0fbe46a4c65c7d3594fb12a8333d9394afc2fb5e181027e45a57dfea6505ceb92e1369587aefe4dc4abe49a3025a4fd9d988f
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,33 @@
|
|
1
|
-
#
|
1
|
+
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
Each new release typically also includes the latest modulesync defaults.
|
5
|
+
These should not affect the functionality of the module.
|
4
6
|
|
7
|
+
## [v1.0.0](https://github.com/voxpupuli/puppet_webhook/tree/v1.0.0) (2017-12-21)
|
8
|
+
[Full Changelog](https://github.com/voxpupuli/puppet_webhook/compare/v0.1.0...v1.0.0)
|
9
|
+
|
10
|
+
**Implemented enhancements:**
|
11
|
+
|
12
|
+
- \(\#puppethack\) Add cli binary [\#40](https://github.com/voxpupuli/puppet_webhook/pull/40) ([dhollinger](https://github.com/dhollinger))
|
13
|
+
|
14
|
+
**Closed issues:**
|
15
|
+
|
16
|
+
- Move all routes into a routes/ directory [\#26](https://github.com/voxpupuli/puppet_webhook/issues/26)
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Update config options and docs [\#41](https://github.com/voxpupuli/puppet_webhook/pull/41) ([dhollinger](https://github.com/dhollinger))
|
21
|
+
- Fix payload gentypes [\#39](https://github.com/voxpupuli/puppet_webhook/pull/39) ([dhollinger](https://github.com/dhollinger))
|
22
|
+
- Add simple config.ru file [\#38](https://github.com/voxpupuli/puppet_webhook/pull/38) ([dhollinger](https://github.com/dhollinger))
|
23
|
+
- Switch to using rack-bodyparser [\#36](https://github.com/voxpupuli/puppet_webhook/pull/36) ([alexjfisher](https://github.com/alexjfisher))
|
24
|
+
- Move routes into a routes directory [\#35](https://github.com/voxpupuli/puppet_webhook/pull/35) ([dhollinger](https://github.com/dhollinger))
|
25
|
+
- Fix generate\_types typo [\#34](https://github.com/voxpupuli/puppet_webhook/pull/34) ([alexjfisher](https://github.com/alexjfisher))
|
26
|
+
- Fix Code Climate badges [\#33](https://github.com/voxpupuli/puppet_webhook/pull/33) ([alexjfisher](https://github.com/alexjfisher))
|
27
|
+
- Add reporting to CodeClimate and associated badges [\#32](https://github.com/voxpupuli/puppet_webhook/pull/32) ([alexjfisher](https://github.com/alexjfisher))
|
28
|
+
- Report coverage to Codacy and add badge [\#31](https://github.com/voxpupuli/puppet_webhook/pull/31) ([alexjfisher](https://github.com/alexjfisher))
|
29
|
+
|
30
|
+
## [v0.1.0](https://github.com/voxpupuli/puppet_webhook/tree/v0.1.0) (2017-11-17)
|
5
31
|
**Implemented enhancements:**
|
6
32
|
|
7
33
|
- Cleanup config loader [\#2](https://github.com/voxpupuli/puppet_webhook/issues/2)
|
@@ -13,6 +39,7 @@
|
|
13
39
|
|
14
40
|
**Merged pull requests:**
|
15
41
|
|
42
|
+
- Development release 0.1.0 [\#24](https://github.com/voxpupuli/puppet_webhook/pull/24) ([dhollinger](https://github.com/dhollinger))
|
16
43
|
- Add rubygems deploy to travis [\#23](https://github.com/voxpupuli/puppet_webhook/pull/23) ([dhollinger](https://github.com/dhollinger))
|
17
44
|
- Fix TFS checks and add more fixtures/tests [\#22](https://github.com/voxpupuli/puppet_webhook/pull/22) ([dhollinger](https://github.com/dhollinger))
|
18
45
|
- Fix README badges after project rename [\#21](https://github.com/voxpupuli/puppet_webhook/pull/21) ([dhollinger](https://github.com/dhollinger))
|
data/README.md
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
[![Build Status](https://img.shields.io/travis/voxpupuli/puppet_webhook.svg)](https://travis-ci.org/voxpupuli/puppet_webhook)
|
5
5
|
[![Gem Version](https://img.shields.io/gem/v/puppet_webhook.svg)](https://rubygems.org/gems/puppet_webhook)
|
6
6
|
[![Gem Downloads](https://img.shields.io/gem/dt/puppet_webhook.svg)](https://rubygems.org/gems/puppet_webhook)
|
7
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/f4f083a54a85f4cc97f0/maintainability)](https://codeclimate.com/github/voxpupuli/puppet_webhook/maintainability)
|
8
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/f4f083a54a85f4cc97f0/test_coverage)](https://codeclimate.com/github/voxpupuli/puppet_webhook/test_coverage)
|
9
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f73823762ec947889866c63c4ea47540)](https://www.codacy.com/app/VoxPupuli/puppet_webhook?utm_source=github.com&utm_medium=referral&utm_content=voxpupuli/puppet_webhook&utm_campaign=Badge_Grade)
|
7
10
|
[![Coverage Status](https://coveralls.io/repos/github/voxpupuli/puppet_webhook/badge.svg?branch=master)](https://coveralls.io/github/voxpupuli/puppet_webhook?branch=master)
|
8
11
|
[![Dependency Status](https://gemnasium.com/badges/github.com/voxpupuli/puppet_webhook.svg)](https://gemnasium.com/github.com/voxpupuli/puppet_webhook)
|
9
12
|
|
@@ -12,11 +15,6 @@
|
|
12
15
|
puppet_webhook is a Sinatra-based application receiving REST-based calls to trigger Puppet and r10k-related tasks such as:
|
13
16
|
|
14
17
|
* Webhooks from Source Code systems to trigger r10k environment and module deploys
|
15
|
-
* REST calls from systems to trigger Puppet Decommissions such as:
|
16
|
-
* `puppet node clean`
|
17
|
-
* `puppet cert clean`
|
18
|
-
* `puppet cert revoke`
|
19
|
-
* etc.
|
20
18
|
* Send notifications via Slack
|
21
19
|
|
22
20
|
## Prerequisites
|
@@ -39,12 +37,24 @@ NOTE: RPM, DEB, and Arch packages are planned for future releases.
|
|
39
37
|
|
40
38
|
### Running puppet_webhook
|
41
39
|
|
42
|
-
|
40
|
+
#### Quick Start
|
43
41
|
|
44
|
-
|
45
|
-
You can also set the `server_type` option in `/etc/puppet_webhook/server.yml` to `daemon` to run the application in the background. By default the application will log to `/var/log/puppet_webhook/access.log`.
|
42
|
+
Simply run `# puppet_webhook` after installation to start puppet_webhook in non-daemon mode on your system. This is great for testing the server out.
|
46
43
|
|
47
|
-
|
44
|
+
#### CLI Tool
|
45
|
+
|
46
|
+
The `puppet_webhook` CLI command has several options you can pass it as well.
|
47
|
+
|
48
|
+
To see these options run `# puppet_webook -h` in your terminal to see all the options.
|
49
|
+
|
50
|
+
#### Start using Rack-based server software
|
51
|
+
|
52
|
+
A `config.ru` file is also packaged with the application to provide users with the ability to start the app using their own rack-based server such as
|
53
|
+
unicorn or puma. It will use the defaults passed to it by said server.
|
54
|
+
|
55
|
+
#### Service Start
|
56
|
+
|
57
|
+
Once the native packages are built, they will include default systemd and/or sysvinit service files that you can use to start puppet_webhook as well.
|
48
58
|
|
49
59
|
### Configuring puppet_webhook
|
50
60
|
|
@@ -56,154 +66,194 @@ Any configuration option is placed in `/etc/puppet_webhook/server.yml` or `/etc/
|
|
56
66
|
|
57
67
|
#### Configuration options
|
58
68
|
|
59
|
-
####
|
69
|
+
#### Command-Line Options
|
70
|
+
|
71
|
+
* `-h, --help`: Display the default help output.
|
72
|
+
* `-d, --debug`: Set logging to debug mode.
|
73
|
+
* `-l [LOGFILE], --logfile [LOGFILE]`: Define a logfile to log to.
|
74
|
+
* `-p PORT, --port PORT`: Define port to listen on. Default: `8088`
|
75
|
+
* `-D, --daemon`: Run WEBrick in Daemon mode.
|
76
|
+
* `--pidfile FILE`: Define the PID File for the application's process. Default: `/var/run/puppet_webhook/webhook.pid`
|
77
|
+
* `--ssl`: Enable SSL Support.
|
78
|
+
* `--ssl-cert FILE`: Specify the SSL cert to use. Pair with `--ssl-key`. Requires `--ssl` option or `ssl_enable: true` in config file.
|
79
|
+
* `--ssl-key FILE`: Specify the SSL Private key to use. Pair with `--ssl-cert`. Requires `--ssl` or `ssl_enable: true` in config file.
|
80
|
+
* `-c FILE, --configfile FILE`: Specifies a config file to use. Must be a `.yml` file in YAML format.
|
81
|
+
|
82
|
+
|
83
|
+
#### Server Configuration File
|
84
|
+
|
85
|
+
The Server configuration file is a YAML formatted file with file extension `.yml` and defined with the `-c` or `--configfile`
|
86
|
+
command line option. These settings are exclusively for setting server configs and currently will override any command line settings
|
87
|
+
passed.
|
88
|
+
|
89
|
+
When using the default SystemD unit file or SysVInit service file, the server configuration file will default to `/etc/puppet_webhook/server.yml` (Not implemented yet).
|
90
|
+
|
91
|
+
##### Options
|
60
92
|
|
61
93
|
#####`server_type`
|
94
|
+
|
62
95
|
Determines if the Webrick server should run in Simple or Daemon mode.
|
63
96
|
* Valid options: [ `simple`, `daemon` ].
|
64
97
|
* Default: `simple`
|
65
98
|
|
66
99
|
##### `logfile`
|
100
|
+
|
67
101
|
Location to write the log file to.
|
68
|
-
* Default: `/var/log/puppet_webhook
|
102
|
+
* Default: `/var/log/puppet_webhook`
|
69
103
|
|
70
|
-
##### `
|
71
|
-
Location of the application's PID file
|
72
|
-
* Default: `/var/run/puppet_webhook/webhook.pid`
|
104
|
+
##### `loglevel`
|
73
105
|
|
74
|
-
|
75
|
-
|
76
|
-
* Default: `/var/run/puppet_webhook/webhook.lock`
|
106
|
+
Define the logging level.
|
107
|
+
* Default: `WARN`
|
77
108
|
|
78
|
-
##### `
|
79
|
-
Location of the Root of the application's directory
|
80
|
-
* Default: `./`
|
81
|
-
NOTE: Currently unused
|
109
|
+
##### `pidfile`
|
82
110
|
|
83
|
-
|
84
|
-
|
85
|
-
* MUST BE VALID IPv4 ADDRESS.
|
86
|
-
* Default: `0.0.0.0`
|
111
|
+
Location of the application's PID file
|
112
|
+
* Default: `/var/run/puppet_webhook/webhook.pid`
|
87
113
|
|
88
114
|
##### `port`
|
115
|
+
|
89
116
|
Port number to bind to.
|
90
117
|
* Valid options: Integer between `1024` and `65535`
|
91
118
|
* Default: `8088`
|
92
119
|
|
93
120
|
##### `enable_ssl`
|
121
|
+
|
94
122
|
Whether or not to enable SSL communication.
|
95
123
|
* Valid options: [ `true`, `false` ]
|
96
124
|
* Default: `false`
|
97
125
|
|
98
|
-
##### `
|
126
|
+
##### `ssl_verify`
|
127
|
+
|
99
128
|
Whether or not to verify the SSL CA/Peer on the certifcate. Set to false if using a self-signed certificate and the CA is not installed locally.
|
100
129
|
* Valid options: [ `true`, `false` ]
|
101
130
|
* Default: `false`
|
102
131
|
|
103
|
-
##### `
|
132
|
+
##### `ssl_cert`
|
133
|
+
|
104
134
|
Path to the public SSL certificate for puppet_webhook. REQUIRED IF `ssl_enable` IS SET TO `true`
|
105
|
-
* Default: ''
|
106
135
|
|
107
|
-
##### `
|
136
|
+
##### `ssl_key`
|
137
|
+
|
108
138
|
Path to the SSL Private Key for puppet_webhook. REQUIRED IF `ssl_enable` IS SET TO `true`
|
109
|
-
* Default: ''
|
110
139
|
|
111
|
-
|
112
|
-
Command to prefix the r10k and puppet commands with when executed.
|
113
|
-
* Default: 'umask 0022;'
|
140
|
+
#### Application Configuration File
|
114
141
|
|
115
|
-
|
142
|
+
This file stores the configuration for the Application itself. A default configuration file is included in the `APP_ROOT/config/app.yml`.
|
116
143
|
|
117
|
-
|
118
|
-
|
144
|
+
The SystemD unit and SysVInit service files will use `/etc/puppet_webhook/app.yml` by default (Not implemented yet).
|
145
|
+
|
146
|
+
Currently, the above two locations are the only valid locations for the app.yml file. Like the Server Config, it must be a .yml file in YAML format.
|
147
|
+
|
148
|
+
##### Options
|
149
|
+
|
150
|
+
##### `protected`
|
151
|
+
|
152
|
+
Whether or not to require authentication when sending to puppet_webhook.
|
119
153
|
* Valid options: [ `true`, `false` ]
|
120
154
|
* Default: `false`
|
121
155
|
|
122
156
|
##### `user`
|
123
|
-
|
124
|
-
|
157
|
+
|
158
|
+
User for which the sending application must authenticate with. Required if `protected` is true.
|
125
159
|
|
126
160
|
##### `pass`
|
127
|
-
Password for which the sending application must authenticate with.
|
128
|
-
* Default: `puppet`
|
129
161
|
|
130
|
-
|
131
|
-
Whether or not to require authentication when sending to puppet_webhook.
|
132
|
-
* Valid options: [ `true`, `false` ]
|
133
|
-
* Default: `true`
|
162
|
+
Password for which the sending application must authenticate with. Require if `protected` is true.
|
134
163
|
|
135
164
|
##### client_cfg
|
165
|
+
|
136
166
|
Mcollective client configuration file.
|
137
167
|
* Default: `/var/lib/peadmin/.mcollective`
|
138
168
|
|
139
169
|
##### client_timeout
|
170
|
+
|
140
171
|
Mcollective client timeout in seconds.
|
141
172
|
* MUST BE A STRING
|
142
173
|
* Default: `"120"`
|
143
174
|
|
144
175
|
##### use_mco_ruby
|
176
|
+
|
145
177
|
Whether or not to execute MCollective via Ruby Client Library or not. REQUIRES MCOLLECTIVE AND MCOLLECTIVE R10K!
|
146
178
|
* Valid options: [ `true`, `false` ]
|
147
179
|
* Default: `false`
|
148
180
|
|
149
|
-
##### discovery_timeout
|
150
|
-
MCollective Ruby discovery timeout. REQUIRES `use_mco_ruby` TO BE `true`.
|
151
|
-
* Default: `'10'`
|
152
|
-
|
153
181
|
##### use_mcollective
|
182
|
+
|
154
183
|
Whether or not to use MCollective CLI command. REQUIRES MCOLLECTIVE AND MCOLLECTIVE R10K.
|
155
184
|
* Valid options: [ `true`, `false` ]
|
156
185
|
* Default: `false`
|
157
186
|
|
187
|
+
##### discovery_timeout
|
188
|
+
|
189
|
+
MCollective Ruby discovery timeout. REQUIRES `use_mco_ruby` TO BE `true`.
|
190
|
+
* Default: `'10'`
|
191
|
+
|
158
192
|
##### slack_webhook
|
193
|
+
|
159
194
|
Whether or not to use Slack Notifications.
|
160
195
|
* Valid options: [ `true`, `false` ]
|
161
196
|
* Default: `false`
|
162
197
|
|
163
|
-
##### slack_channel
|
164
|
-
Slack channel to notify.
|
165
|
-
* Default: `'#default'`
|
166
|
-
|
167
|
-
##### slack_user
|
168
|
-
Slack user to notify as.
|
169
|
-
* Default: `'r10k'`
|
170
|
-
|
171
198
|
##### slack_proxy_url
|
199
|
+
|
172
200
|
The proxy URL for Slack if used.
|
173
201
|
* MUST BE A VALID URL.
|
174
202
|
* Default: `nil`
|
175
203
|
|
176
204
|
##### default_branch
|
205
|
+
|
177
206
|
The default git branch to use with the r10k Control Repo.
|
178
207
|
* Default: `production`
|
179
208
|
|
180
209
|
##### ignore_environment
|
210
|
+
|
181
211
|
An Array of environments for r10k to ignore during deployment.
|
182
212
|
* Default: []
|
183
213
|
|
184
214
|
##### prefix
|
215
|
+
|
185
216
|
r10k Environment Prefix to use. When set to `repo`, `user`, or `command`, the prefix will be generated from the repo_name, repo_user, or `prefix_command`. Otherwise it will set the prefix to the passed string. `false` disables prefix.
|
186
217
|
* Valid Options: [ `repo`, `user`, `command`, `<String_value>`, `false` ]
|
187
|
-
* Default: `
|
218
|
+
* Default: `nil`
|
188
219
|
|
189
220
|
##### prefix_command
|
221
|
+
|
190
222
|
Command to execute that will generate an r10k environment prefix.
|
191
223
|
* Default: ''
|
192
224
|
|
193
225
|
##### r10k_deploy_arguments
|
226
|
+
|
194
227
|
r10k command arguments to pass to the `r10k deploy environment` command.
|
195
228
|
* Default: `"-pv"`
|
196
229
|
|
197
230
|
##### allow_uppercase
|
231
|
+
|
198
232
|
Whether or not to allow uppercase letters in environment names. If false, then puppet_webhook assumes environment names are downcase. If `true`, then puppet_webhook will normalize the environment name.
|
199
233
|
* Valid options: [ `true`, `false` ]
|
200
234
|
* Default: `true`
|
201
235
|
|
202
236
|
##### github_secret
|
237
|
+
|
203
238
|
Used to verify the signature on a repo. Currently only supported for Github repos.
|
204
239
|
* MUST BE A VALID OPENSSL `sha1` HASH.
|
205
240
|
* Default: `nil`
|
206
241
|
|
207
242
|
##### repository_events
|
243
|
+
|
208
244
|
Array of webhook events to ignore.
|
209
245
|
* Default: `nil`
|
246
|
+
|
247
|
+
## Getting Help
|
248
|
+
|
249
|
+
* IRC: Vox Pupuli has a dedicated channel, `#voxpupuli`, on Freenode where `puppet_webhook` questions can be directed.
|
250
|
+
* Mailing Lists: [voxpupuli](https://groups.io/g/voxpupuli)
|
251
|
+
* Slack: Vox Pupuli has a dedicated Slack Channel, `#voxpupuli`, on the [Puppet Community](https://slack.puppet.com/) Slack.
|
252
|
+
|
253
|
+
## Contributors
|
254
|
+
|
255
|
+
A big thank you to all our [Contributor](https://github.com/voxpupuli/puppet_webhook/graphs/contributors)
|
256
|
+
|
257
|
+
## License
|
258
|
+
|
259
|
+
See LICENSE
|
data/bin/puppet_webhook
CHANGED
@@ -1,43 +1,111 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'openssl'
|
3
|
-
require '
|
4
|
-
require 'sinatra/config_file'
|
3
|
+
require 'optparse'
|
5
4
|
require 'webrick'
|
6
5
|
require 'webrick/https'
|
7
6
|
require 'puppet_webhook'
|
8
7
|
|
9
|
-
|
8
|
+
approot = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
9
|
+
options = {
|
10
|
+
host: '0.0.0.0',
|
11
|
+
port: '8088',
|
12
|
+
logfile: $stderr,
|
13
|
+
loglevel: WEBrick::Log::WARN,
|
14
|
+
server_type: WEBrick::SimpleServer
|
15
|
+
}
|
16
|
+
|
17
|
+
ssl_opts = { ssl_verify: false }
|
18
|
+
|
19
|
+
optparse = OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
|
20
|
+
opts.banner = 'Usage: puppet_webhook [-p <port>] [-l <logfile>] [-d]
|
21
|
+
-- Starts the Puppet Webhook API service.
|
22
|
+
|
23
|
+
'
|
24
|
+
|
25
|
+
opts.on('-d', '--debug', 'Display or log messages.') do
|
26
|
+
options[:loglevel] = WEBrick::Log::DEBUG
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('-l [LOGFILE]', '--logfile [LOGFILE]',
|
30
|
+
'Path to logfile. Defaults to no logging, or /var/log/puppet_webhook if no filename is passed.') do |arg|
|
31
|
+
options[:logfile] = arg || '/var/log/puppet_webhook'
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on('-p PORT', '--port PORT', 'Port to listen on. Defaults to 8088.') do |arg|
|
35
|
+
options[:port] = arg
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on('-D', '--daemon', 'Run the server in daemon mode. Defaults to simple if not passed') do
|
39
|
+
options[:server_type] = WEBrick::Daemon
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on('--pidfile FILE', 'Specify the PID file to use.') do |arg|
|
43
|
+
options[:pidfile] = arg || '/var/run/puppet_webhook/webhook.pid'
|
44
|
+
end
|
10
45
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
COMMAND_PREFIX = settings.command_prefix
|
15
|
-
LOGGER = WEBrick::Log.new(settings.logfile, WEBrick::Log::DEBUG)
|
46
|
+
opts.on('--ssl', 'Enable SSL Support.') do
|
47
|
+
ssl_opts[:enable_ssl] = true
|
48
|
+
end
|
16
49
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
50
|
+
opts.on('--ssl-cert FILE', 'Specify the SSL cert to use. Pair with --ssl-key.') do |arg|
|
51
|
+
ssl_opts[:ssl_cert] = OpenSSL::X509::Certificate.new(File.open(arg).read)
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on('--ssl-key FILE', 'Specify the SSL key to use. Pair with --ssl-cert.') do |arg|
|
55
|
+
ssl_opts[:ssl_key] = OpenSSL::PKey::RSA.new(File.open(arg))
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on('-c FILE', '--configfile FILE', 'Specifies a configuration file to use.') do |arg|
|
59
|
+
@server_config = arg
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.separator('')
|
63
|
+
|
64
|
+
opts.on('-h', '--help') do
|
65
|
+
puts
|
66
|
+
puts opts
|
67
|
+
puts
|
68
|
+
exit
|
69
|
+
end
|
22
70
|
end
|
23
71
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
72
|
+
optparse.parse!
|
73
|
+
|
74
|
+
if @server_config
|
75
|
+
config_file(@server_config)
|
76
|
+
if settings.respond_to? :server_type=
|
77
|
+
options[:server_type] = WEBrick::Daemon if settings.server_type == 'daemon'
|
78
|
+
end
|
79
|
+
options[:host] = settings.host if settings.respond_to? :host=
|
80
|
+
options[:port] = settings.port if settings.respond_to? :port=
|
81
|
+
options[:pidfile] = settings.pidfile if settings.respond_to? :pidfile=
|
82
|
+
options[:logfile] = settings.logfile if settings.respond_to? :logfile=
|
83
|
+
options[:loglevel] = settings.loglevel if settings.respond_to? :loglevel=
|
84
|
+
ssl_opts[:enable_ssl] = settings.enable_ssl if settings.respond_to? :enable_ssl=
|
85
|
+
ssl_opts[:ssl_verify] = settings.ssl_verify if settings.respond_to? :ssl_verify=
|
86
|
+
ssl_opts[:ssl_cert] = settings.ssl_cert if settings.respond_to? :ssl_cert=
|
87
|
+
ssl_opts[:ssl_key] = settings.enable_ssl if settings.respond_to? :ssl_key=
|
88
|
+
end
|
89
|
+
|
90
|
+
LOGGER = WEBrick::Log.new(options[:logfile], options[:loglevel])
|
91
|
+
|
92
|
+
webrick_opts = {
|
93
|
+
Host: options[:host],
|
94
|
+
Port: options[:port],
|
95
|
+
DocumentRoot: approot,
|
96
|
+
ServerType: options[:server_type],
|
97
|
+
ServerSoftware: PuppetWebhook,
|
98
|
+
StartCallBack: proc { File.open(options[:pidfile], 'w') { |f| f.write Process.pid } }
|
32
99
|
}
|
33
100
|
|
34
|
-
if
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
101
|
+
if ssl_opts[:enable_ssl]
|
102
|
+
webrick_opts[:SSLEnable] = ssl_opts[:enable_ssl]
|
103
|
+
webrick_opts[:SSLVerifyClient] = ssl_opts[:ssl_verify]
|
104
|
+
webrick_opts[:SSLCertificate] = ssl_opts[:ssl_cert]
|
105
|
+
webrick_opts[:SSLPrivateKey] = ssl_opts[:ssl_key]
|
106
|
+
webrick_opts[:SSLCertName] = [['CN', WEBrick::Utils.getservername]]
|
39
107
|
end
|
40
108
|
|
41
|
-
Rack::Handler::WEBrick.run(PuppetWebhook,
|
109
|
+
Rack::Handler::WEBrick.run(PuppetWebhook, webrick_opts) do |server|
|
42
110
|
%i[INT TERM].each { |sig| trap(sig) { server.stop } }
|
43
111
|
end
|
data/config/app.yml
CHANGED
@@ -1,21 +1,22 @@
|
|
1
|
-
|
1
|
+
# Authentication
|
2
|
+
protected: true
|
2
3
|
user: puppet
|
3
4
|
pass: puppet
|
4
|
-
|
5
|
+
|
6
|
+
# Mcollective
|
5
7
|
client_cfg: "/var/lib/peadmin/.mcollective"
|
6
8
|
client_timeout: "120"
|
7
9
|
use_mco_ruby: false
|
8
10
|
use_mcollective: false
|
11
|
+
discovery_timeout: '10'
|
12
|
+
|
13
|
+
# Slack Notifications
|
9
14
|
slack_webhook: false
|
10
|
-
|
11
|
-
|
12
|
-
slack_proxy_url: ~
|
15
|
+
|
16
|
+
# R10k
|
13
17
|
default_branch: production
|
14
|
-
discovery_timeout: '10'
|
15
18
|
ignore_environments: []
|
16
|
-
prefix: ~
|
17
19
|
prefix_command: ''
|
18
20
|
r10k_deploy_arguments: "-pv"
|
19
21
|
allow_uppercase: true
|
20
|
-
|
21
|
-
repository_events: ~
|
22
|
+
command_prefix: 'umask 0022;'
|
data/lib/helpers/data_parsers.rb
CHANGED
@@ -15,4 +15,8 @@ module DataParsers # rubocop:disable Style/Documentation
|
|
15
15
|
signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), settings.github_secret, payload_body)
|
16
16
|
throw(:halt, [500, "Signatures didn't match!\n"]) unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE'])
|
17
17
|
end
|
18
|
+
|
19
|
+
def payload
|
20
|
+
env['parsed_body']
|
21
|
+
end
|
18
22
|
end
|
data/lib/helpers/deployments.rb
CHANGED
@@ -7,10 +7,10 @@ module Deployments # rubocop:disable Style/Documentation
|
|
7
7
|
message = result.results[:statusmsg]
|
8
8
|
else
|
9
9
|
command = if settings.use_mcollective
|
10
|
-
"#{
|
10
|
+
"#{settings.command_prefix} mco r10k deploy #{branch} #{settings.mco_arguments}"
|
11
11
|
else
|
12
12
|
# If you don't use mcollective then this hook needs to be running as r10k's user i.e. root
|
13
|
-
"#{
|
13
|
+
"#{settings.command_prefix} r10k deploy environment #{branch} #{settings.r10k_deploy_arguments}"
|
14
14
|
end
|
15
15
|
message = run_command(command)
|
16
16
|
end
|
@@ -31,9 +31,9 @@ module Deployments # rubocop:disable Style/Documentation
|
|
31
31
|
|
32
32
|
def deploy_module(module_name)
|
33
33
|
command = if settings.use_mcollective
|
34
|
-
"#{
|
34
|
+
"#{settings.command_prefix} mco r10k deploy_module #{module_name} #{settings.mco_arguments}"
|
35
35
|
else
|
36
|
-
"#{
|
36
|
+
"#{settings.command_prefix} r10k deploy module #{module_name}"
|
37
37
|
end
|
38
38
|
message = run_command(command)
|
39
39
|
LOGGER.info("message: #{message} module_name: #{module_name}")
|
data/lib/helpers/tasks.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'slack-notifier'
|
3
3
|
require 'mcollective'
|
4
|
-
include MCollective::RPC
|
5
4
|
|
6
5
|
module Tasks # rubocop:disable Style/Documentation
|
6
|
+
include MCollective::RPC
|
7
|
+
|
7
8
|
def ignore_env?(env)
|
8
9
|
list = settings.ignore_environments
|
9
10
|
return false if list.nil? || list.empty?
|
@@ -46,28 +47,20 @@ module Tasks # rubocop:disable Style/Documentation
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def run_command(command)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
if Open3.respond_to?('capture3')
|
57
|
-
stdout, stderr, exit_status = Open3.capture3(command)
|
58
|
-
message = "triggered: #{command}\n#{stdout}\n#{stderr}"
|
59
|
-
else
|
60
|
-
message = "forked: #{command}"
|
61
|
-
Process.detach(fork { exec "#{command} &" })
|
62
|
-
exit_status = 0
|
63
|
-
end
|
64
|
-
raise "#{stdout}\n#{stderr}" if exit_status != 0
|
50
|
+
if Open3.respond_to?('capture3')
|
51
|
+
stdout, stderr, exit_status = Open3.capture3(command)
|
52
|
+
message = "triggered: #{command}\n#{stdout}\n#{stderr}"
|
53
|
+
else
|
54
|
+
message = "forked: #{command}"
|
55
|
+
Process.detach(fork { exec "#{command} &" })
|
56
|
+
exit_status = 0
|
65
57
|
end
|
58
|
+
raise "#{stdout}\n#{stderr}" if exit_status != 0
|
66
59
|
message
|
67
60
|
end
|
68
61
|
|
69
62
|
def generate_types(environment)
|
70
|
-
command = "#{
|
63
|
+
command = "#{settings.command_prefix} /opt/puppetlabs/puppet/bin generate types --environment #{environment}"
|
71
64
|
|
72
65
|
message = run_command(command)
|
73
66
|
LOGGER.info("message: #{message} environment: #{environment}")
|
@@ -82,9 +75,6 @@ module Tasks # rubocop:disable Style/Documentation
|
|
82
75
|
def notify_slack(status_message)
|
83
76
|
return unless settings.slack_webhook
|
84
77
|
|
85
|
-
slack_channel = settings.slack_channel || '#default'
|
86
|
-
slack_user = settings.slack_username || 'r10k'
|
87
|
-
|
88
78
|
if settings.slack_proxy_url
|
89
79
|
uri = URI(settings.slack_proxy_url)
|
90
80
|
http_options = {
|
@@ -97,8 +87,8 @@ module Tasks # rubocop:disable Style/Documentation
|
|
97
87
|
end
|
98
88
|
|
99
89
|
notifier = Slack::Notifier.new settings.slack_webhook do
|
100
|
-
defaults channel:
|
101
|
-
username:
|
90
|
+
defaults channel: '#general',
|
91
|
+
username: 'puppet_webhook',
|
102
92
|
icon_emoji: ':ocean:',
|
103
93
|
http_options: http_options
|
104
94
|
end
|
@@ -138,8 +128,9 @@ module Tasks # rubocop:disable Style/Documentation
|
|
138
128
|
end
|
139
129
|
|
140
130
|
def types?
|
141
|
-
return false
|
142
|
-
settings.
|
131
|
+
return false unless settings.respond_to?(:generate_types=)
|
132
|
+
return false if settings.generate_types.nil?
|
133
|
+
settings.generate_types
|
143
134
|
end
|
144
135
|
|
145
136
|
def authorized?
|
@@ -1,9 +1,11 @@
|
|
1
|
-
require 'rack/
|
1
|
+
require 'rack/bodyparser'
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
module Sinatra
|
5
5
|
module Parsers
|
6
6
|
class WebhookJsonParser # rubocop:disable Style/Documentation
|
7
|
+
attr_accessor :env, :data
|
8
|
+
|
7
9
|
def call(body)
|
8
10
|
@data = JSON.parse(body, quirks_mode: true)
|
9
11
|
@vcs = detect_vcs
|
@@ -27,35 +29,23 @@ module Sinatra
|
|
27
29
|
|
28
30
|
def github_webhook?
|
29
31
|
# https://developer.github.com/v3/activity/events/types/#pushevent
|
30
|
-
|
31
|
-
return false unless @data.key? 'repository'
|
32
|
-
return false unless @data['repository'].key? 'id'
|
33
|
-
return false unless @data['repository'].key? 'html_url'
|
34
|
-
return false unless @data['repository']['html_url'] =~ %r{github\.com}
|
35
|
-
true
|
32
|
+
env.key?('HTTP_X_GITHUB_EVENT')
|
36
33
|
end
|
37
34
|
|
38
35
|
def gitlab_webhook?
|
39
36
|
# https://docs.gitlab.com/ce/user/project/integrations/webhooks.html
|
40
|
-
|
41
|
-
return false unless @data.key? 'object_kind'
|
42
|
-
return false unless @data.key? 'ref'
|
43
|
-
true
|
37
|
+
env.key?('HTTP_X_GITLAB_EVENT')
|
44
38
|
end
|
45
39
|
|
46
40
|
# stash/bitbucket server
|
47
41
|
def stash_webhook?
|
48
42
|
# https://confluence.atlassian.com/bitbucketserver/post-service-webhook-for-bitbucket-server-776640367.html
|
49
|
-
|
50
|
-
true
|
43
|
+
env.key?('HTTP_X_ATLASSIAN_TOKEN')
|
51
44
|
end
|
52
45
|
|
53
46
|
def bitbucket_webhook?
|
54
47
|
# https://confluence.atlassian.com/bitbucket/event-payloads-740262817.html
|
55
|
-
|
56
|
-
return false unless @data.key? 'repository'
|
57
|
-
return false unless @data.key? 'push'
|
58
|
-
true
|
48
|
+
env.key?('HTTP_X_EVENT_KEY')
|
59
49
|
end
|
60
50
|
|
61
51
|
def tfs_webhook?
|
@@ -97,8 +87,6 @@ module Sinatra
|
|
97
87
|
@data['push']['changes'][0]['closed']
|
98
88
|
when 'tfs'
|
99
89
|
@data['resource']['refUpdates'][0]['newObjectId'] == '0000000000000000000000000000000000000000'
|
100
|
-
else
|
101
|
-
false
|
102
90
|
end
|
103
91
|
end
|
104
92
|
|
data/lib/puppet_webhook.rb
CHANGED
@@ -4,148 +4,48 @@ require 'json'
|
|
4
4
|
require 'cgi'
|
5
5
|
require 'parsers/webhook_json_parser'
|
6
6
|
|
7
|
+
# Routes
|
8
|
+
require_relative 'routes/default'
|
9
|
+
require_relative 'routes/module'
|
10
|
+
require_relative 'routes/payload'
|
11
|
+
|
7
12
|
class PuppetWebhook < Sinatra::Base # rubocop:disable Style/Documentation
|
8
13
|
set :root, File.dirname(__FILE__)
|
9
|
-
use Rack::
|
14
|
+
use Rack::BodyParser,
|
10
15
|
parsers: { 'application/json' => Sinatra::Parsers::WebhookJsonParser.new },
|
11
16
|
handlers: { 'application/json' => proc { |e, type| [400, { 'Content-Type' => type }, [{ error: e.to_s }.to_json]] } }
|
12
17
|
register Sinatra::ConfigFile
|
13
18
|
|
14
19
|
config_file(File.join(__dir__, '..', 'config', 'app.yml'), '/etc/puppet_webhook/app.yml')
|
15
20
|
|
21
|
+
# Sinatra settings
|
16
22
|
set :static, false
|
17
|
-
set :lock, true
|
23
|
+
set :lock, true
|
24
|
+
|
25
|
+
# Custom Settings
|
26
|
+
set :protected, false unless settings.respond_to? :protected=
|
27
|
+
set :client_cfg, '/var/lib/peadmin/.mcollective' unless settings.respond_to? :client_cfg=
|
28
|
+
set :client_timeout, '120' unless settings.respond_to? :client_timeout=
|
29
|
+
set :use_mco_ruby, false unless settings.respond_to? :use_mco_ruby=
|
30
|
+
set :use_mcollective, false unless settings.respond_to? :use_mcollective=
|
31
|
+
set :discovery_timeout, false unless settings.respond_to? :discovery_timeout=
|
32
|
+
set :slack_webhook, false unless settings.respond_to? :slack_webhook=
|
33
|
+
set :slack_proxy_url, nil unless settings.respond_to? :slack_proxy_url=
|
34
|
+
set :default_branch, 'production' unless settings.respond_to? :default_branch=
|
35
|
+
set :ignore_environments, [] unless settings.respond_to? :ignore_environments=
|
36
|
+
set :prefix, nil unless settings.respond_to? :prefix=
|
37
|
+
set :prefix_command, '' unless settings.respond_to? :prefix_command=
|
38
|
+
set :r10k_deploy_arguments, '-pv' unless settings.respond_to? :r10k_deploy_arguments=
|
39
|
+
set :allow_uppercase, true unless settings.respond_to? :allow_uppercase=
|
40
|
+
set :command_prefix, 'umask 0022;' unless settings.respond_to? :command_prefix=
|
41
|
+
set :github_secret, nil unless settings.respond_to? :github_secret=
|
42
|
+
set :repository_events, nil unless settings.respond_to? :respository_events=
|
18
43
|
|
19
44
|
require 'helpers/init'
|
20
45
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
get '/heartbeat' do
|
26
|
-
return 200, { status: :success, message: 'running' }.to_json
|
27
|
-
end
|
28
|
-
|
29
|
-
# TODO: Move examples into the README.md
|
30
|
-
# Simulate a github post:
|
31
|
-
# curl -X POST \
|
32
|
-
# -H "Content-Type: application/json" \
|
33
|
-
# -d '{ \
|
34
|
-
# "repository": { \
|
35
|
-
# "id": 12345, \
|
36
|
-
# "name": "puppetlabs-stdlib", \
|
37
|
-
# "html_url": "http://github.com", \
|
38
|
-
# "owner": {\
|
39
|
-
# "login": "foo"
|
40
|
-
# } \
|
41
|
-
# } \
|
42
|
-
# }' \
|
43
|
-
# 'https://puppet:puppet@localhost:8088/module' -k -q
|
44
|
-
#
|
45
|
-
# Simulate a BitBucket post:
|
46
|
-
# curl -X POST \
|
47
|
-
# -H "Content-Type: application/json" \
|
48
|
-
# -d '{ \
|
49
|
-
# "repository": { \
|
50
|
-
# "full_name": "puppetlabs/puppetlabs-stdlib", \
|
51
|
-
# "name": "PuppetLabs : StdLib"
|
52
|
-
# } }' \
|
53
|
-
# 'https://puppet:puppet@localhost:8088/module' -k -q
|
54
|
-
#
|
55
|
-
# This example shows that, unlike github, BitBucket allows special characters
|
56
|
-
# in repository names but translates it to generate a full_name which
|
57
|
-
# is used in the repository URL and is most useful for this webhook handler.
|
58
|
-
post '/module' do
|
59
|
-
protected! if settings.protected
|
60
|
-
request.body.rewind # in case someone has already read it
|
61
|
-
|
62
|
-
# Short circuit if we're ignoring this event
|
63
|
-
return 200 if ignore_event?
|
64
|
-
|
65
|
-
# TODO: Move these two lines of code into the parser
|
66
|
-
decoded = request.body.read
|
67
|
-
verify_signature(decoded) if verify_signature?
|
68
|
-
|
69
|
-
module_name = params['module_name']
|
70
|
-
|
71
|
-
module_name = sanitize_input(module_name)
|
72
|
-
LOGGER.info("Deploying module #{module_name}")
|
73
|
-
deploy_module(module_name)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Simulate a github post:
|
77
|
-
# curl -d '{ "ref": "refs/heads/production" }' -H "Accept: application/json" 'https://puppet:puppet@localhost:8088/payload' -k -q
|
78
|
-
#
|
79
|
-
# If using stash look at the stash_mco.rb script included here.
|
80
|
-
# It will filter the stash post and make it look like a github post.
|
81
|
-
#
|
82
|
-
# Simulate a Gitorious post:
|
83
|
-
# curl -X POST -d '%7b%22ref%22%3a%22master%22%7d' 'http://puppet:puppet@localhost:8088/payload' -q
|
84
|
-
# Yes, Gitorious does not support https...
|
85
|
-
#
|
86
|
-
# Simulate a BitBucket post:
|
87
|
-
# curl -X POST -d '{ "push": { "changes": [ { "new": { "name": "production" } } ] } }' \
|
88
|
-
# 'https://puppet:puppet@localhost:8088/payload' -k -q
|
89
|
-
|
90
|
-
post '/payload' do # rubocop:disable Metrics/BlockLength
|
91
|
-
LOGGER.info "params = #{params}"
|
92
|
-
protected! if settings.protected
|
93
|
-
request.body.rewind # in case someone already read it
|
94
|
-
|
95
|
-
# Short circuit if we're ignoring this event
|
96
|
-
return 200 if ignore_event?
|
97
|
-
|
98
|
-
# Check if content type is x-www-form-urlencoded
|
99
|
-
decoded = if request.content_type.to_s.casecmp('application/x-www-form-urlencoded').zero?
|
100
|
-
CGI.unescape(request.body.read).gsub(%r{^payload\=}, '')
|
101
|
-
else
|
102
|
-
request.body.read
|
103
|
-
end
|
104
|
-
verify_signature(decoded) if verify_signature?
|
105
|
-
data = JSON.parse(decoded, quirks_mode: true)
|
106
|
-
|
107
|
-
# Iterate the data structure to determine what's should be deployed
|
108
|
-
branch = params['branch']
|
109
|
-
|
110
|
-
# If prefix is enabled in our config file, determine what the prefix should be
|
111
|
-
prefix = case settings.prefix
|
112
|
-
when :repo
|
113
|
-
params['repo_name']
|
114
|
-
when :user
|
115
|
-
params['repo_user']
|
116
|
-
when :command, TrueClass
|
117
|
-
run_prefix_command(data.to_json)
|
118
|
-
when String
|
119
|
-
settings.prefix
|
120
|
-
end
|
121
|
-
|
122
|
-
# When a branch is being deleted, a deploy against it will result in a failure, as it no longer exists.
|
123
|
-
# Instead, deploy the default branch, which will purge deleted branches per the user's configuration
|
124
|
-
deleted = params['deleted']
|
125
|
-
|
126
|
-
branch = if deleted
|
127
|
-
settings.default_branch
|
128
|
-
else
|
129
|
-
sanitize_input(branch)
|
130
|
-
end
|
131
|
-
|
132
|
-
# r10k doesn't yet know how to deploy all branches from a single source.
|
133
|
-
# The best we can do is just deploy all environments by passing nil to
|
134
|
-
# deploy() if we don't know the correct branch.
|
135
|
-
env = if prefix.nil? || prefix.empty? || branch.nil? || branch.empty?
|
136
|
-
normalize(branch)
|
137
|
-
else
|
138
|
-
normalize("#{prefix}_#{branch}")
|
139
|
-
end
|
140
|
-
|
141
|
-
if ignore_env?(env)
|
142
|
-
LOGGER.info("Skipping deployment of environment #{env} according to ignore_environments configuration parameter")
|
143
|
-
return 200
|
144
|
-
else
|
145
|
-
LOGGER.info("Deploying environment #{env}")
|
146
|
-
deploy(env, deleted)
|
147
|
-
end
|
148
|
-
end
|
46
|
+
register Sinatra::PuppetWebhookRoutes::Default
|
47
|
+
register Sinatra::PuppetWebhookRoutes::Module
|
48
|
+
register Sinatra::PuppetWebhookRoutes::Payload
|
149
49
|
|
150
50
|
not_found do
|
151
51
|
halt 404, "You shall not pass! (page not found)\n"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module PuppetWebhookRoutes
|
5
|
+
# Registers the default GET routes for PuppetWebhook
|
6
|
+
module Default
|
7
|
+
def self.registered(puppet_webhook)
|
8
|
+
puppet_webhook.get '/' do
|
9
|
+
raise Sinatra::NotFound
|
10
|
+
end
|
11
|
+
|
12
|
+
puppet_webhook.get '/heartbeat' do
|
13
|
+
return 200, { status: :success, message: 'running' }.to_json
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module PuppetWebhookRoutes
|
5
|
+
# Registers a POST endpoint for the PuppetWebhook App
|
6
|
+
module Module
|
7
|
+
def self.registered(puppet_webhook)
|
8
|
+
puppet_webhook.post '/module' do
|
9
|
+
protected! if settings.protected
|
10
|
+
request.body.rewind # in case someone has already read it
|
11
|
+
|
12
|
+
# Short circuit if we're ignoring this event
|
13
|
+
return 200 if ignore_event?
|
14
|
+
|
15
|
+
# TODO: Move these two lines of code into the parser
|
16
|
+
decoded = request.body.read
|
17
|
+
verify_signature(decoded) if verify_signature?
|
18
|
+
|
19
|
+
module_name = payload[:module_name]
|
20
|
+
|
21
|
+
module_name = sanitize_input(module_name)
|
22
|
+
LOGGER.info("Deploying module #{module_name}")
|
23
|
+
deploy_module(module_name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module PuppetWebhookRoutes
|
5
|
+
# Registers a POST route for the Payload endpoint on PuppetWebhook
|
6
|
+
module Payload
|
7
|
+
def self.registered(puppet_webhook)
|
8
|
+
puppet_webhook.post '/payload' do # rubocop:disable Metrics/BlockLength
|
9
|
+
LOGGER.info "parsed payload contained: #{payload}"
|
10
|
+
protected! if settings.protected
|
11
|
+
request.body.rewind # in case someone already read it
|
12
|
+
|
13
|
+
# Short circuit if we're ignoring this event
|
14
|
+
return 200 if ignore_event?
|
15
|
+
|
16
|
+
# Check if content type is x-www-form-urlencoded
|
17
|
+
decoded = if request.content_type.to_s.casecmp('application/x-www-form-urlencoded').zero?
|
18
|
+
CGI.unescape(request.body.read).gsub(%r{^payload\=}, '')
|
19
|
+
else
|
20
|
+
request.body.read
|
21
|
+
end
|
22
|
+
verify_signature(decoded) if verify_signature?
|
23
|
+
data = JSON.parse(decoded, quirks_mode: true)
|
24
|
+
|
25
|
+
# Iterate the data structure to determine what's should be deployed
|
26
|
+
branch = payload[:branch]
|
27
|
+
|
28
|
+
# If prefix is enabled in our config file, determine what the prefix should be
|
29
|
+
prefix = case settings.prefix
|
30
|
+
when :repo
|
31
|
+
payload[:repo_name]
|
32
|
+
when :user
|
33
|
+
payload[:repo_user]
|
34
|
+
when :command, TrueClass
|
35
|
+
run_prefix_command(data.to_json)
|
36
|
+
when String
|
37
|
+
settings.prefix
|
38
|
+
end
|
39
|
+
|
40
|
+
# When a branch is being deleted, a deploy against it will result in a failure, as it no longer exists.
|
41
|
+
# Instead, deploy the default branch, which will purge deleted branches per the user's configuration
|
42
|
+
deleted = payload[:deleted]
|
43
|
+
|
44
|
+
branch = if deleted
|
45
|
+
settings.default_branch
|
46
|
+
else
|
47
|
+
sanitize_input(branch)
|
48
|
+
end
|
49
|
+
|
50
|
+
# r10k doesn't yet know how to deploy all branches from a single source.
|
51
|
+
# The best we can do is just deploy all environments by passing nil to
|
52
|
+
# deploy() if we don't know the correct branch.
|
53
|
+
env = if prefix.nil? || prefix.empty? || branch.nil? || branch.empty?
|
54
|
+
normalize(branch)
|
55
|
+
else
|
56
|
+
normalize("#{prefix}_#{branch}")
|
57
|
+
end
|
58
|
+
|
59
|
+
if ignore_env?(env)
|
60
|
+
LOGGER.info("Skipping deployment of environment #{env} according to ignore_environments configuration parameter")
|
61
|
+
return 200
|
62
|
+
else
|
63
|
+
LOGGER.info("Deploying environment #{env}")
|
64
|
+
deploy(env, deleted)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet_webhook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vox Pupuli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: rack-
|
42
|
+
name: rack-bodyparser
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: codacy-coverage
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: coveralls
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -218,13 +232,15 @@ files:
|
|
218
232
|
- README.md
|
219
233
|
- bin/puppet_webhook
|
220
234
|
- config/app.yml
|
221
|
-
- config/server.yml
|
222
235
|
- lib/helpers/data_parsers.rb
|
223
236
|
- lib/helpers/deployments.rb
|
224
237
|
- lib/helpers/init.rb
|
225
238
|
- lib/helpers/tasks.rb
|
226
239
|
- lib/parsers/webhook_json_parser.rb
|
227
240
|
- lib/puppet_webhook.rb
|
241
|
+
- lib/routes/default.rb
|
242
|
+
- lib/routes/module.rb
|
243
|
+
- lib/routes/payload.rb
|
228
244
|
homepage: https://github.com/voxpupuli/puppet_webhook
|
229
245
|
licenses:
|
230
246
|
- apache
|
@@ -246,7 +262,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
262
|
version: '0'
|
247
263
|
requirements: []
|
248
264
|
rubyforge_project:
|
249
|
-
rubygems_version: 2.7.
|
265
|
+
rubygems_version: 2.7.3
|
250
266
|
signing_key:
|
251
267
|
specification_version: 4
|
252
268
|
summary: Sinatra Webhook Server for Puppet/R10K
|
data/config/server.yml
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
server_type: simple
|
2
|
-
logfile: /var/log/puppet_webhook/access.log
|
3
|
-
pidfile: /var/run/puppet_webhook/webhook.pid
|
4
|
-
lockfile: /var/run/puppet_webhook/webhook.lock
|
5
|
-
approot: './'
|
6
|
-
server_software: PuppetWebhook
|
7
|
-
bind_address: 0.0.0.0
|
8
|
-
port: 8088
|
9
|
-
enable_ssl: false
|
10
|
-
verify_ssl: false
|
11
|
-
public_key_path: ''
|
12
|
-
private_key_path: ''
|
13
|
-
command_prefix: 'umask 0022;'
|