Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby by the River

Ruby by the River

Jason Frame

June 29, 2012
Tweet

More Decks by Jason Frame

Other Decks in Programming

Transcript

  1. Technical Summary • 8 major “Key Attract” installations • 37

    eIntros • 6 eStorybooks • 17 public information screens • ~150 Mac Minis Saturday, 1 June 13
  2. Architecture Rails CMS Scheduler RCP Daemon StoryPlayer Mac Mini Role

    specific service Role specific service Role specific service Saturday, 1 June 13
  3. CMS • Venue as content tree • Page per exhibit

    • Content type/class per exhibit type • Revision and publishing controls • Data collection Saturday, 1 June 13
  4. Polar • Lots of content types • Requirements changing daily

    • Declarative JS API for declaring editable content types • Recursive Saturday, 1 June 13
  5. Component Example Polar.createComponent('eintro_page') .container(true) .childLocation('intro_pictures', {only: 'image'}) .childLocation('in_focus', {only: ['image',

    'video', 'audio', 'gallery', 'group', 'cardetails']}) .hasPadding() .hadBorder() .property('eintro_type', { type: 'select', caption: 'eIntro Type', choices: ['Large object', 'Key attract', 'Story in focus', 'Game play'] }) .methods({ render: function() { /* ... */ }, ready: function() { var self = this, this.$tinymce = this.$body.tinymce(tinyMCEOptions.options("tinymce-eintro", {oninit: function(ed) { ed.setContent((self.$object && self.$object.body) || ''); }})); }, _serializeComponent: function() { return { title : this.$title.val(), body : this.$tinymce.tinymce().getContent(), feedback_intro : this.$feedback_intro.val() }; }, _unserializeComponent: function(obj) { this.$title.val(obj.title); this.$feedback_intro.val(obj.feedback_intro); } }); Saturday, 1 June 13
  6. StoryPlayer/RCP • Cocoa-based Webkit wrapper • Plugin architecture for hardware

    support • Javascript/Cocoa bridge • RCP daemon for remote system control • Crash on error, restart Saturday, 1 June 13
  7. Scheduler • Ruby daemon implementing custom UDP messaging protocol •

    Declarative Ruby API for defining available actions Saturday, 1 June 13
  8. Scheduler • Ruby daemon implementing custom UDP messaging protocol •

    Declarative Ruby API for defining available actions • Actions assembled into timed groups called templates Saturday, 1 June 13
  9. Scheduler • Ruby daemon implementing custom UDP messaging protocol •

    Declarative Ruby API for defining available actions • Actions assembled into timed groups called templates • Single API defines both user interface and behaviour Saturday, 1 June 13
  10. Scheduler namespace :opennms do action(:create_outage, :description => 'OpenNMS - Create

    Outage') do |action| action.param(:hosts, :string, :required => true) action.proc = lambda do |app, params| hosts = parse_hosts(params) `/opt/55/bin/update-opennms-outages sleep #{hosts.join(' ')}` end end end namespace :system do rcp_request_action(:sleep, :description => 'System Sleep') do |action| action.proc = lambda do |app, params| hosts = parse_hosts(params) hosts.each { |h| app[:arp_cache].update(h) } ::ShowControl::RCP::Request.command(RCP_CMD_ID_SYS_SLEEP) end end end Saturday, 1 June 13
  11. Fluent API design • Convergent design • Allow customisation with

    lambdas • Don’t abstract everything Saturday, 1 June 13
  12. Fluent API design • Convergent design • Allow customisation with

    lambdas • Don’t abstract everything • Make common tasks easy, but nothing impossible Saturday, 1 June 13
  13. Messy Leaves! action.proc = lambda do |app, params| payload =

    [ RCP_CMD_ID_AUDIO_GAIN, 1, params[:gain] ].pack('nnC') ::ShowControl::RCP::Request.command(RCP_CMD_ID_AUDIO_SET_OUTPUT_GAIN, payload) end action.proc = lambda do |app, params| payload = [ RCP_CMD_ID_AUDIO_GAIN, 1, params[:gain] ].pack('nnC') ::ShowControl::RCP::Request.command(RCP_CMD_ID_AUDIO_SET_OUTPUT_GAIN, payload) end this.$title = this._makeBlock( {inner:false, tail:false, title:'eIntro title'} ) .append('<input type="text"/>') .insertBefore(this.$html.$tail) .find("input"); this.$body = this._makeBlock( {inner:false, tail:false, title:'eIntro body'} ) .append('<textarea />') .insertBefore(this.$html.$tail) .find("textarea"); this.$intro_pictures = this._makeChildContainer('intro_pictures', {padding: true, border: true, title: 'Introduction images'} ) .insertBefore(this.$html.$tail); Saturday, 1 June 13
  14. Daily Occurrence <erno> hm. I've lost a machine.. literally _lost_.

    it responds to ping, it works completely, I just can't figure out where in my apartment it is. http://bash.org/?5273 Saturday, 1 June 13
  15. 1. Network • Unreliable network • Machine identification • No

    switching/routing • DNS Saturday, 1 June 13
  16. 1. Network • Unreliable network • Machine identification • Switching/routing

    • DNS • No remote access - either in or out Saturday, 1 June 13
  17. 1. Network • Unreliable network • Machine identification • No

    switching/routing • DNS • No remote access - either in or out Saturday, 1 June 13
  18. 2. Closed Systems Assertion: Attempting to fix a low level

    problem from a higher level is futile Saturday, 1 June 13
  19. 2. Closed Systems Assertion: Attempting to fix a low level

    problem from a higher level is futile Saturday, 1 June 13
  20. 2. Closed Systems • Turning machines on • HTML5 application

    manifest • HTML5 video playback Saturday, 1 June 13
  21. 2. Closed Systems • Turning machines on • HTML5 application

    manifest • HTML5 video playback Saturday, 1 June 13
  22. 2. Closed Systems • Turning machines on • HTML5 application

    manifest • HTML5 video playback • Embedded devices Saturday, 1 June 13
  23. 2. Closed Systems • Turning machines on • HTML5 application

    manifest • HTML5 video playback • Embedded devices • EOL hardware Saturday, 1 June 13
  24. 2. Closed Systems - Takeaways • Strive to reduce to

    the number of closed systems in your deployment Saturday, 1 June 13
  25. 2. Closed Systems - Takeaways • Strive to reduce to

    the number of closed systems in your deployment • Be aware of the available tools for diagnosing problems at the lowest level necessary Saturday, 1 June 13
  26. 2. Closed Systems - Takeaways • Strive to reduce to

    the number of closed systems in your deployment • Be aware of the available tools for diagnosing problems at the lowest level necessary • Build a degree of leniency into systems you develop for others to integrate with Saturday, 1 June 13
  27. 3. System Imaging • Had to develop baseline system image

    for all machines in the museum Saturday, 1 June 13
  28. 3. System Imaging • Had to develop baseline system image

    for all machines in the museum • 3rd party contractors required image to develop their interactives Saturday, 1 June 13
  29. 3. System Imaging • Had to develop baseline system image

    for all machines in the museum • 3rd party contractors required image to develop their interactives • Machines had to be interchangeable Saturday, 1 June 13
  30. 3. System Imaging • Had to develop baseline system image

    for all machines in the museum • 3rd party contractors required image to develop their interactives • Machines had to be interchangeable • Theory vs Reality Saturday, 1 June 13
  31. world.xml • Idea: every machine can be substituted into any

    role • Global XML file specifies roles by DNS name • Roles define which plists launchd should start on boot • world.xml retrieved from central at boot time Saturday, 1 June 13
  32. System Triage • As new systems appeared online, we would

    “triage” them • All systems based on same image, so all had the same Bonjour hostname on boot • Map serial numbers to hostnames • Set hostname, bring image up to date, reboot Saturday, 1 June 13
  33. • ad hoc, informally-specified implementation of half of Capistrano and

    half of Puppet • control multiple SSH hosts makitzo Saturday, 1 June 13
  34. • ad hoc, informally-specified implementation of half of Capistrano and

    half of Puppet • control multiple SSH hosts • CLI querying for operating on subset of hosts makitzo Saturday, 1 June 13
  35. makitzo - host querying jason@ratchet $ ./makitzo --host foo jason@ratchet

    $ ./makitzo --host foo --host bar jason@ratchet $ ./makitzo --host carwall-* jason@ratchet $ ./makitzo --role carwall --role bikewall Saturday, 1 June 13
  36. • ad hoc, informally-specified implementation of half of Capistrano and

    half of Puppet • control multiple SSH hosts • CLI querying for operating on subset of hosts • built-in command DSL makitzo Saturday, 1 June 13
  37. makitzo - command DSL module Makitzo; module SSH; module Commands

    module Apple def shutdown_at(time) sudo do unless exec("pmset schedule shutdown \"#{time}\"").success? logger.error("couldn't set poweroff time") return false end end true end end end; end; end Saturday, 1 June 13
  38. makitzo - command DSL jason@ratchet $ ./makitzo --host foo --host

    bar exec shutdown_at 18:00:00 Saturday, 1 June 13
  39. • ad hoc, informally-specified implementation of half of Capistrano and

    half of Puppet • control multiple SSH hosts • CLI querying for operating on subset of hosts • built-in command DSL • migrations makitzo Saturday, 1 June 13
  40. • Reconfiguration of development environment • New system triaging •

    Compare output of commands between multiple hosts • Update systems - git pull • Update systems - migrations makitzo - uses Saturday, 1 June 13
  41. makitzo - migrations class InstallUsbSerialDriver < ::Makitzo::Migrations::Migration role :mac_mini def

    up scp_upload(local_migration_file("FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg.zip"), remote_migration_file("FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg.zip")) exec "cd #{remote_directory}; unzip FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg.zip" sudo { install_pkg remote_migration_file('FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg') } end end Saturday, 1 June 13
  42. • Best-effort • Rails-style syntax • Temporary working area •

    Per-host store (slow) or centralised makitzo - migrations Saturday, 1 June 13
  43. 1 year in 3 lines: • Awesome project • Awesome

    people • Never again Saturday, 1 June 13
  44. Photo Credits • Amy Jackson (@octobrrr) • Tom Beddard (@subblue)

    • Andy Magee http://www.flickr.com/photos/ amagee3/ • “Anne” http://www.flickr.com/photos/ilike/ • “Ianan” http://www.flickr.com/photos/ianan/ Saturday, 1 June 13