= ey_cloud_awareness This gem makes it a little easier to live on the EngineYard cloud: * automatically run cap tasks on all your instances * automatically update your ssh aliases * allow your app to get information about the cluster (aka "environment") it's running in We use it over at http://brighterplanet.com. == Don't read this This gem depends on /etc/chef/dna.json being READABLE and containing certain attributes as named by EngineYard. You might have to add: `sudo chmod a+r /etc/chef/dna.json` to your before_migrate.rb script. == Quick start Put this in config/environment.rb: config.gem 'ey_cloud_awareness', :version => '[WHATEVER THE CURRENT GEM VERSION IS]', :lib => false, :source => 'http://gemcutter.org' Put this in your config/deploy.rb (or whereever your Capfile is): # don't miss this line just because it's at the top load "#{Gem.searcher.find('ey_cloud_awareness').full_gem_path}/lib/tasks/capistrano_tasks.rb" task :my_production do role :app_master, 'my_app.com' # or you can use its Elastic IP set :rails_env, 'production' # required set :deploy_to, '/data/my_app' # required find_and_execute_task 'eyc_setup' # required end task :my_staging do role :app_master, 'staging.my_app.com' # or you can use its Elastic IP set :rails_env, 'production' # required set :deploy_to, '/data/my_app' # required find_and_execute_task 'eyc_setup' # required end # add more tasks if you have more cloud environments That should be all. == Running capistrano tasks on your instances Commands like these will work: cap my_production monit:status cap my_production deploy:web:disable cap my_production deploy:web:enable cap my_production passenger:restart cap my_production nginx:restart Every time you use them, a special eyc_setup task is run that gets a fresh list of your environment's instances and sets roles like :app, :web, and :db. == SSH into your instances Let's say you want to ssh into... ssh my_production-app_master Well, you need to keep your ~/.ssh/config up-to-date. Easy! cap my_production eyc:ssh That will magically add or update a block like # START StringReplacer my_production -- DO NOT MODIFY # db_master Host my_production-db_master Hostname ec2-222-222-222-59.compute-1.amazonaws.com User my_user StrictHostKeyChecking no # utility (1) Host my_production-utility1 Hostname ec2-222-222-53-222.compute-1.amazonaws.com User my_user StrictHostKeyChecking no # app_master Host my_production-app_master Hostname ec2-222-222-23-222.compute-1.amazonaws.com User my_user StrictHostKeyChecking no # END StringReplacer my_production -- DO NOT MODIFY Run that again as cap my_staging eyc:ssh ... and it adds # START StringReplacer my_staging -- DO NOT MODIFY # app_master Host my_staging-app_master Hostname ec2-222-222-7-210.compute-1.amazonaws.com User my_user StrictHostKeyChecking no # db_master Host my_staging-db_master Hostname ec2-222-222-52-8.compute-1.amazonaws.com User my_user StrictHostKeyChecking no # END StringReplacer my_staging -- DO NOT MODIFY This leaves you with lots of useful aliases: ssh my_production-db_master ssh my_production-app_master ssh my_production-utility1 ssh my_staging-app_master ssh my_staging-db_master Note that the numbers after app [slaves], db [slaves], and utility [slaves] may change every time you run the task. == Just dumping information about your instances Once you've done the quickstart, try: cap my_production eyc:app # gets a list of your app instances, including app_master cap my_production eyc:utility # ditto for utility instances cap my_production eyc:db # ditto for db instances cap my_production eyc:all # gets a list of all your instances == Using the EngineYardCloudInstance class inside Rails I run a memcached server on every app instance, so I have this in config/environment.rb: Rails::Initializer.run do |config| [...] config.cache_store = :mem_cache_store, EngineYardCloudInstance.app.map { |i| "#{i.private_dns_name}:11211" } [...] end Or whatever you want: >> all_app_instances = EngineYardCloudInstance.app => [#, #, #] >> all_app_instances.first.dns_name => "ec2-67-201-47-30.compute-1.amazonaws.com" >> pp all_app_instances.first.to_hash => {:block_device_mapping=> [{:ebs=> {:status=>"attached", :volumeId=>"vol-26172ee8", :deleteOnTermination=>"false", :attachTime=>"2010-04-07T21:09:37.000Z"}, :deviceName=>"/dev/sdz2"}, {:ebs=> {:status=>"attached", :volumeId=>"vol-26172ee8", :deleteOnTermination=>"false", :attachTime=>"2010-04-07T21:09:37.000Z"}, :deviceName=>"/dev/sdz1"}], :launch_time=>"2010-04-07T21:08:10.000Z", :instance_type=>"c1.medium", :private_dns_name=>"domU-44-44-44-44-A4-02.compute-1.internal", :instance_state=>{:code=>"16", :name=>"running"}, :ami_launch_index=>"0", :users=> [{:password=>"hoppAugEv", :username=>"deploy", :uid=>"1000", :comment=>"", :gid=>"1000"}], :environment=> {:framework_env=>"production", :name=>"my_staging", :stack=>"nginx_passenger"}, :instance_id=>"i-50cf5838", :group_id=>"ey-my_staging-XXXXXXXXXXXXXXXXXXXX", :root_device_type=>"instance-store", :private_ip_address=>"10.201.102.201", :kernel_id=>"aki-9b00e5f2", :placement=>{:availabilityZone=>"us-east-1a"}, :product_codes=>nil, :image_id=>"ami-7044a419", :reason=>nil, :dns_name=>"ec2-67-201-47-30.compute-1.amazonaws.com", :ip_address=>"199.99.99.99", :architecture=>"i386", :instance_role=>"solo", :monitoring=>{:state=>"disabled"}} == A note on caching and network needs I tried to be smart about caching the results of network calls. Stuff like the current instance id, which is pulled from an EC2 metadata server, is stored in CURRENT_INSTANCE_ID_CACHE_PATH = File.expand_path '~/.ey_cloud_awareness/engine_yard_cloud_instance_id' Please let me know if this causes problems. == Copyright Copyright (c) 2009 Seamus Abshere. See LICENSE for details.