ipecache 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +13 -0
- data/README.md +180 -0
- data/Rakefile +2 -0
- data/bin/ipecache +84 -0
- data/ipecache.gemspec +22 -0
- data/lib/ipecache.rb +3 -0
- data/lib/ipecache/plugins.rb +22 -0
- data/lib/ipecache/plugins/akamai.rb +65 -0
- data/lib/ipecache/plugins/ats_chef.rb +61 -0
- data/lib/ipecache/plugins/edgecast.rb +59 -0
- data/lib/ipecache/plugins/fastly.rb +60 -0
- data/lib/ipecache/plugins/plugin.rb +66 -0
- data/lib/ipecache/runner.rb +44 -0
- data/plugins/ATSChef.md +34 -0
- data/plugins/Akamai.md +26 -0
- data/plugins/Edgecast.md +26 -0
- data/plugins/Fastly.md +20 -0
- data/plugins/README.md +63 -0
- metadata +131 -0
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ipecache (0.0.1)
|
5
|
+
app_conf (>= 0.4.0)
|
6
|
+
choice (>= 0.1.6)
|
7
|
+
faraday_middleware (>= 0.9.0)
|
8
|
+
savon (>= 2.1.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
akami (1.2.0)
|
14
|
+
gyoku (>= 0.4.0)
|
15
|
+
nokogiri (>= 1.4.0)
|
16
|
+
app_conf (0.4.0)
|
17
|
+
builder (3.0.0)
|
18
|
+
choice (0.1.6)
|
19
|
+
faraday (0.8.6)
|
20
|
+
multipart-post (~> 1.1)
|
21
|
+
faraday_middleware (0.9.0)
|
22
|
+
faraday (>= 0.7.4, < 0.9)
|
23
|
+
gyoku (1.0.0)
|
24
|
+
builder (>= 2.1.2)
|
25
|
+
httpi (2.0.2)
|
26
|
+
rack
|
27
|
+
multipart-post (1.2.0)
|
28
|
+
nokogiri (1.5.6)
|
29
|
+
nori (2.0.4)
|
30
|
+
rack (1.4.1)
|
31
|
+
savon (2.1.0)
|
32
|
+
akami (~> 1.2.0)
|
33
|
+
builder (>= 2.1.2)
|
34
|
+
gyoku (~> 1.0.0)
|
35
|
+
httpi (~> 2.0.2)
|
36
|
+
nokogiri (>= 1.4.0)
|
37
|
+
nori (~> 2.0.3)
|
38
|
+
wasabi (~> 3.0.0)
|
39
|
+
wasabi (3.0.0)
|
40
|
+
httpi (~> 2.0)
|
41
|
+
nokogiri (>= 1.4.0)
|
42
|
+
|
43
|
+
PLATFORMS
|
44
|
+
ruby
|
45
|
+
|
46
|
+
DEPENDENCIES
|
47
|
+
ipecache!
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Ipecache
|
2
|
+
----------
|
3
|
+
Author:: Jon Cowie (<jcowie@etsy.com>)
|
4
|
+
Copyright:: Copyright (c) 2013 Jon Cowie
|
5
|
+
License:: GPL
|
6
|
+
|
7
|
+
Plugin API
|
8
|
+
----------
|
9
|
+
Modified version of code added to knife-spork under the following license:
|
10
|
+
|
11
|
+
Author:: Seth Vargo (<svargo@customink.com>)
|
12
|
+
Copyright:: Copyright (c) 2012 Seth Vargo
|
13
|
+
License:: GPL
|
data/README.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
Ipecache
|
2
|
+
===========
|
3
|
+
Ipecache is an extensible tool for purging URLs from Caches and CDNs.
|
4
|
+
|
5
|
+
Installation
|
6
|
+
------------
|
7
|
+
### Gem Install (recommended)
|
8
|
+
`ipecache` is available on rubygems. Add the following to your `Gemfile`:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'ipecache'
|
12
|
+
```
|
13
|
+
|
14
|
+
or install the gem manually:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
gem install ipecache
|
18
|
+
```
|
19
|
+
|
20
|
+
Ipecache Configuration
|
21
|
+
-------------------
|
22
|
+
Ipecache will not work with no configuration, so before you can purge anything, you'll need to specify some configuration for the plugins you wish to use.
|
23
|
+
|
24
|
+
Ipecache will look for a configuration file in the following locations, in ascending order of precedence:
|
25
|
+
|
26
|
+
- `/etc/ipecache-config.yml`
|
27
|
+
- `~/.ipecache/ipecache-config.yml`
|
28
|
+
|
29
|
+
Anything set in the configuration file in your home directory for example, will override options set in `/etc`.
|
30
|
+
|
31
|
+
Below is a sample config file with all supported options and all shipped plugins enabled below, followed by an explanation of each section.
|
32
|
+
|
33
|
+
Please note, if you do not want to use a particular plugin, don't specify any configuration for it and it will automatically be disabled.
|
34
|
+
|
35
|
+
```yaml
|
36
|
+
plugins:
|
37
|
+
atschef:
|
38
|
+
knife_config: /my/.chef/knife.rb
|
39
|
+
chef_role: ATSRole
|
40
|
+
fastly:
|
41
|
+
api_key: abc123abc123abc123abc123abc123abc123
|
42
|
+
edgecast:
|
43
|
+
account_id: 1A2B
|
44
|
+
api_key: abc123
|
45
|
+
akamai:
|
46
|
+
username: myusername
|
47
|
+
password: mypassword
|
48
|
+
```
|
49
|
+
|
50
|
+
#### atschef
|
51
|
+
For more information on how to configure the ATS/Chef plugin, please read the [plugins/ATSChef.md](plugins/ATSChef.md) file.
|
52
|
+
|
53
|
+
#### Fastly
|
54
|
+
For more information on how to configure the Fastly CDN plugin, please read the [plugins/Fastly.md](plugins/Fastly.md) file.
|
55
|
+
|
56
|
+
#### Edgecast
|
57
|
+
For more information on how to configure the Edgecast CDN plugin, please read the [plugins/Edgecast.md](plugins/Edgecast.md) file.
|
58
|
+
|
59
|
+
#### Akamai
|
60
|
+
For more information on how to configure the Akamai plugin, please read the [plugins/Akamai.md](plugins/Akamai.md) file.
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
Ipecache Usage
|
65
|
+
-----------
|
66
|
+
The main component of Ipecache, and the program which initialises and calls all plugins is called `ipecache`.
|
67
|
+
|
68
|
+
#### Usage
|
69
|
+
```bash
|
70
|
+
ipecache [-f -u -c -p --status]
|
71
|
+
```
|
72
|
+
|
73
|
+
* Mandatory Parameters (you must specify one or the other)
|
74
|
+
* -f: Specifies a file containg a newline seperated list of URLS to purge
|
75
|
+
* -u: Specifies a single URL to purge
|
76
|
+
|
77
|
+
* Optional Parameters:
|
78
|
+
* --status: Prints the status of all ipecache plugins
|
79
|
+
* -c: Indicates that only CDN plugins should be run
|
80
|
+
* -p: Indicates that only local proxy plugins should be run.
|
81
|
+
|
82
|
+
|
83
|
+
#### Example (Checking plugin status)
|
84
|
+
|
85
|
+
```text
|
86
|
+
$> ipecache --status
|
87
|
+
Ipecache Status:
|
88
|
+
|
89
|
+
Ipecache::Plugins::Akamai: enabled
|
90
|
+
Ipecache::Plugins::ATSChef: enabled
|
91
|
+
Ipecache::Plugins::Edgecast: enabled
|
92
|
+
Ipecache::Plugins::Fastly: enabled
|
93
|
+
```
|
94
|
+
|
95
|
+
#### Example (Purging a single URL from local proxies only)
|
96
|
+
|
97
|
+
```text
|
98
|
+
$> ipecache -u https://img3.etsystatic.com/000/0/5241384/il_340x270.220445599.jpg -p
|
99
|
+
|
100
|
+
Running plugins registered for Proxy Purge...
|
101
|
+
|
102
|
+
|
103
|
+
Ipecache::Plugins::ATSChef: Beginning URL Purge from ATS...
|
104
|
+
Ipecache::Plugins::ATSChef: Finding ATS Servers...
|
105
|
+
Ipecache::Plugins::ATSChef: Purging https://img.mydomain.com/image9.jpg
|
106
|
+
Ipecache::Plugins::ATSChef: --Purge from cache1.mydomain.com not needed, asset not found
|
107
|
+
Ipecache::Plugins::ATSChef: --Purged from cache2.mydomain.com sucessfully
|
108
|
+
|
109
|
+
All done!
|
110
|
+
```
|
111
|
+
|
112
|
+
#### Example (Purging a file containing 2 URLs from CDNS only)
|
113
|
+
|
114
|
+
```text
|
115
|
+
$> ipecache -f ~/urlfile -c
|
116
|
+
|
117
|
+
Running plugins registered for CDN Purge...
|
118
|
+
|
119
|
+
|
120
|
+
Ipecache::Plugins::Akamai: Beginning URL Purge from Akamai...
|
121
|
+
Ipecache::Plugins::Akamai: Purging https://img.mydomain.com/image9.jpg
|
122
|
+
Ipecache::Plugins::Akamai: Purge successful!
|
123
|
+
Ipecache::Plugins::Akamai: Purging https://img.mydomain.com/image10.jpg
|
124
|
+
Ipecache::Plugins::Akamai: Purge successful!
|
125
|
+
|
126
|
+
Ipecache::Plugins::Edgecast: Beginning URL Purge from Edgecast...
|
127
|
+
Ipecache::Plugins::Edgecast: Purging https://img.mydomain.com/image9.jpg
|
128
|
+
Ipecache::Plugins::Edgecast: Purge successful!
|
129
|
+
Ipecache::Plugins::Edgecast: Purging https://img.mydomain.com/image10.jpg
|
130
|
+
Ipecache::Plugins::Edgecast: Purge successful!
|
131
|
+
|
132
|
+
Ipecache::Plugins::Fastly: Beginning URL Purge from Fastly...
|
133
|
+
Ipecache::Plugins::Fastly: Purging https://img.mydomain.com/image9.jpg
|
134
|
+
Ipecache::Plugins::Fastly: Purge successful!
|
135
|
+
Ipecache::Plugins::Fastly: Purging https://img.mydomain.com/imag10.jpg
|
136
|
+
Ipecache::Plugins::Fastly: Purge successful!
|
137
|
+
|
138
|
+
All done!
|
139
|
+
```
|
140
|
+
|
141
|
+
#### Example (Purging a file containing 2 URLs from proxies and CDNS)
|
142
|
+
|
143
|
+
```text
|
144
|
+
$> ipecache -f ~/urlfile
|
145
|
+
|
146
|
+
Running plugins registered for Proxy Purge...
|
147
|
+
|
148
|
+
|
149
|
+
Ipecache::Plugins::ATSChef: Beginning URL Purge from ATS...
|
150
|
+
Ipecache::Plugins::ATSChef: Finding ATS Servers...
|
151
|
+
Ipecache::Plugins::ATSChef: Purging https://img.mydomain.com/image9.jpg
|
152
|
+
Ipecache::Plugins::ATSChef: --Purge from cache1.mydomain.com not needed, asset not found
|
153
|
+
Ipecache::Plugins::ATSChef: --Purged from cache2.mydomain.com sucessfully
|
154
|
+
Ipecache::Plugins::ATSChef: Purging https://img.mydomain.com/image10.jpg
|
155
|
+
Ipecache::Plugins::ATSChef: --Purge from cache1.mydomain.com not needed, asset not found
|
156
|
+
Ipecache::Plugins::ATSChef: --Purged from cache2.mydomain.com sucessfully
|
157
|
+
|
158
|
+
Running plugins registered for CDN Purge...
|
159
|
+
|
160
|
+
|
161
|
+
Ipecache::Plugins::Akamai: Beginning URL Purge from Akamai...
|
162
|
+
Ipecache::Plugins::Akamai: Purging https://img.mydomain.com/image9.jpg
|
163
|
+
Ipecache::Plugins::Akamai: Purge successful!
|
164
|
+
Ipecache::Plugins::Akamai: Purging https://img.mydomain.com/image10.jpg
|
165
|
+
Ipecache::Plugins::Akamai: Purge successful!
|
166
|
+
|
167
|
+
Ipecache::Plugins::Edgecast: Beginning URL Purge from Edgecast...
|
168
|
+
Ipecache::Plugins::Edgecast: Purging https://img.mydomain.com/image9.jpg
|
169
|
+
Ipecache::Plugins::Edgecast: Purge successful!
|
170
|
+
Ipecache::Plugins::Edgecast: Purging https://img.mydomain.com/image10.jpg
|
171
|
+
Ipecache::Plugins::Edgecast: Purge successful!
|
172
|
+
|
173
|
+
Ipecache::Plugins::Fastly: Beginning URL Purge from Fastly...
|
174
|
+
Ipecache::Plugins::Fastly: Purging https://img.mydomain.com/image9.jpg
|
175
|
+
Ipecache::Plugins::Fastly: Purge successful!
|
176
|
+
Ipecache::Plugins::Fastly: Purging https://img.mydomain.com/imag10.jpg
|
177
|
+
Ipecache::Plugins::Fastly: Purge successful!
|
178
|
+
|
179
|
+
All done!
|
180
|
+
```
|
data/Rakefile
ADDED
data/bin/ipecache
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# ipecache - A command line memcached traffic analyzer
|
4
|
+
#
|
5
|
+
# Author:: Jon Cowie (<jcowie@etsy.com>)
|
6
|
+
|
7
|
+
require 'choice'
|
8
|
+
require 'ipecache/runner'
|
9
|
+
include Ipecache::Runner
|
10
|
+
|
11
|
+
Choice.options do
|
12
|
+
header ""
|
13
|
+
header "Specific options:"
|
14
|
+
|
15
|
+
option :status, :required => false do
|
16
|
+
long '--status'
|
17
|
+
desc 'Show ipecache status information'
|
18
|
+
end
|
19
|
+
|
20
|
+
option :urlfile, :required => false do
|
21
|
+
short '-f'
|
22
|
+
long '--file=PATH_TO_URL_FILE'
|
23
|
+
desc 'File containing urls to purge from caches'
|
24
|
+
end
|
25
|
+
|
26
|
+
option :url, :required => false do
|
27
|
+
short '-u'
|
28
|
+
long '--url=URL_TO_PURGE'
|
29
|
+
desc 'URL to be purged from caches'
|
30
|
+
end
|
31
|
+
|
32
|
+
option :proxyonly, :required => false do
|
33
|
+
short '-p'
|
34
|
+
long '--proxy-only'
|
35
|
+
desc 'Only purge from proxies'
|
36
|
+
end
|
37
|
+
|
38
|
+
option :cdnonly, :required => false do
|
39
|
+
short '-c'
|
40
|
+
long '--cdn-only'
|
41
|
+
desc 'Only purge from CDNs'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if Choice.choices[:status]
|
46
|
+
puts "Ipecache Status:"
|
47
|
+
puts ""
|
48
|
+
Ipecache::Plugins.klasses.each do |klass|
|
49
|
+
plugin = klass.new(:config => ipecache_config)
|
50
|
+
puts "#{klass}: #{plugin.enabled? ? 'enabled' : 'disabled'}"
|
51
|
+
end
|
52
|
+
exit 0
|
53
|
+
end
|
54
|
+
|
55
|
+
if Choice.choices[:url]
|
56
|
+
@urls = [Choice.choices[:url]]
|
57
|
+
elsif Choice.choices[:urlfile]
|
58
|
+
urlfile = Choice.choices[:urlfile]
|
59
|
+
if File.exists?(urlfile)
|
60
|
+
@urls = File.open(urlfile, 'r').readlines
|
61
|
+
else
|
62
|
+
puts "Error: #{urlfile} doesn't exist."
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
else
|
66
|
+
Choice.help
|
67
|
+
end
|
68
|
+
|
69
|
+
if !Choice.choices[:cdnonly]
|
70
|
+
puts ""
|
71
|
+
puts "Running plugins registered for Proxy Purge..."
|
72
|
+
puts ""
|
73
|
+
run_plugins(:proxy_purge)
|
74
|
+
end
|
75
|
+
|
76
|
+
if !Choice.choices[:proxyonly]
|
77
|
+
puts ""
|
78
|
+
puts "Running plugins registered for CDN Purge..."
|
79
|
+
puts ""
|
80
|
+
run_plugins(:cdn_purge)
|
81
|
+
end
|
82
|
+
|
83
|
+
puts ""
|
84
|
+
puts "All done!"
|
data/ipecache.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'ipecache'
|
5
|
+
gem.version = '0.0.1'
|
6
|
+
gem.authors = ["Jon Cowie"]
|
7
|
+
gem.email = 'jonlives@gmail.com'
|
8
|
+
gem.homepage = 'https://github.com/jonlives/ipecache'
|
9
|
+
gem.summary = "An extensible tool for purging urls from caches and CDNs"
|
10
|
+
gem.description = "An extensible tool for purging urls from caches and CDNs"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "ipecache"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'app_conf', '>= 0.4.0'
|
19
|
+
gem.add_runtime_dependency 'choice', '>= 0.1.6'
|
20
|
+
gem.add_runtime_dependency 'faraday_middleware', '>= 0.9.0'
|
21
|
+
gem.add_runtime_dependency 'savon', '>= 2.1.0'
|
22
|
+
end
|
data/lib/ipecache.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Ipecache
|
2
|
+
module Plugins
|
3
|
+
# Load each of the drop-in plugins
|
4
|
+
Dir[File.expand_path('../plugins/**/*.rb', __FILE__)].each { |f| require f }
|
5
|
+
|
6
|
+
def self.run(options = {})
|
7
|
+
hook = options[:hook].to_sym
|
8
|
+
|
9
|
+
klasses.each do |klass|
|
10
|
+
plugin = klass.new(options)
|
11
|
+
plugin.send(hook) if plugin.respond_to?(hook) && plugin.enabled?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get and return a list of all subclasses (plugins) that are not the base plugin
|
16
|
+
def self.klasses
|
17
|
+
@@klasses ||= self.constants.collect do |c|
|
18
|
+
self.const_get(c) if self.const_get(c).is_a?(Class) && self.const_get(c) != Ipecache::Plugins::Plugin
|
19
|
+
end.compact
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ipecache/plugins/plugin'
|
2
|
+
|
3
|
+
module Ipecache
|
4
|
+
module Plugins
|
5
|
+
class Akamai < Plugin
|
6
|
+
name :akamai
|
7
|
+
hooks :cdn_purge
|
8
|
+
|
9
|
+
def perform
|
10
|
+
safe_require 'savon'
|
11
|
+
|
12
|
+
username = config.username
|
13
|
+
password = config.password
|
14
|
+
|
15
|
+
if username.nil?
|
16
|
+
plugin_puts("Akamai username not specified, Exiting...")
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
if password.nil?
|
21
|
+
plugin_puts("Akamai password key not specified, Exiting...")
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
puts ""
|
26
|
+
plugin_puts "Beginning URL Purge from Akamai..."
|
27
|
+
|
28
|
+
urls.each do |u|
|
29
|
+
url = u.chomp
|
30
|
+
plugin_puts ("Purging #{url}")
|
31
|
+
|
32
|
+
savon_client = Savon.client({log_level: :info, log: false, convert_request_keys_to: :none, wsdl: 'https://ccuapi.akamai.com/ccuapi-axis.wsdl'})
|
33
|
+
response = savon_client.call(:purge_request, xml: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
34
|
+
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
|
35
|
+
xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"
|
36
|
+
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
|
37
|
+
soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"
|
38
|
+
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">
|
39
|
+
<soap:Body>
|
40
|
+
<purgeRequest xmlns=\"http://ccuapi.akamai.com/purge\">
|
41
|
+
<name xsi:type=\"xsd:string\">#{username}</name>
|
42
|
+
<pwd xsi:type=\"xsd:string\">#{password}</pwd>
|
43
|
+
<network xsi:type=\"xsd:string\"></network>
|
44
|
+
<opt soapenc:arrayType=\"xsd:string[2]\" xsi:type=\"soapenc:Array\">
|
45
|
+
<item xsi:type=\"xsd:string\">type=arl</item>
|
46
|
+
<item xsi:type=\"xsd:string\">action=remove</item>
|
47
|
+
</opt>'
|
48
|
+
<uri soapenc:arrayType=\"xsd:string[1]\" xsi:type=\"soapenc:Array\">
|
49
|
+
<item xsi:type=\"xsd:string\">#{url}</item>
|
50
|
+
</uri>
|
51
|
+
</purgeRequest>
|
52
|
+
</soap:Body>
|
53
|
+
</soap:Envelope>")
|
54
|
+
response_hash = response.to_hash
|
55
|
+
if response_hash[:purge_request_response][:return][:result_msg] != "Success."
|
56
|
+
plugin_puts "An Error occured: #{response_hash[:purge_request_response][:return][:result_msg]}"
|
57
|
+
exit 1
|
58
|
+
else
|
59
|
+
plugin_puts "Purge successful!"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ipecache/plugins/plugin'
|
2
|
+
|
3
|
+
module Ipecache
|
4
|
+
module Plugins
|
5
|
+
class ATSChef < Plugin
|
6
|
+
name :atschef
|
7
|
+
hooks :proxy_purge
|
8
|
+
|
9
|
+
def perform
|
10
|
+
safe_require 'chef'
|
11
|
+
safe_require 'uri'
|
12
|
+
|
13
|
+
knife_file = config.knife_config || ""
|
14
|
+
chef_role = config.chef_role
|
15
|
+
|
16
|
+
if knife_file.empty?
|
17
|
+
plugin_puts "No knife config file specified. Exiting..."
|
18
|
+
exit 1
|
19
|
+
elsif File.exists?(knife_file)
|
20
|
+
Chef::Config.from_file(knife_file)
|
21
|
+
rest_api = Chef::REST.new(Chef::Config[:chef_server_url])
|
22
|
+
else
|
23
|
+
plugin_puts "Knife config file #{knife_file} doesn't exist."
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
if !chef_role
|
28
|
+
plugin_puts "Chef role not specified, Exiting..."
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
|
32
|
+
puts ""
|
33
|
+
plugin_puts "Beginning URL Purge from ATS..."
|
34
|
+
plugin_puts "Finding ATS Servers..."
|
35
|
+
nodes_ats_fqdns = []
|
36
|
+
nodes_ats = rest_api.get_rest("/search/node?q=role:#{chef_role}" )
|
37
|
+
nodes_ats["rows"].each do |n|
|
38
|
+
nodes_ats_fqdns << n.fqdn unless n.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
urls.each do |u|
|
42
|
+
url = u.chomp
|
43
|
+
plugin_puts ("Purging #{url}")
|
44
|
+
nodes_ats_fqdns.each do |ats|
|
45
|
+
hostname = URI.parse(url).host
|
46
|
+
path = URI.parse(url).path
|
47
|
+
result = `ssh #{ats} 'curl -X PURGE -s -o /dev/null -w \"%{http_code}\" --header \"Host: #{hostname}\" \"http://localhost#{path}\"'`
|
48
|
+
if result.include?("200")
|
49
|
+
plugin_puts "--Purged from #{ats} sucessfully"
|
50
|
+
elsif result.include?("404")
|
51
|
+
plugin_puts "--Purge from #{ats} not needed, asset not found"
|
52
|
+
else
|
53
|
+
plugin_puts "--Purge from #{ats} failed"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'ipecache/plugins/plugin'
|
2
|
+
|
3
|
+
module Ipecache
|
4
|
+
module Plugins
|
5
|
+
class Edgecast < Plugin
|
6
|
+
name :edgecast
|
7
|
+
hooks :cdn_purge
|
8
|
+
|
9
|
+
def perform
|
10
|
+
safe_require 'uri'
|
11
|
+
safe_require 'faraday_middleware'
|
12
|
+
safe_require 'json'
|
13
|
+
|
14
|
+
account_id = config.account_id
|
15
|
+
api_key = config.api_key
|
16
|
+
|
17
|
+
if account_id.nil?
|
18
|
+
plugin_puts("Edgecast account id not specified, Exiting...")
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
if api_key.nil?
|
23
|
+
plugin_puts("Edgecast API key not specified, Exiting...")
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
puts ""
|
28
|
+
plugin_puts "Beginning URL Purge from Edgecast..."
|
29
|
+
|
30
|
+
urls.each do |u|
|
31
|
+
url = u.chomp
|
32
|
+
plugin_puts ("Purging #{url}")
|
33
|
+
|
34
|
+
connection = Faraday::Connection.new(
|
35
|
+
{:url => "https://api.edgecast.com",
|
36
|
+
:headers => { :accept => 'application/json',
|
37
|
+
:content_type => 'application/json',
|
38
|
+
:user_agent => 'Ipecache',
|
39
|
+
:authorization => "TOK:#{api_key}"},
|
40
|
+
:ssl => { :verify => true }
|
41
|
+
}) do |builder|
|
42
|
+
builder.request :json
|
43
|
+
builder.adapter Faraday.default_adapter
|
44
|
+
end
|
45
|
+
|
46
|
+
response = connection.put("/v2/mcc/customers/#{account_id}/edge/purge",{ :MediaPath => url, :MediaType => 8})
|
47
|
+
|
48
|
+
if response.status != 200
|
49
|
+
plugin_puts "Response Code: #{response.status}"
|
50
|
+
plugin_puts response.body
|
51
|
+
exit 1
|
52
|
+
else
|
53
|
+
plugin_puts "Purge successful!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'ipecache/plugins/plugin'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Ipecache
|
5
|
+
module Plugins
|
6
|
+
class Fastly < Plugin
|
7
|
+
name :fastly
|
8
|
+
hooks :cdn_purge
|
9
|
+
|
10
|
+
def perform
|
11
|
+
safe_require 'uri'
|
12
|
+
|
13
|
+
api_key = config.api_key
|
14
|
+
|
15
|
+
if api_key.nil?
|
16
|
+
plugin_puts("Fastly API key not specified, Exiting...")
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
puts ""
|
21
|
+
plugin_puts "Beginning URL Purge from Fastly..."
|
22
|
+
|
23
|
+
urls.each do |u|
|
24
|
+
url = u.chomp
|
25
|
+
plugin_puts ("Purging #{url}")
|
26
|
+
hostname = URI.parse(url).host
|
27
|
+
path = URI.parse(url).path
|
28
|
+
|
29
|
+
http = Net::HTTP.new("api.fastly.com", "443")
|
30
|
+
http.use_ssl = true
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
|
33
|
+
request = Net::HTTP::Purge.new(path)
|
34
|
+
request.add_field("X-Forwarded-For", "0.0.0.0")
|
35
|
+
request.add_field("Accept", "application/json")
|
36
|
+
request.add_field("User-Agent", "Ipecache")
|
37
|
+
request.add_field("Content-Type", "application/x-www-form-urlencoded")
|
38
|
+
request.add_field("X-Fastly-Key", api_key)
|
39
|
+
request.add_field("Host", hostname)
|
40
|
+
|
41
|
+
response = http.request(request)
|
42
|
+
|
43
|
+
if response.code.to_i != 200
|
44
|
+
plugin_puts "Response Code: #{response.code}"
|
45
|
+
plugin_puts response.body
|
46
|
+
exit 1
|
47
|
+
else
|
48
|
+
plugin_puts "Purge successful!"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Net::HTTP::Purge < Net::HTTPRequest
|
57
|
+
METHOD = 'PURGE'
|
58
|
+
REQUEST_HAS_BODY = false
|
59
|
+
RESPONSE_HAS_BODY = true
|
60
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Ipecache
|
2
|
+
module Plugins
|
3
|
+
class Plugin
|
4
|
+
# This is the name of the plugin. It must correspond to the name in the yaml configuration
|
5
|
+
# file in order to load this plugin. If an attribute is passed in, the name is set to that
|
6
|
+
# given value. Otherwise, the name is returned.
|
7
|
+
def self.name(name = nil)
|
8
|
+
if name.nil?
|
9
|
+
class_variable_get(:@@name)
|
10
|
+
else
|
11
|
+
class_variable_set(:@@name, name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# This is a convenience method for defining multiple hooks in a single call.
|
16
|
+
def self.hooks(*the_hooks)
|
17
|
+
[the_hooks].flatten.each{ |the_hook| hook(the_hook) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# When defining a hook, we define a method on the instance that corresponds to that
|
21
|
+
# hook. That will be fired when the hook is fired.
|
22
|
+
def self.hook(the_hook)
|
23
|
+
self.send(:define_method, the_hook.to_sym) do
|
24
|
+
perform
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(options = {})
|
29
|
+
@options = {
|
30
|
+
:payload => {}
|
31
|
+
}.merge(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def enabled?
|
35
|
+
!(config.nil? || config.enabled == false)
|
36
|
+
end
|
37
|
+
|
38
|
+
def urls
|
39
|
+
@options[:urls]
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
self.class.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def plugin_puts(message)
|
47
|
+
puts "#{name}: #{message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def config
|
52
|
+
@options[:config].plugins.send(self.class.name.to_sym) unless @options[:config].nil? || @options[:config].plugins.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Wrapper method around require that attempts to include the associated file. If it does not exist
|
56
|
+
# or cannot be loaded, an nice error is produced instead of blowing up.
|
57
|
+
def safe_require(file)
|
58
|
+
begin
|
59
|
+
require file
|
60
|
+
rescue LoadError
|
61
|
+
raise "You are using a plugin for ipecache that requires #{file}, but you have not installed it. Please either run \"gem install #{file}\", add #{file} to your Gemfile or remove the plugin from your configuration."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'app_conf'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'ipecache/plugins'
|
5
|
+
|
6
|
+
module Ipecache
|
7
|
+
module Runner
|
8
|
+
module ClassMethods; end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def ipecache_config
|
12
|
+
return @ipecache_config unless @ipecache_config.nil?
|
13
|
+
|
14
|
+
@ipecache_config = AppConf.new
|
15
|
+
load_paths = [ File.expand_path('config/ipecache-config.yml'), '/etc/ipecache-config.yml', File.expand_path('~/.ipecache/ipecache-config.yml') ]
|
16
|
+
load_paths.each do |load_path|
|
17
|
+
if File.exists?(load_path)
|
18
|
+
@ipecache_config.load(load_path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@ipecache_config
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_plugins(hook)
|
26
|
+
urls = @urls
|
27
|
+
Ipecache::Plugins.run(
|
28
|
+
:config => ipecache_config,
|
29
|
+
:hook => hook.to_sym,
|
30
|
+
:urls => urls
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pretty_print_json(json)
|
35
|
+
JSON.pretty_generate(json)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.included(receiver)
|
40
|
+
receiver.extend(ClassMethods)
|
41
|
+
receiver.send(:include, InstanceMethods)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/plugins/ATSChef.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
ATSChef
|
2
|
+
========
|
3
|
+
Queries chef for nodes in the specified role and purges the URL list from each server
|
4
|
+
|
5
|
+
Gem Requirements
|
6
|
+
----------------
|
7
|
+
This plugin requires the following gems:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'chef'
|
11
|
+
```
|
12
|
+
|
13
|
+
Hooks
|
14
|
+
-----
|
15
|
+
- `proxy_purge`
|
16
|
+
|
17
|
+
Configuration
|
18
|
+
-------------
|
19
|
+
```yaml
|
20
|
+
plugins:
|
21
|
+
atschef:
|
22
|
+
knife_config: /my/.chef/knife.rb
|
23
|
+
chef_role: ATSRole
|
24
|
+
```
|
25
|
+
|
26
|
+
#### knife_config
|
27
|
+
This is the knife.rb that ipecache can use to search against your Chef server
|
28
|
+
|
29
|
+
- Type: `String`
|
30
|
+
|
31
|
+
#### chef_role
|
32
|
+
This is the chef role which your ATS servers live in
|
33
|
+
|
34
|
+
- Type: `String`
|
data/plugins/Akamai.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Akamai
|
2
|
+
========
|
3
|
+
Purges URLS from the Akamai CDN using the Content Control Utility API
|
4
|
+
|
5
|
+
Hooks
|
6
|
+
-----
|
7
|
+
- `cdn_purge`
|
8
|
+
|
9
|
+
Configuration
|
10
|
+
-------------
|
11
|
+
```yaml
|
12
|
+
plugins:
|
13
|
+
akamai:
|
14
|
+
username: foo
|
15
|
+
password: bar
|
16
|
+
```
|
17
|
+
|
18
|
+
#### username
|
19
|
+
This is the username of the Akamai account you want to use
|
20
|
+
|
21
|
+
- Type: `String`
|
22
|
+
|
23
|
+
#### password
|
24
|
+
This is the username of the Akamai account you want to use
|
25
|
+
|
26
|
+
- Type: `String`
|
data/plugins/Edgecast.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Edgecast
|
2
|
+
========
|
3
|
+
Purges URLS from the Edgecast CDN - please note this currently only works with HTTP Small objects.
|
4
|
+
|
5
|
+
Hooks
|
6
|
+
-----
|
7
|
+
- `cdn_purge`
|
8
|
+
|
9
|
+
Configuration
|
10
|
+
-------------
|
11
|
+
```yaml
|
12
|
+
plugins:
|
13
|
+
edgecast:
|
14
|
+
account_id: 1ABC
|
15
|
+
api_key: aaaa-aaaaaa-aaaaaa-aaaaa
|
16
|
+
```
|
17
|
+
|
18
|
+
#### account_id
|
19
|
+
This is your Edgecast account number, found at the top of the Edgecast admin interface
|
20
|
+
|
21
|
+
- Type: `String`
|
22
|
+
|
23
|
+
#### api_key
|
24
|
+
This is your Edgecast API key
|
25
|
+
|
26
|
+
- Type: `String`
|
data/plugins/Fastly.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Fastly
|
2
|
+
========
|
3
|
+
Purges URLS from the Fastly CDN
|
4
|
+
|
5
|
+
Hooks
|
6
|
+
-----
|
7
|
+
- `cdn_purge`
|
8
|
+
|
9
|
+
Configuration
|
10
|
+
-------------
|
11
|
+
```yaml
|
12
|
+
plugins:
|
13
|
+
fastly:
|
14
|
+
api_key: ab123ab123ab123ab123ab123ab123
|
15
|
+
```
|
16
|
+
|
17
|
+
#### api_key
|
18
|
+
This is your fastly API key
|
19
|
+
|
20
|
+
- Type: `String`
|
data/plugins/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
Plugins Directory
|
2
|
+
=================
|
3
|
+
This folder contains relevant documentation for each KnifeSpork plugin. For more information, usage, and options for an particular plugin, click on the assoicated markdown file in the tree above.
|
4
|
+
|
5
|
+
Creating a Plugin
|
6
|
+
-----------------
|
7
|
+
To create a plugin, start with the following basic boiler template:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require 'ipecache/plugins/plugin'
|
11
|
+
|
12
|
+
module Ipecache
|
13
|
+
module Plugins
|
14
|
+
class MyPlugin < Plugin
|
15
|
+
name :my_plugin
|
16
|
+
hooks :my_hooks
|
17
|
+
|
18
|
+
def perform
|
19
|
+
# your plugin code here
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
**Don't forget to update the class name and the `name` at the very top of the class!**
|
27
|
+
|
28
|
+
Hooks
|
29
|
+
-----
|
30
|
+
|
31
|
+
Currently, the only hooks called by the ipecache binary are "proxy_purge" (for plugins for "local" proxy servers) and "cdn_purge" (for CDN plugins). These hooks determine whether or not your plugin will be called when the -c and -p options are passed to the ipecache binary.
|
32
|
+
|
33
|
+
Helpers
|
34
|
+
-------
|
35
|
+
The following "helpers" or "methods" are exposed:
|
36
|
+
|
37
|
+
#### safe_require
|
38
|
+
This method allows you to safely require a gem. This is helpful when your plugin requires an external plugin. It will output a nice error message if the gem cannot be loaded and stop executing.
|
39
|
+
|
40
|
+
#### urls
|
41
|
+
This method gives you the list of URLS to be purged
|
42
|
+
|
43
|
+
#### plugin_puts
|
44
|
+
This method prints strings prefixed by the class name of your plugin, for clarity of output
|
45
|
+
|
46
|
+
#### config
|
47
|
+
This method returns the config associated with the current plugin. For example, if a `spork-config.yml` file looked like this:
|
48
|
+
|
49
|
+
```yaml
|
50
|
+
plugins:
|
51
|
+
my_plugin:
|
52
|
+
option_1: my_value
|
53
|
+
option_2: other_value
|
54
|
+
```
|
55
|
+
|
56
|
+
then
|
57
|
+
|
58
|
+
```text
|
59
|
+
config.option_1 #=> 'my_value'
|
60
|
+
config.option_2 #=> 'other_value'
|
61
|
+
```
|
62
|
+
|
63
|
+
This uses `app_conf`, so you access the keys as methods, not `[]`.
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ipecache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Cowie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: app_conf
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.4.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.4.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: choice
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.1.6
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.1.6
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: faraday_middleware
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: savon
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.1.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.1.0
|
78
|
+
description: An extensible tool for purging urls from caches and CDNs
|
79
|
+
email: jonlives@gmail.com
|
80
|
+
executables:
|
81
|
+
- ipecache
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- CHANGELOG.md
|
86
|
+
- Gemfile
|
87
|
+
- Gemfile.lock
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- bin/ipecache
|
92
|
+
- ipecache.gemspec
|
93
|
+
- lib/ipecache.rb
|
94
|
+
- lib/ipecache/plugins.rb
|
95
|
+
- lib/ipecache/plugins/akamai.rb
|
96
|
+
- lib/ipecache/plugins/ats_chef.rb
|
97
|
+
- lib/ipecache/plugins/edgecast.rb
|
98
|
+
- lib/ipecache/plugins/fastly.rb
|
99
|
+
- lib/ipecache/plugins/plugin.rb
|
100
|
+
- lib/ipecache/runner.rb
|
101
|
+
- plugins/ATSChef.md
|
102
|
+
- plugins/Akamai.md
|
103
|
+
- plugins/Edgecast.md
|
104
|
+
- plugins/Fastly.md
|
105
|
+
- plugins/README.md
|
106
|
+
homepage: https://github.com/jonlives/ipecache
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.24
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: An extensible tool for purging urls from caches and CDNs
|
130
|
+
test_files: []
|
131
|
+
has_rdoc:
|