# Author:: Fastly Inc <support@fastly.com>
# Copyright:: Copyright (c) 2011 Fastly Inc
# License:: Distributes under the same terms as Ruby
# A client library for interacting with the Fastly web acceleration service
require 'fastly/gem_version'
require 'fastly/util'
require 'fastly/fetcher'
require 'fastly/client'
require 'fastly/base'
require 'fastly/belongs_to_service_and_version'
require 'fastly/acl'
require 'fastly/acl_entry'
require 'fastly/backend'
require 'fastly/big_query_logging'
require 'fastly/cache_setting'
require 'fastly/condition'
require 'fastly/customer'
require 'fastly/dictionary'
require 'fastly/dictionary_item'
require 'fastly/director'
require 'fastly/domain'
require 'fastly/header'
require 'fastly/healthcheck'
require 'fastly/gzip'
require 'fastly/invoice'
require 'fastly/match'
require 'fastly/papertrail_logging'
require 'fastly/request_setting'
require 'fastly/response_object'
require 'fastly/service'
require 'fastly/settings'
require 'fastly/snippet'
require 'fastly/dynamic_snippet'
require 'fastly/sumologic_logging'
require 'fastly/syslog'
require 'fastly/token'
require 'fastly/s3_logging'
require 'fastly/gcs_logging'
require 'fastly/user'
require 'fastly/vcl'
require 'fastly/version'
# Top-level Fastly class
class Fastly
include Fastly::Fetcher
# Create a new Fastly client. Options are
#
# user:: your Fastly login
# password:: your Fastly password
# api_key:: your Fastly api key
#
# You only need to pass in C<api_key> OR C<user> and C<password>.
#
# Some methods require full username and password rather than just auth token.
def initialize(opts)
if opts[:api_key].nil? && (opts[:password].nil? || opts[:user].nil?)
raise ArgumentError, "Required options missing. Please pass either ':api_key' or both ':user' and ':password'."
end
client(opts)
self
end
# Whether or not we're authed at all by either username & password or API key
def authed?
client.authed?
end
# Whether or not we're fully (username and password) authed
# Some methods require full username and password rather than just auth token
def fully_authed?
client.fully_authed?
end
# Return a Customer object representing the customer of the current logged in user.
def current_customer
fail AuthRequired unless authed?
@current_customer ||= get(Customer)
end
# Return a User object representing the current logged in user.
def current_user
@current_user ||= get(User)
end
# Purge the specified path from your cache.
def purge(url, soft=false)
client.purge(url, soft ? { headers: { 'Fastly-Soft-Purge' => "1"} } : {})
end
# Fetches historical stats for each of your fastly services and groups the results by service id.
#
# If you pass in a :field opt then fetches only the specified field.
# If you pass in a :service opt then fetches only the specified service.
# The :field and :service opts can be combined.
#
# If you pass in an :aggregate flag then fetches historical stats information aggregated across all of your Fastly services. This cannot be combined with :field and :service.
#
# Other options available are:
#
# from:: earliest time from which to fetch historical statistics
# to:: latest time from which to fetch historical statistics
# by:: the sampling rate used to produce the result set (minute, hour, day)
# region:: restrict query to a particular region
#
# See http://docs.fastly.com/docs/stats for details.
def stats(opts)
if opts[:aggregate] && (opts[:field] || opts[:service])
fail Error, "You can't specify a field or a service for an aggregate request"
end
url = '/stats'
url += '/aggregate' if opts.delete(:aggregate)
if service = opts.delete(:service)
url += "/service/#{service}"
end
if field = opts.delete(:field)
url += "/field/#{field}"
end
client.get_stats(url, opts)
end
# Returns usage information aggregated across all Fastly services and grouped by region.
#
# If the :by_month flag is passed then returns total usage information aggregated by month as well as grouped by service & region.
#
# If the :by_service flag is passed then returns usage information aggregated by service and grouped by service & region.
#
# Other options available are:
#
# from:: earliest time from which to fetch historical statistics
# to:: latest time from which to fetch historical statistics
# by:: the sampling rate used to produce the result set (minute, hour, day)
# region:: restrict query to a particular region
#
# See http://docs.fastly.com/docs/stats for details.
def usage(opts)
url = '/stats/usage'
url += '_by_month' if opts.delete(:by_month)
url += '_by_service' if opts.delete(:by_service)
client.get_stats(url, opts)
end
# Fetches the list of codes for regions that are covered by the Fastly CDN service.
def regions
client.get_stats('/stats/regions')
end
[ACL, ACLEntry, User, Customer, Backend, CacheSetting, Condition, Dictionary, DictionaryItem, Director, Domain, Header, Healthcheck, Gzip, Match, PapertrailLogging, RequestSetting, ResponseObject, Service, Snippet, S3Logging, Syslog, Token, VCL, Version].each do |klass|
type = Util.class_to_path(klass)
if klass.respond_to?(:pluralize)
plural = klass.pluralize
else
plural = "#{type}s"
end
if klass.respond_to?(:singularize)
singular = klass.singularize
else
singular = type
end
# unless the class doesn't have a list path or it already exists
unless klass.list_path.nil? || klass.respond_to?("list_#{plural}".to_sym)
send :define_method, "list_#{plural}".to_sym do |*args|
list(klass, *args)
end
end
send :define_method, "get_#{singular}".to_sym do |*args|
get(klass, *args)
end
send :define_method, "create_#{singular}".to_sym do |obj|
create(klass, obj)
end
send :define_method, "update_#{singular}".to_sym do |obj|
update(klass, obj)
end
send :define_method, "delete_#{singular}".to_sym do |obj|
delete(klass, obj)
end
end
# :method: create_version(opts)
# opts must contain a service_id param
##
# :method: create_backend(opts)
# opts must contain service_id, version and name params
##
# :method: create_dictionary(opts)
# opts must contain service_id, version and name params
##
# :method: create_dictionary_item(opts)
# opts must contain service_id, dictionary_id, item_key and item_value params
##
# :method: create_director(opts)
# opts must contain service_id, version and name params
##
# :method: create_domain(opts)
# opts must contain service_id, version and name params
##
# :method: create_match(opts)
# opts must contain service_id, version and name params
##
# :method: create_healthcheck(opts)
# opts must contain service_id, version and name params
##
# :method: create_s3_logging(opts)
# opts must contain service_id, version and name params
##
# :method: create_papertrail_logging(opts)
# opts must contain service_id, version and name params
##
# :method: create_syslog(opts)
# opts must contain service_id, version and name params
##
# :method: create_vcl(opts)
# opts must contain service_id, version and name params
##
# :method: create_condition(opts)
# opts must contain service_id, version and name params
##
# :method: create_cache_setting(opts)
# opts must contain service_id, version and name params
##
# :method: create_header(opts)
# opts must contain service_id, version and name params
##
# :method: create_gzip(opts)
# opts must contain service_id, version and name params
##
# :method: create_request_setting(opts)
# opts must contain service_id, version and name params
##
# :method: create_response_object(opts)
# opts must contain service_id, version and name params
##
# :method: get_user(id)
# Get a User
##
# :method: get_customer(id)
# Get a customer
##
# :method: get_service(id)
# Get a Service
##
# :method: get_version(service_id, number)
# Get a Version
##
# :method: get_backend(service_id, number, name)
# Get a backend
##
# :method: get_dictionary(service_id, number, name)
# Get a single dictionary
##
# :method: get_dictionary_item(service_id, dictionary_id, name)
# Get a single dictionary item
##
# :method: get_director(service_id, number, name)
# Get a Director
##
# :method: get_domain(service_id, number, name)
# Get a Domain
##
# :method: get_healthcheck(service_id, number, name)
# Get a Healthcheck
##
# :method: get_match(service_id, number, name)
# Get a Match
##
# :method: get_s3_logging(service_id, number, name)
# Get a S3 logging
##
# :method: get_papertrail_logging(service_id, number, name)
# Get a Papertrail logging stream config
##
# :method: get_syslog(service_id, number, name)
# Get a Syslog
##
# :method: get_vcl(service_id, number, name)
# Get a VCL
##
# :method: get_snippet(service_id, number, name)
# Get a VCL snippet
##
# :method: get_version(service_id, number, name)
# Get a Version
##
# :method: get_settings(service_id, number, name)
# Get a Settings
##
# :method: get_condition(service_id, number, name)
# Get a Condition
##
# :method: get_cache_setting(service_id, number, name)
# Get a Cache Setting
##
# :method: get_gzip(service_id, number, name)
# Get a Gzip
##
# :method: get_header(service_id, number, name)
# Get a Header
##
# :method: get_request_setting(service_id, number, name)
# Get a Request Setting
##
# :method: get_response_object(service_id, number, name)
# Get a Response Object
##
# :method: update_user(user)
# You can also call
# user.save!
##
# :method: update_customer(customer)
# You can also call
# customer.save!
##
# :method: update_service(service)
# You can also call
# service.save!
##
# :method: update_version(version)
# You can also call
# version.save!
##
# :method: update_backend(backend)
# You can also call
# backend.save!
##
# :method: update_dictionary(dictionary)
# You can also call
# dictionary.save!
##
# :method: update_dictionary_item(dictionary_item)
# You can also call
# dictionary_item.save!
##
# :method: update_director(director)
# You can also call
# director.save!
##
# :method: update_domain(domain)
# You can also call
# domain.save!
##
# :method: update_healthcheck(healthcheck)
# You can also call
# healthcheck.save!
##
# :method: update_match(match)
# You can also call
# match.save!
##
# :method: update_settings(settings)
# You can also call
# settings.save!
##
# :method: update_s3_logging(s3_logging)
# You can also call
# s3_logging.save!
##
# :method: update_papertrail_logging(papertrail_logging)
# You can also call
# papertrail_logging.save!
##
# :method: update_syslog(syslog)
# You can also call
# syslog.save!
##
# :method: update_vcl(vcl)
# You can also call
# vcl.save!
##
# :method: update_snippet(snippet)
# You can also call
# snippet.save!
##
# :method: update_cache_setting(cache_setting)
# You can also call
# cache_setting.save!
##
# :method: update_header(header)
# You can also call
# header.save!
##
# :method: update_gzip(gzip)
# You can also call
# gzip.save!
##
# :method: update_request_setting(request_setting)
# You can also call
# request_setting.save!
##
# :method: update_response_object(response_object)
# You can also call
# response_object.save!
##
# :method: update_condition(condition)
# You can also call
# condition.save!
##
# :method: update_version(version)
# You can also call
# version.save!
##
# :method: delete_user(user)
# You can also call
# user.delete!
##
# :method: delete_customer(customer)
# You can also call
# customer.delete!
##
# :method: delete_service(service)
# You can also call
# service.delete!
##
# :method: delete_version(version)
# You can also call
# version.delete!
##
# :method:delete_backend(backend)
# You can also call
# backend.delete!
##
# :method: delete_dictionary(dictionary)
# You can also call
# dictionary.delete!
##
# :method: delete_dictionary_item(dictionary_item)
# You can also call
# dictionary_item.delete!
##
# :method: delete_director(backend)
# You can also call
# backend.delete!
##
# :method: delete_domain(domain
# You can also call
# domain.delete!
##
# :method: delete_healthcheck(healthcheck)
# You can also call
# healthcheck.delete!
##
# :method: delete_match(match)
# You can also call
# match.delete!(match)
##
# :method: delete_s3_logging(s3_logging)
# You can also call
# s3_logging.delete!
##
# :method: delete_papertrail_logging(papertrail_logging)
# You can also call
# papertrail_logging.delete!
##
# :method: delete_syslog(syslog)
# You can also call
# syslog.delete!
##
# :method: delete_vcl(vcl)
# You can also call
# vcl.delete!
##
# :method: delete_snippet(snippet)
# You can also call
# snippet.delete!
##
# :method: delete_cache_setting(cache_setting)
# You can also call
# cache_setting.delete!
##
# :method: delete_header(header)
# You can also call
# header.delete!
##
# :method: delete_gzip(gzip)
# You can also call
# gzip.delete!
##
# :method: delete_request_setting(request_setting)
# You can also call
# request_setting.delete!
##
# :method: delete_response_object(response_object)
# You can also call
# response_object.delete!
##
# :method: delete_condition(condition)
# You can also call
# condition.delete!
##
# :method: delete_version(version)
# You can also call
# version.delete!
# :method: list_users(:service_id => service.id, :version => version.number)
#
# Get a list of all users
# :method: list_customers(:service_id => service.id, :version => version.number)
#
# Get a list of all customers
# :method: list_versions(:service_id => service.id, :version => version.number)
#
# Get a list of all versions
# :method: list_services(:service_id => service.id, :version => version.number)
#
# Get a list of all services
# :method: list_backends(:service_id => service.id, :version => version.number)
#
# Get a list of all backends
# :method: list_directors(:service_id => service.id, :version => version.number)
#
# Get a list of all directors
# :method: list_dictionaries(:service_id => service.id, :version => version.number)
#
# Get a list of all dictionaries
# :method: list_dictionary_items(:service_id => service.id, :dictionary_id => dictionary.name)
#
# Get a list of all items belonging to a dictionary
# :method: list_domains(:service_id => service.id, :version => version.number)
#
# Get a list of all domains
# :method: list_healthchecks(:service_id => service.id, :version => version.number)
#
# Get a list of all healthchecks
# :method: list_matchs(:service_id => service.id, :version => version.number)
#
# Get a list of all matches
# :method: list_syslogs(:service_id => service.id, :version => version.number)
#
# Get a list of all syslogs
# :method: list_vcls(:service_id => service.id, :version => version.number)
#
# Get a list of all vcls
# :method: list_snippets(:service_id => service.id, :version => version.number)
#
# Get a list of all vcl snippets
# :method: list_conditions(:service_id => service.id, :version => version.number)
#
# Get a list of all conditions
# :method: list_cache_settings(:service_id => service.id, :version => version.number)
#
# Get a list of all cache settings
# :method: list_headers(:service_id => service.id, :version => version.number)
#
# Get a list of all headers
# :method: list_gzips(:service_id => service.id, :version => version.number)
#
# Get a list of all gzips
# :method: list_request_settings(:service_id => service.id, :version => version.number)
#
# Get a list of all request_settings
# :method: list_response_objects(:service_id => service.id, :version => version.number)
#
# Get a list of all response_objects
# :method: list_versions(:service_id => service.id, :version => version.number)
#
# Get a list of all versions
##
# Attempts to load various config options in the form
#
# <key> = <value>
#
# From a file.
#
# Skips whitespace and lines starting with C<#>.
#
def self.load_config(file)
options = {}
return options unless File.exist?(file)
File.open(file, 'r') do |infile|
while line = infile.gets
line.chomp!
next if line =~ /^#/
next if line =~ /^\s*$/
next unless line =~ /=/
line.strip!
key, val = line.split(/\s*=\s*/, 2)
options[key.to_sym] = val
end
end
options
end
##
# Tries to load options from the file[s] passed in using,
# C<load_options>, stopping when it finds the first one.
#
# Then it overrides those options with command line options
# of the form
#
# --<key>=<value>
#
def self.get_options(*files)
options = {}
files.each do |file|
next unless File.exist?(file)
options = load_config(file)
break
end
while ARGV.size > 0 && ARGV[0] =~ /^-+(\w+)\=(\w+)$/
options[$1.to_sym] = $2
ARGV.shift
end
fail "Couldn't find options from command line arguments or #{files.join(', ')}" unless options.size > 0
options
end
end