Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 246e180a

History | View | Annotate | Download (6.1 kB)

1
#!/usr/bin/python
2
#
3

    
4
import sys
5
import optparse
6

    
7
from ganeti import opcodes
8
from ganeti import mcpu
9
from ganeti import objects
10
from ganeti import constants
11
from ganeti import cli
12
from ganeti import logger
13
from ganeti import errors
14
from ganeti import utils
15

    
16
USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...")
17

    
18
def Usage():
19
  """Shows program usage information and exits the program."""
20

    
21
  print >> sys.stderr, "Usage:"
22
  print >> sys.stderr, USAGE
23
  sys.exit(2)
24

    
25

    
26
def Feedback(msg):
27
  """Simple function that prints out its argument.
28

    
29
  """
30
  print msg
31

    
32

    
33
def ParseOptions():
34
  """Parses the command line options.
35

    
36
  In case of command line errors, it will show the usage and exit the
37
  program.
38

    
39
  Returns:
40
    (options, args), as returned by OptionParser.parse_args
41
  """
42

    
43
  parser = optparse.OptionParser(usage="\n%s" % USAGE,
44
                                 version="%%prog (ganeti) %s" %
45
                                 constants.RELEASE_VERSION,
46
                                 option_class=cli.CliOption)
47

    
48
  parser.add_option("-o", "--os", dest="os", default=None,
49
                    help="OS to use during burnin",
50
                    metavar="<OS>")
51
  parser.add_option("--os-size", dest="os_size", help="Disk size",
52
                    default=4 * 1024, type="unit", metavar="<size>")
53
  parser.add_option("--swap-size", dest="swap_size", help="Swap size",
54
                    default=4 * 1024, type="unit", metavar="<size>")
55
  parser.add_option("-v", "--verbose",
56
                    action="store_true", dest="verbose", default=False,
57
                    help="print command execution messages to stdout")
58
  parser.add_option("--do-replace1", dest="do_replace1",
59
                    help="Do disk replacement with the same secondary",
60
                    action="store_false", default=True)
61
  parser.add_option("--do-replace2", dest="do_replace2",
62
                    help="Do disk replacement with a different secondary",
63
                    action="store_false", default=True)
64
  parser.add_option("--do-failover", dest="do_failover",
65
                    help="Do instance failovers", action="store_false",
66
                    default=True)
67

    
68
  options, args = parser.parse_args()
69
  if len(args) < 1 or options.os is None:
70
    Usage()
71

    
72
  return options, args
73

    
74

    
75
def BurninCluster(opts, args):
76
  """Test a cluster intensively.
77

    
78
  This will create instances and then start/stop/failover them.
79
  It is safe for existing instances but could impact performance.
80

    
81
  """
82

    
83
  logger.SetupLogging(debug=True, program="ganeti/burnin")
84
  proc = mcpu.Processor()
85
  result = proc.ExecOpCode(opcodes.OpQueryNodes(output_fields=["name"],
86
                                                names=[]), Feedback)
87
  nodelist = [data[0] for data in result]
88

    
89
  Feedback("- Testing global parameters")
90

    
91
  result = proc.ExecOpCode(opcodes.OpDiagnoseOS(), Feedback)
92

    
93
  if not result:
94
    Feedback("Can't get the OS list")
95
    return 1
96

    
97
  # filter non-valid OS-es
98
  oses = {}
99
  for node_name in result:
100
    oses[node_name] = [obj for obj in result[node_name]
101
                       if isinstance(obj, objects.OS)]
102

    
103
  fnode = oses.keys()[0]
104
  os_set = set([os_inst.name for os_inst in oses[fnode]])
105
  del oses[fnode]
106
  for node in oses:
107
    os_set &= set([os_inst.name for os_inst in oses[node]])
108

    
109
  if opts.os not in os_set:
110
    Feedback("OS '%s' not found" % opts.os)
111
    return 1
112

    
113
  to_remove = []
114
  try:
115
    idx = 0
116
    for instance_name in args:
117
      next_idx = idx + 1
118
      if next_idx >= len(nodelist):
119
        next_idx = 0
120
      pnode = nodelist[idx]
121
      snode = nodelist[next_idx]
122
      if len(nodelist) > 1:
123
        tplate = constants.DT_REMOTE_RAID1
124
      else:
125
        tplate = constants.DT_PLAIN
126

    
127
      op = opcodes.OpCreateInstance(instance_name=instance_name, mem_size=128,
128
                                    disk_size=opts.os_size,
129
                                    swap_size=opts.swap_size,
130
                                    disk_template=tplate,
131
                                    mode=constants.INSTANCE_CREATE,
132
                                    os_type=opts.os, pnode=pnode,
133
                                    snode=snode, vcpus=1,
134
                                    start=True,
135
                                    wait_for_sync=True)
136
      Feedback("- Add instance %s on node %s" % (instance_name, pnode))
137
      result = proc.ExecOpCode(op, Feedback)
138
      to_remove.append(instance_name)
139
      idx = next_idx
140

    
141

    
142
    if opts.do_replace1:
143
      if len(nodelist) > 1:
144
        # failover
145
        for instance_name in args:
146
          op = opcodes.OpReplaceDisks(instance_name=instance_name,
147
                                      remote_node=None)
148

    
149
          Feedback("- Replace disks for instance %s" % (instance_name))
150
          result = proc.ExecOpCode(op, Feedback)
151
      else:
152
        Feedback("- Can't run replace1, not enough nodes")
153

    
154
    if opts.do_failover:
155
      if len(nodelist) > 1:
156
        # failover
157
        for instance_name in args:
158
          op = opcodes.OpFailoverInstance(instance_name=instance_name,
159
                                          ignore_consistency=True)
160

    
161
          Feedback("- Failover instance %s" % (instance_name))
162
          result = proc.ExecOpCode(op, Feedback)
163
      else:
164
        Feedback("- Can't run failovers, not enough nodes")
165

    
166
    # stop / start
167
    for instance_name in args:
168
      op = opcodes.OpShutdownInstance(instance_name=instance_name)
169
      Feedback("- Shutdown instance %s" % instance_name)
170
      result = proc.ExecOpCode(op, Feedback)
171
      op = opcodes.OpStartupInstance(instance_name=instance_name, force=False)
172
      Feedback("- Start instance %s" % instance_name)
173
      result = proc.ExecOpCode(op, Feedback)
174

    
175
  finally:
176
    # remove
177
    for instance_name in to_remove:
178
      op = opcodes.OpRemoveInstance(instance_name=instance_name)
179
      Feedback("- Remove instance %s" % instance_name)
180
      result = proc.ExecOpCode(op, Feedback)
181

    
182
  return 0
183

    
184
def main():
185
  """Main function"""
186

    
187
  opts, args = ParseOptions()
188
  try:
189
    utils.Lock('cmd', max_retries=15, debug=True)
190
  except errors.LockError, err:
191
    logger.ToStderr(str(err))
192
    return 1
193
  try:
194
    retval = BurninCluster(opts, args)
195
  finally:
196
    utils.Unlock('cmd')
197
    utils.LockCleanup()
198
  return retval
199

    
200
if __name__ == "__main__":
201
  main()