Revision 6b93ec9d

b/daemons/ganeti-noded
232 232
    disks = [objects.Disk.FromDict(cf) for cf in params[1]]
233 233
    return backend.CloseBlockDevices(params[0], disks)
234 234

  
235
  # blockdev/drbd specific methods ----------
236

  
237
  @staticmethod
238
  def perspective_drbd_disconnect_net(params):
239
    """Disconnects the network connection of drbd disks.
240

  
241
    Note that this is only valid for drbd disks, so the members of the
242
    disk list must all be drbd devices.
243

  
244
    """
245
    nodes_ip, disks = params
246
    disks = [objects.Disk.FromDict(cf) for cf in disks]
247
    return backend.DrbdDisconnectNet(nodes_ip, disks)
248

  
249
  @staticmethod
250
  def perspective_drbd_attach_net(params):
251
    """Attaches the network connection of drbd disks.
252

  
253
    Note that this is only valid for drbd disks, so the members of the
254
    disk list must all be drbd devices.
255

  
256
    """
257
    nodes_ip, disks, instance_name, multimaster = params
258
    disks = [objects.Disk.FromDict(cf) for cf in disks]
259
    return backend.DrbdAttachNet(nodes_ip, disks, instance_name, multimaster)
260

  
261
  @staticmethod
262
  def perspective_drbd_wait_sync(params):
263
    """Wait until DRBD disks are synched.
264

  
265
    Note that this is only valid for drbd disks, so the members of the
266
    disk list must all be drbd devices.
267

  
268
    """
269
    nodes_ip, disks = params
270
    disks = [objects.Disk.FromDict(cf) for cf in disks]
271
    return backend.DrbdWaitSync(nodes_ip, disks)
272

  
235 273
  # export/import  --------------------------
236 274

  
237 275
  @staticmethod
b/lib/backend.py
2177 2177
  return (True, "Done")
2178 2178

  
2179 2179

  
2180
def _FindDisks(nodes_ip, disks):
2181
  """Sets the physical ID on disks and returns the block devices.
2182

  
2183
  """
2184
  # set the correct physical ID
2185
  my_name = utils.HostInfo().name
2186
  for cf in disks:
2187
    cf.SetPhysicalID(my_name, nodes_ip)
2188

  
2189
  bdevs = []
2190

  
2191
  for cf in disks:
2192
    rd = _RecursiveFindBD(cf)
2193
    if rd is None:
2194
      return (False, "Can't find device %s" % cf)
2195
    bdevs.append(rd)
2196
  return (True, bdevs)
2197

  
2198

  
2199
def DrbdDisconnectNet(nodes_ip, disks):
2200
  """Disconnects the network on a list of drbd devices.
2201

  
2202
  """
2203
  status, bdevs = _FindDisks(nodes_ip, disks)
2204
  if not status:
2205
    return status, bdevs
2206

  
2207
  # disconnect disks
2208
  for rd in bdevs:
2209
    try:
2210
      rd.DisconnectNet()
2211
    except errors.BlockDeviceError, err:
2212
      logging.exception("Failed to go into standalone mode")
2213
      return (False, "Can't change network configuration: %s" % str(err))
2214
  return (True, "All disks are now disconnected")
2215

  
2216

  
2217
def DrbdAttachNet(nodes_ip, disks, instance_name, multimaster):
2218
  """Attaches the network on a list of drbd devices.
2219

  
2220
  """
2221
  status, bdevs = _FindDisks(nodes_ip, disks)
2222
  if not status:
2223
    return status, bdevs
2224

  
2225
  if multimaster:
2226
    for cf, rd in zip(disks, bdevs):
2227
      try:
2228
        _SymlinkBlockDev(instance_name, rd.dev_path, cf.iv_name)
2229
      except EnvironmentError, err:
2230
        return (False, "Can't create symlink: %s" % str(err))
2231
  # reconnect disks, switch to new master configuration and if
2232
  # needed primary mode
2233
  for rd in bdevs:
2234
    try:
2235
      rd.AttachNet(multimaster)
2236
    except errors.BlockDeviceError, err:
2237
      return (False, "Can't change network configuration: %s" % str(err))
2238
  # wait until the disks are connected; we need to retry the re-attach
2239
  # if the device becomes standalone, as this might happen if the one
2240
  # node disconnects and reconnects in a different mode before the
