opcodes.py 10.6 KB
Newer Older
Iustin Pop's avatar
Iustin Pop committed
1
#
Iustin Pop's avatar
Iustin Pop committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#

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


"""OpCodes module

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

Iustin Pop's avatar
Iustin Pop committed
27
28
Every operation which modifies the cluster state is expressed via
opcodes.
Iustin Pop's avatar
Iustin Pop committed
29
30
31
32
33
34
35

"""

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

36

Iustin Pop's avatar
Iustin Pop committed
37
class BaseOpCode(object):
38
39
  """A simple serializable object.

Iustin Pop's avatar
Iustin Pop committed
40
41
42
  This object serves as a parent class for OpCode without any custom
  field handling.

43
44

  """
Iustin Pop's avatar
Iustin Pop committed
45
46
47
48
49
  __slots__ = []

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

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  def __getstate__(self):
    state = {}
    for name in self.__slots__:
      if hasattr(self, name):
        state[name] = getattr(self, name)
    return state

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

    for name in self.__slots__:
      if name not in state:
        delattr(self, name)

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


Iustin Pop's avatar
Iustin Pop committed
74
class OpCode(BaseOpCode):
75
76
77
78
79
80
81
82
  """Abstract OpCode"""
  OP_ID = "OP_ABSTRACT"
  __slots__ = []

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

    """
Iustin Pop's avatar
Iustin Pop committed
83
    data = BaseOpCode.__getstate__(self)
84
85
86
87
    data["OP_ID"] = self.OP_ID
    return data

  @classmethod
88
  def LoadOpCode(cls, data):
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    """Generic load opcode method.

    """
    if not isinstance(data, dict):
      raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
    if "OP_ID" not in data:
      raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
    op_id = data["OP_ID"]
    op_class = None
    for item in globals().values():
      if (isinstance(item, type) and
          issubclass(item, cls) and
          hasattr(item, "OP_ID") and
          getattr(item, "OP_ID") == op_id):
        op_class = item
        break
    if op_class is None:
      raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
                       op_id)
    op = op_class()
    new_data = data.copy()
    del new_data["OP_ID"]
    op.__setstate__(new_data)
    return op

Iustin Pop's avatar
Iustin Pop committed
114
115
116
117
118
119
120
121

class OpDestroyCluster(OpCode):
  """Destroy the cluster."""
  OP_ID = "OP_CLUSTER_DESTROY"
  __slots__ = []


class OpQueryClusterInfo(OpCode):
Iustin Pop's avatar
Iustin Pop committed
122
  """Query cluster information."""
Iustin Pop's avatar
Iustin Pop committed
123
124
125
126
127
  OP_ID = "OP_CLUSTER_QUERY"
  __slots__ = []


class OpVerifyCluster(OpCode):
Iustin Pop's avatar
Iustin Pop committed
128
  """Verify the cluster state."""
Iustin Pop's avatar
Iustin Pop committed
129
  OP_ID = "OP_CLUSTER_VERIFY"
130
  __slots__ = ["skip_checks"]
Iustin Pop's avatar
Iustin Pop committed
131
132


Iustin Pop's avatar
Iustin Pop committed
133
134
135
136
137
138
139
class OpVerifyDisks(OpCode):
  """Verify the cluster disks.

  Parameters: none

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

145
146
147
148
  In normal operation, all lists should be empty. A non-empty instance
  list (3rd element of the result) is still ok (errors were fixed) but
  non-empty node list means some node is down, and probably there are
  unfixable drbd errors.
Iustin Pop's avatar
Iustin Pop committed
149
150
151
152
153
154
155
156
157

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

  """
  OP_ID = "OP_CLUSTER_VERIFY_DISKS"
  __slots__ = []


Iustin Pop's avatar
Iustin Pop committed
158
class OpMasterFailover(OpCode):
Iustin Pop's avatar
Iustin Pop committed
159
  """Do a master failover."""
Iustin Pop's avatar
Iustin Pop committed
160
161
162
163
164
  OP_ID = "OP_CLUSTER_MASTERFAILOVER"
  __slots__ = []


class OpDumpClusterConfig(OpCode):
Iustin Pop's avatar
Iustin Pop committed
165
  """Dump the cluster configuration."""
Iustin Pop's avatar
Iustin Pop committed
166
167
168
169
  OP_ID = "OP_CLUSTER_DUMPCONFIG"
  __slots__ = []


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


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


182
183
# node opcodes

Iustin Pop's avatar
Iustin Pop committed
184
185
186
187
188
189
190
191
192
class OpRemoveNode(OpCode):
  """Remove a node."""
  OP_ID = "OP_NODE_REMOVE"
  __slots__ = ["node_name"]


class OpAddNode(OpCode):
  """Add a node."""
  OP_ID = "OP_NODE_ADD"
193
  __slots__ = ["node_name", "primary_ip", "secondary_ip", "readd"]
Iustin Pop's avatar
Iustin Pop committed
194
195
196
197
198


class OpQueryNodes(OpCode):
  """Compute the list of nodes."""
  OP_ID = "OP_NODE_QUERY"
199
  __slots__ = ["output_fields", "names"]
Iustin Pop's avatar
Iustin Pop committed
200
201


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


Iustin Pop's avatar
Iustin Pop committed
208
209
210
# instance opcodes

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


225
class OpReinstallInstance(OpCode):
Iustin Pop's avatar
Iustin Pop committed
226
  """Reinstall an instance's OS."""
