Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
237 lines (125 sloc) 9.97 KB
h2. Disclaimer!
The following document describes Chronatog as a web cron service. The descriptions presented are accurate with one important exception: *ACTUAL CRON IS NOT YET IMPLEMENTED*. This means you can register as many callbacks as you want, see them, delete them etc... but they will never actually run. Chronatog is currently entirely missing it's underlying actual cron component.
h1. Chronatog
Chronatog is:
# A simple service providing basic web cron. (lib/server)
# A ruby client implementation for the chronatog.engineyard.com web service. (lib/client, chronatog-client.gemspec)
# An example service demonstrating how to integrate with the EngineYard services API. (lib/ey_integration)
# A gem for use by the internal EngineYard services API implementation, for testing. (chronatog.gemspec)
# This document designed for helping partners get started with the EY services API. (README.textile)
!https://github.com/engineyard/chronatog/raw/master/images/chronatog.jpg!
h2. Getting Started: Deploying your own Chronatog
h3. Become a Partner
First you need a partner account with EngineYard. Once you have one, you should be able to login at "https://services.engineyard.com":https://services.engineyard.com.
h3. Save your credentials
In Chronatog, credentials are stored in config/ey_partner_credentials.yml.
Example to generate this file in script/console:
bc.. $ script/console
> <%= save_creds_call %>
=> <%= save_creds_result %>
h3. Test your connection
To test your connection to services.engineyard.com, you can make a GET request to the registration url. This returns a listing of currently registered services.
Example:
bc.. $ script/console
> <%= list_services_call %>
=> <%= list_services_result %>
p. Behind the scenes, Chronatog is calling out to @EY::ServicesAPI@.
@list_services@ is a method on @EY::ServicesAPI::Connection@.
h3. Register your services
For the remainder of the setup steps, you will need to have Chronatog running somewhere with a publicly accessible url.
To register your service, you make a POST request to the registration url, passing a JSON body describing your service. Included in that description are callback URLS, so in order to generate them Chronatog needs to know it's public-facing url.
Example:
bc.. $ script/console
> registration_url = <%= registration_url %>
> <%= set_chronatog_url %>
> <%= register_service_call %>
=> <%= register_service_result %>
p. Behind the scene, Chronatog is calling @register_service@ on a @EY::ServicesAPI::Connection@. The first parameter is the @registration_url@. The second parameter is a hash describing the service being registered.
In the case of this example it looks something like:
bc.. <%= service_registration_params %>
h3. Viewing your service on cloud.engineyard.com
If your service registration succeeded, you should see it's information displayed when you visit @https://services.engineyard.com@. From there you can enable testing of your service with any cloud account you have access to.
!https://github.com/engineyard/chronatog/raw/master/images/enable_for_testing.png!
If you don't have any cloud accounts, you can create a free trial account at: @https://cloud.engineyard.com/@.
Once enabled for testing, you should see your service available if you navigate to "Services" in the menu bar from @https://cloud.engineyard.com@.
!https://github.com/engineyard/chronatog/raw/master/images/enable_on_account.png!
h3. Verifying requests from Engine Yard
By using the @EY::ApiHMAC::ApiAuth::LookupServer@ middleware in the API controller, Chronatog verifies that each request to it's API is correctly signed by the requester. The block passed to the middleware is expected to return the @auth_key@ correspondent to the @auth_id@ given. It is then up to @EY::ApiHMAC@ to calculate a signature and verify that it matches the one in the request (@env@).
bc.. <%= hmac_middleware %>
h3. Enabling your service
When you click 'enable', EngineYard will make a call to your @service_accounts_url@ to create a service account. In the case of Chronatog, this callback is handled by creating a customer record.
The request will look something like this:
bc.. POST <%= service_account_creation_url %>
<%= service_account_creation_params %>
p. Chronatog will handle the callback with the implementation defined in the API controller:
bc.. <%= customer_creation %>
p. As part of handling the callback, a @Customer@ will be created:
bc.. <%= customer_creation_created_customer %>
p. Chronatog returns a JSON response that tells EngineYard some information about the customer.
The code for generating that response:
bc.. <%= customer_creation_response %>
p. Notice @EY::ServicesAPI::Message@ in the code above. The subject text should now appear in the context of the Chronatog service on @https://cloud.engineyard.com@.
What the generated response looks like:
bc.. <%= service_account_creation_response %>
h3. Visiting Chronatog over SSO
With the service enabled, a "Visit" link should appear. Following this link will redirect to the @configuration_url@ provided in the response to service enablement.
The configuration url provided by Chronatog in this example was:
bc.. <%= service_configuration_url %>
p. When EY signs the url it provides additional parameters, such that it looks like this:
bc.. <%= service_configuration_url_signed %>
p. Chronatog will verify the SSO request with a before filter that looks like this:
bc.. <%= sso_before_filter %>
h3. Provisioning a Chronatog Scheduler
With the service enabled in EngineYard cloud, it should appear available for provisioning when you drill-down in the UI to viewing a single environment within the context of a single application.
!https://github.com/engineyard/chronatog/raw/master/images/provision.png!
Clicking "Provision" will cause EngineYard to call to your @provisioned_services_url@ to create a provisioned service. In the case of Chronatog, this callback is handled by creating a scheduler.
The request will look something like this:
bc.. POST <%= service_provisioning_url %>
<%= service_provisioning_params %>
p. Chronatog will handle the callback with the implementation defined in the API controller:
bc.. <%= service_provisioning %>
p. As part of handling the callback, a @Customer@ will be created:
bc.. <%= service_provisioning_created_scheduler %>
p. Chronatog returns a JSON response that tells EngineYard some information about the created scheduler.
The code for generating the response:
bc.. <%= service_provisioning_response %>
p. Notice @EY::ServicesAPI::Message@ in the code above. The subject text should now appear in the context of the relevant application and environment on @https://cloud.engineyard.com@.
What the response JSON looks like:
bc.. <%= service_provisioning_response_json %>
h3. Using the provisioned Chronatog service in your app
The Chronatog service has been enabled and provisioned. Values for @service_url@, @auth_username@, and @auth_password@ have been generated and sent back to EngineYard. Now it's time to make use of the service in your application. Just check-in few changes to your app and deploy!
The public client gem for the Chronatog API is called @chronatog-client@. Add it to your Gemfile like this:
bc.. gem 'chronatog-client', :require => 'chronatog/client'
p. To initialize the Chronatog client with the provisioned configs, you'll also need another gem, @ey_config@:
bc.. gem 'ey_config'
p. With these 2 gems installed, setting up Chronatog can be done like so:
bc.. <%= chronatog_setup_from_ey_config %>
p. @EY::Config@ works by reading the contents of @config/ey_services_config_local.yml@ or @config/ey_services_config_deploy.yml@. In order to develop with a fake version of the Chronatog API locally, you can create @config/ey_services_config_local.yml@ with the contents:
bc.. <%= ey_services_config_local_yaml_contents %>
p. When you deploy, EngineYard will create @config/ey_services_config_deploy.yml@. It might look something like this:
bc.. <%= ey_services_config_deploy_yaml_example %>
p. The existence of @config/ey_services_config_deploy.yml@ will override all settings in @config/ey_services_config_local.yml@.
h3. Disabling the Chronatog Service
As amazing as our Chronatog web service is, we still need to support user's deciding they don't need it anymore and disabling it.
When the service is disabled, EngineYard will make a DELETE call to the @url@ provided when the service account was first created.
The request will look something like this:
bc.. DELETE <%= service_account_delete_url %>
p. Chronatog will handle that request with the implementation defined in the API controller:
bc.. <%= customer_cancellation %>
p. Notice the call to @customer.bill!@. This causes Chronatog to send a final bill for services before destroying the customer. The request sent looks something like this:
bc.. POST <%= final_bill_url %>
<%= final_bill_params %>
h3. Billing
Hopefully, normally, customers will use the Chronatog service for a long period of time before canceling. So we need a way to charge them periodically as well.
The mechanism for this is currently a manual process run once a month via script/console.
Simply run:
bc.. $ script/console
> <%= bill_all_call %>
p. This, of course, will call @bill!@ on all customers, which calculates charges and sends an invoice to the @invoices_url@ for each customer.
The implementation as defined in @Chronatog::EyIntegration::CustomerExtensions@ calculates the total amount owed based on the last time billing was run for each customer (@last_billed_at@ or @created_at@). It then sends an invoice to the @invoices_url@ and sets the @last_billed_at@ to now.
bc.. <%= customer_billing %>
h3. More
TODO: provisioned service SSO.
TODO: using those API keys works. Chronatog automatically updates the status to tell the user they are now using the service. Tell them how many jobs are scheduled.
TODO: using the API to create more than 10 jobs on the free plan and Chronatog sends a notification prompting you to upgrade.
TODO: Examining the monthly billing job Chronatog created in itself and forcing it to run.