Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 22d31e49

History | View | Annotate | Download (6.3 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(feedback=Feedback)
85
  result = proc.ExecOpCode(opcodes.OpQueryNodes(output_fields=["name"],
86
                                                names=[]))
87
  nodelist = [data[0] for data in result]
88

    
89
  Feedback("- Testing global parameters")
90

    
91
  result = proc.ExecOpCode(opcodes.OpDiagnoseOS())
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
                                    ip_check=True,
136
                                    wait_for_sync=True)
137
      Feedback("- Add instance %s on node %s" % (instance_name, pnode))
138
      result = proc.ExecOpCode(op)
139
      to_remove.append(instance_name)
140
      idx = next_idx
141

    
142

    
143
    if opts.do_replace1:
144
      if len(nodelist) > 1:
145
        # failover
146
        for instance_name in args:
147
          op = opcodes.OpReplaceDisks(instance_name=instance_name,
148
                                      remote_node=None,
149
                                      mode=constants.REPLACE_DISK_ALL,
150
                                      disks=["sda", "sdb"])
151

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

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

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

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

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

    
185
  return 0
186

    
187
def main():
188
  """Main function"""
189

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

    
203
if __name__ == "__main__":
204
  main()