1 from starcluster import utils
2 from starcluster import exception
3 from starcluster import clustersetup
4 from starcluster.logger import log
5
6
8 """
9 Starts a TMUX session on StarCluster configured with split panes for all
10 nodes. This allows you to interactively run commands on all nodes and see
11 all the output at once.
12 """
13 _layouts = ['even-horizontal', 'even-vertical', 'main-horizontal',
14 'main-vertical', 'tiled']
15
16 - def __init__(self, envname="starcluster"):
17 self._envname = envname
18 self._nodes = None
19 self._master = None
20 self._user = None
21 self._user_shell = None
22 self._volumes = None
23
29
30 - def _select_layout(self, node, envname, layout="main-vertical", window=''):
36
37 - def _resize_pane(self, node, envname, pane, units, up=False):
38 upordown = '-D %s' % units
39 if up:
40 upordown = '-D %s' % units
41 cmd = 'tmux resize-pane -t %s:%s %s' % (envname, pane, upordown)
42 return node.ssh.execute(cmd)
43
44 - def _split_window(self, node, envname, window='', vertical=False):
45 cmd = 'tmux split-window'
46 if vertical:
47 cmd += ' -h'
48 return node.ssh.execute('%s -t %s:%s' % (cmd, envname, window))
49
51 cmd = 'tmux rename-window -t %s:%s %s' % (envname, window, name)
52 return node.ssh.execute(cmd)
53
55 status = node.ssh.get_status('tmux has-session -t %s' % envname)
56 return status == 0
57
58 - def _send_keys(self, node, envname, cmd, window=''):
59 node.ssh.execute('tmux send-keys -t %s:%s "%s"' % (envname, window,
60 cmd))
61 node.ssh.execute('tmux send-keys -t %s:%s "Enter"' % (envname, window))
62
64 node.ssh.execute('tmux new-session -d -s %s' % envname, detach=True)
65
68
70 node.ssh.execute('tmux new-window -n %s -t %s:' % (title, envname))
71
73 node.ssh.execute('tmux select-window -t %s:%s' % (envname, window))
74
76 node.ssh.execute('tmux select-pane -t %s:%s.%s' %
77 (envname, window, pane))
78
84
85 - def setup_tmuxcc(self, client=None, nodes=None, user='root',
86 layout='tiled'):
87 log.info("Creating TMUX Control Center for user '%s'" % user)
88 client = client or self._master
89 nodes = nodes or self._nodes
90 envname = self._envname
91 orig_user = client.ssh._username
92 if orig_user != user:
93 client.ssh.connect(username=user)
94 chunks = [chunk for chunk in utils.chunk_list(nodes, items=8)]
95 num_windows = len(chunks) + len(nodes)
96 if len(nodes) == 0:
97 log.error("Cluster has no nodes, exiting...")
98 return
99 self.create_session(client, envname, num_windows=num_windows)
100 if len(nodes) == 1 and client == nodes[0]:
101 return
102 if not self._supports_layout(client, envname, layout, window=0):
103 log.warn("failed to select layout '%s', defaulting to "
104 "'main-vertical'" % layout)
105 layout = "main-vertical"
106 status = self._select_layout(client, envname, layout, window=0)
107 if status != 0:
108 raise exception.PluginError("failed to set a layout")
109 for i, chunk in enumerate(chunks):
110 self._rename_window(client, envname, i, 'all%s' % i)
111 for j, node in enumerate(chunk):
112 if j != 0:
113 self._split_window(client, envname, i)
114 self._select_layout(client, envname, window=i, layout=layout)
115 if node.alias != client.alias:
116 self._send_keys(client, envname, cmd='ssh %s' % node.alias,
117 window="%d.%d" % (i, j))
118 for i, node in enumerate(nodes):
119 window = i + len(chunks)
120 self._rename_window(client, envname, window, node.alias)
121 if node.alias != client.alias:
122 self._send_keys(client, envname, cmd='ssh %s' % node.alias,
123 window=window)
124 self._select_window(client, envname, window=0)
125 self._select_pane(client, envname, window=0, pane=0)
126 if orig_user != user:
127 client.ssh.connect(username=orig_user)
128
137
138 - def run(self, nodes, master, user, user_shell, volumes):
139 log.info("Starting TMUX Control Center...")
140 self._nodes = nodes
141 self._master = master
142 self._user = user
143 self._user_shell = user_shell
144 self._volumes = volumes
145 self.add_to_utmp_group(master, user)
146 self.setup_tmuxcc(user=user)
147 self.setup_tmuxcc(user='root')
148
149 - def on_add_node(self, node, nodes, master, user, user_shell, volumes):
150 log.info("Adding %s to TMUX Control Center" % node.alias)
151
152
153 - def on_remove_node(self, node, nodes, master, user, user_shell, volumes):
154 log.info("Removing %s from TMUX Control Center" % node.alias)
155