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

Ruby by the River

Ruby by the River

Avatar for Jason Frame

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