launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/worker/uniter/debug/client.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package debug 5 6 import ( 7 "encoding/base64" 8 "launchpad.net/goyaml" 9 "strings" 10 ) 11 12 type hookArgs struct { 13 Hooks []string `yaml:"hooks,omitempty"` 14 } 15 16 // ClientScript returns a bash script suitable for executing 17 // on the unit system to intercept hooks via tmux shell. 18 func ClientScript(c *HooksContext, hooks []string) string { 19 // If any hook is "*", then the client is interested in all. 20 for _, hook := range hooks { 21 if hook == "*" { 22 hooks = nil 23 break 24 } 25 } 26 27 s := strings.Replace(debugHooksClientScript, "{unit_name}", c.Unit, -1) 28 s = strings.Replace(s, "{tmux_conf}", tmuxConf, 1) 29 s = strings.Replace(s, "{entry_flock}", c.ClientFileLock(), -1) 30 s = strings.Replace(s, "{exit_flock}", c.ClientExitFileLock(), -1) 31 32 yamlArgs := encodeArgs(hooks) 33 base64Args := base64.StdEncoding.EncodeToString(yamlArgs) 34 s = strings.Replace(s, "{hook_args}", base64Args, 1) 35 return s 36 } 37 38 func encodeArgs(hooks []string) []byte { 39 // Marshal to YAML, then encode in base64 to avoid shell escapes. 40 yamlArgs, err := goyaml.Marshal(hookArgs{Hooks: hooks}) 41 if err != nil { 42 // This should not happen: we're in full control. 43 panic(err) 44 } 45 return yamlArgs 46 } 47 48 const debugHooksClientScript = `#!/bin/bash 49 ( 50 # Lock the juju-<unit>-debug lockfile. 51 flock -n 8 || (echo "Failed to acquire {entry_flock}: unit is already being debugged" 2>&1; exit 1) 52 ( 53 # Close the inherited lock FD, or tmux will keep it open. 54 exec 8>&- 55 56 # Write out the debug-hooks args. 57 echo "{hook_args}" | base64 -d > {entry_flock} 58 59 # Lock the juju-<unit>-debug-exit lockfile. 60 flock -n 9 || exit 1 61 62 # Wait for tmux to be installed. 63 while [ ! -f /usr/bin/tmux ]; do 64 sleep 1 65 done 66 67 if [ ! -f ~/.tmux.conf ]; then 68 if [ -f /usr/share/byobu/profiles/tmux ]; then 69 # Use byobu/tmux profile for familiar keybindings and branding 70 echo "source-file /usr/share/byobu/profiles/tmux" > ~/.tmux.conf 71 else 72 # Otherwise, use the legacy juju/tmux configuration 73 cat > ~/.tmux.conf <<END 74 {tmux_conf} 75 END 76 fi 77 fi 78 79 ( 80 # Close the inherited lock FD, or tmux will keep it open. 81 exec 9>&- 82 exec tmux new-session -s {unit_name} 83 ) 84 ) 9>{exit_flock} 85 ) 8>{entry_flock} 86 exit $? 87 ` 88 89 const tmuxConf = ` 90 # Status bar 91 set-option -g status-bg black 92 set-option -g status-fg white 93 94 set-window-option -g window-status-current-bg red 95 set-window-option -g window-status-current-attr bright 96 97 set-option -g status-right '' 98 99 # Panes 100 set-option -g pane-border-fg white 101 set-option -g pane-active-border-fg white 102 103 # Monitor activity on windows 104 set-window-option -g monitor-activity on 105 106 # Screen bindings, since people are more familiar with that. 107 set-option -g prefix C-a 108 bind C-a last-window 109 bind a send-key C-a 110 111 bind | split-window -h 112 bind - split-window -v 113 114 # Fix CTRL-PGUP/PGDOWN for vim 115 set-window-option -g xterm-keys on 116 117 # Prevent ESC key from adding delay and breaking Vim's ESC > arrow key 118 set-option -s escape-time 0 119 `