Share
Embed
Transcript
83 slides
-
Technical Summary • 8 major “Key Attract” installations • 37
eIntros • 6 eStorybooks • 17 public information screens • ~150 Mac Minis Saturday, 1 June 13 -
Architecture Rails CMS Scheduler RCP Daemon StoryPlayer Mac Mini Role
specific service Role specific service Role specific service Saturday, 1 June 13 -
CMS • Venue as content tree • Page per exhibit
• Content type/class per exhibit type • Revision and publishing controls • Data collection Saturday, 1 June 13 -
Polar • Lots of content types • Requirements changing daily
• Declarative JS API for declaring editable content types • Recursive Saturday, 1 June 13 -
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 -
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 -
Scheduler • Ruby daemon implementing custom UDP messaging protocol •
Declarative Ruby API for defining available actions Saturday, 1 June 13 -
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 -
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 -
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 -
Fluent API design • Convergent design • Allow customisation with
lambdas Saturday, 1 June 13 -
Fluent API design • Convergent design • Allow customisation with
lambdas • Don’t abstract everything Saturday, 1 June 13 -
Fluent API design • Convergent design • Allow customisation with
lambdas • Don’t abstract everything • Make common tasks easy, but nothing impossible Saturday, 1 June 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 -
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 -
1. Network • Unreliable network • Machine identification • No
switching/routing Saturday, 1 June 13 -
1. Network • Unreliable network • Machine identification • No
switching/routing • DNS Saturday, 1 June 13 -
1. Network • Unreliable network • Machine identification • Switching/routing
• DNS • No remote access - either in or out Saturday, 1 June 13 -
1. Network • Unreliable network • Machine identification • No
switching/routing • DNS • No remote access - either in or out Saturday, 1 June 13 -
2. Closed Systems Assertion: Attempting to fix a low level
problem from a higher level is futile Saturday, 1 June 13 -
2. Closed Systems Assertion: Attempting to fix a low level
problem from a higher level is futile Saturday, 1 June 13 -
2. Closed Systems • Turning machines on • HTML5 application
manifest Saturday, 1 June 13 -
2. Closed Systems • Turning machines on • HTML5 application
manifest • HTML5 video playback Saturday, 1 June 13 -
2. Closed Systems • Turning machines on • HTML5 application
manifest • HTML5 video playback Saturday, 1 June 13 -
2. Closed Systems • Turning machines on • HTML5 application
manifest • HTML5 video playback • Embedded devices Saturday, 1 June 13 -
2. Closed Systems • Turning machines on • HTML5 application
manifest • HTML5 video playback • Embedded devices • EOL hardware Saturday, 1 June 13 -
2. Closed Systems - Takeaways • Strive to reduce to
the number of closed systems in your deployment Saturday, 1 June 13 -
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 -
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 -
3. System Imaging • Had to develop baseline system image
for all machines in the museum Saturday, 1 June 13 -
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 -
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 -
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 -
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 -
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 -
• ad hoc, informally-specified implementation of half of Capistrano and
half of Puppet makitzo Saturday, 1 June 13 -
• ad hoc, informally-specified implementation of half of Capistrano and
half of Puppet • control multiple SSH hosts makitzo Saturday, 1 June 13 -
• 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 -
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 -
• 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 -
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 -
makitzo - command DSL jason@ratchet $ ./makitzo --host foo --host
bar exec shutdown_at 18:00:00 Saturday, 1 June 13 -
• 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 -
• 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 -
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 -
• Best-effort • Rails-style syntax • Temporary working area makitzo
- migrations Saturday, 1 June 13 -
• Best-effort • Rails-style syntax • Temporary working area •
Per-host store (slow) or centralised makitzo - migrations Saturday, 1 June 13 -
1 year in 3 lines: • Awesome project • Awesome
people Saturday, 1 June 13 -
1 year in 3 lines: • Awesome project • Awesome
people • Never again Saturday, 1 June 13 -
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