| # Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved. |
| # |
| # This copyrighted material is made available to anyone wishing to use, |
| # modify, copy, or redistribute it subject to the terms and conditions |
| # of the GNU General Public License v.2. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
| from .automatedproperties import AutomatedProperties |
| |
| from . import utils |
| from .cfg import MANAGER_INTERFACE |
| import dbus |
| from . import cfg |
| from . import cmdhandler |
| from .fetch import load_pvs, load_vgs |
| from .request import RequestEntry |
| from .refresh import event_add |
| |
| |
| # noinspection PyPep8Naming |
| class Manager(AutomatedProperties): |
| _Version_meta = ("t", MANAGER_INTERFACE) |
| |
| def __init__(self, object_path): |
| super(Manager, self).__init__(object_path) |
| self.set_interface(MANAGER_INTERFACE) |
| |
| @property |
| def Version(self): |
| return '1.0.0' |
| |
| @staticmethod |
| def _pv_create(device, create_options): |
| |
| # Check to see if we are already trying to create a PV for an existing |
| # PV |
| pv = cfg.om.get_object_path_by_uuid_lvm_id( |
| device, device, None, False) |
| if pv: |
| raise dbus.exceptions.DBusException( |
| MANAGER_INTERFACE, "PV Already exists!") |
| |
| created_pv = [] |
| rc, out, err = cmdhandler.pv_create(create_options, [device]) |
| if rc == 0: |
| pvs = load_pvs([device], emit_signal=True)[0] |
| for p in pvs: |
| created_pv = p.dbus_object_path() |
| else: |
| raise dbus.exceptions.DBusException( |
| MANAGER_INTERFACE, |
| 'Exit code %s, stderr = %s' % (str(rc), err)) |
| |
| return created_pv |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='sia{sv}', |
| out_signature='(oo)', |
| async_callbacks=('cb', 'cbe')) |
| def PvCreate(self, device, tmo, create_options, cb, cbe): |
| utils.validate_device_path(MANAGER_INTERFACE, device) |
| r = RequestEntry( |
| tmo, Manager._pv_create, |
| (device, create_options), cb, cbe) |
| cfg.worker_q.put(r) |
| |
| @staticmethod |
| def _create_vg(name, pv_object_paths, create_options): |
| pv_devices = [] |
| |
| for p in pv_object_paths: |
| pv = cfg.om.get_object_by_path(p) |
| if pv: |
| pv_devices.append(pv.Name) |
| else: |
| raise dbus.exceptions.DBusException( |
| MANAGER_INTERFACE, 'object path = %s not found' % p) |
| |
| rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name) |
| created_vg = "/" |
| |
| if rc == 0: |
| vgs = load_vgs([name], emit_signal=True)[0] |
| for v in vgs: |
| created_vg = v.dbus_object_path() |
| |
| # Update the PVS |
| load_pvs(refresh=True, emit_signal=True, cache_refresh=False) |
| else: |
| raise dbus.exceptions.DBusException( |
| MANAGER_INTERFACE, |
| 'Exit code %s, stderr = %s' % (str(rc), err)) |
| return created_vg |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='saoia{sv}', |
| out_signature='(oo)', |
| async_callbacks=('cb', 'cbe')) |
| def VgCreate(self, name, pv_object_paths, tmo, create_options, cb, cbe): |
| utils.validate_vg_name(MANAGER_INTERFACE, name) |
| r = RequestEntry( |
| tmo, Manager._create_vg, |
| (name, pv_object_paths, create_options,), |
| cb, cbe) |
| cfg.worker_q.put(r) |
| |
| @staticmethod |
| def _refresh(): |
| utils.log_debug('Manager.Refresh - entry') |
| |
| # This is a diagnostic and should not be run in normal operation, so |
| # lets remove the log entries for refresh as it's implied. |
| rc = cfg.load(log=False) |
| |
| if rc != 0: |
| utils.log_debug('Manager.Refresh - exit %d' % (rc), |
| 'bg_black', 'fg_light_red') |
| else: |
| utils.log_debug('Manager.Refresh - exit %d' % (rc)) |
| return rc |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| out_signature='t', |
| async_callbacks=('cb', 'cbe')) |
| def Refresh(self, cb, cbe): |
| """ |
| Take all the objects we know about and go out and grab the latest |
| more of a test method at the moment to make sure we are handling object |
| paths correctly. |
| |
| :param cb Callback for result |
| :param cbe Callback for errors |
| |
| Returns the number of changes, object add/remove/properties changed |
| """ |
| r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False) |
| cfg.worker_q.put(r) |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='s', |
| out_signature='o') |
| def LookUpByLvmId(self, key): |
| """ |
| Given a lvm id in one of the forms: |
| |
| /dev/sda |
| some_vg |
| some_vg/some_lv |
| Oe1rPX-Pf0W-15E5-n41N-ZmtF-jXS0-Osg8fn |
| |
| return the object path in O(1) time. |
| |
| :param key: The lookup value |
| :return: Return the object path. If object not found you will get '/' |
| """ |
| p = cfg.om.get_object_path_by_uuid_lvm_id( |
| key, key, gen_new=False) |
| if p: |
| return p |
| return '/' |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='b') |
| def UseLvmShell(self, yes_no): |
| """ |
| Allow the client to enable/disable lvm shell, used for testing |
| :param yes_no: |
| :return: Nothing |
| """ |
| cmdhandler.set_execution(yes_no) |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='s', out_signature='i') |
| def ExternalEvent(self, command): |
| |
| event_add((command,)) |
| return dbus.Int32(0) |
| |
| @staticmethod |
| def _pv_scan(activate, cache, device_path, major_minor, scan_options): |
| |
| rc, out, err = cmdhandler.pv_scan( |
| activate, cache, device_path, |
| major_minor, scan_options) |
| |
| if rc == 0: |
| # This could potentially change the state quite a bit, so lets |
| # update everything to be safe |
| cfg.load() |
| return '/' |
| else: |
| raise dbus.exceptions.DBusException( |
| MANAGER_INTERFACE, |
| 'Exit code %s, stderr = %s' % (str(rc), err)) |
| |
| @dbus.service.method( |
| dbus_interface=MANAGER_INTERFACE, |
| in_signature='bbasa(ii)ia{sv}', |
| out_signature='o', |
| async_callbacks=('cb', 'cbe')) |
| def PvScan(self, activate, cache, device_paths, major_minors, |
| tmo, scan_options, cb, cbe): |
| """ |
| Scan all supported LVM block devices in the system for physical volumes |
| NOTE: major_minors & device_paths only usable when cache == True |
| :param activate: If True, activate any newly found LVs |
| :param cache: If True, update lvmetad |
| :param device_paths: Array of device paths or empty |
| :param major_minors: Array of structures (major,minor) |
| :param tmo: Timeout for operation |
| :param scan_options: Additional options to pvscan |
| :param cb: Not visible in API (used for async. callback) |
| :param cbe: Not visible in API (used for async. error callback) |
| :return: '/' if operation done, else job path |
| """ |
| for d in device_paths: |
| utils.validate_device_path(MANAGER_INTERFACE, d) |
| |
| r = RequestEntry( |
| tmo, Manager._pv_scan, |
| (activate, cache, device_paths, major_minors, |
| scan_options), cb, cbe, False) |
| cfg.worker_q.put(r) |
| |
| @property |
| def lvm_id(self): |
| """ |
| Intended to be overridden by classes that inherit |
| """ |
| return str(id(self)) |
| |
| @property |
| def Uuid(self): |
| """ |
| Intended to be overridden by classes that inherit |
| """ |
| import uuid |
| return uuid.uuid1() |