- Implement “gnt-node volumes”
[ganeti-local] / scripts / gnt-node
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2006, 2007 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 import sys
23 from optparse import make_option
24
25 from ganeti.cli import *
26 from ganeti import opcodes
27 from ganeti import logger
28 from ganeti import utils
29
30
31 def AddNode(opts, args):
32   """Add node cli-to-processor bridge."""
33   op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip)
34   SubmitOpCode(op)
35
36
37 def ListNodes(opts, args):
38   """List nodes and their properties.
39
40   """
41   if opts.output is None:
42     selected_fields = ["name", "dtotal", "dfree",
43                        "mtotal", "mnode", "mfree",
44                        "pinst", "sinst"]
45   else:
46     selected_fields = opts.output.split(",")
47
48   op = opcodes.OpQueryNodes(output_fields=selected_fields)
49   output = SubmitOpCode(op)
50
51   mlens = [0 for name in selected_fields]
52   format_fields = []
53   unitformat_fields = ("dtotal", "dfree", "mtotal", "mnode", "mfree")
54   for field in selected_fields:
55     if field in ("dtotal", "dfree", "mtotal", "mnode",
56                  "mfree", "pinst", "sinst"):
57       format_fields.append("%*s")
58     else:
59       format_fields.append("%-*s")
60
61   separator = opts.separator
62   if "%" in separator:
63     separator = separator.replace("%", "%%")
64   format = separator.join(format_fields)
65
66   for row in output:
67     for idx, val in enumerate(row):
68       if opts.human_readable and selected_fields[idx] in unitformat_fields:
69         try:
70           val = int(val)
71         except ValueError:
72           pass
73         else:
74           val = row[idx] = utils.FormatUnit(val)
75       mlens[idx] = max(mlens[idx], len(val))
76
77   if not opts.no_headers:
78     header_list = {"name": "Node", "pinst": "Pinst", "sinst": "Sinst",
79                    "pip": "PrimaryIP", "sip": "SecondaryIP",
80                    "dtotal": "DTotal", "dfree": "DFree",
81                    "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree"}
82     args = []
83     for idx, name in enumerate(selected_fields):
84       hdr = header_list[name]
85       mlens[idx] = max(mlens[idx], len(hdr))
86       args.append(mlens[idx])
87       args.append(hdr)
88     logger.ToStdout(format % tuple(args))
89
90   for row in output:
91     args = []
92     for idx, val in enumerate(row):
93       args.append(mlens[idx])
94       args.append(val)
95     logger.ToStdout(format % tuple(args))
96
97   return 0
98
99
100 def ShowNodeConfig(opts, args):
101   """Show node information.
102
103   """
104   op = opcodes.OpQueryNodeData(nodes=args)
105   result = SubmitOpCode(op)
106
107   for name, primary_ip, secondary_ip, pinst, sinst in result:
108     logger.ToStdout("Node name: %s" % name)
109     logger.ToStdout("  primary ip: %s" % primary_ip)
110     logger.ToStdout("  secondary ip: %s" % secondary_ip)
111     if pinst:
112       logger.ToStdout("  primary for instances:")
113       for iname in pinst:
114         logger.ToStdout("    - %s" % iname)
115     else:
116       logger.ToStdout("  primary for no instances")
117     if sinst:
118       logger.ToStdout("  secondary for instances:")
119       for iname in sinst:
120         logger.ToStdout("    - %s" % iname)
121     else:
122       logger.ToStdout("  secondary for no instances")
123
124   return 0
125
126
127 def RemoveNode(opts, args):
128   """Remove node cli-to-processor bridge."""
129   op = opcodes.OpRemoveNode(node_name=args[0])
130   SubmitOpCode(op)
131
132
133 def ListVolumes(opts, args):
134   """List logical volumes on node(s).
135
136   """
137   if opts.output is None:
138     selected_fields = ["node", "phys", "vg",
139                        "name", "size", "instance"]
140   else:
141     selected_fields = opts.output.split(",")
142
143   op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
144   output = SubmitOpCode(op)
145
146   mlens = [0 for name in selected_fields]
147   format_fields = []
148   unitformat_fields = ("size",)
149   for field in selected_fields:
150     if field in unitformat_fields:
151       format_fields.append("%*s")
152     else:
153       format_fields.append("%-*s")
154
155   separator = opts.separator
156   if "%" in separator:
157     separator = separator.replace("%", "%%")
158   format = separator.join(format_fields)
159
160   for row in output:
161     for idx, val in enumerate(row):
162       if opts.human_readable and selected_fields[idx] in unitformat_fields:
163         try:
164           val = int(val)
165         except ValueError:
166           pass
167         else:
168           val = row[idx] = utils.FormatUnit(val)
169       mlens[idx] = max(mlens[idx], len(val))
170
171   if not opts.no_headers:
172     header_list = {"node": "Node", "phys": "PhysDev",
173                    "vg": "VG", "name": "Name",
174                    "size": "Size", "instance": "Instance"}
175     args = []
176     for idx, name in enumerate(selected_fields):
177       hdr = header_list[name]
178       mlens[idx] = max(mlens[idx], len(hdr))
179       args.append(mlens[idx])
180       args.append(hdr)
181     logger.ToStdout(format % tuple(args))
182
183   for row in output:
184     args = []
185     for idx, val in enumerate(row):
186       args.append(mlens[idx])
187       args.append(val)
188     logger.ToStdout(format % tuple(args))
189
190   return 0
191
192
193 commands = {
194   'add': (AddNode, ARGS_ONE,
195           [DEBUG_OPT,
196            make_option("-s", "--secondary-ip", dest="secondary_ip",
197                        help="Specify the secondary ip for the node",
198                        metavar="ADDRESS", default=None),],
199           "<node_name>", "Add a node to the cluster"),
200   'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT],
201            "[<node_name>...]", "Show information about the node(s)"),
202   'list': (ListNodes, ARGS_NONE,
203            [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
204            "", "Lists the nodes in the cluster"),
205   'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
206              "<node_name>", "Removes a node from the cluster"),
207   'volumes': (ListVolumes, ARGS_ANY,
208               [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
209               "[<node_name>...]", "List logical volumes on node(s)"),
210   }
211
212
213 if __name__ == '__main__':
214   retcode = GenericMain(commands)
215   sys.exit(retcode)