Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ e9f745aa

History | View | Annotate | Download (6.2 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
                                    ip_check=True,
136
                                    wait_for_sync=True)
137
      Feedback("- Add instance %s on node %s" % (instance_name, pnode))
138
      result = proc.ExecOpCode(op, Feedback)
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

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

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

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

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

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

    
183
  return 0
184

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

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

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