Source code for mcvirt.node.drbd

"""Provides interface to mange the DRBD installation."""

# Copyright (c) 2014 - I.T. Dev Ltd
#
# This file is part of MCVirt.
#
# MCVirt 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.
#
# MCVirt 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 MCVirt.  If not, see <http://www.gnu.org/licenses/>

from Cheetah.Template import Template
import os
from texttable import Texttable
import Pyro4
import random
import string

from mcvirt.exceptions import DrbdNotInstalledException, DrbdAlreadyEnabled
from mcvirt.mcvirt_config import MCVirtConfig
from mcvirt.system import System
from mcvirt.auth.permissions import PERMISSIONS
from mcvirt.rpc.pyro_object import PyroObject
from mcvirt.rpc.lock import locking_method
from mcvirt.utils import get_hostname
from mcvirt.constants import DirectoryLocation


[docs]class Drbd(PyroObject): """Performs configuration of DRBD on the node""" CONFIG_DIRECTORY = '/etc/drbd.d' GLOBAL_CONFIG = CONFIG_DIRECTORY + '/global_common.conf' GLOBAL_CONFIG_TEMPLATE = DirectoryLocation.TEMPLATE_DIR + '/drbd_global.conf' DrbdADM = '/sbin/drbdadm' CLUSTER_SIZE = 2 @Pyro4.expose()
[docs] def is_enabled(self): """Determine whether Drbd is enabled on the node or not""" return self.get_config()['enabled']
@Pyro4.expose()
[docs] def is_installed(self): """Determine if the 'drbdadm' command is present to determine if the 'drbd8-utils' package is installed """ return os.path.isfile(self.DrbdADM)
[docs] def ensure_installed(self): """Ensure that Drbd is installed on the node""" if not self.is_installed(): raise DrbdNotInstalledException('drbdadm not found' + ' (Is the drbd8-utils package installed?)')
@Pyro4.expose() @locking_method() def enable(self, secret=None): """Ensure the machine is suitable to run Drbd""" # Ensure user has the ability to manage Drbd self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_DRBD) # Ensure that Drbd is installed self.ensure_installed() if self.is_enabled() and self._is_cluster_master: raise DrbdAlreadyEnabled('Drbd has already been enabled on this node') if secret is None: secret = self.generate_secret() # Set the secret in the local configuration self.set_secret(secret) if self._is_cluster_master: # Enable Drbd on the remote nodes cluster = self._get_registered_object('cluster') def remote_command(node): remote_drbd = node.get_connection('node_drbd') remote_drbd.enable(secret=secret) cluster.run_remote_command(callback_method=remote_command) # Generate the global Drbd configuration self.generate_config() # Update the local configuration def update_config(config): config['drbd']['enabled'] = 1 MCVirtConfig().update_config(update_config, 'Enabled Drbd')
[docs] def get_config(self): """Return the global Drbd configuration""" mcvirt_config = MCVirtConfig() if 'drbd' in mcvirt_config.get_config().keys(): return mcvirt_config.get_config()['drbd'] else: return self.get_default_config()
@staticmethod
[docs] def get_default_config(): """Return the default configuration for DRBD""" default_config = \ { 'enabled': 0, 'secret': '', 'sync_rate': '10M', 'protocol': 'C' } return default_config
[docs] def generate_config(self): """Generate the Drbd configuration""" # Obtain the MCVirt Drbd config drbd_config = self.get_config() # Replace the variables in the template with the local Drbd configuration config_content = Template(file=self.GLOBAL_CONFIG_TEMPLATE, searchList=[drbd_config]) # Write the Drbd configuration fh = open(self.GLOBAL_CONFIG, 'w') fh.write(config_content.respond()) fh.close() # Update Drbd running configuration self.adjust_drbd_config()
[docs] def generate_secret(self): """Generate a random secret for Drbd""" return ''.join([random.choice(string.ascii_letters + string.digits) for _ in xrange(16)])
[docs] def set_secret(self, secret): """Set the Drbd configuration in the global MCVirt config file""" def update_config(config): config['drbd']['secret'] = secret MCVirtConfig().update_config(update_config, 'Set Drbd secret')
[docs] def adjust_drbd_config(self, resource='all'): """Perform a Drbd adjust, which updates the Drbd running configuration""" if (len(self.get_all_drbd_hard_drive_object())): System.runCommand([Drbd.DrbdADM, 'adjust', resource])
[docs] def get_all_drbd_hard_drive_object(self, include_remote=False): """Obtain all hard drive objects that are backed by DRBD""" hard_drive_objects = [] vm_factory = self._get_registered_object('virtual_machine_factory') for vm_object in vm_factory.getAllVirtualMachines(): if (get_hostname() in vm_object.getAvailableNodes() or include_remote): all_hard_drive_objects = vm_object.getHardDriveObjects() for hard_drive_object in all_hard_drive_objects: if (hard_drive_object.get_type() is 'Drbd'): hard_drive_objects.append(hard_drive_object) return hard_drive_objects
[docs] def get_used_drbd_ports(self): """Return a list of used Drbd ports""" return [hdd.drbd_port for hdd in self.get_all_drbd_hard_drive_object(include_remote=True)]
[docs] def get_used_drbd_minors(self): """Return a list of used Drbd minor IDs""" return [hdd.drbd_minor for hdd in self.get_all_drbd_hard_drive_object(include_remote=True)]
@Pyro4.expose()
[docs] def list(self): """List the Drbd volumes and statuses""" # Create table and add headers table = Texttable() table.set_deco(Texttable.HEADER | Texttable.VLINES) table.header(('Volume Name', 'VM', 'Minor', 'Port', 'Role', 'Connection State', 'Disk State', 'Sync Status')) # Set column alignment and widths table.set_cols_width((30, 20, 5, 5, 20, 20, 20, 13)) table.set_cols_align(('l', 'l', 'c', 'c', 'l', 'c', 'l', 'c')) # Iterate over Drbd objects, adding to the table for drbd_object in self.get_all_drbd_hard_drive_object(True): table.add_row((drbd_object.resource_name, drbd_object.vm_object.get_name(), drbd_object.drbd_minor, drbd_object.drbd_port, 'Local: %s, Remote: %s' % (drbd_object._drbdGetRole()[0].name, drbd_object._drbdGetRole()[1].name), drbd_object._drbdGetConnectionState().name, 'Local: %s, Remote: %s' % (drbd_object._drbdGetDiskState()[0].name, drbd_object._drbdGetDiskState()[1].name), 'In Sync' if drbd_object._isInSync() else 'Out of Sync')) return table.draw()