fastlyctl 1.0.15 → 1.0.16
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 +4 -4
- data/README.md +16 -4
- data/fastlyctl.gemspec +1 -0
- data/lib/fastlyctl.rb +2 -0
- data/lib/fastlyctl/cli.rb +1 -0
- data/lib/fastlyctl/clone_utils.rb +2 -2
- data/lib/fastlyctl/commands/acl.rb +1 -1
- data/lib/fastlyctl/commands/condition.rb +1 -1
- data/lib/fastlyctl/commands/copy.rb +1 -1
- data/lib/fastlyctl/commands/dictionary.rb +3 -3
- data/lib/fastlyctl/commands/purge_all.rb +3 -4
- data/lib/fastlyctl/commands/snippet.rb +1 -1
- data/lib/fastlyctl/commands/tls.rb +70 -0
- data/lib/fastlyctl/commands/tls/managed.rb +119 -0
- data/lib/fastlyctl/commands/watch.rb +2 -1
- data/lib/fastlyctl/fetcher.rb +40 -14
- data/lib/fastlyctl/subcommand_patch.rb +5 -0
- data/lib/fastlyctl/utils.rb +20 -0
- data/lib/fastlyctl/version.rb +1 -1
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c53f586abe251025a9bd645fcf0ebffc7054424d09d9db8b114e7392e9568477
|
4
|
+
data.tar.gz: bbe5746a703ce8c051e8cd98fa63405b6d33da3e77794ed5099d13b0acad5767
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fb81e003390783de19f713bc6443272d9d84d03ded47c6a4a4aef0cf381724633e2524aeac22c3dfd8578cf91db42185da20daa74fede3189f24f3ffeb50daa
|
7
|
+
data.tar.gz: 7d261f97f4ecd5f17958b1e6b5a323f6375561565771319a3ee35a9869e74b4d910ff4be01dacd721b31c73c7d4752651cdd61a40932ec1140085d1f6f99f329
|
data/README.md
CHANGED
@@ -321,6 +321,22 @@ Flags:
|
|
321
321
|
* --d: When used with the create command, specifies that the snippet should be dynamic.
|
322
322
|
* --y: Answer yes to all prompts
|
323
323
|
|
324
|
+
### tls
|
325
|
+
|
326
|
+
#### managed
|
327
|
+
|
328
|
+
Usage:
|
329
|
+
|
330
|
+
```
|
331
|
+
fastlyctl tls managed [subcommand] [domain]
|
332
|
+
```
|
333
|
+
|
334
|
+
Available Subcommands:
|
335
|
+
* create: Create a Managed TLS Subscription for `[domain]`
|
336
|
+
* status: Print the status of all Managed TLS Subscriptions
|
337
|
+
* challenges: Print the challenges available for the verification of a certificate for `[domain]`
|
338
|
+
* delete: Delete a Managed TLS Subscription for `[domain]`
|
339
|
+
|
324
340
|
### token
|
325
341
|
|
326
342
|
Manipulate tokens for an account.
|
@@ -371,10 +387,6 @@ Flags:
|
|
371
387
|
|
372
388
|
The `--debug` flag is available on any command. Using it will cause fastlyctl to print the libcurl output for any requests it makes.
|
373
389
|
|
374
|
-
## Contributing
|
375
|
-
|
376
|
-
Submit a pull request. Don't break anything.
|
377
|
-
|
378
390
|
## License
|
379
391
|
|
380
392
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/fastlyctl.gemspec
CHANGED
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_runtime_dependency "thor", "~> 0.19.4"
|
35
35
|
spec.add_runtime_dependency 'diffy', '~> 3.2.1'
|
36
36
|
spec.add_runtime_dependency 'launchy', '~> 2.4.3', '>= 2.4.3'
|
37
|
+
spec.add_runtime_dependency 'openssl', '~> 2.1.2', '>= 2.1.2'
|
37
38
|
end
|
data/lib/fastlyctl.rb
CHANGED
@@ -6,11 +6,13 @@ require "uri"
|
|
6
6
|
require "launchy"
|
7
7
|
require "erb"
|
8
8
|
require "pp"
|
9
|
+
require "openssl"
|
9
10
|
|
10
11
|
require "fastlyctl/version"
|
11
12
|
require "fastlyctl/fetcher"
|
12
13
|
require "fastlyctl/clone_utils"
|
13
14
|
require "fastlyctl/utils"
|
15
|
+
require "fastlyctl/subcommand_patch"
|
14
16
|
require "fastlyctl/cli"
|
15
17
|
|
16
18
|
include ERB::Util
|
data/lib/fastlyctl/cli.rb
CHANGED
@@ -59,12 +59,12 @@ module FastlyCTL
|
|
59
59
|
|
60
60
|
if main === true
|
61
61
|
# the "main-ness" of the vcl does not get carried over during creation. must explicitly set main
|
62
|
-
FastlyCTL::Fetcher.api_request(:put, "/service/#{sid}/version/#{version}/vcl/#{
|
62
|
+
FastlyCTL::Fetcher.api_request(:put, "/service/#{sid}/version/#{version}/vcl/#{FastlyCTL::Utils.percent_encode(obj["name"])}/main")
|
63
63
|
end
|
64
64
|
|
65
65
|
if type == "director"
|
66
66
|
backends.each do |b|
|
67
|
-
FastlyCTL::Fetcher.api_request(:post, "/service/#{sid}/version/#{version}/director/#{
|
67
|
+
FastlyCTL::Fetcher.api_request(:post, "/service/#{sid}/version/#{version}/director/#{FastlyCTL::Utils.percent_encode(obj["name"])}/backend/#{b}", body: obj )
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -20,7 +20,7 @@ module FastlyCTL
|
|
20
20
|
version = FastlyCTL::Fetcher.get_writable_version(id) unless options[:version]
|
21
21
|
version ||= options[:version]
|
22
22
|
|
23
|
-
encoded_name =
|
23
|
+
encoded_name = FastlyCTL::Utils.percent_encode(name) if name
|
24
24
|
|
25
25
|
case action
|
26
26
|
when "create"
|
@@ -32,7 +32,7 @@ module FastlyCTL
|
|
32
32
|
version = FastlyCTL::Fetcher.get_writable_version(id) unless options[:version]
|
33
33
|
version ||= options[:version].to_i
|
34
34
|
|
35
|
-
encoded_name =
|
35
|
+
encoded_name = FastlyCTL::Utils.percent_encode(name) if name
|
36
36
|
|
37
37
|
case action
|
38
38
|
when "list"
|
@@ -19,7 +19,7 @@ module FastlyCTL
|
|
19
19
|
path += "/#{obj_name}" unless obj_type == "settings"
|
20
20
|
obj = FastlyCTL::Fetcher.api_request(:get, path)
|
21
21
|
|
22
|
-
encoded_name =
|
22
|
+
encoded_name = FastlyCTL::Utils.percent_encode(obj_name)
|
23
23
|
|
24
24
|
if (obj_type == "settings")
|
25
25
|
puts "Copying settings from #{id} version #{source_version} to #{target_id} version #{target_version}..."
|
@@ -20,7 +20,7 @@ module FastlyCTL
|
|
20
20
|
version = FastlyCTL::Fetcher.get_writable_version(id) unless options[:version]
|
21
21
|
version ||= options[:version]
|
22
22
|
|
23
|
-
encoded_name =
|
23
|
+
encoded_name = FastlyCTL::Utils.percent_encode(name) if name
|
24
24
|
|
25
25
|
case action
|
26
26
|
when "create"
|
@@ -49,14 +49,14 @@ module FastlyCTL
|
|
49
49
|
abort "Must specify name for dictionary" unless name
|
50
50
|
abort "Must specify key and value for dictionary item" unless (key && value)
|
51
51
|
dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}")
|
52
|
-
FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/dictionary/#{dict["id"]}/item/#{key}", params: { item_value: value })
|
52
|
+
FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/dictionary/#{dict["id"]}/item/#{FastlyCTL::Utils.percent_encode(key)}", params: { item_value: value })
|
53
53
|
|
54
54
|
say("Dictionary item #{key} set to #{value}.")
|
55
55
|
when "remove"
|
56
56
|
abort "Must specify name for dictionary" unless name
|
57
57
|
abort "Must specify key for dictionary item" unless key
|
58
58
|
dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}")
|
59
|
-
FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/dictionary/#{dict["id"]}/item/#{key}")
|
59
|
+
FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/dictionary/#{dict["id"]}/item/#{FastlyCTL::Utils.percent_encode(key)}")
|
60
60
|
|
61
61
|
say("Item #{key} removed from dictionary #{name}.")
|
62
62
|
when "list_items"
|
@@ -3,11 +3,10 @@ module FastlyCTL
|
|
3
3
|
desc "purge_all", "Purge all content from a service."
|
4
4
|
method_option :service, :aliases => ["--s"]
|
5
5
|
def purge_all
|
6
|
-
|
6
|
+
id = FastlyCTL::Utils.parse_directory unless options[:service]
|
7
|
+
id ||= options[:service]
|
7
8
|
|
8
|
-
id
|
9
|
-
|
10
|
-
abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless (id || options[:service])
|
9
|
+
abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id
|
11
10
|
|
12
11
|
FastlyCTL::Fetcher.api_request(:post, "/service/#{id}/purge_all")
|
13
12
|
|
@@ -18,7 +18,7 @@ module FastlyCTL
|
|
18
18
|
version = FastlyCTL::Fetcher.get_writable_version(id) unless options[:version]
|
19
19
|
version ||= options[:version].to_i
|
20
20
|
|
21
|
-
encoded_name =
|
21
|
+
encoded_name = FastlyCTL::Utils.percent_encode(name) if name
|
22
22
|
|
23
23
|
filename = options.key?(:filename) ? options[:filename] : "#{name}.snippet"
|
24
24
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "fastlyctl/commands/tls/managed"
|
2
|
+
|
3
|
+
module FastlyCTL
|
4
|
+
class TLSSubCmd < SubCommandBase
|
5
|
+
SubcommandPrefix = "tls"
|
6
|
+
|
7
|
+
desc "managed SUBCOMMAND ...ARGS", "Interface with Fastly Managed TLS Subscriptions (lets-encrypt)"
|
8
|
+
subcommand "managed", TLSManagedSubCmd
|
9
|
+
end
|
10
|
+
|
11
|
+
class CLI < Thor
|
12
|
+
desc "tls SUBCOMMAND ...ARGS", "Interface with Fastly TLS"
|
13
|
+
subcommand "tls", TLSSubCmd
|
14
|
+
end
|
15
|
+
|
16
|
+
module TLSUtils
|
17
|
+
def self.get_tls_configs
|
18
|
+
data = FastlyCTL::Fetcher.api_request(:get,"/tls/configurations",{use_vnd:true})["data"]
|
19
|
+
if data.length == 0
|
20
|
+
thor = Thor::Shell::Basic.new
|
21
|
+
thor.say "No TLS Configurations found. You may need to upgrade to a paid account if you are using a free account."
|
22
|
+
thor.say "If you need assistance, please contact support@fastly.com."
|
23
|
+
if (thor.yes?("Would you like to open the TLS configuration page in the Fastly app?"))
|
24
|
+
FastlyCTL::Utils.open_app_path("/network/domains")
|
25
|
+
end
|
26
|
+
abort
|
27
|
+
end
|
28
|
+
|
29
|
+
return data
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.select_tls_config(configs)
|
33
|
+
thor = Thor::Shell::Basic.new
|
34
|
+
if configs.length == 1
|
35
|
+
thor.say "Using TLS Configuration #{configs[0]["id"]} - #{configs[0]["name"]}"
|
36
|
+
return configs[0]
|
37
|
+
end
|
38
|
+
|
39
|
+
loop do
|
40
|
+
i = 1
|
41
|
+
configs.each do |c|
|
42
|
+
bulk = c["attributes"]["bulk"] ? " [Platform TLS]" : ""
|
43
|
+
thor.say("[#{i}]#{bulk} #{c["id"]} - #{c["name"]}\n")
|
44
|
+
i += 1
|
45
|
+
end
|
46
|
+
|
47
|
+
selected = thor.ask("Which TLS Configuration would you like to use? Please type the number next to the configuration(s) above.").to_i
|
48
|
+
if selected > 0 && selected <= (configs.length+1)
|
49
|
+
selected -= 1
|
50
|
+
thor.say "Using TLS Configuration #{configs[selected]["id"]} - #{configs[selected]["name"]}"
|
51
|
+
return configs[selected]
|
52
|
+
end
|
53
|
+
|
54
|
+
thor.say "#{selcted} is in invalid selection. Please try again."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.print_challenges(tls_authorization)
|
59
|
+
thor = Thor::Shell::Basic.new
|
60
|
+
thor.say "\nIn order to verify your ownership of the domain, the Certificate Authority provided the following challenges:"
|
61
|
+
tls_authorization["attributes"]["challenges"].each do |challenge|
|
62
|
+
thor.say("\n#{challenge["type"]}: Create #{challenge["record_type"]} record for #{challenge["record_name"]} with value(s) of:")
|
63
|
+
challenge["values"].each do |val|
|
64
|
+
thor.say(" #{val}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
thor.say("\nNote: If you don't want to move all traffic to Fastly right now, use the managed-dns option. The other options result in traffic for that hostname being directed to Fastly.")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module FastlyCTL
|
2
|
+
class TLSManagedSubCmd < SubCommandBase
|
3
|
+
SubcommandPrefix = "tls managed"
|
4
|
+
DomainRegex = /(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/
|
5
|
+
|
6
|
+
desc "create <domain>", "Create a Fastly Managed TLS Subscription for [domain]. A Certificate will be requested from lets-encrypt once you satisfy one of the challenges. You can learn more about the challenge types here: https://letsencrypt.org/docs/challenge-types/ and Fastly's API documentation here: https://docs.fastly.com/api/tls-subscriptions."
|
7
|
+
def create(domain)
|
8
|
+
abort "Must specify valid domain name" unless domain =~ DomainRegex
|
9
|
+
|
10
|
+
tls_configs = FastlyCTL::TLSUtils.get_tls_configs
|
11
|
+
tls_config = FastlyCTL::TLSUtils.select_tls_config(tls_configs)
|
12
|
+
|
13
|
+
payload = {
|
14
|
+
data: {
|
15
|
+
type: "tls_subscription",
|
16
|
+
attributes: {
|
17
|
+
certificate_authority: "lets-encrypt"
|
18
|
+
},
|
19
|
+
relationships: {
|
20
|
+
tls_domains: {
|
21
|
+
data: [
|
22
|
+
{
|
23
|
+
type: "tls_domain",
|
24
|
+
id: domain
|
25
|
+
}
|
26
|
+
]
|
27
|
+
},
|
28
|
+
tls_configuration: {
|
29
|
+
data: {
|
30
|
+
type: "tls_configuration",
|
31
|
+
id: tls_config["id"]
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
subscription = FastlyCTL::Fetcher.api_request(:post,"/tls/subscriptions", {
|
39
|
+
body: payload.to_json,
|
40
|
+
use_vnd: true
|
41
|
+
})
|
42
|
+
|
43
|
+
tls_authorization = FastlyCTL::Utils.filter_vnd(subscription["included"],"tls_authorization")
|
44
|
+
abort "Unable to fetch TLS Authorization for the domain." unless tls_authorization.length > 0
|
45
|
+
FastlyCTL::TLSUtils.print_challenges(tls_authorization[0])
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "status", "Print status of Fastly Managed TLS Subscriptions"
|
49
|
+
def status
|
50
|
+
subscriptions = FastlyCTL::Fetcher.api_request(:get,"/tls/subscriptions", {
|
51
|
+
use_vnd: true
|
52
|
+
})
|
53
|
+
|
54
|
+
if subscriptions["data"].length == 0
|
55
|
+
say("No Fastly Managed TLS Subscriptions found.")
|
56
|
+
abort
|
57
|
+
end
|
58
|
+
|
59
|
+
subscriptions["data"].each do |subscription|
|
60
|
+
output = subscription["relationships"]["tls_domains"]["data"][0]["id"]
|
61
|
+
output += " - " + subscription["attributes"]["certificate_authority"]
|
62
|
+
output += " - " + subscription["attributes"]["state"]
|
63
|
+
say(output)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "challenges", "Print challenges available for a domain's verification."
|
68
|
+
def challenges(domain)
|
69
|
+
abort "Must specify valid domain name" unless domain =~ DomainRegex
|
70
|
+
|
71
|
+
domains = FastlyCTL::Fetcher.api_request(:get,"/tls/domains?include=tls_subscriptions.tls_authorizations", {
|
72
|
+
use_vnd: true
|
73
|
+
})
|
74
|
+
|
75
|
+
tls_authorizations = FastlyCTL::Utils.filter_vnd(domains["included"],"tls_authorization")
|
76
|
+
|
77
|
+
tls_authorizations.each do |tls_authorization|
|
78
|
+
tls_authorization["attributes"]["challenges"].each do |challenge|
|
79
|
+
if challenge["record_name"] == domain
|
80
|
+
FastlyCTL::TLSUtils.print_challenges(tls_authorization)
|
81
|
+
abort
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
say("#{domain} not found in domain list.")
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "delete", "Delete a Fastly Managed TLS Subscription"
|
90
|
+
def delete(domain)
|
91
|
+
abort "Must specify valid domain name" unless domain =~ DomainRegex
|
92
|
+
|
93
|
+
activation = FastlyCTL::Fetcher.api_request(:get,"/tls/activations?filter[tls_domain.id]=#{domain}", {use_vnd: true})
|
94
|
+
|
95
|
+
if activation["data"].length >= 1
|
96
|
+
say("TLS is currently active for #{domain}. If you proceed, Fastly will no longer be able to serve TLS requests to clients for #{domain}.")
|
97
|
+
answer = ask("Please type the name of the domain to confirm deactivation and deletion of the Fastly Managed TLS subscription: ")
|
98
|
+
abort "Supplied domain does not match the domain requested for deletion--aborting." unless answer == domain
|
99
|
+
|
100
|
+
FastlyCTL::Fetcher.api_request(:delete,"/tls/activations/#{activation["data"][0]["id"]}",{use_vnd:true})
|
101
|
+
end
|
102
|
+
|
103
|
+
subscriptions = FastlyCTL::Fetcher.api_request(:get,"/tls/subscriptions", {
|
104
|
+
use_vnd: true
|
105
|
+
})
|
106
|
+
|
107
|
+
subscriptions["data"].each do |subscription|
|
108
|
+
next unless subscription["relationships"]["tls_domains"]["data"][0]["id"] == domain
|
109
|
+
|
110
|
+
FastlyCTL::Fetcher.api_request(:delete,"/tls/subscriptions/#{subscription["id"]}",{use_vnd:true})
|
111
|
+
|
112
|
+
say("TLS Subscription for #{domain} has been deleted.")
|
113
|
+
abort
|
114
|
+
end
|
115
|
+
|
116
|
+
say("No TLS Subscription found for #{domain}...")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -33,7 +33,8 @@ module FastlyCTL
|
|
33
33
|
# gbps
|
34
34
|
uncacheable = agg["pass"] + agg["synth"] + agg["errors"]
|
35
35
|
bw = ((agg["resp_header_bytes"] + agg["resp_body_bytes"]).to_f * 8.0) / 1000000000.0
|
36
|
-
|
36
|
+
shield = agg["shield"] || 0
|
37
|
+
hit_rate = (1.0 - ((agg["miss"] - shield).to_f / ((agg["requests"] - uncacheable).to_f))) * 100.0
|
37
38
|
passes = agg["pass"]
|
38
39
|
miss_time = agg["miss"] > 0 ? ((agg["miss_time"] / agg["miss"]) * 1000).round(0) : 0
|
39
40
|
synth = agg["synth"]
|
data/lib/fastlyctl/fetcher.rb
CHANGED
@@ -7,6 +7,7 @@ module FastlyCTL
|
|
7
7
|
options[:body] ||= nil
|
8
8
|
options[:force_session] ||= false
|
9
9
|
options[:expected_responses] ||= [200]
|
10
|
+
options[:use_vnd] ||= false
|
10
11
|
|
11
12
|
headers = {"Accept" => "application/json", "Connection" => "close", "User-Agent" => "FastlyCTL: https://github.com/fastly/fastlyctl"}
|
12
13
|
|
@@ -27,6 +28,15 @@ module FastlyCTL
|
|
27
28
|
|
28
29
|
headers["Content-Type"] = "application/x-www-form-urlencoded" if (method == :post || method == :put)
|
29
30
|
|
31
|
+
if options[:use_vnd]
|
32
|
+
headers["Accept"] = "application/vnd.api+json"
|
33
|
+
|
34
|
+
if (method == :post || method == :put)
|
35
|
+
headers["Content-Type"] = "application/vnd.api+json"
|
36
|
+
end
|
37
|
+
options[:expected_responses].push(*[201,202,203,204])
|
38
|
+
end
|
39
|
+
|
30
40
|
headers.merge!(options[:headers]) if options[:headers].count > 0
|
31
41
|
|
32
42
|
# dont allow header splitting on anything
|
@@ -54,25 +64,41 @@ module FastlyCTL
|
|
54
64
|
end
|
55
65
|
else
|
56
66
|
case response.response_code
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
when 400
|
68
|
+
error = "400: Bad API request--something was wrong with the request made by FastlyCTL."
|
69
|
+
when 403
|
70
|
+
error = "403: Access Denied by API. Run login command to authenticate."
|
71
|
+
when 404
|
72
|
+
error = "404: Service does not exist or bad path requested."
|
73
|
+
when 503
|
74
|
+
error = "503: Error from Fastly API--see details below."
|
75
|
+
when 0
|
76
|
+
error = "0: Network connection error occurred."
|
77
|
+
else
|
78
|
+
error = "API responded with status #{response.response_code}."
|
67
79
|
end
|
68
80
|
|
69
81
|
error += " Method: #{method.to_s.upcase}, Path: #{path}\n"
|
70
|
-
|
82
|
+
|
83
|
+
if (options[:use_vnd])
|
84
|
+
begin
|
85
|
+
error_resp = JSON.parse(response.response_body)
|
86
|
+
rescue JSON::ParserError
|
87
|
+
error_resp = {"errors" => [{"title" => "Error parsing response JSON","details" => "No further information available. Please file a github issue at https://github.com/fastly/fastlyctl"}]}
|
88
|
+
end
|
89
|
+
|
90
|
+
error_resp["errors"].each do |e|
|
91
|
+
next unless e.key?("title") && e.key?("detail")
|
92
|
+
error += e["title"] + " --- " + e["detail"] + "\n"
|
93
|
+
end
|
94
|
+
else
|
95
|
+
error += "Message from API: #{response.response_body}"
|
96
|
+
end
|
71
97
|
|
72
98
|
abort error
|
73
99
|
end
|
74
100
|
|
75
|
-
return response.response_body
|
101
|
+
return response.response_body unless (response.headers["Content-Type"] =~ /json$/)
|
76
102
|
|
77
103
|
if response.response_body.length > 1
|
78
104
|
begin
|
@@ -161,7 +187,7 @@ module FastlyCTL
|
|
161
187
|
end
|
162
188
|
|
163
189
|
def self.upload_snippet(service,version,content,name)
|
164
|
-
return FastlyCTL::Fetcher.api_request(:put, "/service/#{service}/version/#{version}/snippet/#{name}", {:endpoint => :api, body: {
|
190
|
+
return FastlyCTL::Fetcher.api_request(:put, "/service/#{service}/version/#{version}/snippet/#{FastlyCTL::Utils.percent_encode(name)}", {:endpoint => :api, body: {
|
165
191
|
content: content
|
166
192
|
}
|
167
193
|
})
|
@@ -178,7 +204,7 @@ module FastlyCTL
|
|
178
204
|
end
|
179
205
|
end
|
180
206
|
|
181
|
-
response = FastlyCTL::Fetcher.api_request(:put, "/service/#{service}/version/#{version}/vcl/#{name}", {:endpoint => :api, body: params, expected_responses: [200,404]})
|
207
|
+
response = FastlyCTL::Fetcher.api_request(:put, "/service/#{service}/version/#{version}/vcl/#{FastlyCTL::Utils.percent_encode(name)}", {:endpoint => :api, body: params, expected_responses: [200,404]})
|
182
208
|
|
183
209
|
# The VCL got deleted so recreate it.
|
184
210
|
if response["msg"] == "Record not found"
|
data/lib/fastlyctl/utils.rb
CHANGED
@@ -4,6 +4,10 @@ module FastlyCTL
|
|
4
4
|
Launchy.open(FastlyCTL::FASTLY_APP + FastlyCTL::TANGO_PATH + id)
|
5
5
|
end
|
6
6
|
|
7
|
+
def self.open_app_path(path)
|
8
|
+
Launchy.open(FastlyCTL::FASTLY_APP + path)
|
9
|
+
end
|
10
|
+
|
7
11
|
def self.parse_directory(path=false)
|
8
12
|
directory = Dir.pwd unless path
|
9
13
|
directory = path if path
|
@@ -68,5 +72,21 @@ module FastlyCTL
|
|
68
72
|
|
69
73
|
return diff
|
70
74
|
end
|
75
|
+
|
76
|
+
def self.percent_encode(string)
|
77
|
+
# CGI.escape replace whitespace to "+" which is "%20" in a percent-encoding manner
|
78
|
+
CGI.escape(string).gsub('+', '%20')
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.filter_vnd(haystack,needle)
|
82
|
+
results = []
|
83
|
+
haystack.each do |i|
|
84
|
+
next unless i["type"] == needle
|
85
|
+
|
86
|
+
results.push(i)
|
87
|
+
end
|
88
|
+
|
89
|
+
return results
|
90
|
+
end
|
71
91
|
end
|
72
92
|
end
|
data/lib/fastlyctl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlyctl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Basile
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -72,6 +72,26 @@ dependencies:
|
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 2.4.3
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: openssl
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 2.1.2
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 2.1.2
|
85
|
+
type: :runtime
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 2.1.2
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 2.1.2
|
75
95
|
description: This gem provides a CLI for managing Fastly configurations
|
76
96
|
email:
|
77
97
|
- stephen@fastly.com
|
@@ -111,10 +131,13 @@ files:
|
|
111
131
|
- lib/fastlyctl/commands/purge_all.rb
|
112
132
|
- lib/fastlyctl/commands/skeleton.rb
|
113
133
|
- lib/fastlyctl/commands/snippet.rb
|
134
|
+
- lib/fastlyctl/commands/tls.rb
|
135
|
+
- lib/fastlyctl/commands/tls/managed.rb
|
114
136
|
- lib/fastlyctl/commands/token.rb
|
115
137
|
- lib/fastlyctl/commands/upload.rb
|
116
138
|
- lib/fastlyctl/commands/watch.rb
|
117
139
|
- lib/fastlyctl/fetcher.rb
|
140
|
+
- lib/fastlyctl/subcommand_patch.rb
|
118
141
|
- lib/fastlyctl/utils.rb
|
119
142
|
- lib/fastlyctl/version.rb
|
120
143
|
homepage: http://www.github.com/fastly/fastlyctl
|