root / tools / burnin @ 24a40d57
History | View | Annotate | Download (6.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 | 9f13fc7a | Iustin Pop | parser.add_option("--do-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 | 9f13fc7a | Iustin Pop | parser.add_option("--do-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 | 9f13fc7a | Iustin Pop | parser.add_option("--do-failover", dest="do_failover", |
65 | 9f13fc7a | Iustin Pop | help="Do instance failovers", action="store_false", |
66 | 9f13fc7a | Iustin Pop | default=True) |
67 | a8083063 | Iustin Pop | |
68 | a8083063 | Iustin Pop | options, args = parser.parse_args() |
69 | 9f13fc7a | Iustin Pop | if len(args) < 1 or options.os is None: |
70 | a8083063 | Iustin Pop | Usage() |
71 | a8083063 | Iustin Pop | |
72 | a8083063 | Iustin Pop | return options, args |
73 | a8083063 | Iustin Pop | |
74 | a8083063 | Iustin Pop | |
75 | a8083063 | Iustin Pop | def BurninCluster(opts, args): |
76 | a8083063 | Iustin Pop | """Test a cluster intensively. |
77 | a8083063 | Iustin Pop | |
78 | a8083063 | Iustin Pop | This will create instances and then start/stop/failover them. |
79 | a8083063 | Iustin Pop | It is safe for existing instances but could impact performance. |
80 | a8083063 | Iustin Pop | |
81 | a8083063 | Iustin Pop | """ |
82 | a8083063 | Iustin Pop | |
83 | a8083063 | Iustin Pop | logger.SetupLogging(debug=True, program="ganeti/burnin") |
84 | 1a8c0ce1 | Iustin Pop | proc = mcpu.Processor(feedback=Feedback) |
85 | 246e180a | Iustin Pop | result = proc.ExecOpCode(opcodes.OpQueryNodes(output_fields=["name"], |
86 | 1a8c0ce1 | Iustin Pop | names=[])) |
87 | a8083063 | Iustin Pop | nodelist = [data[0] for data in result] |
88 | a8083063 | Iustin Pop | |
89 | a8083063 | Iustin Pop | Feedback("- Testing global parameters") |
90 | a8083063 | Iustin Pop | |
91 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(opcodes.OpDiagnoseOS()) |
92 | a8083063 | Iustin Pop | |
93 | a8083063 | Iustin Pop | if not result: |
94 | a8083063 | Iustin Pop | Feedback("Can't get the OS list") |
95 | a8083063 | Iustin Pop | return 1 |
96 | a8083063 | Iustin Pop | |
97 | a8083063 | Iustin Pop | # filter non-valid OS-es |
98 | a8083063 | Iustin Pop | oses = {} |
99 | a8083063 | Iustin Pop | for node_name in result: |
100 | a8083063 | Iustin Pop | oses[node_name] = [obj for obj in result[node_name] |
101 | a8083063 | Iustin Pop | if isinstance(obj, objects.OS)] |
102 | a8083063 | Iustin Pop | |
103 | a8083063 | Iustin Pop | fnode = oses.keys()[0] |
104 | a8083063 | Iustin Pop | os_set = set([os_inst.name for os_inst in oses[fnode]]) |
105 | a8083063 | Iustin Pop | del oses[fnode] |
106 | a8083063 | Iustin Pop | for node in oses: |
107 | a8083063 | Iustin Pop | os_set &= set([os_inst.name for os_inst in oses[node]]) |
108 | a8083063 | Iustin Pop | |
109 | a8083063 | Iustin Pop | if opts.os not in os_set: |
110 | 9f13fc7a | Iustin Pop | Feedback("OS '%s' not found" % opts.os) |
111 | a8083063 | Iustin Pop | return 1 |
112 | a8083063 | Iustin Pop | |
113 | a8083063 | Iustin Pop | to_remove = [] |
114 | a8083063 | Iustin Pop | try: |
115 | a8083063 | Iustin Pop | idx = 0 |
116 | a8083063 | Iustin Pop | for instance_name in args: |
117 | a8083063 | Iustin Pop | next_idx = idx + 1 |
118 | a8083063 | Iustin Pop | if next_idx >= len(nodelist): |
119 | a8083063 | Iustin Pop | next_idx = 0 |
120 | a8083063 | Iustin Pop | pnode = nodelist[idx] |
121 | a8083063 | Iustin Pop | snode = nodelist[next_idx] |
122 | a8083063 | Iustin Pop | if len(nodelist) > 1: |
123 | a8083063 | Iustin Pop | tplate = constants.DT_REMOTE_RAID1 |
124 | a8083063 | Iustin Pop | else: |
125 | a8083063 | Iustin Pop | tplate = constants.DT_PLAIN |
126 | a8083063 | Iustin Pop | |
127 | a8083063 | Iustin Pop | op = opcodes.OpCreateInstance(instance_name=instance_name, mem_size=128, |
128 | a8083063 | Iustin Pop | disk_size=opts.os_size, |
129 | a8083063 | Iustin Pop | swap_size=opts.swap_size, |
130 | a8083063 | Iustin Pop | disk_template=tplate, |
131 | a8083063 | Iustin Pop | mode=constants.INSTANCE_CREATE, |
132 | a8083063 | Iustin Pop | os_type=opts.os, pnode=pnode, |
133 | a8083063 | Iustin Pop | snode=snode, vcpus=1, |
134 | a8083063 | Iustin Pop | start=True, |
135 | e9f745aa | Iustin Pop | ip_check=True, |
136 | a8083063 | Iustin Pop | wait_for_sync=True) |
137 | a8083063 | Iustin Pop | Feedback("- Add instance %s on node %s" % (instance_name, pnode)) |
138 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
139 | a8083063 | Iustin Pop | to_remove.append(instance_name) |
140 | a8083063 | Iustin Pop | idx = next_idx |
141 | a8083063 | Iustin Pop | |
142 | a8083063 | Iustin Pop | |
143 | 9f13fc7a | Iustin Pop | if opts.do_replace1: |
144 | 9f13fc7a | Iustin Pop | if len(nodelist) > 1: |
145 | 9f13fc7a | Iustin Pop | # failover |
146 | 9f13fc7a | Iustin Pop | for instance_name in args: |
147 | 9f13fc7a | Iustin Pop | op = opcodes.OpReplaceDisks(instance_name=instance_name, |
148 | 9f13fc7a | Iustin Pop | remote_node=None) |
149 | 9f13fc7a | Iustin Pop | |
150 | 9f13fc7a | Iustin Pop | Feedback("- Replace disks for instance %s" % (instance_name)) |
151 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
152 | 9f13fc7a | Iustin Pop | else: |
153 | 9f13fc7a | Iustin Pop | Feedback("- Can't run replace1, not enough nodes") |
154 | a8083063 | Iustin Pop | |
155 | 9f13fc7a | Iustin Pop | if opts.do_failover: |
156 | 9f13fc7a | Iustin Pop | if len(nodelist) > 1: |
157 | 9f13fc7a | Iustin Pop | # failover |
158 | 9f13fc7a | Iustin Pop | for instance_name in args: |
159 | 9f13fc7a | Iustin Pop | op = opcodes.OpFailoverInstance(instance_name=instance_name, |
160 | 9f13fc7a | Iustin Pop | ignore_consistency=True) |
161 | 9f13fc7a | Iustin Pop | |
162 | 9f13fc7a | Iustin Pop | Feedback("- Failover instance %s" % (instance_name)) |
163 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
164 | 9f13fc7a | Iustin Pop | else: |
165 | 9f13fc7a | Iustin Pop | Feedback("- Can't run failovers, not enough nodes") |
166 | a8083063 | Iustin Pop | |
167 | a8083063 | Iustin Pop | # stop / start |
168 | a8083063 | Iustin Pop | for instance_name in args: |
169 | a8083063 | Iustin Pop | op = opcodes.OpShutdownInstance(instance_name=instance_name) |
170 | a8083063 | Iustin Pop | Feedback("- Shutdown instance %s" % instance_name) |
171 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
172 | a8083063 | Iustin Pop | op = opcodes.OpStartupInstance(instance_name=instance_name, force=False) |
173 | a8083063 | Iustin Pop | Feedback("- Start instance %s" % instance_name) |
174 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
175 | a8083063 | Iustin Pop | |
176 | a8083063 | Iustin Pop | finally: |
177 | a8083063 | Iustin Pop | # remove |
178 | a8083063 | Iustin Pop | for instance_name in to_remove: |
179 | a8083063 | Iustin Pop | op = opcodes.OpRemoveInstance(instance_name=instance_name) |
180 | a8083063 | Iustin Pop | Feedback("- Remove instance %s" % instance_name) |
181 | 1a8c0ce1 | Iustin Pop | result = proc.ExecOpCode(op) |
182 | a8083063 | Iustin Pop | |
183 | a8083063 | Iustin Pop | return 0 |
184 | a8083063 | Iustin Pop | |
185 | a8083063 | Iustin Pop | def main(): |
186 | 3ecf6786 | Iustin Pop | """Main function""" |
187 | 3ecf6786 | Iustin Pop | |
188 | 3ecf6786 | Iustin Pop | opts, args = ParseOptions() |
189 | 3ecf6786 | Iustin Pop | try: |
190 | 3ecf6786 | Iustin Pop | utils.Lock('cmd', max_retries=15, debug=True) |
191 | 3ecf6786 | Iustin Pop | except errors.LockError, err: |
192 | 3ecf6786 | Iustin Pop | logger.ToStderr(str(err)) |
193 | 3ecf6786 | Iustin Pop | return 1 |
194 | 3ecf6786 | Iustin Pop | try: |
195 | 3ecf6786 | Iustin Pop | retval = BurninCluster(opts, args) |
196 | 3ecf6786 | Iustin Pop | finally: |
197 | 3ecf6786 | Iustin Pop | utils.Unlock('cmd') |
198 | 3ecf6786 | Iustin Pop | utils.LockCleanup() |
199 | 3ecf6786 | Iustin Pop | return retval |
200 | a8083063 | Iustin Pop | |
201 | a8083063 | Iustin Pop | if __name__ == "__main__": |
202 | 3ecf6786 | Iustin Pop | main() |