Class: FastlyCTL::CLI
- Inherits:
-
Thor
- Object
- Thor
- FastlyCTL::CLI
- Defined in:
- lib/fastlyctl/cli.rb,
lib/fastlyctl/commands/acl.rb,
lib/fastlyctl/commands/tls.rb,
lib/fastlyctl/commands/copy.rb,
lib/fastlyctl/commands/diff.rb,
lib/fastlyctl/commands/open.rb,
lib/fastlyctl/commands/clone.rb,
lib/fastlyctl/commands/login.rb,
lib/fastlyctl/commands/token.rb,
lib/fastlyctl/commands/watch.rb,
lib/fastlyctl/commands/domain.rb,
lib/fastlyctl/commands/upload.rb,
lib/fastlyctl/commands/logging.rb,
lib/fastlyctl/commands/snippet.rb,
lib/fastlyctl/commands/activate.rb,
lib/fastlyctl/commands/download.rb,
lib/fastlyctl/commands/skeleton.rb,
lib/fastlyctl/commands/condition.rb,
lib/fastlyctl/commands/purge_all.rb,
lib/fastlyctl/commands/dictionary.rb,
lib/fastlyctl/commands/create_service.rb
Class Method Summary collapse
Instance Method Summary collapse
- #acl(action, name = false, ip = false) ⇒ Object
- #activate ⇒ Object
- #clone(id, target_id) ⇒ Object
- #condition(action, name = false) ⇒ Object
- #copy(id, target_id, obj_type, obj_name = false) ⇒ Object
- #create_service(name) ⇒ Object
- #dictionary(action, name = false, key = false, value = false) ⇒ Object
- #diff ⇒ Object
- #domain(action, host = false) ⇒ Object
- #download(vcl_name = false) ⇒ Object
-
#initialize(a, b, c) ⇒ CLI
constructor
A new instance of CLI.
- #login ⇒ Object
- #open(domain = false) ⇒ Object
- #purge_all ⇒ Object
- #skeleton(name = "main") ⇒ Object
- #snippet(action, name = false) ⇒ Object
- #token(action) ⇒ Object
- #upload ⇒ Object
- #version ⇒ Object
- #watch(pop = false) ⇒ Object
Constructor Details
#initialize(a, b, c) ⇒ CLI
Returns a new instance of CLI.
27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/fastlyctl/cli.rb', line 27 def initialize(a,b,c) unless File.exist?(FastlyCTL::TOKEN_FILE) || ENV['FASTLYCLI_TOKEN'] if yes?("Unable to locate API token. Would you like to login first?") self.login end end super if .key?(:debug) Typhoeus::Config.verbose = true end end |
Class Method Details
.print_condition_header ⇒ Object
12 13 14 15 16 |
# File 'lib/fastlyctl/commands/condition.rb', line 12 def self.print_condition_header puts puts "Name".ljust(40) + " | " + "Priority".ljust(8) + " | " + "Type".ljust(10) + " | " + "Statement".ljust(20) puts "-------------------------------------------------------------------------------------------------------" end |
.print_conditions(conditions) ⇒ Object
18 19 20 21 22 23 24 |
# File 'lib/fastlyctl/commands/condition.rb', line 18 def self.print_conditions(conditions) self.print_condition_header conditions.each { |c| puts "%s | %s | %s | %s " % [c["name"].ljust(40), c["priority"].ljust(8), c["type"].ljust(10), c["statement"].ljust(20)] } end |
Instance Method Details
#acl(action, name = false, ip = false) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/fastlyctl/commands/acl.rb', line 14 def acl(action, name=false, ip=false) id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Specify service id with --service or use from within service directory." unless id version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] version ||= [:version] encoded_name = FastlyCTL::Utils.percent_encode(name) if name case action when "create" abort "Must specify name for ACL" unless name FastlyCTL::Fetcher.api_request(:post, "/service/#{id}/version/#{version}/acl", params: { name: name }) say("ACL #{name} created.") when "delete" abort "Must specify name for ACL" unless name FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/version/#{version}/acl/#{encoded_name}") say("ACL #{name} deleted.") when "list" resp = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl") say("No ACLs on service in this version.") unless resp.length > 0 resp.each do |d| puts "#{d["id"]} - #{d["name"]}" end when "add" abort "Must specify name for ACL" unless name abort "Must specify IP" unless ip subnet = false if ip.include?("/") ip = ip.sub(/\/(\d{1,2})/,"") subnet = $1 end acl = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl/#{encoded_name}") params = { ip: ip, negated: .key?(:negate) ? "1" : "0" } params[:subnet] = subnet if subnet FastlyCTL::Fetcher.api_request(:post, "/service/#{id}/acl/#{acl["id"]}/entry", params: params) say("#{ip} added to ACL #{name}.") when "remove" abort "Must specify name for ACL" unless name abort "Must specify IP for ACL entry" unless ip acl = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl/#{encoded_name}") entries = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/acl/#{acl["id"]}/entries") entry = false entries.each do |e| if e["ip"] == ip entry = e break end end abort "IP #{ip} not found in ACL" unless entry FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/acl/#{acl["id"]}/entry/#{entry["id"]}") say("IP #{ip} removed from ACL #{name}.") when "list_ips" abort "Must specify name for ACL" unless name acl = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl/#{encoded_name}") entries = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/acl/#{acl["id"]}/entries") say("No items in ACL.") unless entries.length > 0 entries.each do |i| puts "#{i["ip"]}#{i["subnet"].nil? ? "" : "/"+i["subnet"].to_s} - Negated: #{i["negated"] == "0" ? "false" : "true"}" end when "sync" abort "Must specify name for ACL" unless name abort "Must supply comma separated list of IPs as the \"ip\" parameter" unless ip ips = ip.split(',').to_set.to_a entry_ids = Hash.new current_ips = [] acl = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl/#{encoded_name}") entries = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/acl/#{acl["id"]}/entries") entries.each do |entry| ip_with_subnet = entry["ip"] ip_with_subnet += "/" + entry["subnet"].to_s if (entry.key?("subnet") && !entry["subnet"].nil?) entry_ids[ip_with_subnet] = entry["id"] current_ips.push(ip_with_subnet) end to_add = ips - current_ips to_remove = current_ips - ips bulk = [] to_add.each do |add| subnet = false if add.include?("/") add = add.sub(/\/(\d{1,2})/,"") subnet = $1 end params = { "op" => "create", "ip" => add } params["subnet"] = subnet if subnet bulk.push(params) end to_remove.each do |remove| entry_id = entry_ids[remove] remove = remove.sub(/\/(\d{1,2})/,"") if remove.include?("/") bulk.push({ "op" => "delete", "id" => entry_id }) end FastlyCTL::Fetcher.api_request(:patch, "/service/#{id}/acl/#{acl["id"]}/entries", {body: {entries: bulk}.to_json, headers: {"Content-Type" => "application/json"}}) say("Sync operation completed successfully with #{bulk.length} operations.") when "bulk_add" abort "Must specify name for ACL" unless name abort "Must specify JSON blob of operations in ip field. Documentation on this can be found here: https://docs.fastly.com/api/config#acl_entry_c352ca5aee49b7898535cce488e3ba82" unless ip acl = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/acl/#{encoded_name}") FastlyCTL::Fetcher.api_request(:patch, "/service/#{id}/acl/#{acl["id"]}/entries", {body: ip, headers: {"Content-Type" => "application/json"}}) say("Bulk add operation completed successfully.") else abort "#{action} is not a valid command" end end |
#activate ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/fastlyctl/commands/activate.rb', line 7 def activate id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id writable_version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] writable_version ||= [:version].to_i if .key?(:comment) FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/version/#{writable_version}",{ params: {comment: [:comment]} }) end FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/version/#{writable_version}/activate") say("Version #{writable_version} on #{id} activated.") end |
#clone(id, target_id) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/fastlyctl/commands/clone.rb', line 6 def clone(id,target_id) version = FastlyCTL::Fetcher.get_active_version(id) unless [:version] version ||= [:version] target_version = FastlyCTL::Fetcher.api_request(:post, "/service/#{target_id}/version")["number"] puts "Copying #{id} version #{version} to #{target_id} version #{target_version}..." FastlyCTL::CloneUtils::OBJECT_TYPES.each do |type,| next if (type.include?("logging/") && .key?(:skip_logging)) response = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/#{type}") response = [response] unless response.is_a?(Array) next unless response.length > 0 puts "Copying #{response.length} " + (response.length == 1 ? FastlyCTL::CloneUtils.unpluralize(type) : FastlyCTL::CloneUtils.pluralize(type)) response.each do |obj| FastlyCTL::CloneUtils.copy(obj,type,target_id,target_version) end end target_active_version = FastlyCTL::Fetcher.get_active_version(target_id) response = FastlyCTL::Fetcher.api_request(:get, "/service/#{target_id}/version/#{target_active_version}/domain") return unless response.length > 0 puts "Restoring #{response.length} " + (response.length == 1 ? "domain" : "domains" + " from #{target_id} version #{target_active_version}...") response.each do |domain| FastlyCTL::CloneUtils.copy(domain,"domain",target_id,target_version) end end |
#condition(action, name = false) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/fastlyctl/commands/condition.rb', line 26 def condition(action,name=false) id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] version ||= [:version].to_i encoded_name = FastlyCTL::Utils.percent_encode(name) if name case action when "list" conditions = FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/condition") CLI.print_conditions(conditions) when "create" abort "Must supply a condition name as second parameter" unless name abort "Must supply a statement to create a condition" unless [:statement] params = {} params[:name] = name params[:statement] = [:statement] params[:priority] = [:priority] if .key?(:priority) params[:type] = [:type] if .key?(:type) params[:comment] = [:comment] if .key?(:comment) FastlyCTL::Fetcher.api_request(:post,"/service/#{id}/version/#{version}/condition",{ params: params }) say("Condition #{name} created on #{id} version #{version}") when "update" abort "Must supply a condition name as second parameter" unless name if .key?(:type) puts "WARNING: Can not change the TYPE of a condition, you must delete and re-create, type parameter is ignored in update method.\n" end params = {} params[:statement] = [:statement] if .key?(:statement) params[:priority] = [:priority] if .key?(:priority) params[:comment] = [:comment] if .key?(:comment) FastlyCTL::Fetcher.api_request(:put,"/service/#{id}/version/#{version}/condition/#{encoded_name}",{ params: params }) say("Condition #{name} updated on #{id} version #{version}") when "show" abort "Must supply a condition name as second parameter" unless name c = FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/condition/#{encoded_name}") CLI.print_conditions([c]) when "delete" abort "Must supply a condition name as second parameter" unless name c = FastlyCTL::Fetcher.api_request(:delete,"/service/#{id}/version/#{version}/condition/#{encoded_name}") say("Condition #{name} deleted on #{id} version #{version}") end end |
#copy(id, target_id, obj_type, obj_name = false) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/fastlyctl/commands/copy.rb', line 6 def copy(id,target_id,obj_type,obj_name=false) abort "Object name must be specified for all object types except settings" if (obj_name === false && obj_type != "settings") source_version = FastlyCTL::Fetcher.get_active_version(id) unless [:version1] source_version ||= [:version1] target_version = FastlyCTL::Fetcher.get_writable_version(target_id) unless [:version2] target_version ||= [:version2] unless FastlyCTL::CloneUtils::OBJECT_TYPES.include?(obj_type) abort "Object type #{obj_type} is invalid. Must be one of: #{FastlyCTL::CloneUtils::OBJECT_TYPES.keys.join(', ')}" end path = "/service/#{id}/version/#{source_version}/#{obj_type}" path += "/#{obj_name}" unless obj_type == "settings" obj = FastlyCTL::Fetcher.api_request(:get, path) encoded_name = FastlyCTL::Utils.percent_encode(obj_name) if (obj_type == "settings") puts "Copying settings from #{id} version #{source_version} to #{target_id} version #{target_version}..." else existing_obj = FastlyCTL::Fetcher.api_request(:get, "/service/#{target_id}/version/#{target_version}/#{obj_type}/#{encoded_name}",{ expected_responses: [200,404] }) if existing_obj.key?("name") abort unless yes?("A #{FastlyCTL::CloneUtils.unpluralize(obj_type)} named #{obj_name} already exists on #{target_id} version #{target_version}. Delete it and proceed?") FastlyCTL::Fetcher.api_request(:delete,"/service/#{target_id}/version/#{target_version}/#{obj_type}/#{encoded_name}") end puts "Copying #{FastlyCTL::CloneUtils.unpluralize(obj_type)} #{obj_name} from #{id} version #{source_version} to #{target_id} version #{target_version}..." end FastlyCTL::CloneUtils.copy(obj,obj_type,target_id,target_version) end |
#create_service(name) ⇒ Object
4 5 6 7 8 9 10 |
# File 'lib/fastlyctl/commands/create_service.rb', line 4 def create_service(name) service = FastlyCTL::Fetcher.api_request(:post, "/service", { params: { name: name }}) if yes?("Service #{service["id"]} has been created. Would you like to open the configuration page?") FastlyCTL::Utils.open_service(service["id"]) end end |
#dictionary(action, name = false, key = false, value = false) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/fastlyctl/commands/dictionary.rb', line 14 def dictionary(action, name=false, key=false, value=false) id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Specify service id with --service or use from within service directory." unless id version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] version ||= [:version] encoded_name = FastlyCTL::Utils.percent_encode(name) if name case action when "create" abort "Must specify name for dictionary" unless name params = { name: name } params[:write_only] = true if .key?(:write_only) FastlyCTL::Fetcher.api_request(:post, "/service/#{id}/version/#{version}/dictionary", params: params) say("Dictionary #{name} created.") when "delete" abort "Must specify name for dictionary" unless name FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") say("Dictionary #{name} deleted.") when "list" resp = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary") say("No dictionaries on service in this version.") unless resp.length > 0 resp.each do |d| puts "#{d["id"]} - #{d["name"]}" end when "upsert" abort "Must specify name for dictionary" unless name abort "Must specify key and value for dictionary item" unless (key && value) dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/dictionary/#{dict["id"]}/item/#{FastlyCTL::Utils.percent_encode(key)}", params: { item_value: value }) say("Dictionary item #{key} set to #{value}.") when "remove" abort "Must specify name for dictionary" unless name abort "Must specify key for dictionary item" unless key dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") FastlyCTL::Fetcher.api_request(:delete, "/service/#{id}/dictionary/#{dict["id"]}/item/#{FastlyCTL::Utils.percent_encode(key)}") say("Item #{key} removed from dictionary #{name}.") when "list_items" abort "Must specify name for dictionary" unless name dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") resp = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/dictionary/#{dict["id"]}/items") say("No items in dictionary.") unless resp.length > 0 resp.each do |i| puts "#{i["item_key"]} : #{i["item_value"]}" end when "sync" abort "Must specify name for dictionary" unless name abort "Must supply comma separated list of keys and values as the \"key\" parameter. " unless key pairs = {} key.split(',').to_set.to_a.each do |kv| kv = kv.split("=") if kv.include?("=") kv = kv.split(":") if kv.include?(":") abort "Keys and values must be separated by an = or : symbol. Found \"#{kv}\"" unless kv.is_a?(Array) pairs[kv[0]] = kv[1] end item_ids = Hash.new bulk = [] dictionary = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") items = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/dictionary/#{dictionary["id"]}/items") items.each do |item| unless pairs.key?(item["item_key"]) bulk.push({ "op" => "delete", "item_key" => item["item_key"] }) next end if (pairs[item["item_key"]] != item["item_value"]) bulk.push({ "op": "upsert", "item_key": item["item_key"], "item_value": item["item_value"] }) end pairs.delete(item["item_key"]) end pairs.each do |k,v| bulk.push({ "op": "create", "item_key": k, "item_value": v }) end FastlyCTL::Fetcher.api_request(:patch, "/service/#{id}/dictionary/#{dictionary["id"]}/items", {body: {items: bulk}.to_json, headers: {"Content-Type" => "application/json"}}) say("Sync operation completed successfully with #{bulk.length} operations.") when "bulk_add" abort "Must specify name for dictionary" unless name abort "Must specify JSON blob of operations in key field. Documentation on this can be found here: https://docs.fastly.com/api/config#dictionary_item_dc826ce1255a7c42bc48eb204eed8f7f" unless key dict = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/dictionary/#{encoded_name}") FastlyCTL::Fetcher.api_request(:patch, "/service/#{id}/dictionary/#{dict["id"]}/items", {body: key, headers: {"Content-Type" => "application/json"}}) say("Bulk add operation completed successfully.") else abort "#{action} is not a valid command" end end |
#diff ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/fastlyctl/commands/diff.rb', line 9 def diff if [:service1] service1 = [:service1] else service1 = FastlyCTL::Utils.parse_directory abort "Could not parse service id from directory" unless service1 end if [:service2] service2 = [:service2] else service2 = FastlyCTL::Utils.parse_directory # use service1 for both if unspecified service2 = service1 unless service2 end # diffing different services - no references to local vcl here if service1 != service2 version1 = .key?(:version1) ? [:version1] : FastlyCTL::Fetcher.get_active_version(service1) version2 = .key?(:version2) ? [:version2] : FastlyCTL::Fetcher.get_active_version(service2) end # diffing the same service if service1 == service2 # if both are specified, diff them if [:version1] && [:version2] version1 = [:version1] version2 = [:version2] end # if version1 is not specified, diff local with version 2 if ![:version1] && [:version2] version1 = false version2 = [:version2] end # if version2 is not specified, diff local with version 1 if [:version1] && ![:version2] version1 = [:version1] version2 = false end if ![:version1] && ![:version2] # if neither are specified, diff local with active version version1 = FastlyCTL::Fetcher.get_active_version(service2) version2 = false end end say("Diffing#{[:generated] ? " generated VCL for" : ""} #{service1} #{version1 ? "version "+version1.to_s : "local VCL"} with #{service2} #{version2 ? "version "+version2.to_s : "local VCL"}.") if version1 v1_vcls = FastlyCTL::Fetcher.get_vcl(service1, version1,[:generated]) else abort "Cannot diff generated VCL with local VCL" if [:generated] Dir.foreach(Dir.pwd) do |p| next unless File.file?(p) next unless p =~ /\.vcl$/ v1_vcls ||= Array.new v1_vcls << { "name" => p.chomp(".vcl"), "content" => File.read(p) } end end if version2 v2_vcls = FastlyCTL::Fetcher.get_vcl(service2, version2,[:generated]) else abort "Cannot diff generated VCL with local VCL" if [:generated] Dir.foreach(Dir.pwd) do |p| next unless File.file?(p) next unless p =~ /\.vcl$/ v2_vcls ||= Array.new v2_vcls << { "name" => p.chomp(".vcl"), "content" => File.read(p) } end end if [:generated] say(FastlyCTL::Utils.diff_generated(v1_vcls,v2_vcls)) else say(FastlyCTL::Utils.diff_versions(v1_vcls,v2_vcls)) end end |
#domain(action, host = false) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/fastlyctl/commands/domain.rb', line 6 def domain(action,host=false) id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] version ||= [:version].to_i case action when "create" FastlyCTL::Fetcher.api_request(:post,"/service/#{id}/version/#{version}/domain",{ params: { name: host, } }) say("#{host} created on #{id} version #{version}") when "delete" FastlyCTL::Fetcher.api_request(:delete,"/service/#{id}/version/#{version}/domain/#{host}") say("#{host} deleted on #{id} version #{version}") when "list" domains = FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/domain") say("Listing all domains for #{id} version #{version}") domains.each do |d| puts d["name"] end when "check" if host == "all" domains = FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/domain/check_all") else domains = [FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/domain/#{host}/check")] end domains.each do |d| say("#{d[0]["name"]} -> #{d[1]}") end else abort "#{action} is not a valid command" end end |
#download(vcl_name = false) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/fastlyctl/commands/download.rb', line 7 def download(vcl_name=false) parsed_id = FastlyCTL::Utils.parse_directory if [:service] abort "Already in a service directory, go up one level in order to specify"\ "service id with --service." if parsed_id id = [:service] parsed = false else abort "Could not parse service id from directory. Specify service id with "\ "--service option or use from within service directory." unless parsed_id id = parsed_id parsed = true end service = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/details") version = FastlyCTL::Fetcher.get_active_version(id) unless [:version] version ||= [:version] if [:generated] generated = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/generated_vcl") File.open("generated.vcl", 'w+') {|f| f.write(generated["content"]) } abort "Generated VCL for version #{version} written to generated.vcl." end vcl = FastlyCTL::Fetcher.get_vcl(id, version) snippet = FastlyCTL::Fetcher.get_snippets(id, version) sname = service["name"] if sname.include? "/" sname = sname.tr("/","_") end folder_name = parsed ? "./" : "#{sname} - #{service["id"]}/" Dir.mkdir(folder_name) unless (File.directory?(folder_name) || parsed) if vcl vcl.each do |v,k| next if (vcl_name && vcl_name != v["name"]) filename = "#{folder_name}#{v["name"]}.vcl" if File.exist?(filename) unless yes?("Are you sure you want to overwrite #{filename}") say("Skipping #{filename}") next end end File.open(filename, 'w+') {|f| f.write(v["content"]) } say("VCL content for version #{version} written to #{filename}") end end if snippet snippet.each do |s,k| filename = "#{folder_name}#{s["name"]}.snippet" if File.exist?(filename) unless yes?("Are you sure you want to overwrite #{filename}") say("Skipping #{filename}") next end end File.open(filename, 'w+') {|f| f.write(s["content"]) } say("Snippet content for version #{version} written to #{filename}") end end unless vcl || snippet say("No VCLs or snippets on this service, however a folder has been created. Create VCLs in this folder and upload.") end end |
#login ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/fastlyctl/commands/login.rb', line 4 def login if FastlyCTL::Token abort unless yes?("You already have an access token, are you sure you want to authenticate again?") end if yes?("Does your organization use SSO to login to Fastly? If so, type \"yes\" and create a 'global' or 'root' scoped token in your web browser. Copy the token to the file ~/.fastlyctl_token and save it.") Launchy.open(FastlyCTL::FASTLY_APP + "/account/personal/tokens/new") abort end say("Proceeding with username/password login...") username = ask("Username: ") password = ask("Password: ", :echo => false) say("") if username.include?("@fastly.com") && !username.include?("+") scope = "root" else scope = "global" end say("Creating #{scope} scope token...") o = { username: username, password: password, scope: scope, name: "fastlyctl_token" } resp = FastlyCTL::Fetcher.create_token(o) token = resp["access_token"] token_id = resp["id"] File.open(FastlyCTL::TOKEN_FILE , 'w+') {|f| f.write(token) } File.chmod(0600, FastlyCTL::TOKEN_FILE) resp = FastlyCTL::Fetcher.api_request(:get, "/tokens", { headers: {"Fastly-Key" => token}}) abort unless resp.count > 0 resp.each do |t| next unless (t["name"] == "fastlyctl_token" && t["id"] != token_id) if yes?("There was already a token created with the name fastlyctl_token. To avoid creating multiple tokens, should it be deleted?") FastlyCTL::Fetcher.api_request(:delete, "/tokens/#{t["id"]}", {headers: {"Fastly-Key" => token}, expected_responses: [204]}) say("Token with id #{t["id"]} deleted.") end end end |
#open(domain = false) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/fastlyctl/commands/open.rb', line 5 def open(domain=false) if ([:service] && domain) say("Both domain and service id supplied, using service id.") domain = false end if [:service] id = [:service] elsif domain id = FastlyCTL::Fetcher.domain_to_service_id(domain) else id = FastlyCTL::Utils.parse_directory abort "Could not parse service id from directory. Use the --s <service> flag OR vcl open <domain>." unless id end FastlyCTL::Utils.open_service(id) end |
#purge_all ⇒ Object
5 6 7 8 9 10 11 12 13 14 |
# File 'lib/fastlyctl/commands/purge_all.rb', line 5 def purge_all id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id FastlyCTL::Fetcher.api_request(:post, "/service/#{id}/purge_all") say("Purge all on #{id} completed.") end |
#skeleton(name = "main") ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/fastlyctl/commands/skeleton.rb', line 5 def skeleton(name="main") id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id filename = "#{name}.vcl" version = FastlyCTL::Fetcher.get_active_version(id) boilerplate = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{version}/boilerplate") if (File.exist?(filename)) say("#{filename} exists, please delete it if you want this command to overwrite it.") abort end File.open(filename , 'w+') {|f| f.write(boilerplate) } say("Boilerplate written to #{filename}.") end |
#snippet(action, name = false) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/fastlyctl/commands/snippet.rb', line 12 def snippet(action,name=false) id = FastlyCTL::Utils.parse_directory unless [:service] id ||= [:service] abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless id version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] version ||= [:version].to_i encoded_name = FastlyCTL::Utils.percent_encode(name) if name filename = .key?(:filename) ? [:filename] : "#{name}.snippet" case action when "upload" abort "Must supply a snippet name as second parameter" unless name abort "No snippet file for #{name} found locally" unless File.exists?(filename) active_version = FastlyCTL::Fetcher.get_active_version(id) snippets = FastlyCTL::Fetcher.get_snippets(id, active_version) abort "No snippets found in active version" unless snippets.is_a?(Array) && snippets.length > 0 snippet = false snippets.each do |s| if s["name"] == name abort "This command is for dynamic snippets only. Use vcl upload for versioned snippets" if s["dynamic"] == "0" snippet = s end end abort "No snippet named #{name} found on active version" unless snippet # get the snippet from the dynamic snippet api endpoint so you have the updated content snippet = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/snippet/#{snippet["id"]}") new_content = File.read(filename) priority = .key(:priority) ? [:priority] : snippet[:priority] unless .key?(:yes) say(FastlyCTL::Utils.get_diff(snippet["content"],new_content)) abort unless yes?("Given the above diff between the old dyanmic snippet content and the new content, are you sure you want to upload your changes? REMEMBER, THIS SNIPPET IS VERSIONLESS AND YOUR CHANGES WILL BE LIVE IMMEDIATELY!") end FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/snippet/#{snippet["snippet_id"]}", {:endpoint => :api, body: { content: new_content, priority: priority.to_s } }) say("New snippet content for #{name} uploaded successfully") when "create" abort "Must supply a snippet name as second parameter" unless name content = "# Put snippet content here." FastlyCTL::Fetcher.api_request(:post,"/service/#{id}/version/#{version}/snippet",{ params: { name: name, type: [:type] ? [:type] : "recv", content: content, dynamic: .key?(:dynamic) ? 1 : 0, priority: .key?(:priority) ? [:priority].to_s : "100" } }) say("#{name} created on #{id} version #{version}") unless File.exists?(filename) File.open(filename, 'w+') {|f| content } say("Blank snippet file created locally.") return end if .key?(:yes) || yes?("Local file #{filename} found. Would you like to upload its content?") FastlyCTL::Fetcher.upload_snippet(id,version,File.read(filename),name) say("Local snippet file content successfully uploaded.") end when "delete" abort "Must supply a snippet name as second parameter" unless name FastlyCTL::Fetcher.api_request(:delete,"/service/#{id}/version/#{version}/snippet/#{encoded_name}") say("#{name} deleted on #{id} version #{version}") return unless File.exists?(filename) if .key?(:yes) || yes?("Would you like to delete the local file #{name}.snippet associated with this snippet?") File.delete(filename) say("Local snippet file #{filename} deleted.") end when "list" snippets = FastlyCTL::Fetcher.api_request(:get,"/service/#{id}/version/#{version}/snippet") say("Listing all snippets for #{id} version #{version}") snippets.each do |d| say("#{d["name"]}: Subroutine: #{d["type"]}, Dynamic: #{d["dynamic"]}") end else abort "#{action} is not a valid command" end end |
#token(action) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/fastlyctl/commands/token.rb', line 7 def token(action) case action when "list" if [:customer] tokens = FastlyCTL::Fetcher.api_request(:get, "/customer/#{[:customer]}/tokens") else tokens = FastlyCTL::Fetcher.api_request(:get, "/tokens") end abort "No tokens to display!" unless tokens.length > 0 pp tokens when "create" scope = [:scope] scope ||= "global" say("You must authenticate again to create tokens.") username = ask("Username: ") password = ask("Password: ", :echo => false) say("") name = ask("What would you like to name your token? (enter here):") o = { username: username, password: password, scope: scope, name: name || "fastlyctl_token" }.compare_by_identity [:services].split(",").each do |v| o["services[]"] = v end if [:services] o[:customer] = [:customer] if [:customer] resp = FastlyCTL::Fetcher.create_token(o) say("token: #{resp["access_token"]}") when "delete" id = ask("What is the ID of the token you'd like to delete?") FastlyCTL::Fetcher.api_request(:delete, "/tokens/#{id}", expected_responses: [204]) say("Token with id #{id} deleted.") else abort "#{action} is not a valid command" end end |
#upload ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/fastlyctl/commands/upload.rb', line 6 def upload id = FastlyCTL::Utils.parse_directory abort "Could not parse service id from directory. Use -s <service> to specify, vcl download, then try again." unless id vcls = {} snippets = {} Dir.foreach(Dir.pwd) do |p| next unless File.file?(p) if p =~ /\.vcl$/ vcls[p.chomp(".vcl")] = {"content" => File.read(p), "name" => p.chomp(".vcl")} next end if (p =~ /\.snippet$/) snippets[p.chomp(".snippet")] = {"content" => File.read(p), "name" => p.chomp(".snippet")} end end writable_version = FastlyCTL::Fetcher.get_writable_version(id) unless [:version] writable_version ||= [:version].to_i active_version = FastlyCTL::Fetcher.get_active_version(id); old_vcls = FastlyCTL::Fetcher.get_vcl(id, active_version) old_snippets = FastlyCTL::Fetcher.get_snippets(id, active_version) old_snippets_writable = FastlyCTL::Fetcher.get_snippets(id, writable_version) main_found = false old_vcls ||= {} old_vcls.each do |v| next unless vcls.has_key? v["name"] diff = FastlyCTL::Utils.get_diff(v["content"], vcls[v["name"]]["content"]) vcls[v["name"]]["matched"] = true vcls[v["name"]]["new"] = false main_found = vcls[v["name"]]["main"] = v["main"] == true ? true : false vcls[v["name"]]["diff_length"] = diff.length next if diff.length < 2 say(diff) end old_snippets ||= {} old_snippets.each do |s| next unless snippets.has_key? s["name"] diff = FastlyCTL::Utils.get_diff(s["content"], snippets[s["name"]]["content"]) if s["dynamic"] == "1" snippets[s["name"]]["skip_because_dynamic"] = true next end snippets[s["name"]]["matched"] = true snippets[s["name"]]["diff_length"] = diff.length next if diff.length < 2 say(diff) end old_snippets_writable ||= {} old_snippets_writable.each do |s| next unless snippets.has_key? s["name"] next if (old_snippets.select {|os| os["name"] == s["name"]}).length > 0 if s["dynamic"] == "1" snippets[s["name"]]["skip_because_dynamic"] = true next end snippets[s["name"]]["matched"] = true snippets[s["name"]]["diff_length"] = 3 say(FastlyCTL::Utils.get_diff("",snippets[s["name"]]["content"])) end vcls.delete_if do |k,v| if v["name"] == "generated" next unless yes?("The name of this file is 'generated.vcl'. Please do not upload generated VCL back to a service. Are you sure you want to upload this file?") end if (v["matched"] == true) #dont upload if the file isn't different from the old file if (v["diff_length"] > 1) false else true end elsif yes?("VCL #{v["name"]} does not currently exist on the service, would you like to create it?") v["new"] = true if !main_found v["main"] = true main_found = true end say(FastlyCTL::Utils.get_diff("", v["content"])) false else say("Not uploading #{v["name"]}") true end end snippets.delete_if do |k,s| if (s["matched"] == true) #dont upload if the file isn't different from the old file if (s["diff_length"] > 1) false else true end else if s.key?("skip_because_dynamic") true else say("Not uploading #{s["name"]} because it does not exist on the service. Use the \"snippet create\" command to create it.") true end end end abort unless yes?("Given the above diff, are you sure you want to upload your changes?") vcls.each do |k,v| FastlyCTL::Fetcher.upload_vcl(id, writable_version, v["content"], v["name"], v["main"], v["new"]) say("#{v["name"]} uploaded to #{id}") end snippets.each do |k,s| FastlyCTL::Fetcher.upload_snippet(id, writable_version, s["content"], s["name"]) say("#{s["name"]} uploaded to #{id}") end if .key?(:comment) FastlyCTL::Fetcher.api_request(:put, "/service/#{id}/version/#{writable_version}",{ params: {comment: [:comment]} }) end validation = FastlyCTL::Fetcher.api_request(:get, "/service/#{id}/version/#{writable_version}/validate") abort "Compiler reported the following error with the generated VCL: #{validation["msg"]}" if validation["status"] == "error" say("VCL(s) have been uploaded to version #{writable_version} and validated.") end |
#version ⇒ Object
42 43 44 |
# File 'lib/fastlyctl/cli.rb', line 42 def version say("VCL gem version is #{FastlyCTL::VERSION}") end |
#watch(pop = false) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/fastlyctl/commands/watch.rb', line 5 def watch(pop=false) service = [:service] service ||= FastlyCTL::Utils.parse_directory abort "Could not parse service id from directory. Use --s <service> to specify, vcl download, then try again." unless service ts = false pop = pop.upcase if pop while true data = FastlyCTL::Fetcher.api_request(:get,"/rt/v1/channel/#{service}/ts/#{ts ? ts : 'h/limit/120'}", :endpoint => :rt) unless data["Data"].length > 0 say("No data to display!") abort end if pop unless data["Data"][0]["datacenter"].key?(pop) abort "Could not locate #{pop} in data feed." end agg = data["Data"][0]["datacenter"][pop] else agg = data["Data"][0]["aggregated"] end rps = agg["requests"] # gbps uncacheable = agg["pass"] + agg["synth"] + agg["errors"] bw = ((agg["resp_header_bytes"] + agg["resp_body_bytes"]).to_f * 8.0) / 1000000000.0 shield = agg["shield"] || 0 hit_rate = (1.0 - ((agg["miss"] - shield).to_f / ((agg["requests"] - uncacheable).to_f))) * 100.0 passes = agg["pass"] miss_time = agg["miss"] > 0 ? ((agg["miss_time"] / agg["miss"]) * 1000).round(0) : 0 synth = agg["synth"] errors = agg["errors"] $stdout.flush print " #{rps} req/s | #{bw.round(3)}gb/s | #{hit_rate.round(2)}% Hit Ratio | #{passes} passes/s | #{synth} synths/s | #{miss_time}ms miss time | #{errors} errors/s \r" ts = data["Timestamp"] end end |