varnish_rest_api 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.buildpath +5 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/Gemfile.orig +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +208 -0
- data/Rakefile +2 -0
- data/bin/varnishrestapi.rb +5 -0
- data/examples/config.ru +9 -0
- data/lib/varnish_rest_api/varnish_base.rb +199 -0
- data/lib/varnish_rest_api/version.rb +3 -0
- data/lib/varnish_rest_api.rb +152 -0
- data/lib/varnish_rest_api.yaml +11 -0
- data/lib/views/error.erb +9 -0
- data/lib/views/help.erb +91 -0
- data/varnish_rest_api.gemspec +30 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 51ea11f88e1b5c03c9bf2ff42432c4eb14f6c10b
|
4
|
+
data.tar.gz: cf4faad7e206ec9cdf52ee40379593f7070689bd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e3e2e865b03b00495ad4e4e12db73943a2967776d76881f866308ca79ed3ac5794f74350b5e61e5d77d90dbae9e7fbe58209ed78f88f7073af69e9a5843bc7d
|
7
|
+
data.tar.gz: 782a08d98d20563567b1ab9b26b35f07307e882332c087f7d984e71c12be5cf6f099614c6485698f10e8e76f08c479a468f1f1bd5a8b2ddca85fb6f445fa9fcb
|
data/.buildpath
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.orig
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Jonathan Colby
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
# varnish-rest-api
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
A small RESTful HTTP API for [Varnish](<https://www.varnish-cache.org>) written with [Sinatra](<http://www.sinatrarb.com/intro.html>). It is designed to be run on the varnish node(s) since it executes varnishadm on the varnish node itself. It can be started as a stand-alone server using Thin, or as a rack-aware application.
|
6
|
+
|
7
|
+
#### Features
|
8
|
+
|
9
|
+
* REST calls output JSON
|
10
|
+
* (optional) use zookeeper to register varnish nodes
|
11
|
+
* configurable with a yaml configuration file and sane defaults
|
12
|
+
|
13
|
+
|
14
|
+
## Getting Started
|
15
|
+
|
16
|
+
### Installing
|
17
|
+
|
18
|
+
*NOTE: It is recommended to use a ruby version manager such as [rvm](<https://rvm.io/>) instead of installing with the system ruby. With a ruby version manager, you can prevent "contaminating" your system-level ruby installation by creating an isolated ruby environment independent of system-installed ruby libraries. Plus, on some systems, installing gems at the system level may require root privileges.*
|
19
|
+
|
20
|
+
```
|
21
|
+
gem install varnish_rest_api
|
22
|
+
```
|
23
|
+
|
24
|
+
### Configuration
|
25
|
+
|
26
|
+
Configuration settings are stored in a file called **varnish_rest_api.yaml**. The default, example configuration can be found in the [github](<https://github.com/joncolby/varnish_rest_api/tree/master/lib>) repo or on your local system in the installed gem location.
|
27
|
+
|
28
|
+
This file is search for in the following paths in this order. The first file found is used:
|
29
|
+
|
30
|
+
* **/etc/varnish_rest_api.yaml**
|
31
|
+
* **HOME-DIR-OF-PROCESS-USER/varnish_rest_api.yaml**
|
32
|
+
* **GEMFILE-PATH/lib/varnish_rest_api.yaml**
|
33
|
+
|
34
|
+
To locate and copy the default yaml configuration:
|
35
|
+
|
36
|
+
```
|
37
|
+
$gem contents varnish_rest_api |grep yaml$
|
38
|
+
..
|
39
|
+
/usr/lib/ruby/gems/1.8/gems/varnish_rest_api-0.0.2/lib/varnish_rest_api.yaml
|
40
|
+
..
|
41
|
+
|
42
|
+
$cp /usr/lib/ruby/gems/1.8/gems/varnish_rest_api-0.0.2/lib/varnish_rest_api.yaml ~/
|
43
|
+
|
44
|
+
```
|
45
|
+
|
46
|
+
copy the secret file:
|
47
|
+
|
48
|
+
```
|
49
|
+
sudo cp /etc/varnish/secret ~
|
50
|
+
sudo chown <username> ~/secret
|
51
|
+
sudo chmod 0600 ~/secret
|
52
|
+
```
|
53
|
+
|
54
|
+
*(defaults configured in the application)*
|
55
|
+
```
|
56
|
+
---
|
57
|
+
port: 10001 <-- port server will run on (standalone mode)
|
58
|
+
bind_ip: '0.0.0.0' <-- this will bind the server to all interfaces (standalone mode)
|
59
|
+
secret: /etc/varnish/secret <-- IMPORTANT. This must be a valid,readable path to the varnish "secret" file
|
60
|
+
mgmt_port: 6082 <-- varnish management port
|
61
|
+
mgmt_host: localhost <-- varnish management ip
|
62
|
+
varnishadm_path: /usr/bin/varnishadm <-- path to varnishadm binary
|
63
|
+
instance: default <-- if more than one instance configured, specify instance name
|
64
|
+
use_zookeeper: false <-- zookeeper can be used to report available vanrish nodes
|
65
|
+
zookeeper_host: zookeeper_host:2181
|
66
|
+
zookeeper_basenode: /varnish
|
67
|
+
```
|
68
|
+
|
69
|
+
|
70
|
+
### Running
|
71
|
+
|
72
|
+
|
73
|
+
#### Standalone executable
|
74
|
+
|
75
|
+
An executable script is included in the gem and will be added to your $PATH after installation. The standalone executable uses Thin/WEBrick.
|
76
|
+
|
77
|
+
```
|
78
|
+
$ varnishrestapi.rb
|
79
|
+
|
80
|
+
using configuration file: /home/vagrant/.rvm/gems/ruby-2.2.1@gemtest/gems/varnish_rest_api-0.0.2/lib/varnish_rest_api.yaml
|
81
|
+
varnishadm command line: /usr/bin/varnishadm -T localhost:6082 -S /home/vagrant/secret
|
82
|
+
[2015-03-27 14:17:58] INFO WEBrick 1.3.1
|
83
|
+
[2015-03-27 14:17:58] INFO ruby 2.2.1 (2015-02-26) [x86_64-linux]
|
84
|
+
== Sinatra (v1.4.6) has taken the stage on 10001 for development with backup from WEBrick
|
85
|
+
[2015-03-27 14:17:58] INFO WEBrick::HTTPServer#start: pid=14591 port=10001
|
86
|
+
```
|
87
|
+
|
88
|
+
#### Rackup
|
89
|
+
|
90
|
+
create a config.ru file with the following contents:
|
91
|
+
|
92
|
+
```
|
93
|
+
require 'rubygems'
|
94
|
+
require 'sinatra'
|
95
|
+
set :environment, ENV['RACK_ENV'].to_sym
|
96
|
+
disable :run, :reload
|
97
|
+
require 'varnish_rest_api'
|
98
|
+
run VarnishRestApi
|
99
|
+
```
|
100
|
+
|
101
|
+
Start server with the rackup command:
|
102
|
+
|
103
|
+
```
|
104
|
+
$ rackup -p10001 --host 0.0.0.0 config.ru
|
105
|
+
using configuration file: /etc/varnish_rest_api.yaml
|
106
|
+
varnishadm command line: /usr/bin/varnishadm -T localhost:6082 -S /home/vagrant/secret
|
107
|
+
Thin web server (v1.6.3 codename Protein Powder)
|
108
|
+
Maximum connections set to 1024
|
109
|
+
Listening on 0.0.0.0:10001, CTRL+C to stop
|
110
|
+
192.168.33.1 - - [28/Mar/2015:14:36:18 +0000] "GET / HTTP/1.1" 200 1905 0.0199
|
111
|
+
```
|
112
|
+
#### Example using Nginx/Passenger
|
113
|
+
|
114
|
+
Install nginx with passenger support. Excellent documentation available here: [Passenger documentation](<https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html#bundler_support>) and [nginx centos how-to](<https://www.digitalocean.com/community/tutorials/how-to-compile-nginx-from-source-on-a-centos-6-4-x64-vps>)
|
115
|
+
|
116
|
+
##### Concise How-to (nginx yum installation method)
|
117
|
+
|
118
|
+
Install passenger gem:
|
119
|
+
|
120
|
+
```
|
121
|
+
$gem install passenger
|
122
|
+
```
|
123
|
+
|
124
|
+
configure passenger support for nginx with provided script:
|
125
|
+
|
126
|
+
```
|
127
|
+
$passenger-install-nginx-module
|
128
|
+
```
|
129
|
+
|
130
|
+
create the following directory structure for the application:
|
131
|
+
|
132
|
+
```
|
133
|
+
/var/www/varnishapi
|
134
|
+
|
|
135
|
+
+-- config.ru <-- see rackup example above for contents
|
136
|
+
|
|
137
|
+
+-- public/
|
138
|
+
|
|
139
|
+
+-- tmp/
|
140
|
+
```
|
141
|
+
|
142
|
+
make sure these lines are in your nginx.conf:
|
143
|
+
|
144
|
+
```
|
145
|
+
...
|
146
|
+
http {
|
147
|
+
|
148
|
+
types_hash_bucket_size 64;
|
149
|
+
server_names_hash_bucket_size 128;
|
150
|
+
|
151
|
+
passenger_root /home/vagrant/.rvm/gems/<your-active-rvm-ruby>/gems/passenger-5.0.5;
|
152
|
+
passenger_ruby /home/vagrant/.rvm/gems/<your-active-rvm-ruby>/wrappers/ruby
|
153
|
+
...
|
154
|
+
|
155
|
+
...
|
156
|
+
server {
|
157
|
+
listen 80;
|
158
|
+
server_name localhost;
|
159
|
+
|
160
|
+
root /var/www/varnishapi/public;
|
161
|
+
passenger_enabled on;
|
162
|
+
...
|
163
|
+
```
|
164
|
+
|
165
|
+
start nginx and verify running processes:
|
166
|
+
|
167
|
+
```
|
168
|
+
$ passenger-memory-stats
|
169
|
+
...
|
170
|
+
----- Passenger processes -----
|
171
|
+
PID VMSize Private Name
|
172
|
+
-------------------------------
|
173
|
+
14717 351.3 MB 0.9 MB PassengerAgent watchdog
|
174
|
+
14720 628.9 MB 1.4 MB PassengerAgent server
|
175
|
+
14725 222.9 MB 0.8 MB PassengerAgent logger
|
176
|
+
14741 285.7 MB 2.2 MB Passenger AppPreloader: /var/www/varnishapi
|
177
|
+
14761 354.4 MB 12.2 MB Passenger RubyApp: /var/www/varnishapi/public
|
178
|
+
14768 354.5 MB 9.8 MB Passenger RubyApp: /var/www/varnishapi/public
|
179
|
+
14775 352.6 MB 2.3 MB Passenger RubyApp: /var/www/varnishapi/public
|
180
|
+
...
|
181
|
+
```
|
182
|
+
|
183
|
+
### Usage Documentation
|
184
|
+
The usage documentation is available at the root context:
|
185
|
+
|
186
|
+
```
|
187
|
+
http://your-ip-address:10001/
|
188
|
+
```
|
189
|
+
|
190
|
+
### WORD OF WARNING!
|
191
|
+
|
192
|
+
This small web application is meant to run in an controlled environment and offers no encryption or authentication. Anyone who can access the Rest API can potentially remove all of your varnish backends or overload your vanish process with calls to the "varnishadm" command. Use at your own risk!
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
### RESTful API Actions
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
| Method | Url | Description | Remarks |
|
201
|
+
|------|------|------|------|
|
202
|
+
| GET | /list | list all backends | read-only |
|
203
|
+
| GET | /ping | ping varnish process | read-only |
|
204
|
+
| GET | /banner | display varnish banner with version information | read-only |
|
205
|
+
| GET | /status | display status of varnish process | read-only |
|
206
|
+
| GET | /ban | ban all objects immediately | effectively purges objects. See varnish [documentation](<https://www.varnish-cache.org/docs/3.0/tutorial/purging.html>) |
|
207
|
+
| GET | /*backend*/in | sets backend health to "auto", allowing probe to decide if backend is healthy | use partial or complete backend name as it appears in VCL. The Rest API will not process request if more than one backend is found matching for the pattern |
|
208
|
+
| GET | /*backend*/out | sets backend health to "sick" | use partial or complete backend name as it appears in VCL. The Rest API will not process request if more than one backend is found matching for the pattern|
|
data/Rakefile
ADDED
data/examples/config.ru
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
|
2
|
+
require 'open3'
|
3
|
+
require 'json'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'zk'
|
6
|
+
require 'socket'
|
7
|
+
|
8
|
+
|
9
|
+
class VarnishBase
|
10
|
+
|
11
|
+
def initialize(params = {})
|
12
|
+
@mgmt_port = params.fetch(:mgmt_port, 6082)
|
13
|
+
@mgmt_host = params.fetch(:mgmt_host, 'localhost')
|
14
|
+
@instance = params.fetch(:instance, 'default')
|
15
|
+
@use_zookeeper = params.fetch(:use_zookeeper, false)
|
16
|
+
@zookeeper_host = params.fetch(:zookeeper_host, nil)
|
17
|
+
@zookeeper_basenode = params.fetch(:zookeeper_basenode, '/varnish')
|
18
|
+
@secret = params.fetch(:secret, '/etc/varnish/secret')
|
19
|
+
@varnishadm_path = params.fetch(:varnishadm_path, '/usr/bin/varnishadm')
|
20
|
+
@varnishadm = "#{@varnishadm_path.to_s} -T #{@mgmt_host.to_s}:#{@mgmt_port.to_s} -S #{@secret.to_s}"
|
21
|
+
@hostname = Socket.gethostname
|
22
|
+
|
23
|
+
puts "varnishadm command line: " + @varnishadm.to_s
|
24
|
+
|
25
|
+
if @use_zookeeper && !@zookeeper_host.empty?
|
26
|
+
puts "configured to use use zookeeper"
|
27
|
+
begin
|
28
|
+
@zk = ZK.new(@zookeeper_host)
|
29
|
+
rescue RuntimeError => e
|
30
|
+
abort "problem connecting to zookeeper host: #{@zookeeper_host}"
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
@zk.create(@zookeeper_basenode + '/' + @hostname, @hostname, :mode => :ephemeral_sequential)
|
35
|
+
rescue ZK::Exceptions::NoNode => zke
|
36
|
+
@zk.create(@zookeeper_basenode,'', :mode => :persistent)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def output(result)
|
43
|
+
result[:error].empty? ? result[:output] : result[:error]
|
44
|
+
end
|
45
|
+
|
46
|
+
def varnish_major_version
|
47
|
+
varnishadm("banner")[:output].each do |d|
|
48
|
+
m = /^varnish-([0-9]+).*/.match(d)
|
49
|
+
unless m.nil?
|
50
|
+
return m[1].to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
return 0
|
54
|
+
end
|
55
|
+
|
56
|
+
# banning has the effect of purging content
|
57
|
+
# https://www.varnish-software.com/static/book/Cache_invalidation.html#banning
|
58
|
+
def ban_all
|
59
|
+
command = varnish_major_version >= 4 ? '\'ban req.url ~ .\'' : '\'ban.url .\''
|
60
|
+
result = output(varnishadm(command))
|
61
|
+
JSON.pretty_generate({ command => result.empty? ? "command successful" : result })
|
62
|
+
end
|
63
|
+
|
64
|
+
# ping
|
65
|
+
def ping
|
66
|
+
JSON.pretty_generate({ 'ping' => output(varnishadm("ping")) })
|
67
|
+
end
|
68
|
+
|
69
|
+
# backend enable/disable
|
70
|
+
def set_health(backend,health,options={})
|
71
|
+
default_options = {
|
72
|
+
:safe => true,
|
73
|
+
:json => false
|
74
|
+
}
|
75
|
+
options = default_options.merge!(options)
|
76
|
+
|
77
|
+
unless ["sick","auto"].include?(health)
|
78
|
+
error = { 'error' => "invalid health '#{health}'. health must be 'sick' or 'auto'"}
|
79
|
+
return options[:json] ? JSON.pretty_generate(error) : error
|
80
|
+
end
|
81
|
+
|
82
|
+
backends_found = list_backends(:expression => backend)
|
83
|
+
|
84
|
+
if options[:safe] && backends_found.size > 1
|
85
|
+
error = { 'error' => "multiple backends found for pattern '#{backend}': " + backends_found.collect { |b| b.backend_name }.join(',')}
|
86
|
+
return options[:json] ? JSON.pretty_generate(error) : error
|
87
|
+
end
|
88
|
+
|
89
|
+
varnishadm("backend.set_health #{backend} #{health}")
|
90
|
+
list_backends(:expression => backend, :json => options[:json])
|
91
|
+
end
|
92
|
+
|
93
|
+
# list backends
|
94
|
+
def list_backends(options={})
|
95
|
+
default_options = {
|
96
|
+
:expression => nil,
|
97
|
+
:json => false
|
98
|
+
}
|
99
|
+
options = default_options.merge!(options)
|
100
|
+
backends = Array.new
|
101
|
+
command = "backend.list"
|
102
|
+
|
103
|
+
unless options[:expression].nil? || options[:expression].empty?
|
104
|
+
command += " #{options[:expression]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
varnishadm_result = varnishadm(command)
|
108
|
+
#puts "command => " + command
|
109
|
+
|
110
|
+
unless varnishadm_result[:error].empty?
|
111
|
+
return options[:json] ? JSON.pretty_generate(varnishadm_result[:error]) : varnishadm_result[:error]
|
112
|
+
end
|
113
|
+
|
114
|
+
varnishadm_result[:output].to_a.each_with_index do |line,i|
|
115
|
+
#varnishadm(command)[:output].to_a.each_with_index do |line,i|
|
116
|
+
next if i < 1
|
117
|
+
backend = OpenStruct.new
|
118
|
+
#server1(127.0.0.1,80) 1 probe Sick 0/5
|
119
|
+
#line = "server1(127.0.0.1,80) 1 probe Sick 0/5"
|
120
|
+
components = line.squeeze.split
|
121
|
+
host_re = /(.*?)\((.*?)\)\s+(\d+)\s+(.*?)\s+(.*)/
|
122
|
+
match = host_re.match(line)
|
123
|
+
backend.backend_name = match[1].to_s
|
124
|
+
backend.host = match[2].to_s
|
125
|
+
backend.refs = match[3].to_s
|
126
|
+
backend.admin = match[4].to_s
|
127
|
+
backend.health = match[5].to_s
|
128
|
+
backends << backend
|
129
|
+
end
|
130
|
+
options[:json] ? JSON.pretty_generate(backends.map { |o| Hash[o.each_pair.to_a] }) : backends
|
131
|
+
end
|
132
|
+
|
133
|
+
# Display the varnish banner
|
134
|
+
def banner
|
135
|
+
JSON.pretty_generate({ 'banner' => output(varnishadm("banner"))})
|
136
|
+
end
|
137
|
+
|
138
|
+
# Display the current status of the varnish process
|
139
|
+
def status
|
140
|
+
JSON.pretty_generate({ 'status' => output(varnishadm("status"))})
|
141
|
+
end
|
142
|
+
|
143
|
+
# Run the varnishadm command and capture and return stdout,stderr
|
144
|
+
def varnishadm(cmd)
|
145
|
+
output = Array.new
|
146
|
+
error = Array.new
|
147
|
+
begin
|
148
|
+
Open3.popen3(@varnishadm + ' ' + cmd) do |stdin, stdout, stderr, wait_thr|
|
149
|
+
|
150
|
+
exit_status = wait_thr.value
|
151
|
+
|
152
|
+
unless exit_status.success?
|
153
|
+
#raise
|
154
|
+
$stderr.puts "varnishadm exited with code #{exit_status.exitstatus}"
|
155
|
+
while line = stderr.gets
|
156
|
+
$stderr.puts line
|
157
|
+
if line.strip.length > 0
|
158
|
+
error << line.strip
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
while line = stdout.gets
|
164
|
+
if line.strip.length > 0
|
165
|
+
output << line.strip
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
rescue Errno::ENOENT => e
|
171
|
+
$stderr.puts "error running varnishadm: #{e.message}"
|
172
|
+
error << "error running varnishadm: #{e.message}"
|
173
|
+
output << "error running varnishadm: #{e.message}"
|
174
|
+
end
|
175
|
+
|
176
|
+
return { :output => output, :error => error}
|
177
|
+
end
|
178
|
+
|
179
|
+
def to_s
|
180
|
+
"instance #{@instance}"
|
181
|
+
end
|
182
|
+
|
183
|
+
private :varnishadm, :varnish_major_version, :output
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
=begin
|
189
|
+
v = Varnish.new
|
190
|
+
puts v.status
|
191
|
+
puts "="
|
192
|
+
puts v.banner
|
193
|
+
puts "="
|
194
|
+
puts v.list_backends(:expression => "server3", :json=>true)
|
195
|
+
puts "="
|
196
|
+
puts v.list_backends
|
197
|
+
=end
|
198
|
+
|
199
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'varnish_rest_api/varnish_base'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class VarnishRestApi < Sinatra::Application
|
6
|
+
|
7
|
+
CONFIG_FILE = "varnish_rest_api.yaml"
|
8
|
+
CONFIG_PATHS = [ '/etc/' + CONFIG_FILE, ENV['HOME'] + '/' + CONFIG_FILE , File.dirname(__FILE__) + '/' + CONFIG_FILE ]
|
9
|
+
CONFIG = CONFIG_PATHS.detect {|config| File.file?(config) }
|
10
|
+
|
11
|
+
if !CONFIG
|
12
|
+
$stderr.puts "no configuration file found in paths: " + CONFIG_PATHS.join(',')
|
13
|
+
exit!
|
14
|
+
else
|
15
|
+
puts "using configuration file: " + CONFIG
|
16
|
+
end
|
17
|
+
|
18
|
+
config_parsed = begin
|
19
|
+
YAML.load(File.open(CONFIG))
|
20
|
+
rescue ArgumentError, Errno::ENOENT => e
|
21
|
+
$stderr.puts "Exception while opening yaml config file: #{e}"
|
22
|
+
exit!
|
23
|
+
end
|
24
|
+
|
25
|
+
config_file = Hash.new
|
26
|
+
begin
|
27
|
+
config_file = config_parsed.inject({}){|h,(k,v)| h[k.to_sym] = v; h}
|
28
|
+
rescue NoMethodError => e
|
29
|
+
$stderr.puts "error parsing configuration yaml"
|
30
|
+
end
|
31
|
+
|
32
|
+
# default configuration
|
33
|
+
config_default = {
|
34
|
+
:bind_ip => '0.0.0.0',
|
35
|
+
:port => 4567,
|
36
|
+
:mgmt_port => 6082,
|
37
|
+
:mgmt_host => 'localhost',
|
38
|
+
:secret => '/etc/varnish/secret',
|
39
|
+
:varnishadm_path => '/usr/bin/varnishadm',
|
40
|
+
:instance => "default",
|
41
|
+
:use_zookeeper => false,
|
42
|
+
:zookeeper_host => nil,
|
43
|
+
:zookeeper_basenode => '/varnish'
|
44
|
+
}
|
45
|
+
|
46
|
+
config = config_default.merge!(config_file)
|
47
|
+
|
48
|
+
varnish = VarnishBase.new(:instance => config[:instance], \
|
49
|
+
:zookeeper_host => config[:zookeeper_host], \
|
50
|
+
:use_zookeeper => config[:use_zookeeper], \
|
51
|
+
:zookeeper_basenode => config[:zookeeper_basenode], \
|
52
|
+
:secret => config[:secret], \
|
53
|
+
:mgmt_port => config[:mgmt_port], \
|
54
|
+
:mgmt_host => config[:mgmt_host], \
|
55
|
+
:varnishadm_path => config[:varnishadm_path])
|
56
|
+
|
57
|
+
# sinatra configuration
|
58
|
+
configure do
|
59
|
+
set :root, File.dirname(__FILE__)
|
60
|
+
set :bind, config[:bind_ip]
|
61
|
+
set :port, config[:port]
|
62
|
+
set :server, %w[thin mongrel webrick]
|
63
|
+
set :show_exceptions, true
|
64
|
+
end
|
65
|
+
|
66
|
+
before do
|
67
|
+
content_type :json
|
68
|
+
end
|
69
|
+
|
70
|
+
not_found do
|
71
|
+
content_type :html
|
72
|
+
@status = status.to_i
|
73
|
+
erb :help
|
74
|
+
end
|
75
|
+
|
76
|
+
helpers do
|
77
|
+
end
|
78
|
+
|
79
|
+
error do
|
80
|
+
'Sorry there was a nasty error - ' + env['sinatra.error'].name
|
81
|
+
end
|
82
|
+
|
83
|
+
['/', '/help', '/usage'].each do |route|
|
84
|
+
get route do
|
85
|
+
content_type :html
|
86
|
+
erb :help
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# display the varnish banner containing varnish version information
|
91
|
+
get '/banner' do
|
92
|
+
varnish.banner
|
93
|
+
end
|
94
|
+
|
95
|
+
# run varnishadm ping call to varnish
|
96
|
+
get '/ping' do
|
97
|
+
varnish.ping
|
98
|
+
end
|
99
|
+
|
100
|
+
# report the status of the varnish process
|
101
|
+
get '/status' do
|
102
|
+
varnish.status
|
103
|
+
end
|
104
|
+
|
105
|
+
# display all backends and state
|
106
|
+
get '/list' do
|
107
|
+
varnish.list_backends(:json => true)
|
108
|
+
end
|
109
|
+
|
110
|
+
# purge cache objects using the ban feature
|
111
|
+
get '/ban' do
|
112
|
+
varnish.ban_all
|
113
|
+
end
|
114
|
+
|
115
|
+
# set the health of a backend. Acceptable actions are "sick" and "auto". Auto indicates the varnish probe should decide whether to send traffic to this backend based on probe health
|
116
|
+
# only one backend at a time can be changed. This is a safety feature due to varnish-cli greedy and unpredictable expression pattern matching.
|
117
|
+
get %r{^/(.*?)/(in|out)$} do
|
118
|
+
backend = params[:captures].first
|
119
|
+
action = params[:captures].last
|
120
|
+
health = action == 'out' ? 'sick' : 'auto'
|
121
|
+
backends = varnish.set_health(backend,health)
|
122
|
+
|
123
|
+
if backends.empty?
|
124
|
+
content_type :html
|
125
|
+
halt 400, erb(:error, :locals => { :message => "No backend found for pattern #{backend}"})
|
126
|
+
elsif backends.class == Hash && backends.has_key?("error")
|
127
|
+
content_type :html
|
128
|
+
error = backends['error']
|
129
|
+
halt 400, erb(:error, :locals => { :message => error})
|
130
|
+
end
|
131
|
+
redirect to('/list')
|
132
|
+
end
|
133
|
+
|
134
|
+
=begin
|
135
|
+
v = Varnish.new
|
136
|
+
puts v.status
|
137
|
+
puts "="
|
138
|
+
puts v.banner
|
139
|
+
puts "="
|
140
|
+
puts v.list_backends(:expression => "server3", :json=>true)
|
141
|
+
puts "="
|
142
|
+
puts v.list_backends(:expression => "server2",:json=>true)
|
143
|
+
puts v.set_health("server11","sick")
|
144
|
+
puts v.set_health("server3","auto")
|
145
|
+
puts v.set_health("server","auto",false)
|
146
|
+
puts "="
|
147
|
+
puts v.ping
|
148
|
+
puts "="
|
149
|
+
puts v.ban_all
|
150
|
+
=end
|
151
|
+
run! if app_file == $0
|
152
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
---
|
2
|
+
port: 10001
|
3
|
+
bind_ip: '0.0.0.0'
|
4
|
+
secret: /home/vagrant/secret
|
5
|
+
mgmt_port: 6082
|
6
|
+
mgmt_host: localhost
|
7
|
+
varnishadm_path: /usr/bin/varnishadm
|
8
|
+
instance: default
|
9
|
+
use_zookeeper: false
|
10
|
+
zookeeper_host: autodeploy38-2:2181
|
11
|
+
zookeeper_basenode: /varnish
|
data/lib/views/error.erb
ADDED
data/lib/views/help.erb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
<html>
|
2
|
+
<style>
|
3
|
+
h2 {
|
4
|
+
text-align: center;
|
5
|
+
color: red;
|
6
|
+
}
|
7
|
+
h1 {
|
8
|
+
text-align: left;
|
9
|
+
}
|
10
|
+
table {
|
11
|
+
border-spacing: 5px;
|
12
|
+
}
|
13
|
+
tr:nth-child(even) {
|
14
|
+
background-color: #eee;
|
15
|
+
}
|
16
|
+
tr:nth-child(odd) {
|
17
|
+
background-color: #fff;
|
18
|
+
}
|
19
|
+
th {
|
20
|
+
text-align: left;
|
21
|
+
color: white;
|
22
|
+
background-color: black;
|
23
|
+
}
|
24
|
+
</style>
|
25
|
+
<% if status == 404 %>
|
26
|
+
<h2>Error: <%= request.path_info %> is not a valid url</h2>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
<table>
|
32
|
+
<caption><h3>Varnish REST API help</h3></caption>
|
33
|
+
<tr>
|
34
|
+
<th>Method</th>
|
35
|
+
<th>URL</th>
|
36
|
+
<th>Description</th>
|
37
|
+
<th>Remarks</th>
|
38
|
+
</tr>
|
39
|
+
|
40
|
+
<tr>
|
41
|
+
<td>GET</td>
|
42
|
+
<td>/list</td>
|
43
|
+
<td>list all backends</td>
|
44
|
+
<td>read-only</td>
|
45
|
+
</tr>
|
46
|
+
|
47
|
+
<tr>
|
48
|
+
<td>GET</td>
|
49
|
+
<td>/ping</td>
|
50
|
+
<td>ping varnish process</td>
|
51
|
+
<td>read-only</td>
|
52
|
+
</tr>
|
53
|
+
<tr>
|
54
|
+
<td>GET</td>
|
55
|
+
<td>/banner</td>
|
56
|
+
<td>display varnish banner with version information</td>
|
57
|
+
<td>read-only</td>
|
58
|
+
</tr>
|
59
|
+
|
60
|
+
<tr>
|
61
|
+
<td>GET</td>
|
62
|
+
<td>/status</td>
|
63
|
+
<td>display status of varnish process</td>
|
64
|
+
<td>read-only</td>
|
65
|
+
</tr>
|
66
|
+
|
67
|
+
<tr>
|
68
|
+
<td>GET</td>
|
69
|
+
<td>/ban</td>
|
70
|
+
<td>ban all objects immediately</td>
|
71
|
+
<td>effectively purges objects. See <a href="https://www.varnish-cache.org/docs/3.0/tutorial/purging.html">here</a> and <a href="https://www.varnish-software.com/static/book/Cache_invalidation.html">here</a></td>
|
72
|
+
</tr>
|
73
|
+
|
74
|
+
<tr>
|
75
|
+
<td>GET</td>
|
76
|
+
<td>/{backend}/in</td>
|
77
|
+
<td>sets backend health to "auto", allowing probe to decide if backend is healthy</td>
|
78
|
+
<td>use partial or complete backend name as it appears in VCL. The Rest API will not process request if more than one backend is found matching for the pattern</td>
|
79
|
+
</tr>
|
80
|
+
<tr>
|
81
|
+
<td>GET</td>
|
82
|
+
<td>/{backend}/out</td>
|
83
|
+
<td>sets backend health to "sick"</td>
|
84
|
+
<td>use partial or complete backend name as it appears in VCL. The Rest API will not process request if more than one backend is found matching for the pattern</td>
|
85
|
+
</tr>
|
86
|
+
<tr>
|
87
|
+
</tr>
|
88
|
+
</table>
|
89
|
+
|
90
|
+
|
91
|
+
</html>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'varnish_rest_api/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "varnish_rest_api"
|
8
|
+
spec.version = VarnishRestApi::VERSION
|
9
|
+
spec.authors = ["Jonathan Colby"]
|
10
|
+
spec.email = ["jcolby@team.mobile.de"]
|
11
|
+
spec.summary = %q{A sinatra rest api for varnish.}
|
12
|
+
spec.description = %q{A restful http api for setting backend health, banning cache objects and getting status information. Executes varnishadm via http rest calls.}
|
13
|
+
spec.homepage = "http://rubygems.org/gems/varnish_rest_api"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.files << ["bin/varnishrestapi.rb"]
|
18
|
+
spec.files << ["examples/config.ru"]
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "sinatra"
|
24
|
+
spec.add_dependency "zk"
|
25
|
+
spec.add_dependency "zookeeper"
|
26
|
+
spec.add_dependency "json"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: varnish_rest_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Colby
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sinatra
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: zk
|
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: zookeeper
|
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: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.7'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.7'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
description: A restful http api for setting backend health, banning cache objects
|
98
|
+
and getting status information. Executes varnishadm via http rest calls.
|
99
|
+
email:
|
100
|
+
- jcolby@team.mobile.de
|
101
|
+
executables:
|
102
|
+
- varnishrestapi.rb
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".buildpath"
|
107
|
+
- ".gitignore"
|
108
|
+
- Gemfile
|
109
|
+
- Gemfile.orig
|
110
|
+
- LICENSE.txt
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/varnishrestapi.rb
|
114
|
+
- examples/config.ru
|
115
|
+
- lib/varnish_rest_api.rb
|
116
|
+
- lib/varnish_rest_api.yaml
|
117
|
+
- lib/varnish_rest_api/varnish_base.rb
|
118
|
+
- lib/varnish_rest_api/version.rb
|
119
|
+
- lib/views/error.erb
|
120
|
+
- lib/views/help.erb
|
121
|
+
- varnish_rest_api.gemspec
|
122
|
+
homepage: http://rubygems.org/gems/varnish_rest_api
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.4.5
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: A sinatra rest api for varnish.
|
146
|
+
test_files: []
|
147
|
+
has_rdoc:
|