fastly 1.1.4 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HISTORY.md +7 -3
- data/README.md +0 -2
- data/bin/fastly_upload_vcl +18 -18
- data/fastly.gemspec +11 -11
- data/lib/ext/curb_fu/response/base.rb +20 -0
- data/lib/fastly.rb +69 -83
- data/lib/fastly/base.rb +9 -9
- data/lib/fastly/belongs_to_service_and_version.rb +9 -14
- data/lib/fastly/cache_setting.rb +32 -34
- data/lib/fastly/client.rb +55 -120
- data/lib/fastly/client/curl.rb +57 -0
- data/lib/fastly/condition.rb +32 -32
- data/lib/fastly/customer.rb +1 -1
- data/lib/fastly/director.rb +4 -4
- data/lib/fastly/fetcher.rb +10 -12
- data/lib/fastly/gem_version.rb +2 -2
- data/lib/fastly/gzip.rb +26 -27
- data/lib/fastly/header.rb +67 -68
- data/lib/fastly/invoice.rb +17 -16
- data/lib/fastly/origin.rb +4 -5
- data/lib/fastly/request_setting.rb +68 -69
- data/lib/fastly/response_object.rb +46 -47
- data/lib/fastly/s3_logging.rb +48 -50
- data/lib/fastly/service.rb +20 -26
- data/lib/fastly/settings.rb +10 -11
- data/lib/fastly/syslog.rb +53 -57
- data/lib/fastly/user.rb +4 -6
- data/lib/fastly/util.rb +1 -0
- data/lib/fastly/version.rb +25 -30
- data/test/admin_test.rb +8 -8
- data/test/api_key_test.rb +20 -39
- data/test/common.rb +64 -66
- data/test/fastly/util_test.rb +1 -0
- data/test/full_login_test.rb +77 -82
- data/test/helper.rb +15 -24
- data/test/missing_api_key_test.rb +1 -1
- data/test/stats_test.rb +42 -50
- metadata +17 -13
data/lib/fastly/base.rb
CHANGED
@@ -5,9 +5,9 @@ class Fastly
|
|
5
5
|
|
6
6
|
def initialize(opts, fetcher)
|
7
7
|
@keys = []
|
8
|
-
opts.each do |key,val|
|
8
|
+
opts.each do |key, val|
|
9
9
|
next unless self.respond_to? "#{key}="
|
10
|
-
|
10
|
+
send("#{key}=", val)
|
11
11
|
@keys.push(key)
|
12
12
|
end
|
13
13
|
self.fetcher = fetcher
|
@@ -28,7 +28,7 @@ class Fastly
|
|
28
28
|
def as_hash
|
29
29
|
ret = {}
|
30
30
|
@keys.each do |key|
|
31
|
-
ret[key] =
|
31
|
+
ret[key] = send("#{key}") unless key =~ /^_/
|
32
32
|
end
|
33
33
|
ret
|
34
34
|
end
|
@@ -45,20 +45,20 @@ class Fastly
|
|
45
45
|
"/#{path}/#{id}"
|
46
46
|
end
|
47
47
|
|
48
|
-
def self.post_path(
|
48
|
+
def self.post_path(_opts = {})
|
49
49
|
"/#{path}"
|
50
50
|
end
|
51
51
|
|
52
|
-
def self.list_path(opts={})
|
52
|
+
def self.list_path(opts = {})
|
53
53
|
post_path(opts)
|
54
54
|
end
|
55
55
|
|
56
|
-
def self.put_path(
|
57
|
-
get_path(
|
56
|
+
def self.put_path(object)
|
57
|
+
get_path(object.id)
|
58
58
|
end
|
59
59
|
|
60
|
-
def self.delete_path(
|
61
|
-
put_path(
|
60
|
+
def self.delete_path(object)
|
61
|
+
put_path(object)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
class Fastly
|
2
|
+
# Encapsulates behavior of objects requiring both service and version
|
2
3
|
class BelongsToServiceAndVersion < Base
|
4
|
+
attr_writer :version
|
5
|
+
|
3
6
|
# Return the Service object this belongs to
|
4
7
|
def service
|
5
|
-
@service ||= fetcher.get(
|
6
|
-
end
|
7
|
-
|
8
|
-
# Set the Version object this belongs to
|
9
|
-
def version=(version)
|
10
|
-
@version = version
|
8
|
+
@service ||= fetcher.get(Service, service_id)
|
11
9
|
end
|
12
10
|
|
13
11
|
# Get the Version object this belongs to
|
@@ -16,18 +14,16 @@ class Fastly
|
|
16
14
|
end
|
17
15
|
|
18
16
|
# Get the number of the Version this belongs to
|
19
|
-
def version_number
|
17
|
+
def version_number # rubocop:disable all
|
20
18
|
@version
|
21
|
-
end
|
19
|
+
end # rubocop:enable all
|
22
20
|
|
23
21
|
# :nodoc:
|
24
22
|
def as_hash
|
25
|
-
super.delete_if { |var|
|
23
|
+
super.delete_if { |var| %w(service_id version).include?(var) }
|
26
24
|
end
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
def self.get_path(service, version, name, options={})
|
26
|
+
def self.get_path(service, version, name, _opts = {})
|
31
27
|
"/service/#{service}/version/#{version}/#{path}/#{name}"
|
32
28
|
end
|
33
29
|
|
@@ -36,12 +32,11 @@ class Fastly
|
|
36
32
|
end
|
37
33
|
|
38
34
|
def self.put_path(obj)
|
39
|
-
get_path(obj.service_id, obj.version_number,obj.name)
|
35
|
+
get_path(obj.service_id, obj.version_number, obj.name)
|
40
36
|
end
|
41
37
|
|
42
38
|
def self.delete_path(obj)
|
43
39
|
put_path(obj)
|
44
40
|
end
|
45
|
-
|
46
41
|
end
|
47
42
|
end
|
data/lib/fastly/cache_setting.rb
CHANGED
@@ -2,46 +2,44 @@ class Fastly
|
|
2
2
|
# customize cache handling. Best used with conditions.
|
3
3
|
class CacheSetting < BelongsToServiceAndVersion
|
4
4
|
attr_accessor :service_id, :name, :action, :cache_condition, :ttl, :stale_ttl
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
##
|
6
|
+
# :attr: service_id
|
7
|
+
#
|
8
|
+
# The id of the service this belongs to.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
##
|
11
|
+
# :attr: version
|
12
|
+
#
|
13
|
+
# The number of the version this belongs to.
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
##
|
16
|
+
# :attr: name
|
17
|
+
#
|
18
|
+
# The name of the gzip setting
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
##
|
21
|
+
# :attr: action
|
22
|
+
#
|
23
|
+
# Allows for termination of execution and either cache, pass, or restart
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
##
|
26
|
+
# :attr: ttl
|
27
|
+
#
|
28
|
+
# Sets the time to live
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
##
|
31
|
+
# :attr: stale_ttl
|
32
|
+
#
|
33
|
+
# Sets the max time to live for stale (unreachable) objects
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
##
|
36
|
+
# :attr: cache_condition
|
37
|
+
#
|
38
|
+
# Name of the cache condition used to test whether this settings object
|
39
|
+
# should be used.
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Util.class_to_path(self, true)
|
45
|
-
end
|
41
|
+
def self.path
|
42
|
+
Util.class_to_path(self, true)
|
43
|
+
end
|
46
44
|
end
|
47
45
|
end
|
data/lib/fastly/client.rb
CHANGED
@@ -1,40 +1,36 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'net/https'
|
3
1
|
require 'json'
|
4
2
|
require 'cgi'
|
5
|
-
require 'pp'
|
6
3
|
require 'uri'
|
4
|
+
require 'fastly/client/curl'
|
7
5
|
|
8
6
|
class Fastly
|
9
7
|
# The UserAgent to communicate with the API
|
10
8
|
class Client #:nodoc: all
|
11
|
-
begin
|
12
|
-
require 'curb-fu'
|
13
|
-
CURB_FU=true
|
14
|
-
rescue LoadError
|
15
|
-
CURB_FU=false
|
16
|
-
end
|
17
|
-
|
18
9
|
attr_accessor :http, :api_key, :user, :password, :cookie, :customer
|
19
10
|
|
20
11
|
def initialize(opts)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
@api_key = opts.fetch(:api_key, nil)
|
13
|
+
@user = opts.fetch(:user, nil)
|
14
|
+
@password = opts.fetch(:password, nil)
|
15
|
+
@customer = opts.fetch(:customer, nil)
|
16
|
+
|
17
|
+
base = opts.fetch(:base_url, 'https://api.fastly.com')
|
25
18
|
uri = URI.parse(base)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
port = opts.has_key?(:base_port) ? opts[:base_port] : (scheme == "https") ? 443 : 80
|
30
|
-
self.http = curb ? Fastly::Client::Curl.new(host, port) : Net::HTTP.new(host, port)
|
31
|
-
self.http.use_ssl = (scheme == "https")
|
19
|
+
|
20
|
+
@http = Curl.new(uri)
|
21
|
+
|
32
22
|
return self unless fully_authed?
|
33
23
|
|
34
24
|
# If we're fully authed (i.e username and password ) then we need to log in
|
35
|
-
resp =
|
36
|
-
|
37
|
-
|
25
|
+
resp = http.post('/login', make_params(user: user, password: password))
|
26
|
+
|
27
|
+
if resp.success?
|
28
|
+
@cookie = resp['Set-Cookie']
|
29
|
+
else
|
30
|
+
fail Unauthorized
|
31
|
+
end
|
32
|
+
|
33
|
+
self
|
38
34
|
end
|
39
35
|
|
40
36
|
def require_key!
|
@@ -56,133 +52,72 @@ class Fastly
|
|
56
52
|
!(user.nil? || password.nil?)
|
57
53
|
end
|
58
54
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def get(path, params={})
|
64
|
-
path += "?"+make_params(params) unless params.empty?
|
65
|
-
resp = self.http.get(path, headers)
|
55
|
+
def get(path, params = {})
|
56
|
+
path += "?#{make_params(params)}" unless params.empty?
|
57
|
+
resp = http.get(path, headers)
|
66
58
|
return nil if 404 == resp.status
|
67
|
-
|
59
|
+
fail Error, resp.message unless resp.success?
|
68
60
|
JSON.parse(resp.body)
|
69
61
|
end
|
70
62
|
|
71
|
-
def get_stats(path, params={})
|
63
|
+
def get_stats(path, params = {})
|
72
64
|
content = get(path, params)
|
73
|
-
|
74
|
-
content[
|
65
|
+
|
66
|
+
case content['status']
|
67
|
+
when 'success' then content['data']
|
68
|
+
else
|
69
|
+
fail Error, content['message']
|
70
|
+
end
|
75
71
|
end
|
76
72
|
|
77
|
-
def post(path, params={})
|
73
|
+
def post(path, params = {})
|
78
74
|
post_and_put(:post, path, params)
|
79
75
|
end
|
80
76
|
|
81
|
-
def put(path, params={})
|
77
|
+
def put(path, params = {})
|
82
78
|
post_and_put(:put, path, params)
|
83
79
|
end
|
84
80
|
|
85
81
|
def delete(path)
|
86
|
-
resp =
|
87
|
-
|
82
|
+
resp = http.delete(path, headers)
|
83
|
+
resp.success?
|
88
84
|
end
|
89
85
|
|
90
86
|
private
|
91
87
|
|
92
|
-
def post_and_put(method, path, params={})
|
88
|
+
def post_and_put(method, path, params = {})
|
93
89
|
query = make_params(params)
|
94
|
-
resp =
|
95
|
-
|
90
|
+
resp = http.send(method, path, query, headers.merge('Content-Type' => 'application/x-www-form-urlencoded'))
|
91
|
+
|
92
|
+
if resp.success?
|
93
|
+
JSON.parse(resp.body)
|
94
|
+
else
|
95
|
+
fail Error, resp.message
|
96
|
+
end
|
97
|
+
|
96
98
|
JSON.parse(resp.body)
|
97
99
|
end
|
98
100
|
|
99
101
|
def headers
|
100
|
-
headers =
|
101
|
-
|
102
|
-
else
|
103
|
-
fully_authed? ? { 'Cookie' => cookie } : api_key_header
|
104
|
-
end
|
105
|
-
headers.merge!('Fastly-Explicit-Customer' => customer) if customer
|
106
|
-
headers.merge!('Content-Accept' => 'application/json')
|
107
|
-
ensure
|
108
|
-
@require_key = nil
|
109
|
-
end
|
110
|
-
|
111
|
-
def api_key_header
|
112
|
-
{ 'X-Fastly-Key' => api_key }
|
102
|
+
headers = fully_authed? ? { 'Cookie' => cookie } : { 'Fastly-Key' => api_key }
|
103
|
+
headers.merge('Content-Accept' => 'application/json')
|
113
104
|
end
|
114
105
|
|
115
106
|
def make_params(params)
|
116
|
-
params.map
|
117
|
-
next if
|
118
|
-
|
119
|
-
|
107
|
+
param_ary = params.map do |key, value|
|
108
|
+
next if value.nil?
|
109
|
+
key = key.to_s
|
110
|
+
|
111
|
+
if value.is_a?(Hash)
|
112
|
+
value.map do |sub_key, sub_value|
|
113
|
+
"#{CGI.escape("#{key}[#{sub_key}]")}=#{CGI.escape(sub_value.to_s)}"
|
114
|
+
end
|
120
115
|
else
|
121
|
-
|
122
|
-
new_key = "#{key}[#{sub_key}]"
|
123
|
-
"#{CGI.escape(new_key)}=#{CGI.escape(sub_val.to_s)}"
|
124
|
-
}
|
116
|
+
"#{CGI.escape(key)}=#{CGI.escape(value.to_s)}"
|
125
117
|
end
|
126
|
-
}.flatten.delete_if { |v| v.nil? }.join("&")
|
127
|
-
end
|
128
|
-
|
129
|
-
# :nodoc: all
|
130
|
-
class Curl
|
131
|
-
attr_accessor :host, :port, :protocol
|
132
|
-
|
133
|
-
def initialize(host, port=443)
|
134
|
-
self.host = host
|
135
|
-
self.port = port
|
136
|
-
self.protocol = 'https'
|
137
118
|
end
|
138
119
|
|
139
|
-
|
140
|
-
CurbFu.get({ :host => host, :port => port, :path => path, :headers => headers, :protocol => protocol })
|
141
|
-
end
|
142
|
-
|
143
|
-
def post(path, params, headers={})
|
144
|
-
CurbFu.post({ :host => host, :port => port, :path => path, :headers => headers, :protocol => protocol }, params)
|
145
|
-
end
|
146
|
-
|
147
|
-
def put(path, params, headers={})
|
148
|
-
CurbFu.put({ :host => host, :port => port, :path => path, :headers => headers, :params => params, :protocol => protocol }, params)
|
149
|
-
end
|
150
|
-
|
151
|
-
def delete(path, headers={})
|
152
|
-
CurbFu.delete({ :host => host, :port => port, :path => path, :headers => headers, :protocol => protocol })
|
153
|
-
end
|
154
|
-
|
155
|
-
def use_ssl=(ssl)
|
156
|
-
self.protocol = ssl ? 'https' : 'http'
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# :nodoc: all
|
163
|
-
class Net::HTTPResponse
|
164
|
-
def success?
|
165
|
-
return Net::HTTPSuccess === self
|
166
|
-
end
|
167
|
-
|
168
|
-
def status
|
169
|
-
return self.code.to_i
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
# :nodoc: all
|
176
|
-
class CurbFu::Response::Base
|
177
|
-
def get_fields(key)
|
178
|
-
if ( match = @headers.find{|k,v| k.downcase == key.downcase} )
|
179
|
-
[match.last].flatten
|
180
|
-
else
|
181
|
-
[]
|
120
|
+
param_ary.flatten.delete_if { |v| v.nil? }.join('&')
|
182
121
|
end
|
183
122
|
end
|
184
|
-
|
185
|
-
def [](key)
|
186
|
-
get_fields(key).last
|
187
|
-
end
|
188
123
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'curb-fu'
|
2
|
+
|
3
|
+
class Fastly
|
4
|
+
class Client
|
5
|
+
# :nodoc: all
|
6
|
+
class Curl
|
7
|
+
attr_accessor :uri, :host, :port, :protocol
|
8
|
+
|
9
|
+
def initialize(uri)
|
10
|
+
@uri = uri
|
11
|
+
@host = uri.host
|
12
|
+
@port = uri.port
|
13
|
+
@protocol = uri.scheme
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, headers = {})
|
17
|
+
CurbFu.get({
|
18
|
+
host: host,
|
19
|
+
port: port,
|
20
|
+
path: path,
|
21
|
+
headers: headers,
|
22
|
+
protocol: protocol
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def post(path, params, headers = {})
|
27
|
+
CurbFu.post({
|
28
|
+
host: host,
|
29
|
+
port: port,
|
30
|
+
path: path,
|
31
|
+
headers: headers,
|
32
|
+
protocol: protocol
|
33
|
+
}, params)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(path, params, headers = {})
|
37
|
+
CurbFu.put({
|
38
|
+
host: host,
|
39
|
+
port: port,
|
40
|
+
path: path,
|
41
|
+
headers: headers,
|
42
|
+
protocol: protocol
|
43
|
+
}, params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete(path, headers = {})
|
47
|
+
CurbFu.delete({
|
48
|
+
host: host,
|
49
|
+
port: port,
|
50
|
+
path: path,
|
51
|
+
headers: headers,
|
52
|
+
protocol: protocol
|
53
|
+
})
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|