Statistics
| Branch: | Tag: | Revision:

root / lib / opcodes.py @ 2467e0d3

History | View | Annotate | Download (10.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""OpCodes module
23

24
This module implements the data structures which define the cluster
25
operations - the so-called opcodes.
26

27

28
This module implements the logic for doing operations in the cluster. There
29
are two kinds of classes defined:
30
  - opcodes, which are small classes only holding data for the task at hand
31
  - logical units, which know how to deal with their specific opcode only
32

33
"""
34

    
35
# this are practically structures, so disable the message about too
36
# few public methods:
37
# pylint: disable-msg=R0903
38

    
39

    
40
class BaseJO(object):
41
  """A simple serializable object.
42

43
  This object serves as a parent class for both OpCode and Job since
44
  they are serialized in the same way.
45

46
  """
47
  __slots__ = []
48

    
49
  def __init__(self, **kwargs):
50
    for key in kwargs:
51
      if key not in self.__slots__:
52
        raise TypeError("Object %s doesn't support the parameter '%s'" %
53
                        (self.__class__.__name__, key))
54
      setattr(self, key, kwargs[key])
55

    
56
  def __getstate__(self):
57
    state = {}
58
    for name in self.__slots__:
59
      if hasattr(self, name):
60
        state[name] = getattr(self, name)
61
    return state
62

    
63
  def __setstate__(self, state):
64
    if not isinstance(state, dict):
65
      raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
66
                       type(state))
67

    
68
    for name in self.__slots__:
69
      if name not in state:
70
        delattr(self, name)
71

    
72
    for name in state:
73
      setattr(self, name, state[name])
74

    
75

    
76
class OpCode(BaseJO):
77
  """Abstract OpCode"""
78
  OP_ID = "OP_ABSTRACT"
79
  __slots__ = []
80

    
81
  def __getstate__(self):
82
    """Specialized getstate for opcodes.
83

84
    """
85
    data = BaseJO.__getstate__(self)
86
    data["OP_ID"] = self.OP_ID
87
    return data
88

    
89
  @classmethod
90
  def LoadOpCode(cls, data):
91
    """Generic load opcode method.
92

93
    """
94
    if not isinstance(data, dict):
95
      raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
96
    if "OP_ID" not in data:
97
      raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
98
    op_id = data["OP_ID"]
99
    op_class = None
100
    for item in globals().values():
101
      if (isinstance(item, type) and
102
          issubclass(item, cls) and
103
          hasattr(item, "OP_ID") and
104
          getattr(item, "OP_ID") == op_id):
105
        op_class = item
106
        break
107
    if op_class is None:
108
      raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
109
                       op_id)
110
    op = op_class()
111
    new_data = data.copy()
112
    del new_data["OP_ID"]
113
    op.__setstate__(new_data)
114
    return op
115

    
116

    
117
class OpDestroyCluster(OpCode):
118
  """Destroy the cluster."""
119
  OP_ID = "OP_CLUSTER_DESTROY"
120
  __slots__ = []
121

    
122

    
123
class OpQueryClusterInfo(OpCode):
124
  """Query cluster information."""
125
  OP_ID = "OP_CLUSTER_QUERY"
126
  __slots__ = []
127

    
128

    
129
class OpVerifyCluster(OpCode):
130
  """Verify the cluster state."""
131
  OP_ID = "OP_CLUSTER_VERIFY"
132
  __slots__ = ["skip_checks"]
133

    
134

    
135
class OpVerifyDisks(OpCode):
136
  """Verify the cluster disks.
137

138
  Parameters: none
139

140
  Result: two lists:
141
    - list of node names with bad data returned (unreachable, etc.)
142
    - dist of node names with broken volume groups (values: error msg)
143
    - list of instances with degraded disks (that should be activated)
144
    - dict of instances with missing logical volumes (values: (node, vol)
145
      pairs with details about the missing volumes)
146

147
  In normal operation, all lists should be empty. A non-empty instance
148
  list (3rd element of the result) is still ok (errors were fixed) but
149
  non-empty node list means some node is down, and probably there are
150
  unfixable drbd errors.
151

152
  Note that only instances that are drbd-based are taken into
153
  consideration. This might need to be revisited in the future.
154

155
  """
156
  OP_ID = "OP_CLUSTER_VERIFY_DISKS"
157
  __slots__ = []
158

    
159

    
160
class OpMasterFailover(OpCode):
161
  """Do a master failover."""
162
  OP_ID = "OP_CLUSTER_MASTERFAILOVER"
163
  __slots__ = []
164

    
165

    
166
class OpDumpClusterConfig(OpCode):
167
  """Dump the cluster configuration."""
168
  OP_ID = "OP_CLUSTER_DUMPCONFIG"
169
  __slots__ = []
170

    
171

    
172
class OpRenameCluster(OpCode):
173
  """Rename the cluster."""
174
  OP_ID = "OP_CLUSTER_RENAME"
175
  __slots__ = ["name"]
176

    
177

    
178
class OpSetClusterParams(OpCode):
179
  """Change the parameters of the cluster."""
180
  OP_ID = "OP_CLUSTER_SET_PARAMS"
181
  __slots__ = ["vg_name"]
182

    
183

    
184
# node opcodes
185

    
186
class OpRemoveNode(OpCode):
187
  """Remove a node."""
188
  OP_ID = "OP_NODE_REMOVE"
189
  __slots__ = ["node_name"]
190

    
191

    
192
class OpAddNode(OpCode):
193
  """Add a node."""
194
  OP_ID = "OP_NODE_ADD"
195
  __slots__ = ["node_name", "primary_ip", "secondary_ip", "readd"]
196

    
197

    
198
class OpQueryNodes(OpCode):
199
  """Compute the list of nodes."""
200
  OP_ID = "OP_NODE_QUERY"
201
  __slots__ = ["output_fields", "names"]
202

    
203

    
204
class OpQueryNodeVolumes(OpCode):
205
  """Get list of volumes on node."""
206
  OP_ID = "OP_NODE_QUERYVOLS"
207
  __slots__ = ["nodes", "output_fields"]
208

    
209

    
210
# instance opcodes
211

    
212
class OpCreateInstance(OpCode):
213
  """Create an instance."""
214
  OP_ID = "OP_INSTANCE_CREATE"
215
  __slots__ = [
216
    "instance_name", "mem_size", "disk_size", "os_type", "pnode",
217
    "disk_template", "snode", "swap_size", "mode",
218
    "vcpus", "ip", "bridge", "src_node", "src_path", "start",
219
    "wait_for_sync", "ip_check", "mac",
220
    "kernel_path", "initrd_path", "hvm_boot_order", "hvm_acpi",
221
    "hvm_pae", "hvm_cdrom_image_path", "vnc_bind_address",
222
    "file_storage_dir", "file_driver",
223
    "iallocator",
224
    ]
225

    
226

    
227
class OpReinstallInstance(OpCode):
228
  """Reinstall an instance's OS."""
229
  OP_ID = "OP_INSTANCE_REINSTALL"
230
  __slots__ = ["instance_name", "os_type"]
231

    
232

    
233
class OpRemoveInstance(OpCode):
234
  """Remove an instance."""
235
  OP_ID = "OP_INSTANCE_REMOVE"
236
  __slots__ = ["instance_name", "ignore_failures"]
237

    
238

    
239
class OpRenameInstance(OpCode):
240
  """Rename an instance."""
241
  OP_ID = "OP_INSTANCE_RENAME"
242
  __slots__ = ["instance_name", "ignore_ip", "new_name"]
243

    
244

    
245
class OpStartupInstance(OpCode):
246
  """Startup an instance."""
247
  OP_ID = "OP_INSTANCE_STARTUP"
248
  __slots__ = ["instance_name", "force", "extra_args"]
249

    
250

    
251
class OpShutdownInstance(OpCode):
252
  """Shutdown an instance."""
253
  OP_ID = "OP_INSTANCE_SHUTDOWN"
254
  __slots__ = ["instance_name"]
255

    
256

    
257
class OpRebootInstance(OpCode):
258
  """Reboot an instance."""
259
  OP_ID = "OP_INSTANCE_REBOOT"
260
  __slots__ = ["instance_name", "reboot_type", "extra_args",
261
               "ignore_secondaries" ]
262

    
263

    
264
class OpReplaceDisks(OpCode):
265
  """Replace the disks of an instance."""
266
  OP_ID = "OP_INSTANCE_REPLACE_DISKS"
267
  __slots__ = ["instance_name", "remote_node", "mode", "disks", "iallocator"]
268

    
269

    
270
class OpFailoverInstance(OpCode):
271
  """Failover an instance."""
272
  OP_ID = "OP_INSTANCE_FAILOVER"
273
  __slots__ = ["instance_name", "ignore_consistency"]
274

    
275

    
276
class OpConnectConsole(OpCode):
277
  """Connect to an instance's console."""
278
  OP_ID = "OP_INSTANCE_CONSOLE"
279
  __slots__ = ["instance_name"]
280

    
281

    
282
class OpActivateInstanceDisks(OpCode):
283
  """Activate an instance's disks."""
284
  OP_ID = "OP_INSTANCE_ACTIVATE_DISKS"
285
  __slots__ = ["instance_name"]
286

    
287

    
288
class OpDeactivateInstanceDisks(OpCode):
289
  """Deactivate an instance's disks."""
290
  OP_ID = "OP_INSTANCE_DEACTIVATE_DISKS"
291
  __slots__ = ["instance_name"]
292

    
293

    
294
class OpQueryInstances(OpCode):
295
  """Compute the list of instances."""
296
  OP_ID = "OP_INSTANCE_QUERY"
297
  __slots__ = ["output_fields", "names"]
298

    
299

    
300
class OpQueryInstanceData(OpCode):
301
  """Compute the run-time status of instances."""
302
  OP_ID = "OP_INSTANCE_QUERY_DATA"
303
  __slots__ = ["instances"]
304

    
305

    
306
class OpSetInstanceParams(OpCode):
307
  """Change the parameters of an instance."""
308
  OP_ID = "OP_INSTANCE_SET_PARAMS"
309
  __slots__ = [
310
    "instance_name", "mem", "vcpus", "ip", "bridge", "mac",
311
    "kernel_path", "initrd_path", "hvm_boot_order", "hvm_acpi",
312
    "hvm_pae", "hvm_cdrom_image_path", "vnc_bind_address"
313
    ]
314

    
315

    
316
class OpGrowDisk(OpCode):
317
  """Grow a disk of an instance."""
318
  OP_ID = "OP_INSTANCE_GROW_DISK"
319
  __slots__ = ["instance_name", "disk", "amount"]
320

    
321

    
322
# OS opcodes
323
class OpDiagnoseOS(OpCode):
324
  """Compute the list of guest operating systems."""
325
  OP_ID = "OP_OS_DIAGNOSE"
326
  __slots__ = ["output_fields", "names"]
327

    
328

    
329
# Exports opcodes
330
class OpQueryExports(OpCode):
331
  """Compute the list of exported images."""
332
  OP_ID = "OP_BACKUP_QUERY"
333
  __slots__ = ["nodes"]
334

    
335

    
336
class OpExportInstance(OpCode):
337
  """Export an instance."""
338
  OP_ID = "OP_BACKUP_EXPORT"
339
  __slots__ = ["instance_name", "target_node", "shutdown"]
340

    
341
class OpRemoveExport(OpCode):
342
  """Remove an instance's export."""
343
  OP_ID = "OP_BACKUP_REMOVE"
344
  __slots__ = ["instance_name"]
345

    
346
# Tags opcodes
347
class OpGetTags(OpCode):
348
  """Returns the tags of the given object."""
349
  OP_ID = "OP_TAGS_GET"
350
  __slots__ = ["kind", "name"]
351

    
352

    
353
class OpSearchTags(OpCode):
354
  """Searches the tags in the cluster for a given pattern."""
355
  OP_ID = "OP_TAGS_SEARCH"
356
  __slots__ = ["pattern"]
357

    
358

    
359
class OpAddTags(OpCode):
360
  """Add a list of tags on a given object."""
361
  OP_ID = "OP_TAGS_SET"
362
  __slots__ = ["kind", "name", "tags"]
363

    
364

    
365
class OpDelTags(OpCode):
366
  """Remove a list of tags from a given object."""
367
  OP_ID = "OP_TAGS_DEL"
368
  __slots__ = ["kind", "name", "tags"]
369

    
370

    
371
# Test opcodes
372
class OpTestDelay(OpCode):
373
  """Sleeps for a configured amount of time.
374

375
  This is used just for debugging and testing.
376

377
  Parameters:
378
    - duration: the time to sleep
379
    - on_master: if true, sleep on the master
380
    - on_nodes: list of nodes in which to sleep
381

382
  If the on_master parameter is true, it will execute a sleep on the
383
  master (before any node sleep).
384

385
  If the on_nodes list is not empty, it will sleep on those nodes
386
  (after the sleep on the master, if that is enabled).
387

388
  As an additional feature, the case of duration < 0 will be reported
389
  as an execution error, so this opcode can be used as a failure
390
  generator. The case of duration == 0 will not be treated specially.
391

392
  """
393
  OP_ID = "OP_TEST_DELAY"
394
  __slots__ = ["duration", "on_master", "on_nodes"]
395

    
396

    
397
class OpTestAllocator(OpCode):
398
  """Allocator framework testing.
399

400
  This opcode has two modes:
401
    - gather and return allocator input for a given mode (allocate new
402
      or replace secondary) and a given instance definition (direction
403
      'in')
404
    - run a selected allocator for a given operation (as above) and
405
      return the allocator output (direction 'out')
406

407
  """
408
  OP_ID = "OP_TEST_ALLOCATOR"
409
  __slots__ = [
410
    "direction", "mode", "allocator", "name",
411
    "mem_size", "disks", "disk_template",
412
    "os", "tags", "nics", "vcpus",
413
    ]