2241
  # other node reconnects; in this case, one or both of the nodes will
2242
  # decide it has wrong configuration and switch to standalone
2243
  RECONNECT_TIMEOUT = 2 * 60
2244
  sleep_time = 0.100 # start with 100 miliseconds
2245
  timeout_limit = time.time() + RECONNECT_TIMEOUT
2246
  while time.time() < timeout_limit:
2247
    all_connected = True
2248
    for rd in bdevs:
2249
      stats = rd.GetProcStatus()
2250
      if not (stats.is_connected or stats.is_in_resync):
2251
        all_connected = False
2252
      if stats.is_standalone:
2253
        # peer had different config info and this node became
2254
        # standalone, even though this should not happen with the
2255
        # new staged way of changing disk configs
2256
        try:
2257
          rd.ReAttachNet(multimaster)
2258
        except errors.BlockDeviceError, err:
2259
          return (False, "Can't change network configuration: %s" % str(err))
2260
    if all_connected:
2261
      break
2262
    time.sleep(sleep_time)
2263
    sleep_time = min(5, sleep_time * 1.5)
2264
  if not all_connected:
2265
    return (False, "Timeout in disk reconnecting")
2266
  if multimaster:
2267
    # change to primary mode
2268
    for rd in bdevs:
2269
      rd.Open()
2270
  if multimaster:
2271
    msg = "multi-master and primary"
2272
  else:
2273
    msg = "single-master"
2274
  return (True, "Disks are now configured as %s" % msg)
2275

  
2276

  
2277
def DrbdWaitSync(nodes_ip, disks):
2278
  """Wait until DRBDs have synchronized.
2279

  
2280
  """
2281
  status, bdevs = _FindDisks(nodes_ip, disks)
2282
  if not status:
2283
    return status, bdevs
2284

  
2285
  min_resync = 100
2286
  alldone = True
2287
  failure = False
2288
  for rd in bdevs:
2289
    stats = rd.GetProcStatus()
2290
    if not (stats.is_connected or stats.is_in_resync):
2291
      failure = True
2292
      break
2293
    alldone = alldone and (not stats.is_in_resync)
2294
    if stats.sync_percent is not None:
2295
      min_resync = min(min_resync, stats.sync_percent)
2296
  return (not failure, (alldone, min_resync))
2297

  
2298

  
2180 2299
class HooksRunner(object):
2181 2300
  """Hook runner.
2182 2301

  
b/lib/bdev.py
567 567
    self.is_diskless = self.ldisk == "Diskless"
568 568
    self.is_disk_uptodate = self.ldisk == "UpToDate"
569 569

  
570
    self.is_in_resync = self.cstatus in ('SyncSource', 'SyncTarget')
571

  
570 572
    m = self.SYNC_RE.match(procline)
571 573
    if m:
572 574
      self.sync_percent = float(m.group(1))
b/lib/rpc.py
736 736
    params = [instance_name, [cf.ToDict() for cf in disks]]
737 737
    return self._SingleNodeCall(node, "blockdev_close", params)
738 738

  
739
  def call_drbd_disconnect_net(self, node_list, nodes_ip, disks):
740
    """Disconnects the network of the given drbd devices.
741

  
742
    This is a multi-node call.
743

  
744
    """
745
    return self._MultiNodeCall(node_list, "drbd_disconnect_net",
746
                               [nodes_ip, [cf.ToDict() for cf in disks]])
747

  
748
  def call_drbd_attach_net(self, node_list, nodes_ip,
749
                           disks, instance_name, multimaster):
750
    """Disconnects the given drbd devices.
751

  
752
    This is a multi-node call.
753

  
754
    """
755
    return self._MultiNodeCall(node_list, "drbd_attach_net",
756
                               [nodes_ip, [cf.ToDict() for cf in disks],
757
                                instance_name, multimaster])
758

  
759
  def call_drbd_wait_sync(self, node_list, nodes_ip, disks):
760
    """Waits for the synchronization of drbd devices is complete.
761

  
762
    This is a multi-node call.
763

  
764
    """
765
    return self._MultiNodeCall(node_list, "drbd_wait_sync",
766
                               [nodes_ip, [cf.ToDict() for cf in disks]])
767

  
739 768
  @classmethod
740 769
  def call_upload_file(cls, node_list, file_name, address_list=None):
741 770
    """Upload a file.

Also available in: Unified diff