github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/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  	"strings"
     9  
    10  	goyaml "gopkg.in/yaml.v2"
    11  )
    12  
    13  type hookArgs struct {
    14  	Hooks []string `yaml:"hooks,omitempty"`
    15  }
    16  
    17  // ClientScript returns a bash script suitable for executing
    18  // on the unit system to intercept hooks via tmux shell.
    19  func ClientScript(c *HooksContext, hooks []string) string {
    20  	// If any hook is "*", then the client is interested in all.
    21  	for _, hook := range hooks {
    22  		if hook == "*" {
    23  			hooks = nil
    24  			break
    25  		}
    26  	}
    27  
    28  	s := strings.Replace(debugHooksClientScript, "{unit_name}", c.Unit, -1)
    29  	s = strings.Replace(s, "{tmux_conf}", tmuxConf, 1)
    30  	s = strings.Replace(s, "{entry_flock}", c.ClientFileLock(), -1)
    31  	s = strings.Replace(s, "{exit_flock}", c.ClientExitFileLock(), -1)
    32  
    33  	yamlArgs := encodeArgs(hooks)
    34  	base64Args := base64.StdEncoding.EncodeToString(yamlArgs)
    35  	s = strings.Replace(s, "{hook_args}", base64Args, 1)
    36  	return s
    37  }
    38  
    39  func encodeArgs(hooks []string) []byte {
    40  	// Marshal to YAML, then encode in base64 to avoid shell escapes.
    41  	yamlArgs, err := goyaml.Marshal(hookArgs{Hooks: hooks})
    42  	if err != nil {
    43  		// This should not happen: we're in full control.
    44  		panic(err)
    45  	}
    46  	return yamlArgs
    47  }
    48  
    49  const debugHooksClientScript = `#!/bin/bash
    50  (
    51  cleanup_on_exit() 
    52  { 
    53  	echo "Cleaning up the debug session"
    54  	tmux kill-session -t {unit_name}; 
    55  }
    56  trap cleanup_on_exit EXIT
    57  
    58  # Lock the juju-<unit>-debug lockfile.
    59  flock -n 8 || (
    60  	echo "Found existing debug sessions, attempting to reconnect" 2>&1
    61  	exec tmux attach-session -t {unit_name}
    62  	exit $?
    63  	)
    64  (
    65  # Close the inherited lock FD, or tmux will keep it open.
    66  exec 8>&-
    67  
    68  # Write out the debug-hooks args.
    69  echo "{hook_args}" | base64 -d > {entry_flock}
    70  
    71  # Lock the juju-<unit>-debug-exit lockfile.
    72  flock -n 9 || exit 1
    73  
    74  # Wait for tmux to be installed.
    75  while [ ! -f /usr/bin/tmux ]; do
    76      sleep 1
    77  done
    78  
    79  if [ ! -f ~/.tmux.conf ]; then
    80          if [ -f /usr/share/byobu/profiles/tmux ]; then
    81                  # Use byobu/tmux profile for familiar keybindings and branding
    82                  echo "source-file /usr/share/byobu/profiles/tmux" > ~/.tmux.conf
    83          else
    84                  # Otherwise, use the legacy juju/tmux configuration
    85                  cat > ~/.tmux.conf <<END
    86                  {tmux_conf}
    87  END
    88          fi
    89  fi
    90  
    91  (
    92      # Close the inherited lock FD, or tmux will keep it open.
    93      exec 9>&-
    94      if ! tmux has-session -t {unit_name}; then
    95  		tmux new-session -d -s {unit_name}
    96  	fi
    97  	client_count=$(tmux list-clients | wc -l)
    98  	if [ $client_count -ge 1 ]; then
    99  		session_name={unit_name}"-"$client_cnt
   100  		exec tmux new-session -d -t {unit_name} -s $session_name
   101  		exec tmux attach-session -t $session_name \; set-option destroy-unattached
   102  	else
   103  	    exec tmux attach-session -t {unit_name}
   104  	fi
   105  )
   106  ) 9>{exit_flock}
   107  ) 8>{entry_flock}
   108  exit $?
   109  `
   110  
   111  const tmuxConf = `
   112  # Status bar
   113  set-option -g status-bg black
   114  set-option -g status-fg white
   115  
   116  set-window-option -g window-status-current-bg red
   117  set-window-option -g window-status-current-attr bright
   118  
   119  set-option -g status-right ''
   120  
   121  # Panes
   122  set-option -g pane-border-fg white
   123  set-option -g pane-active-border-fg white
   124  
   125  # Monitor activity on windows
   126  set-window-option -g monitor-activity on
   127  
   128  # Screen bindings, since people are more familiar with that.
   129  set-option -g prefix C-a
   130  bind C-a last-window
   131  bind a send-key C-a
   132  
   133  bind | split-window -h
   134  bind - split-window -v
   135  
   136  # Fix CTRL-PGUP/PGDOWN for vim
   137  set-window-option -g xterm-keys on
   138  
   139  # Prevent ESC key from adding delay and breaking Vim's ESC > arrow key
   140  set-option -s escape-time 0
   141  `