require 'aws' class AWS::S3::Bucket def filename self.key.split('/').last end attr_accessor :cache_dir end class AWS::S3::S3Object def local_path new_path = (self.bucket.cache_dir + self.key) new_path.parent.mkpath new_path.open('w'){ |f| f.write(self.read) } new_path.chmod(0600) new_path end end class AWS::EC2::Instance def change_in_status new_status = self.status rescue :nonexistent old_status = @prev_status @prev_status = new_status return nil unless old_status and old_status != new_status {from: old_status, to: new_status} end def hash self.class.hash + self.id.hash end end class AWS::CloudFormation::StackEvent def operation self.resource_status.split('_', 2).first end attr_accessor :live attr_accessor :op attr_accessor :detail def status stat = self.resource_status.split('_', 2).last return "started" if (self.resource_type == "AWS::CloudFormation::Stack" and stat == "IN_PROGRESS") return "WORKING" if stat == "IN_PROGRESS" stat end def error self.resource_status_reason if (self.resource_status_reason and self.resource_status_reason !~ / Initiated$/) end end class AWS::CloudFormation::Stack attr_accessor :service_registry def cancel_update self.client.cancel_update_stack(stack_name: self.name) end def resources_of_type(type_name) self.resources.find_all{ |r| r.resource_type == "AWS::#{type_name}" && r.resource_status =~ /_COMPLETE/ && r.resource_status != "DELETE_COMPLETE" } end def distributions self.resources_of_type("CloudFront::Distribution").map{ |res| @service_registry[:cloudfront].distributions[res.physical_resource_id] } end def buckets self.resources_of_type("S3::Bucket").map{ |res| @service_registry[:s3].buckets[res.physical_resource_id] }.find_all{ |r| r.exists? } end def manual_instances self.resources_of_type("EC2::Instance").map{ |res| @service_registry[:ec2].instances[res.physical_resource_id] } end def autoscaled_instances self.resources_of_type("AutoScaling::AutoScalingGroup").map{ |res| @service_registry[:autoscaling].groups[res.physical_resource_id].ec2_instances.to_a }.flatten end def instances self.manual_instances + self.autoscaled_instances end def elastic_ips self.resources_of_type("EC2::EIP").map{ |res| @service_registry[:ec2].elastic_ips[res.physical_resource_id] } end def server_certificates(opts = {}) certs = @service_registry[:iam].server_certificates.find_all{ |cert| cert.path == "/cloudfront/#{self.name}/" } if cnames = opts.delete(:domain) certs = Hash[ *(certs.map{ |cert| [cert.name, cert] }.flatten) ] cnames = [cnames] unless cnames.kind_of?(Array) cnames = cnames.flatten possible_cert_names = cnames.map{ |cname| parts = cname.split('.').reverse; (1..parts.length).map{ |len| parts[0, len].reverse.join('.') }.reverse }.flatten possible_cert_names.map{ |cname| certs[cname] }.compact else certs end end end class AWS::CloudFront def distributions DistributionCollection.new(self) end class DistributionCollection def initialize(svc) @svc = svc end def [](k) Distribution.new(@svc, @svc.client.get_distribution(id: k)) end def each dists = @svc.client.list_distributions[:items] dists.each do |dist| yield Distribution.new(@svc, @svc.client.get_distribution(id: dist[:id])) end end include Enumerable end end class AWS::CloudFront::Distribution def initialize(svc, data) @svc = svc @data = data end def tags {} end def eql?(o) o.kind_of?(self.class) and o.id == self.id end def hash self.class.hash + self.id.hash end def refresh! @data = @svc.client.get_distribution(id: @data[:id]) end def aliases @data[:distribution_config][:aliases][:items] end def id @data[:id] end def config self.make_exportable(@data[:distribution_config]) end def status self.refresh! @data[:status] end def change_in_status new_status = self.status rescue :nonexistent old_status = @prev_status @prev_status = new_status return nil unless old_status and old_status != new_status {from: old_status, to: new_status} end def make_exportable(o) case o when nil "" when Hash h = {} o.each{ |k, v| h[k] = make_exportable(v) } h when Array o.map{ |e| make_exportable(e) } else o end end def update begin yield @svc.client.update_distribution( id: self.id, distribution_config: self.config, if_match: @data[:etag] ) end end def price_class @data[:distribution_config][:price_class].split('_').last.downcase.intern end def price_class=(new_class) @data[:distribution_config][:price_class] = "PriceClass_#{new_class.to_s.capitalize}" end def certificate @data[:distribution_config][:viewer_certificate][:iam_certificate_id] end def certificate=(cert_id) @data[:distribution_config][:viewer_certificate] = { iam_certificate_id: cert_id, ssl_support_method: "sni-only" } end end