puppet-twitch 0.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 +15 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +102 -0
- data/bin/puppet-twitch +4 -0
- data/lib/puppet_twitch/basic_http_server.rb +85 -0
- data/lib/puppet_twitch/controller.rb +52 -0
- data/lib/puppet_twitch/logger.rb +43 -0
- data/lib/puppet_twitch/param_parser.rb +27 -0
- data/lib/puppet_twitch/puppet.rb +30 -0
- data/lib/puppet_twitch/server.rb +16 -0
- data/lib/puppet_twitch/version.rb +3 -0
- data/puppet-twitch.gemspec +24 -0
- data/spec/puppet_twitch/basic_http_server_spec.rb +25 -0
- data/spec/puppet_twitch/param_parser_spec.rb +44 -0
- data/spec/spec_helper.rb +5 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MmY4YzJlMTY4ZTZkYjAwOTRmNDdiMzdhNGE2Yjc5NGNiZDNhYWY2Zg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzQ3NDFlYThmYzNkMmMwZTNlMDE2ZjhiNjVlY2M4NzUyM2Y5NGQ5YQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODQzNzQ0ODEzNGU5NWZhNzYxNGM1NjAwZTE2ZmUzYjNiNGM0MDA0OWIwNTEz
|
10
|
+
N2Q2YjgzMTY2ZWMwZDQ4NDM4ZjBkMjM5N2E2ZWE2MWVjZmM2YjY2MjdhNDJh
|
11
|
+
Mzk5ZTFkYWU2YWQ4MGNhYTkyZDk5MmM2MjhhNjA2ZWU4ZTRjOTg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
Mzc5MDVjMmYwOWYxNmUwMjMwY2Q5NTAyOWM3ODZmMzRmYTI1MzVkNThiODlj
|
14
|
+
NGQyMjYwZjAzM2M4ZWVmMWJkY2E3MWZjNGZmZWNhMzkwMDdlNTQ4Yzk0NDdl
|
15
|
+
YWEwOGRkMDE1YzhkODkwOGRiMjczMWRlYzg1MzJjNDlmOTMyMzk=
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 TomPoulton
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Puppet Twitch
|
2
|
+
|
3
|
+
Puppet Twitch provides a lightweight http interface for remotely triggering puppet runs. That's it! The plan was to not use more resources than it had to, and also not open up any security holes.
|
4
|
+
|
5
|
+
Currently this project is definitely in the beta phase, there are probably a few kinks to work out, and it's worth highlighting that at the moment **puppet twitch doesn't use a "proper" http server**, it's just a TCP socket with an http shaped regex. This makes it lightweight, but there might be a whole bunch of compatibility/security issues with it, so I'm looking to swap that out (see ToDo section)
|
6
|
+
|
7
|
+
### Triggering puppet
|
8
|
+
|
9
|
+
To trigger a puppet run on a node running puppet-twitch, simply hit the `/puppet/twitch` endpoint over http. For example, to trigger puppet on `node01.example.com` running puppet-twitch on the default port:
|
10
|
+
|
11
|
+
`$ curl http://node01.example.com:2023/puppet/twitch`
|
12
|
+
|
13
|
+
Puppet-twitch will respond with one of the following (`<status code>, <body>`):
|
14
|
+
- `202, Triggered puppet run` - The puppet run has been triggered asynchronously
|
15
|
+
- `409, Puppet already running` - Either the server is already processing a request, or puppet's lock file exists indicating the agent is already running
|
16
|
+
- `500, <error message>` - Something went wrong!
|
17
|
+
|
18
|
+
##### Async
|
19
|
+
|
20
|
+
You can use the `async` parameter (default `true`) to make the request wait for the puppet run to finish before returning. Note that this can be a few minutes, so timeouts etc will need to be taken into account:
|
21
|
+
|
22
|
+
`$ curl http://node01.example.com:2023/puppet/twitch?async=false`
|
23
|
+
|
24
|
+
In this case puppet-twitch will respond with `200, Puppet run complete`
|
25
|
+
|
26
|
+
### Puppet Install
|
27
|
+
|
28
|
+
There is a puppet module called `twitch` in the source that can be used to setup and install puppet-twitch. The module isn't in the forge yet so copy and paste for now.
|
29
|
+
|
30
|
+
To use the defaults on Linux, simply `include twitch`. This will:
|
31
|
+
- Create a user and group called `twitch`
|
32
|
+
- Add specific puppet commands to `/etc/sudoers.d/twitch` (see `init.pp` in the `twitch` module for the list of commands)
|
33
|
+
- Create the `/var/run/puppet-twitch` directory that is writable by the `twitch` user
|
34
|
+
- Install the gem
|
35
|
+
- Start the server as the `twitch` user on the default port (2023)
|
36
|
+
|
37
|
+
The `twitch` class is parameterized, so user, port, run directory, etc can be configured if necessary
|
38
|
+
|
39
|
+
##### Prerequisites
|
40
|
+
- **ruby 1.9.3** or above as `require_relative` isn't supported by lower versions
|
41
|
+
- Open the port to incoming connections, the `twitch` module will not change any network configuration.
|
42
|
+
- Add `/etc/sudoers.d` to the `sudoers` file. This is a common configuration and is done by default on some VMs (e.g.Vagrant boxes, EC2 instances) but the `twitch` module assumes this is already setup.
|
43
|
+
|
44
|
+
### Manual Install:
|
45
|
+
|
46
|
+
`$ gem install puppet-twitch` (run as root so that it's available to all users)
|
47
|
+
|
48
|
+
Use the `puppet-twitch` command to start/stop the server
|
49
|
+
|
50
|
+
`$ puppet-twitch {start|stop|restart|status} dir=</path/to/run/dir> [-- [bind=<binding>] [port=<port>]]`
|
51
|
+
|
52
|
+
For example to start the server on a custom port
|
53
|
+
|
54
|
+
`$ puppet-twitch start dir=/var/run/puppet-twitch -- port=8090`
|
55
|
+
|
56
|
+
And then stop it
|
57
|
+
|
58
|
+
`$ puppet-twitch stop dir=/var/run/puppet-twitch`
|
59
|
+
|
60
|
+
##### Prerequisites
|
61
|
+
- All prerequisites from the puppet install apply
|
62
|
+
- Create a user to run the server (one that doesn't have root permissions)
|
63
|
+
- Allow user to run the necessary puppet commands with `sudo` and without password (see `init.pp` for commands)
|
64
|
+
- Create a run directory for pids and logs (writable by the user)
|
65
|
+
|
66
|
+
##### Args:
|
67
|
+
- `dir`: Absolute path for directory that will store the pids and logs. **The directory must be manually created and must be writable by the user that is running the server**. It must be provided for every action (`start`/`stop`/`status` etc), there is a ToDo to fix this
|
68
|
+
- `bind`: The IP address to bind to, defaults to `0.0.0.0`
|
69
|
+
- `port`: The port to listen on, defaults to `2023`
|
70
|
+
|
71
|
+
### Running from source (for development/testing)
|
72
|
+
|
73
|
+
You can use `rake install` to build and install the gem locally (I recommend using `rvm` gemsets to isolate gem installs), but you can also run the code direct from source in two ways:
|
74
|
+
- `ruby lib/puppet-twitch/controller.rb [bind=<binding>] [port=<port>]`
|
75
|
+
- `ruby lib/puppet-twitch/server.rb dir=</path/to/run/dir> [-- [bind=<binding>] [port=<port>]]`
|
76
|
+
|
77
|
+
The difference is that running `controller.rb` will run the server in the foreground and output will be logged to `STDOUT`. Running `server.rb` will start the server as a daemon and output will be logged to a logfile in the run directory
|
78
|
+
|
79
|
+
If you want to run the server in single threaded mode (i.e. the server doesn't fork threads for incoming connections) then set `async = false` in `controller.rb`, this is useful for debugging issues that aren't related to threading.
|
80
|
+
|
81
|
+
##### Vagrant
|
82
|
+
|
83
|
+
To test in a more isolated environment you can use vagrant, just spin up the boxes (see `nodes.json`), ssh into a node, then run puppet. After that, puppet-twitch should be running on the node and you can test by hitting the endpoint:
|
84
|
+
|
85
|
+
```
|
86
|
+
[user@localhost] $ vagrant up
|
87
|
+
[user@localhost] $ vagrant ssh node01
|
88
|
+
[vagrant@node01] $ sudo puppet agent -t
|
89
|
+
[vagrant@node01] $ curl http://localhost:2023/puppet/twitch
|
90
|
+
```
|
91
|
+
|
92
|
+
The puppet class that's applied to the nodes (`twitch::test::vagrant`) inherits from the normal `twitch` class but also:
|
93
|
+
- Gives the `twitch` user a password (set to `twitch`) and a shell (`/bin/bash`) so you can switch to the `twitch` user for debugging
|
94
|
+
- Installs the gem from the project's `pkg` directory that is mounted by vagrant, rather than downloading the gem from rubygems
|
95
|
+
|
96
|
+
In order to get local changes running on the vagrant machines, use the `rake latest` command which builds the gem as normal, but then also creates a symlink called `puppet-twitch-latest.gem` to the built gem. This is the file that the `twitch::test::vagrant` class looks for so that you don't have to specify a version
|
97
|
+
|
98
|
+
### ToDo:
|
99
|
+
- Proper http server - I tried using Sinatra but it wasn't playing nice with Daemons and logging
|
100
|
+
- Auth key/password - At the moment anyone with network access to the port can trigger a run, not a massive deal as all they can do is trigger a puppet run, but it might be nice to add a configurable key/phrase/password
|
101
|
+
- Add support for Windows - It should be easy(-ish) to configure, I tried to write everything in an agnostic manner, but need to test and fix
|
102
|
+
- Cache run directory - It's annoying having to provide the run directory for each action
|
data/bin/puppet-twitch
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require_relative 'logger'
|
3
|
+
require_relative 'param_parser'
|
4
|
+
|
5
|
+
module PuppetTwitch
|
6
|
+
|
7
|
+
class BasicHttpServer
|
8
|
+
|
9
|
+
attr_accessor :logger
|
10
|
+
|
11
|
+
def initialize(bind, port, multiple_threads = true)
|
12
|
+
@bind = bind
|
13
|
+
@port = port
|
14
|
+
@multiple_threads = multiple_threads
|
15
|
+
@logger = PuppetTwitch::Logger.new()
|
16
|
+
@logger.level = PuppetTwitch::Logger::DEBUG
|
17
|
+
@actions = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def start()
|
21
|
+
@logger.info 'Starting server ...'
|
22
|
+
server = TCPServer.new(@bind, @port)
|
23
|
+
@logger.info "Listening on #{@bind}:#{@port}"
|
24
|
+
|
25
|
+
server_loop = proc { |socket|
|
26
|
+
begin
|
27
|
+
process_request socket
|
28
|
+
rescue => e
|
29
|
+
@logger.error e.to_s
|
30
|
+
socket.puts form_response(500, 'Unexpected error')
|
31
|
+
ensure
|
32
|
+
socket.close
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
loop do
|
37
|
+
if @multiple_threads
|
38
|
+
Thread.fork(server.accept, &server_loop)
|
39
|
+
else
|
40
|
+
server_loop.call server.accept
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_request(socket)
|
46
|
+
client_ip = socket.peeraddr[3]
|
47
|
+
client_hostname = socket.peeraddr[2]
|
48
|
+
request = socket.gets
|
49
|
+
|
50
|
+
endpoint, params = get_endpoint_and_params(request)
|
51
|
+
@logger.info "Connection from: #{client_hostname} (#{client_ip}) | Endpoint: #{endpoint} | Params: #{params}"
|
52
|
+
|
53
|
+
response = @actions.has_key?(endpoint) ? @actions[endpoint].call(params) : [400, "Unrecognised endpoint: #{endpoint}"]
|
54
|
+
@logger.debug "#{response[0]}: #{response[1]}"
|
55
|
+
|
56
|
+
socket.puts form_response(response[0], response[1])
|
57
|
+
@logger.debug "Closing connection from #{client_ip}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def endpoint(endpoint, &block)
|
61
|
+
@actions[endpoint] = block
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_endpoint_and_params(request)
|
65
|
+
match = request.match(/^\s*(?<verb>GET|POST|PUT|DELETE) (?<endpoint>[\w\-\/]*)(\?(?<params>\S*)\s*|\s*)HTTP.*/)
|
66
|
+
return match['endpoint'], parse_params(match['params'])
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_params(param_string)
|
70
|
+
PuppetTwitch::ParamParser.parse(param_string.to_s.strip.split('&'))
|
71
|
+
end
|
72
|
+
|
73
|
+
def form_response(status, body)
|
74
|
+
<<-EOF
|
75
|
+
HTTP/1.1 #{status}
|
76
|
+
Content-Type: text/plain
|
77
|
+
Content-Length: #{body.bytesize}
|
78
|
+
Connection: close
|
79
|
+
|
80
|
+
#{body}
|
81
|
+
EOF
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'basic_http_server'
|
4
|
+
require_relative 'param_parser'
|
5
|
+
require_relative 'puppet'
|
6
|
+
require_relative 'version'
|
7
|
+
|
8
|
+
module PuppetTwitch
|
9
|
+
|
10
|
+
args = ParamParser.parse(ARGV)
|
11
|
+
|
12
|
+
bind = args[:bind] || '0.0.0.0'
|
13
|
+
port = args[:port] || 2023
|
14
|
+
threads = true
|
15
|
+
|
16
|
+
@processing_request = Mutex.new
|
17
|
+
http_server = PuppetTwitch::BasicHttpServer.new(bind, port, threads)
|
18
|
+
|
19
|
+
http_server.endpoint '/puppet/twitch' do |params|
|
20
|
+
response = []
|
21
|
+
if @processing_request.try_lock
|
22
|
+
begin
|
23
|
+
if PuppetTwitch::Puppet.is_running?
|
24
|
+
response = [409, 'Puppet already running']
|
25
|
+
else
|
26
|
+
async = (params[:async].to_s != 'false')
|
27
|
+
PuppetTwitch::Puppet.run_puppet(async)
|
28
|
+
response = async ? [202, 'Triggered puppet run'] : [200, 'Puppet run complete']
|
29
|
+
end
|
30
|
+
rescue => e
|
31
|
+
http_server.logger.error e.to_s
|
32
|
+
response = [500, 'Error running puppet']
|
33
|
+
ensure
|
34
|
+
@processing_request.unlock
|
35
|
+
end
|
36
|
+
else
|
37
|
+
response = [409, 'Puppet already running']
|
38
|
+
end
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
http_server.endpoint '/version' do
|
43
|
+
[200, PuppetTwitch::VERSION]
|
44
|
+
end
|
45
|
+
|
46
|
+
http_server.endpoint '/info' do
|
47
|
+
[200, 'Puppet Twitch - A simple endpoint for triggering puppet']
|
48
|
+
end
|
49
|
+
|
50
|
+
http_server.start
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module PuppetTwitch
|
2
|
+
|
3
|
+
# Logger just prints to STDOUT.
|
4
|
+
# When the server is running in the foreground (not Daemonized),
|
5
|
+
# all output is visible in the terminal.
|
6
|
+
# When the server is running as a Daemon,
|
7
|
+
# STDOUT is redirected to a logfile,
|
8
|
+
# so this simple logger works for both scenarios
|
9
|
+
|
10
|
+
class Logger
|
11
|
+
|
12
|
+
DEBUG = 0
|
13
|
+
INFO = 1
|
14
|
+
WARN = 2
|
15
|
+
ERROR = 3
|
16
|
+
|
17
|
+
attr_accessor :level
|
18
|
+
|
19
|
+
def initialize(level = INFO)
|
20
|
+
@level = level
|
21
|
+
end
|
22
|
+
|
23
|
+
def debug(message)
|
24
|
+
log DEBUG, "Log [DEBUG]: #{message}"
|
25
|
+
end
|
26
|
+
def info(message)
|
27
|
+
log INFO, "Log [INFO]: #{message}"
|
28
|
+
end
|
29
|
+
def warn(message)
|
30
|
+
log WARN, "Log [WARN]: #{message}"
|
31
|
+
end
|
32
|
+
def error(message)
|
33
|
+
log ERROR, "Log [ERROR]: #{message}"
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def log(level, message)
|
39
|
+
puts message if level >= @level
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PuppetTwitch
|
2
|
+
|
3
|
+
class ParamParser
|
4
|
+
|
5
|
+
# Takes an array of parameter strings and
|
6
|
+
# returns a hash of the parameters and their values where
|
7
|
+
# the keys are the parameter names as symbols.
|
8
|
+
#
|
9
|
+
# Parameter strings can have the following formats:
|
10
|
+
# 'name=value' --> { :name => 'value' }
|
11
|
+
# 'name' --> { :name => true }
|
12
|
+
#
|
13
|
+
def self.parse(param_strings)
|
14
|
+
params = {}
|
15
|
+
param_strings.each { |pair|
|
16
|
+
key_value = pair.split('=')
|
17
|
+
if key_value.size > 2 || pair[-1] == '='
|
18
|
+
raise StandardError, "Invalid parameter format: #{pair}"
|
19
|
+
else
|
20
|
+
params[key_value[0].to_sym] = (key_value.size == 1) ? true : key_value[1]
|
21
|
+
end
|
22
|
+
}
|
23
|
+
params
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PuppetTwitch
|
2
|
+
|
3
|
+
class Puppet
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def is_running?
|
7
|
+
lock_file_path_cmd = 'puppet config print agent_catalog_run_lockfile'
|
8
|
+
lock_file_path = `#{sudo_if_required lock_file_path_cmd}`.strip
|
9
|
+
if $?.to_i != 0
|
10
|
+
raise StandardError, "Failed to find puppet lock file path: #{lock_file_path}"
|
11
|
+
end
|
12
|
+
File.exists?(lock_file_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_puppet(async = true)
|
16
|
+
command = async ? 'puppet agent --onetime' : 'puppet agent --onetime --no-daemonize'
|
17
|
+
output = `#{sudo_if_required command}`
|
18
|
+
exit_code = $?
|
19
|
+
unless [0, 2].include?(exit_code.to_i) # 2 indicates a puppet change, 3 is a failure
|
20
|
+
raise StandardError, "Error running puppet: #{exit_code}: #{output}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def sudo_if_required(command)
|
25
|
+
"sudo #{command}" unless Gem.win_platform?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'daemons'
|
2
|
+
require_relative 'param_parser'
|
3
|
+
|
4
|
+
args = PuppetTwitch::ParamParser.parse(ARGV.reject {|arg| arg == '--'})
|
5
|
+
run_dir = args[:dir]
|
6
|
+
abort 'Please provide a run directory' unless run_dir
|
7
|
+
|
8
|
+
# Pids and log files will be written to run_dir directory
|
9
|
+
options = {
|
10
|
+
:dir_mode => :normal,
|
11
|
+
:dir => run_dir,
|
12
|
+
:log_output => true,
|
13
|
+
:monitor => true,
|
14
|
+
}
|
15
|
+
|
16
|
+
Daemons.run(File.expand_path('../controller.rb', __FILE__), options)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'puppet_twitch/version'
|
6
|
+
|
7
|
+
excude = ['.gitignore', 'Rakefile', 'puppet/.*', 'nodes.json', 'Vagrantfile']
|
8
|
+
|
9
|
+
Gem::Specification.new do |gem|
|
10
|
+
gem.name = 'puppet-twitch'
|
11
|
+
gem.version = PuppetTwitch::VERSION
|
12
|
+
gem.description = 'Trigger a puppet run remotely'
|
13
|
+
gem.summary = 'http trigger for puppet'
|
14
|
+
gem.author = 'Tom Poulton'
|
15
|
+
gem.license = 'MIT'
|
16
|
+
gem.homepage = 'http://github.com/Accuity/puppet-twitch'
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split($/).reject { |file| file =~ /^(#{excude.join('|')})$/ }
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ['lib']
|
22
|
+
|
23
|
+
gem.add_dependency('daemons', '~> 1.2.2')
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/puppet_twitch/basic_http_server'
|
3
|
+
|
4
|
+
module PuppetTwitch
|
5
|
+
|
6
|
+
describe BasicHttpServer do
|
7
|
+
|
8
|
+
describe '#get_endpoint_and_params' do
|
9
|
+
|
10
|
+
let(:basic_http_server) { BasicHttpServer.new('0.0.0.0', 1234) }
|
11
|
+
|
12
|
+
it 'returns endpoint' do
|
13
|
+
endpoint, params = basic_http_server.get_endpoint_and_params('GET /foo HTTP')
|
14
|
+
expect(endpoint).to eq '/foo'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns endpoint containing punctuation' do
|
18
|
+
endpoint, params = basic_http_server.get_endpoint_and_params('GET /foo_bar/baz-baa HTTP')
|
19
|
+
expect(endpoint).to eq '/foo_bar/baz-baa'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/puppet_twitch/param_parser'
|
3
|
+
|
4
|
+
module PuppetTwitch
|
5
|
+
|
6
|
+
describe ParamParser do
|
7
|
+
|
8
|
+
describe '.parse' do
|
9
|
+
|
10
|
+
it 'converts param keys to symbols' do
|
11
|
+
params = ParamParser.parse ['foo=bar']
|
12
|
+
expect(params).to have_key :foo
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'parses multiple key value params' do
|
16
|
+
params = ParamParser.parse ['foo=bar', 'baz=baa']
|
17
|
+
expect(params).to eq( {:foo => 'bar', :baz => 'baa'} )
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'empty params are set to true' do
|
21
|
+
params = ParamParser.parse ['foo', 'bar']
|
22
|
+
expect(params).to eq( {:foo => true, :bar => true} )
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns empty hash for empty input array' do
|
26
|
+
params = ParamParser.parse []
|
27
|
+
expect(params).to eq( {} )
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises error when param is malformed' do
|
31
|
+
expect {
|
32
|
+
ParamParser.parse ['foo=bar=baz']
|
33
|
+
}.to raise_error StandardError, /Invalid parameter format/
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'raises error when param value is missing' do
|
37
|
+
expect {
|
38
|
+
ParamParser.parse ['foo=']
|
39
|
+
}.to raise_error StandardError, /Invalid parameter format/
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puppet-twitch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Poulton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: daemons
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.2
|
27
|
+
description: Trigger a puppet run remotely
|
28
|
+
email:
|
29
|
+
executables:
|
30
|
+
- puppet-twitch
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- Gemfile
|
35
|
+
- LICENSE.txt
|
36
|
+
- README.md
|
37
|
+
- bin/puppet-twitch
|
38
|
+
- lib/puppet_twitch/basic_http_server.rb
|
39
|
+
- lib/puppet_twitch/controller.rb
|
40
|
+
- lib/puppet_twitch/logger.rb
|
41
|
+
- lib/puppet_twitch/param_parser.rb
|
42
|
+
- lib/puppet_twitch/puppet.rb
|
43
|
+
- lib/puppet_twitch/server.rb
|
44
|
+
- lib/puppet_twitch/version.rb
|
45
|
+
- puppet-twitch.gemspec
|
46
|
+
- spec/puppet_twitch/basic_http_server_spec.rb
|
47
|
+
- spec/puppet_twitch/param_parser_spec.rb
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
homepage: http://github.com/Accuity/puppet-twitch
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.4.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: http trigger for puppet
|
73
|
+
test_files:
|
74
|
+
- spec/puppet_twitch/basic_http_server_spec.rb
|
75
|
+
- spec/puppet_twitch/param_parser_spec.rb
|
76
|
+
- spec/spec_helper.rb
|