root / tools / burnin @ 65fe4693
History | View | Annotate | Download (7.1 kB)
1 | a8083063 | Iustin Pop | #!/usr/bin/python |
---|---|---|---|
2 | a8083063 | Iustin Pop | # |
3 | a8083063 | Iustin Pop | |
4 | a8083063 | Iustin Pop | import sys |
5 | a8083063 | Iustin Pop | import optparse |
6 | a8083063 | Iustin Pop | |
7 | a8083063 | Iustin Pop | from ganeti import opcodes |
8 | a8083063 | Iustin Pop | from ganeti import mcpu |
9 | a8083063 | Iustin Pop | from ganeti import objects |
10 | a8083063 | Iustin Pop | from ganeti import constants |
11 | a8083063 | Iustin Pop | from ganeti import cli |
12 | a8083063 | Iustin Pop | from ganeti import logger |
13 | 9f13fc7a | Iustin Pop | from ganeti import errors |
14 | 9f13fc7a | Iustin Pop | from ganeti import utils |
15 | a8083063 | Iustin Pop | |
16 | 9f13fc7a | Iustin Pop | USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...") |
17 | a8083063 | Iustin Pop | |
18 | a8083063 | Iustin Pop | def Usage(): |
19 | a8083063 | Iustin Pop | """Shows program usage information and exits the program.""" |
20 | a8083063 | Iustin Pop | |
21 | a8083063 | Iustin Pop | print >> sys.stderr, "Usage:" |
22 | a8083063 | Iustin Pop | print >> sys.stderr, USAGE |
23 | a8083063 | Iustin Pop | sys.exit(2) |
24 | a8083063 | Iustin Pop | |
25 | a8083063 | Iustin Pop | |
26 | a8083063 | Iustin Pop | def Feedback(msg): |
27 | 3ecf6786 | Iustin Pop | """Simple function that prints out its argument. |
28 | 3ecf6786 | Iustin Pop | |
29 | 3ecf6786 | Iustin Pop | """ |
30 | 3ecf6786 | Iustin Pop | print msg |
31 | a8083063 | Iustin Pop | |
32 | a8083063 | Iustin Pop | |
33 | a8083063 | Iustin Pop | def ParseOptions(): |
34 | a8083063 | Iustin Pop | """Parses the command line options. |
35 | a8083063 | Iustin Pop | |
36 | a8083063 | Iustin Pop | In case of command line errors, it will show the usage and exit the |
37 | a8083063 | Iustin Pop | program. |
38 | a8083063 | Iustin Pop | |
39 | a8083063 | Iustin Pop | Returns: |
40 | a8083063 | Iustin Pop | (options, args), as returned by OptionParser.parse_args |
41 | a8083063 | Iustin Pop | """ |
42 | a8083063 | Iustin Pop | |
43 | a8083063 | Iustin Pop | parser = optparse.OptionParser(usage="\n%s" % USAGE, |
44 | a8083063 | Iustin Pop | version="%%prog (ganeti) %s" % |
45 | a8083063 | Iustin Pop | constants.RELEASE_VERSION, |
46 | a8083063 | Iustin Pop | option_class=cli.CliOption) |
47 | a8083063 | Iustin Pop | |
48 | a8083063 | Iustin Pop | parser.add_option("-o", "--os", dest="os", default=None, |
49 | a8083063 | Iustin Pop | help="OS to use during burnin", |
50 | a8083063 | Iustin Pop | metavar="<OS>") |
51 | a8083063 | Iustin Pop | parser.add_option("--os-size", dest="os_size", help="Disk size", |
52 | a8083063 | Iustin Pop | default=4 * 1024, type="unit", metavar="<size>") |
53 | a8083063 | Iustin Pop | parser.add_option("--swap-size", dest="swap_size", help="Swap size", |
54 | a8083063 | Iustin Pop | default=4 * 1024, type="unit", metavar="<size>") |
55 | a8083063 | Iustin Pop | parser.add_option("-v", "--verbose", |
56 | a8083063 | Iustin Pop | action="store_true", dest="verbose", default=False, |
57 | a8083063 | Iustin Pop | help="print command execution messages to stdout") |
58 | 79f87a76 | Iustin Pop | parser.add_option("--no-replace1", dest="do_replace1", |
59 | 9f13fc7a | Iustin Pop | help="Do disk replacement with the same secondary", |
60 | 9f13fc7a | Iustin Pop | action="store_false", default=True) |
61 | 79f87a76 | Iustin Pop | parser.add_option("--no-replace2", dest="do_replace2", |
62 | 9f13fc7a | Iustin Pop | help="Do disk replacement with a different secondary", |
63 | 9f13fc7a | Iustin Pop | action="store_false", default=True) |
64 | 79f87a76 | Iustin Pop | parser.add_option("--no-failover", dest="do_failover", |
65 | 9f13fc7a | Iustin Pop | help="Do instance failovers", action="store_false", |
66 | 9f13fc7a | Iustin Pop | default=True) |
67 | 79f87a76 | Iustin Pop | parser.add_option("-t", "--disk-template", dest="disk_template", |
68 | 79f87a76 | Iustin Pop | choices=("remote_raid1", "drbd8"), default="remote_raid1", |
69 | 79f87a76 | Iustin Pop | help="Template type for network mirroring (remote_raid1" |
70 | 79f87a76 | Iustin Pop | " or drbd8) [remote_raid1]") |
71 | 519bfbae | Iustin Pop | parser.add_option("-n", "--nodes", dest="nodes", default="", |
72 | 519bfbae | Iustin Pop | help="Comma separated list of nodes to perform the burnin" |
73 | 519bfbae | Iustin Pop | " on (defaults to all nodes)") |
74 | a8083063 | Iustin Pop | |
75 | a8083063 | Iustin Pop | options, args = parser.parse_args() |
76 | 9f13fc7a | Iustin Pop | if len(args) < 1 or options.os is None: |
77 | a8083063 | Iustin Pop | Usage() |
78 | a8083063 | Iustin Pop | |
79 | a8083063 | Iustin Pop | return options, args |
80 | a8083063 | Iustin Pop | |
81 | a8083063 | Iustin Pop | |
82 | a8083063 | Iustin Pop | def BurninCluster(opts, args): |
83 | a8083063 | Iustin Pop | """Test a cluster intensively. |
84 | a8083063 | Iustin Pop | |
85 | a8083063 | Iustin Pop | This will create instances and then start/stop/failover them. |
86 | a8083063 | Iustin Pop | It is safe for existing instances but could impact performance. |
87 | a8083063 | Iustin Pop | |
88 | a8083063 | Iustin Pop | """ |
89 | a8083063 | Iustin Pop | |
90 | a8083063 | Iustin Pop | logger.SetupLogging(debug=True, program="ganeti/burnin") |
91 | 1a8c0ce1 | Iustin Pop | proc = mcpu.Processor(feedback=Feedback) |
92 | 519bfbae | Iustin Pop | if opts.nodes: |
93 | 519bfbae | Iustin Pop | names = opts.nodes.split(",") |
94 | 519bfbae | Iustin Pop | else: |
95 | 519bfbae | Iustin Pop | names = [] |
96 | 519bfbae | Iustin Pop | try: |
97 | 519bfbae | Iustin Pop | result = proc.ExecOpCode(opcodes.OpQueryNodes(output_fields=["name"], |
98 | 519bfbae | Iustin Pop | names=names)) |
99 | 519bfbae | Iustin Pop | except errors.GenericError, err: |
100 | 519bfbae | Iustin Pop | err_code, msg = cli.FormatError(err) |
101 | 519bfbae | Iustin Pop | Feedback(msg) |
102 | 519bfbae | Iustin Pop | return err_code |
103 | a8083063 | Iustin Pop | nodelist = [data[0] for data in result] |
104 | a8083063 | Iustin Pop | |
105 | a8083063 | Iustin Pop | Feedback("- Testing global parameters") |
106 | a8083063 | Iustin Pop | |
107 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(opcodes.OpDiagnoseOS()) |
108 | a8083063 | Iustin Pop | |
109 | a8083063 | Iustin Pop | if not result: |
110 | a8083063 | Iustin Pop | Feedback("Can't get the OS list") |
111 | a8083063 | Iustin Pop | return 1 |
112 | a8083063 | Iustin Pop | |
113 | a8083063 | Iustin Pop | # filter non-valid OS-es |
114 | a8083063 | Iustin Pop | oses = {} |
115 | a8083063 | Iustin Pop | for node_name in result: |
116 | a8083063 | Iustin Pop | oses[node_name] = [obj for obj in result[node_name] |
117 | a8083063 | Iustin Pop | if isinstance(obj, objects.OS)] |
118 | a8083063 | Iustin Pop | |
119 | a8083063 | Iustin Pop | fnode = oses.keys()[0] |
120 | a8083063 | Iustin Pop | os_set = set([os_inst.name for os_inst in oses[fnode]]) |
121 | a8083063 | Iustin Pop | del oses[fnode] |
122 | a8083063 | Iustin Pop | for node in oses: |
123 | a8083063 | Iustin Pop | os_set &= set([os_inst.name for os_inst in oses[node]]) |
124 | a8083063 | Iustin Pop | |
125 | a8083063 | Iustin Pop | if opts.os not in os_set: |
126 | 9f13fc7a | Iustin Pop | Feedback("OS '%s' not found" % opts.os) |
127 | a8083063 | Iustin Pop | return 1 |
128 | a8083063 | Iustin Pop | |
129 | a8083063 | Iustin Pop | to_remove = [] |
130 | 79f87a76 | Iustin Pop | if opts.disk_template == "remote_raid1": |
131 | 79f87a76 | Iustin Pop | disk_template = constants.DT_REMOTE_RAID1 |
132 | 79f87a76 | Iustin Pop | elif opts.disk_template == "drbd8": |
133 | 79f87a76 | Iustin Pop | disk_template = constants.DT_DRBD8 |
134 | 79f87a76 | Iustin Pop | else: |
135 | 79f87a76 | Iustin Pop | Feedback("Unknown disk template '%s'" % opts.disk_template) |
136 | 79f87a76 | Iustin Pop | return 1 |
137 | a8083063 | Iustin Pop | try: |
138 | a8083063 | Iustin Pop | idx = 0 |
139 | a8083063 | Iustin Pop | for instance_name in args: |
140 | a8083063 | Iustin Pop | next_idx = idx + 1 |
141 | a8083063 | Iustin Pop | if next_idx >= len(nodelist): |
142 | a8083063 | Iustin Pop | next_idx = 0 |
143 | a8083063 | Iustin Pop | pnode = nodelist[idx] |
144 | a8083063 | Iustin Pop | snode = nodelist[next_idx] |
145 | a8083063 | Iustin Pop | if len(nodelist) > 1: |
146 | 79f87a76 | Iustin Pop | tplate = disk_template |
147 | a8083063 | Iustin Pop | else: |
148 | a8083063 | Iustin Pop | tplate = constants.DT_PLAIN |
149 | a8083063 | Iustin Pop | |
150 | a8083063 | Iustin Pop | op = opcodes.OpCreateInstance(instance_name=instance_name, mem_size=128, |
151 | a8083063 | Iustin Pop | disk_size=opts.os_size, |
152 | a8083063 | Iustin Pop | swap_size=opts.swap_size, |
153 | a8083063 | Iustin Pop | disk_template=tplate, |
154 | a8083063 | Iustin Pop | mode=constants.INSTANCE_CREATE, |
155 | a8083063 | Iustin Pop | os_type=opts.os, pnode=pnode, |
156 | a8083063 | Iustin Pop | snode=snode, vcpus=1, |
157 | a8083063 | Iustin Pop | start=True, |
158 | e9f745aa | Iustin Pop | ip_check=True, |
159 | a8083063 | Iustin Pop | wait_for_sync=True) |
160 | a8083063 | Iustin Pop | Feedback("- Add instance %s on node %s" % (instance_name, pnode)) |
161 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
162 | a8083063 | Iustin Pop | to_remove.append(instance_name) |
163 | a8083063 | Iustin Pop | idx = next_idx |
164 | a8083063 | Iustin Pop | |
165 | a8083063 | Iustin Pop | |
166 | 9f13fc7a | Iustin Pop | if opts.do_replace1: |
167 | 9f13fc7a | Iustin Pop | if len(nodelist) > 1: |
168 | 9f13fc7a | Iustin Pop | # failover |
169 | 9f13fc7a | Iustin Pop | for instance_name in args: |
170 | 9f13fc7a | Iustin Pop | op = opcodes.OpReplaceDisks(instance_name=instance_name, |
171 | 22d31e49 | Michael Hanselmann | remote_node=None, |
172 | 22d31e49 | Michael Hanselmann | mode=constants.REPLACE_DISK_ALL, |
173 | 22d31e49 | Michael Hanselmann | disks=["sda", "sdb"]) |
174 | 9f13fc7a | Iustin Pop | |
175 | 9f13fc7a | Iustin Pop | Feedback("- Replace disks for instance %s" % (instance_name)) |
176 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
177 | 9f13fc7a | Iustin Pop | else: |
178 | 9f13fc7a | Iustin Pop | Feedback("- Can't run replace1, not enough nodes") |
179 | a8083063 | Iustin Pop | |
180 | 9f13fc7a | Iustin Pop | if opts.do_failover: |
181 | 9f13fc7a | Iustin Pop | if len(nodelist) > 1: |
182 | 9f13fc7a | Iustin Pop | # failover |
183 | 9f13fc7a | Iustin Pop | for instance_name in args: |
184 | 9f13fc7a | Iustin Pop | op = opcodes.OpFailoverInstance(instance_name=instance_name, |
185 | 9f13fc7a | Iustin Pop | ignore_consistency=True) |
186 | 9f13fc7a | Iustin Pop | |
187 | 9f13fc7a | Iustin Pop | Feedback("- Failover instance %s" % (instance_name)) |
188 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
189 | 9f13fc7a | Iustin Pop | else: |
190 | 9f13fc7a | Iustin Pop | Feedback("- Can't run failovers, not enough nodes") |
191 | a8083063 | Iustin Pop | |
192 | a8083063 | Iustin Pop | # stop / start |
193 | a8083063 | Iustin Pop | for instance_name in args: |
194 | a8083063 | Iustin Pop | op = opcodes.OpShutdownInstance(instance_name=instance_name) |
195 | a8083063 | Iustin Pop | Feedback("- Shutdown instance %s" % instance_name) |
196 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
197 | a8083063 | Iustin Pop | op = opcodes.OpStartupInstance(instance_name=instance_name, force=False) |
198 | a8083063 | Iustin Pop | Feedback("- Start instance %s" % instance_name) |
199 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
200 | a8083063 | Iustin Pop | |
201 | a8083063 | Iustin Pop | finally: |
202 | a8083063 | Iustin Pop | # remove |
203 | a8083063 | Iustin Pop | for instance_name in to_remove: |
204 | a8083063 | Iustin Pop | op = opcodes.OpRemoveInstance(instance_name=instance_name) |
205 | a8083063 | Iustin Pop | Feedback("- Remove instance %s" % instance_name) |
206 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
207 | a8083063 | Iustin Pop | |
208 | a8083063 | Iustin Pop | return 0 |
209 | a8083063 | Iustin Pop | |
210 | a8083063 | Iustin Pop | def main(): |
211 | 3ecf6786 | Iustin Pop | """Main function""" |
212 | 3ecf6786 | Iustin Pop | |
213 | 3ecf6786 | Iustin Pop | opts, args = ParseOptions() |
214 | 3ecf6786 | Iustin Pop | try: |
215 | 3ecf6786 | Iustin Pop | utils.Lock('cmd', max_retries=15, debug=True) |
216 | 3ecf6786 | Iustin Pop | except errors.LockError, err: |
217 | 3ecf6786 | Iustin Pop | logger.ToStderr(str(err)) |
218 | 3ecf6786 | Iustin Pop | return 1 |
219 | 3ecf6786 | Iustin Pop | try: |
220 | 3ecf6786 | Iustin Pop | retval = BurninCluster(opts, args) |
221 | 3ecf6786 | Iustin Pop | finally: |
222 | 3ecf6786 | Iustin Pop | utils.Unlock('cmd') |
223 | 3ecf6786 | Iustin Pop | utils.LockCleanup() |
224 | 3ecf6786 | Iustin Pop | return retval |
225 | a8083063 | Iustin Pop | |
226 | a8083063 | Iustin Pop | if __name__ == "__main__": |
227 | 3ecf6786 | Iustin Pop | main() |