227
  OP_ID = "OP_INSTANCE_REINSTALL"
228
  __slots__ = ["instance_name", "os_type"]
229
230


Iustin Pop's avatar
Iustin Pop committed
231
232
233
class OpRemoveInstance(OpCode):
  """Remove an instance."""
  OP_ID = "OP_INSTANCE_REMOVE"
Iustin Pop's avatar
Iustin Pop committed
234
  __slots__ = ["instance_name", "ignore_failures"]
Iustin Pop's avatar
Iustin Pop committed
235
236


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


Iustin Pop's avatar
Iustin Pop committed
243
class OpStartupInstance(OpCode):
Iustin Pop's avatar
Iustin Pop committed
244
  """Startup an instance."""
Iustin Pop's avatar
Iustin Pop committed
245
246
247
248
249
  OP_ID = "OP_INSTANCE_STARTUP"
  __slots__ = ["instance_name", "force", "extra_args"]


class OpShutdownInstance(OpCode):
Iustin Pop's avatar
Iustin Pop committed
250
  """Shutdown an instance."""
Iustin Pop's avatar
Iustin Pop committed
251
252
253
254
  OP_ID = "OP_INSTANCE_SHUTDOWN"
  __slots__ = ["instance_name"]


255
256
class OpRebootInstance(OpCode):
  """Reboot an instance."""
Iustin Pop's avatar
Iustin Pop committed
257
  OP_ID = "OP_INSTANCE_REBOOT"
258
259
260
261
  __slots__ = ["instance_name", "reboot_type", "extra_args",
               "ignore_secondaries" ]


Iustin Pop's avatar
Iustin Pop committed
262
class OpReplaceDisks(OpCode):
Iustin Pop's avatar
Iustin Pop committed
263
  """Replace the disks of an instance."""
Iustin Pop's avatar
Iustin Pop committed
264
  OP_ID = "OP_INSTANCE_REPLACE_DISKS"
265
  __slots__ = ["instance_name", "remote_node", "mode", "disks", "iallocator"]
Iustin Pop's avatar
Iustin Pop committed
266
267
268
269
270
271
272
273
274


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


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


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


class OpDeactivateInstanceDisks(OpCode):
Iustin Pop's avatar
Iustin Pop committed
287
  """Deactivate an instance's disks."""
Iustin Pop's avatar
Iustin Pop committed
288
289
290
291
292
293
294
  OP_ID = "OP_INSTANCE_DEACTIVATE_DISKS"
  __slots__ = ["instance_name"]


class OpQueryInstances(OpCode):
  """Compute the list of instances."""
  OP_ID = "OP_INSTANCE_QUERY"
295
  __slots__ = ["output_fields", "names"]
Iustin Pop's avatar
Iustin Pop committed
296
297
298
299
300
301
302
303


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


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


Iustin Pop's avatar
Iustin Pop committed
314
315
316
317
318
319
class OpGrowDisk(OpCode):
  """Grow a disk of an instance."""
  OP_ID = "OP_INSTANCE_GROW_DISK"
  __slots__ = ["instance_name", "disk", "amount"]


Iustin Pop's avatar
Iustin Pop committed
320
321
322
323
# OS opcodes
class OpDiagnoseOS(OpCode):
  """Compute the list of guest operating systems."""
  OP_ID = "OP_OS_DIAGNOSE"
324
  __slots__ = ["output_fields", "names"]
Iustin Pop's avatar
Iustin Pop committed
325

326

Iustin Pop's avatar
Iustin Pop committed
327
328
329
330
331
332
# Exports opcodes
class OpQueryExports(OpCode):
  """Compute the list of exported images."""
  OP_ID = "OP_BACKUP_QUERY"
  __slots__ = ["nodes"]

333

Iustin Pop's avatar
Iustin Pop committed
334
335
336
337
class OpExportInstance(OpCode):
  """Export an instance."""
  OP_ID = "OP_BACKUP_EXPORT"
  __slots__ = ["instance_name", "target_node", "shutdown"]
338

339
340
341
342
class OpRemoveExport(OpCode):
  """Remove an instance's export."""
  OP_ID = "OP_BACKUP_REMOVE"
  __slots__ = ["instance_name"]
343
344
345
346
347
348
349
350

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


Iustin Pop's avatar
Iustin Pop committed
351
352
353
354
355
356
class OpSearchTags(OpCode):
  """Searches the tags in the cluster for a given pattern."""
  OP_ID = "OP_TAGS_SEARCH"
  __slots__ = ["pattern"]


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


363
364
class OpDelTags(OpCode):
  """Remove a list of tags from a given object."""
365
  OP_ID = "OP_TAGS_DEL"
366
  __slots__ = ["kind", "name", "tags"]
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392


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

  This is used just for debugging and testing.

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

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

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

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

  """
  OP_ID = "OP_TEST_DELAY"
  __slots__ = ["duration", "on_master", "on_nodes"]
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411


class OpTestAllocator(OpCode):
  """Allocator framework testing.

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

  """
  OP_ID = "OP_TEST_ALLOCATOR"
  __slots__ = [
    "direction", "mode", "allocator", "name",
    "mem_size", "disks", "disk_template",
    "os", "tags", "nics", "vcpus",
    ]