Slide 1

Slide 1 text

Go Remote Control Anthony Eden of DNSimple

Slide 2

Slide 2 text

How do you easily operate 40 nodes remotely?

Slide 3

Slide 3 text

You could SSH

Slide 4

Slide 4 text

OR

Slide 5

Slide 5 text

You can Go Remote Control

Slide 6

Slide 6 text

Small Go Service on each node

Slide 7

Slide 7 text

Hubot calls HTTPS endpoints

Slide 8

Slide 8 text

Go invokes scripts on the node

Slide 9

Slide 9 text

deploy nameserver srv1-iad

Slide 10

Slide 10 text

Executing update on ns1a-srv1-iad - this may take some time Executing update on ns3a-srv1-iad - this may take some time Executing update on ns2a-srv1-iad - this may take some time Executing update on ns4a-srv1-iad - this may take some time

Slide 11

Slide 11 text

Result of update on ns4a-srv1-iad: Silencing Sensu sensu silenced for ns4a.srv1.iad.dnsimple.com Stopping exabgp exabgp stopped Stopping erldnsimple erldnsimple stopped Running chef client Chef client exit status: 0 chef client run completed erldnsimple started Starting exabgp exabgp started Unsilencing Sensu sensu unsilenced for ns4a.srv1.iad.dnsimple.com

Slide 12

Slide 12 text

callGoRemoteControl = (msg, host, action, callback) -> baseUrl = "https://#{host}.example.com:9876" actionUrl = "#{baseUrl}/#{action}" httpAuthToken = "" msg.http(baseUrl) .headers 'Authorization': httpAuthToken .get() (err, res, body) -> if err msg.send "Failed to connect to node: #{err}" else msg.send "Executing #{action} on #{host} - this may take some time" msg.http(actionUrl) .headers 'Authorization': httpAuthToken .get() (err, res, body) -> if callback callback(host, action, body) else message = "Result of #{action} on #{host}:\n" message += body msg.send(message)

Slide 13

Slide 13 text

module.exports = (robot) -> # Stop a DNSimple name server, run chef-client and start it back up robot.respond /deploy nameserver (\w+-\w+-\w+)$/i, (msg) -> host = msg.match[1] callGoRemoteControl(msg, host, 'update')

Slide 14

Slide 14 text

#!/usr/bin/env ruby require 'open3' require_relative 'stop' require_relative 'start' require_relative 'status' def run_chef_client puts "Running chef client" o, e, s = Open3.capture3("chef-client") puts "Chef client exit status: #{s.exitstatus}" if s.exitstatus == 0 notify("chef client run completed", true) else notify("chef client run failed: #{e}", false) end end def main silence stop_exabgp stop_erldnsimple remove_erldnsimple_run_file run_chef_client || return while !erldnsimple_started? sleep 3 end if name_server_answering? puts "erldnsimple started" start_exabgp || return unsilence else puts "erldnsimple failed to start properly" end end if __FILE__==$0 main end

Slide 15

Slide 15 text

https://github.com/aetrion/go-remote-control

Slide 16

Slide 16 text

https://gist.github.com/aeden/4435503566665b8cc267