Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
678
utils/opencas.py
Normal file
678
utils/opencas.py
Normal file
@@ -0,0 +1,678 @@
|
||||
#!/usr/bin/env python2
|
||||
#
|
||||
# Copyright(c) 2012-2019 Intel Corporation
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
import subprocess
|
||||
import csv
|
||||
import re
|
||||
import os
|
||||
import stat
|
||||
|
||||
# Casadm functionality
|
||||
|
||||
|
||||
class casadm:
|
||||
casadm_path = '/sbin/casadm'
|
||||
|
||||
class result:
|
||||
def __init__(self, cmd):
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
self.exit_code = p.wait()
|
||||
output = p.communicate()
|
||||
self.stdout = output[0]
|
||||
self.stderr = output[1]
|
||||
|
||||
class CasadmError(Exception):
|
||||
def __init__(self, result):
|
||||
super(casadm.CasadmError, self).__init__('casadm error')
|
||||
self.result = result
|
||||
|
||||
@classmethod
|
||||
def run_cmd(cls, cmd):
|
||||
result = cls.result(cmd)
|
||||
if result.exit_code != 0:
|
||||
raise cls.CasadmError(result)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_version(cls):
|
||||
cmd = [cls.casadm_path,
|
||||
'--version',
|
||||
'--output-format', 'csv']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def list_caches(cls):
|
||||
cmd = [cls.casadm_path,
|
||||
'--list-caches',
|
||||
'--output-format', 'csv']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def check_cache_device(cls, device):
|
||||
cmd = [cls.casadm_path,
|
||||
'--script',
|
||||
'--check-cache-device',
|
||||
'--cache-device', device]
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def start_cache(cls, device, cache_id=None, cache_mode=None,
|
||||
cache_line_size=None, load=False, force=False):
|
||||
cmd = [cls.casadm_path,
|
||||
'--start-cache',
|
||||
'--cache-device', device]
|
||||
if cache_id:
|
||||
cmd += ['--cache-id', str(cache_id)]
|
||||
if cache_mode:
|
||||
cmd += ['--cache-mode', cache_mode]
|
||||
if cache_line_size:
|
||||
cmd += ['--cache-line-size', str(cache_line_size)]
|
||||
if load:
|
||||
cmd += ['--load']
|
||||
if force:
|
||||
cmd += ['--force']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def add_core(cls, device, cache_id, core_id=None, try_add=False):
|
||||
cmd = [cls.casadm_path,
|
||||
'--script',
|
||||
'--add-core',
|
||||
'--core-device', device,
|
||||
'--cache-id', str(cache_id)]
|
||||
if core_id is not None:
|
||||
cmd += ['--core-id', str(core_id)]
|
||||
if try_add:
|
||||
cmd += ['--try-add']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def stop_cache(cls, cache_id, no_flush=False):
|
||||
cmd = [cls.casadm_path,
|
||||
'--stop-cache',
|
||||
'--cache-id', str(cache_id)]
|
||||
if no_flush:
|
||||
cmd += ['--no-data-flush']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def remove_core(cls, cache_id, core_id, detach=False, force=False):
|
||||
cmd = [cls.casadm_path,
|
||||
'--script',
|
||||
'--remove-core',
|
||||
'--cache-id', str(cache_id),
|
||||
'--core-id', str(core_id)]
|
||||
if detach:
|
||||
cmd += ['--detach']
|
||||
if force:
|
||||
cmd += ['--no-flush']
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def set_param(cls, namespace, cache_id, **kwargs):
|
||||
cmd = [cls.casadm_path,
|
||||
'--set-param', '--name', namespace,
|
||||
'--cache-id', str(cache_id)]
|
||||
|
||||
for param, value in kwargs.items():
|
||||
cmd += ['--'+param.replace('_', '-'), str(value)]
|
||||
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def get_params(cls, namespace, cache_id, **kwargs):
|
||||
cmd = [cls.casadm_path,
|
||||
'--get-param', '--name', namespace,
|
||||
'--cache-id', str(cache_id)]
|
||||
|
||||
for param, value in kwargs.items():
|
||||
cmd += ['--'+param.replace('_', '-'), str(value)]
|
||||
|
||||
cmd += ['-o', 'csv']
|
||||
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def flush_parameters(cls, cache_id, policy_type):
|
||||
cmd = [cls.casadm_path,
|
||||
'--flush-parameters',
|
||||
'--cache-id', str(cache_id),
|
||||
'--cleaning-policy-type', policy_type]
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def io_class_load_config(cls, cache_id, ioclass_file):
|
||||
cmd = [cls.casadm_path,
|
||||
'--io-class',
|
||||
'--load-config',
|
||||
'--cache-id', str(cache_id),
|
||||
'--file', ioclass_file]
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
# Configuration file parser
|
||||
|
||||
|
||||
class cas_config(object):
|
||||
default_location = '/etc/opencas/opencas.conf'
|
||||
|
||||
class ConflictingConfigException(ValueError):
|
||||
pass
|
||||
|
||||
class AlreadyConfiguredException(ValueError):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_by_id_path(path):
|
||||
for id_path in os.listdir('/dev/disk/by-id'):
|
||||
full_path = '/dev/disk/by-id/{0}'.format(id_path)
|
||||
if os.path.realpath(full_path) == os.path.realpath(path):
|
||||
return full_path
|
||||
|
||||
raise ValueError('By-id device link not found for {0}'.format(path))
|
||||
|
||||
@staticmethod
|
||||
def check_block_device(path):
|
||||
if not os.path.exists(path) and path.startswith('/dev/cas'):
|
||||
return
|
||||
|
||||
try:
|
||||
mode = os.stat(path).st_mode
|
||||
except:
|
||||
raise ValueError('{0} not found'.format(path))
|
||||
|
||||
if not stat.S_ISBLK(mode):
|
||||
raise ValueError('{0} is not block device'.format(path))
|
||||
|
||||
class cache_config(object):
|
||||
def __init__(self, cache_id, device, cache_mode, **params):
|
||||
self.cache_id = int(cache_id)
|
||||
self.device = device
|
||||
self.cache_mode = cache_mode
|
||||
self.params = params
|
||||
self.cores = dict()
|
||||
|
||||
@classmethod
|
||||
def from_line(cls, line, allow_incomplete=False):
|
||||
values = line.split()
|
||||
if len(values) < 3:
|
||||
raise ValueError('Invalid cache configuration (too few columns)')
|
||||
elif len(values) > 4:
|
||||
raise ValueError('Invalid cache configuration (too many columns)')
|
||||
|
||||
cache_id = int(values[0])
|
||||
device = values[1]
|
||||
cache_mode = values[2].lower()
|
||||
|
||||
params = dict()
|
||||
if len(values) > 3:
|
||||
for param in values[3].split(','):
|
||||
param_name, param_value = param.split('=')
|
||||
if param_name in params:
|
||||
raise ValueError('Invalid cache configuration (repeated parameter')
|
||||
params[param_name] = param_value
|
||||
|
||||
cache_config = cls(cache_id, device, cache_mode, **params)
|
||||
cache_config.validate_config(False, allow_incomplete)
|
||||
|
||||
return cache_config
|
||||
|
||||
def validate_config(self, force, allow_incomplete=False):
|
||||
type(self).check_cache_id_valid(self.cache_id)
|
||||
self.check_recursive()
|
||||
self.check_cache_mode_valid(self.cache_mode)
|
||||
for param_name, param_value in self.params.iteritems():
|
||||
self.validate_parameter(param_name, param_value)
|
||||
|
||||
if not allow_incomplete:
|
||||
cas_config.check_block_device(self.device)
|
||||
if not force:
|
||||
self.check_cache_device_empty()
|
||||
|
||||
def validate_parameter(self, param_name, param_value):
|
||||
if param_name == 'ioclass_file':
|
||||
if not os.path.exists(param_value):
|
||||
raise ValueError('Incorrect path to io_class file')
|
||||
elif param_name == 'cleaning_policy':
|
||||
self.check_cleaning_policy_valid(param_value)
|
||||
elif param_name == 'cache_line_size':
|
||||
self.check_cache_line_size_valid(param_value)
|
||||
else:
|
||||
raise ValueError('{0} is unknown parameter name'.format(param_name))
|
||||
|
||||
@staticmethod
|
||||
def check_cache_id_valid(cache_id):
|
||||
if not 1 <= int(cache_id) <= 16384:
|
||||
raise ValueError('{0} is invalid cache id'.format(cache_id))
|
||||
|
||||
def check_cache_device_empty(self):
|
||||
try:
|
||||
result = casadm.run_cmd(['lsblk', '-o', 'NAME', '-l', '-n', self.device])
|
||||
except:
|
||||
# lsblk returns non-0 if it can't probe for partitions
|
||||
# this means that we're probably dealing with atomic device
|
||||
# let it through
|
||||
return
|
||||
|
||||
if len(list(filter(lambda a: a != '', result.stdout.split('\n')))) > 1:
|
||||
raise ValueError(
|
||||
'Partitions found on device {0}. Use force option to ignore'.
|
||||
format(self.device))
|
||||
|
||||
def check_cache_mode_valid(self, cache_mode):
|
||||
if cache_mode.lower() not in ['wt', 'pt', 'wa', 'wb']:
|
||||
raise ValueError('Invalid cache mode {0}'.format(cache_mode))
|
||||
|
||||
def check_cleaning_policy_valid(self, cleaning_policy):
|
||||
if cleaning_policy.lower() not in ['acp', 'alru', 'nop']:
|
||||
raise ValueError('{0} is invalid cleaning policy name'.format(
|
||||
cleaning_policy))
|
||||
|
||||
def check_cache_line_size_valid(self, cache_line_size):
|
||||
if cache_line_size not in ['4', '8', '16', '32', '64']:
|
||||
raise ValueError('{0} is invalid cache line size'.format(
|
||||
cache_line_size))
|
||||
|
||||
def check_recursive(self):
|
||||
if not self.device.startswith('/dev/cas'):
|
||||
return
|
||||
|
||||
ids = self.device.split('/dev/cas')[1]
|
||||
device_cache_id, _ = ids.split('-')
|
||||
|
||||
if int(device_cache_id) == self.cache_id:
|
||||
raise ValueError('Recursive configuration detected')
|
||||
|
||||
def to_line(self):
|
||||
ret = '{0}\t{1}\t{2}'.format(self.cache_id, self.device, self.cache_mode)
|
||||
if len(self.params) > 0:
|
||||
i = 0
|
||||
for param, value in self.params.iteritems():
|
||||
if i > 0:
|
||||
ret += ','
|
||||
else:
|
||||
ret += '\t'
|
||||
|
||||
ret += '{0}={1}'.format(param, value)
|
||||
i += 1
|
||||
ret += '\n'
|
||||
|
||||
return ret
|
||||
|
||||
class core_config(object):
|
||||
def __init__(self, cache_id, core_id, path):
|
||||
self.cache_id = int(cache_id)
|
||||
self.core_id = int(core_id)
|
||||
self.device = path
|
||||
|
||||
@classmethod
|
||||
def from_line(cls, line, allow_incomplete=False):
|
||||
values = line.split()
|
||||
if len(values) > 3:
|
||||
raise ValueError('Invalid core configuration (too many columns)')
|
||||
elif len(values) < 3:
|
||||
raise ValueError('Invalid core configuration (too few columns)')
|
||||
|
||||
cache_id = int(values[0])
|
||||
core_id = int(values[1])
|
||||
device = values[2]
|
||||
|
||||
core_config = cls(cache_id, core_id, device)
|
||||
|
||||
core_config.validate_config(allow_incomplete)
|
||||
|
||||
return core_config
|
||||
|
||||
def validate_config(self, allow_incomplete=False):
|
||||
self.check_core_id_valid()
|
||||
self.check_recursive()
|
||||
cas_config.cache_config.check_cache_id_valid(self.cache_id)
|
||||
if not allow_incomplete:
|
||||
cas_config.check_block_device(self.device)
|
||||
|
||||
def check_core_id_valid(self):
|
||||
if not 0 <= int(self.core_id) <= 4095:
|
||||
raise ValueError('{0} is invalid core id'.format(self.core_id))
|
||||
|
||||
def check_recursive(self):
|
||||
if not self.device.startswith('/dev/cas'):
|
||||
return
|
||||
|
||||
ids = self.device.split('/dev/cas')[1]
|
||||
device_cache_id, _ = ids.split('-')
|
||||
|
||||
if int(device_cache_id) == self.cache_id:
|
||||
raise ValueError('Recursive configuration detected')
|
||||
|
||||
def to_line(self):
|
||||
return '{0}\t{1}\t{2}\n'.format(self.cache_id, self.core_id, self.device)
|
||||
|
||||
def __init__(self, caches=None, cores=None, version_tag=None):
|
||||
self.caches = caches if caches else dict()
|
||||
|
||||
self.cores = cores if cores else list()
|
||||
|
||||
self.version_tag = version_tag
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, config_file, allow_incomplete=False):
|
||||
section_caches = False
|
||||
section_cores = False
|
||||
|
||||
try:
|
||||
with open(config_file, 'r') as conf:
|
||||
version_tag = conf.readline()
|
||||
if not re.findall(r'^version=.*$', version_tag):
|
||||
raise ValueError('No version tag found!')
|
||||
|
||||
config = cls(version_tag=version_tag)
|
||||
|
||||
for line in conf:
|
||||
line = line.split('#')[0].rstrip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
if line == '[caches]':
|
||||
section_caches = True
|
||||
continue
|
||||
|
||||
if line == '[cores]':
|
||||
section_caches = False
|
||||
section_cores = True
|
||||
continue
|
||||
|
||||
if section_caches:
|
||||
cache = cas_config.cache_config.from_line(line, allow_incomplete)
|
||||
config.insert_cache(cache)
|
||||
elif section_cores:
|
||||
core = cas_config.core_config.from_line(line, allow_incomplete)
|
||||
config.insert_core(core)
|
||||
except ValueError:
|
||||
raise
|
||||
except IOError:
|
||||
raise Exception('Couldn\'t open config file')
|
||||
except:
|
||||
raise
|
||||
|
||||
return config
|
||||
|
||||
def insert_cache(self, new_cache_config):
|
||||
if new_cache_config.cache_id in self.caches:
|
||||
if (os.path.realpath(self.caches[new_cache_config.cache_id].device)
|
||||
!= os.path.realpath(new_cache_config.device)):
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'Other cache device configured under this id')
|
||||
else:
|
||||
raise cas_config.AlreadyConfiguredException(
|
||||
'Cache already configured')
|
||||
|
||||
for cache_id, cache in self.caches.iteritems():
|
||||
if cache_id != new_cache_config.cache_id:
|
||||
if (os.path.realpath(new_cache_config.device)
|
||||
== os.path.realpath(cache.device)):
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'This cache device is already configured as a cache')
|
||||
|
||||
for _, core in cache.cores.iteritems():
|
||||
if (os.path.realpath(core.device)
|
||||
== os.path.realpath(new_cache_config.device)):
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'This cache device is already configured as a core')
|
||||
|
||||
try:
|
||||
new_cache_config.device = cas_config.get_by_id_path(new_cache_config.device)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.caches[new_cache_config.cache_id] = new_cache_config
|
||||
|
||||
def insert_core(self, new_core_config):
|
||||
if new_core_config.cache_id not in self.caches:
|
||||
raise KeyError('Cache id {0} doesn\'t exist'.format(new_core_config.cache_id))
|
||||
|
||||
try:
|
||||
for cache_id, cache in self.caches.iteritems():
|
||||
if (os.path.realpath(cache.device)
|
||||
== os.path.realpath(new_core_config.device)):
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'Core device already configured as a cache')
|
||||
|
||||
for core_id, core in cache.cores.iteritems():
|
||||
if (cache_id == new_core_config.cache_id
|
||||
and core_id == new_core_config.core_id):
|
||||
if (os.path.realpath(core.device)
|
||||
== os.path.realpath(new_core_config.device)):
|
||||
raise cas_config.AlreadyConfiguredException(
|
||||
'Core already configured')
|
||||
else:
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'Other core device configured under this id')
|
||||
else:
|
||||
if (os.path.realpath(core.device)
|
||||
== os.path.realpath(new_core_config.device)):
|
||||
raise cas_config.ConflictingConfigException(
|
||||
'This core device is already configured as a core')
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
new_core_config.device = cas_config.get_by_id_path(new_core_config.device)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.caches[new_core_config.cache_id].cores[new_core_config.core_id] = new_core_config
|
||||
self.cores += [new_core_config]
|
||||
|
||||
def is_empty(self):
|
||||
if len(self.caches) > 0 or len(self.cores) > 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def write(self, config_file):
|
||||
try:
|
||||
with open(config_file, 'w') as conf:
|
||||
conf.write('{0}\n'.format(self.version_tag))
|
||||
conf.write('# This config was automatically generated\n')
|
||||
|
||||
conf.write('[caches]\n')
|
||||
for _, cache in self.caches.iteritems():
|
||||
conf.write(cache.to_line())
|
||||
|
||||
conf.write('\n[cores]\n')
|
||||
for core in self.cores:
|
||||
conf.write(core.to_line())
|
||||
|
||||
except:
|
||||
raise Exception('Couldn\'t write config file')
|
||||
|
||||
# Config helper functions
|
||||
|
||||
|
||||
def start_cache(cache, load, force=False):
|
||||
casadm.start_cache(
|
||||
device=cache.device,
|
||||
cache_id=cache.cache_id,
|
||||
cache_mode=cache.cache_mode,
|
||||
cache_line_size=cache.params.get('cache_line_size'),
|
||||
load=load,
|
||||
force=force)
|
||||
|
||||
def configure_cache(cache):
|
||||
if cache.params.has_key('cleaning_policy'):
|
||||
casadm.set_param('cleaning', cache_id=cache.cache_id,
|
||||
policy=cache.params['cleaning_policy'])
|
||||
if cache.params.has_key('ioclass_file'):
|
||||
casadm.io_class_load_config(cache_id=cache.cache_id,
|
||||
ioclass_file=cache.params['ioclass_file'])
|
||||
|
||||
def add_core(core, attach):
|
||||
casadm.add_core(
|
||||
device=core.device,
|
||||
cache_id=core.cache_id,
|
||||
core_id=core.core_id,
|
||||
try_add=attach)
|
||||
|
||||
# Another helper functions
|
||||
|
||||
def is_cache_started(cache_config):
|
||||
dev_list = get_caches_list()
|
||||
for dev in dev_list:
|
||||
if dev['type'] == 'cache' and int(dev['id']) == cache_config.cache_id:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_core_added(core_config):
|
||||
dev_list = get_caches_list()
|
||||
cache_id = 0
|
||||
for dev in dev_list:
|
||||
if dev['type'] == 'cache':
|
||||
cache_id = int(dev['id'])
|
||||
|
||||
if (dev['type'] == 'core' and
|
||||
cache_id == core_config.cache_id and
|
||||
int(dev['id']) == core_config.core_id):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_caches_list():
|
||||
result = casadm.list_caches()
|
||||
return list(csv.DictReader(result.stdout.split('\n')))
|
||||
|
||||
def check_cache_device(device):
|
||||
result = casadm.check_cache_device(device)
|
||||
return list(csv.DictReader(result.stdout.split('\n')))[0]
|
||||
|
||||
def get_cas_version():
|
||||
version = casadm.get_version()
|
||||
|
||||
ret = {}
|
||||
for line in version.stdout.split('\n')[1:]:
|
||||
try:
|
||||
component, version = line.split(',')
|
||||
except:
|
||||
continue
|
||||
ret[component] = version
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class CompoundException(Exception):
|
||||
def __init__(self):
|
||||
super(CompoundException, self).__init__()
|
||||
self.exception_list = list()
|
||||
|
||||
def __str__(self):
|
||||
s = "Multiple exceptions occured:\n" if len(self.exception_list) > 1 else ""
|
||||
|
||||
for e in self.exception_list:
|
||||
s += '{0}\n'.format(str(e))
|
||||
|
||||
return s
|
||||
|
||||
def add_exception(self, e):
|
||||
if type(e) is CompoundException:
|
||||
self.exception_list += e.exception_list
|
||||
else:
|
||||
self.exception_list += [e]
|
||||
|
||||
def is_empty(self):
|
||||
return len(self.exception_list) == 0
|
||||
|
||||
def raise_nonempty(self):
|
||||
if self.is_empty():
|
||||
return
|
||||
else:
|
||||
raise self
|
||||
|
||||
def detach_core_recursive(cache_id, core_id, flush):
|
||||
# Catching exceptions is left to uppermost caller of detach_core_recursive
|
||||
# as the immediate caller that made a recursive call depends on the callee
|
||||
# to remove core and thus release reference to lower level cache volume.
|
||||
l_cache_id = ''
|
||||
for dev in get_caches_list():
|
||||
if dev['type'] == 'cache':
|
||||
l_cache_id = dev['id']
|
||||
elif dev['type'] == 'core' and dev['status'] == 'Active':
|
||||
if '/dev/cas{0}-{1}'.format(cache_id, core_id) in dev['disk']:
|
||||
detach_core_recursive(l_cache_id, dev['id'], flush)
|
||||
elif l_cache_id == cache_id and dev['id'] == core_id and dev['status'] != 'Active':
|
||||
return
|
||||
|
||||
casadm.remove_core(cache_id, core_id, detach = True, force = not flush)
|
||||
|
||||
def detach_all_cores(flush):
|
||||
error = CompoundException()
|
||||
|
||||
try:
|
||||
dev_list = get_caches_list()
|
||||
except casadm.CasadmError as e:
|
||||
raise Exception('Unable to list caches. Reason:\n{0}'.format(
|
||||
e.result.stderr))
|
||||
except:
|
||||
raise Exception('Unable to list caches.')
|
||||
|
||||
for dev in dev_list:
|
||||
if dev['type'] == 'cache':
|
||||
cache_id = dev['id']
|
||||
elif dev['type'] == 'core' and dev['status'] == "Active":
|
||||
# In case of exception we proceed with detaching remaining core instances
|
||||
# to gracefully shutdown as many cache instances as possible.
|
||||
try:
|
||||
detach_core_recursive(cache_id, dev['id'], flush)
|
||||
except casadm.CasadmError as e:
|
||||
error.add_exception(Exception(
|
||||
'Unable to detach core {0}. Reason:\n{1}'.format(
|
||||
dev['disk'], e.result.stderr)))
|
||||
except:
|
||||
error.add_exception(Exception(
|
||||
'Unable to detach core {0}.'.format(dev['disk'])))
|
||||
|
||||
error.raise_nonempty()
|
||||
|
||||
def stop_all_caches(flush):
|
||||
error = CompoundException()
|
||||
|
||||
try:
|
||||
dev_list = get_caches_list()
|
||||
except casadm.CasadmError as e:
|
||||
raise Exception('Unable to list caches. Reason:\n{0}'.format(
|
||||
e.result.stderr))
|
||||
except:
|
||||
raise Exception('Unable to list caches.')
|
||||
|
||||
for dev in dev_list:
|
||||
if dev['type'] == 'cache':
|
||||
# In case of exception we proceed with stopping subsequent cache instances
|
||||
# to gracefully shutdown as many cache instances as possible.
|
||||
try:
|
||||
casadm.stop_cache(dev['id'], not flush)
|
||||
except casadm.CasadmError as e:
|
||||
error.add_exception(Exception(
|
||||
'Unable to stop cache {0}. Reason:\n{1}'.format(
|
||||
dev['disk'], e.result.stderr)))
|
||||
except:
|
||||
error.add_exception(Exception(
|
||||
'Unable to stop cache {0}.'.format(dev['disk'])))
|
||||
|
||||
error.raise_nonempty()
|
||||
|
||||
def stop(flush):
|
||||
error = CompoundException()
|
||||
|
||||
try:
|
||||
detach_all_cores(flush)
|
||||
except Exception as e:
|
||||
error.add_exception(e)
|
||||
|
||||
try:
|
||||
stop_all_caches(False)
|
||||
except Exception as e:
|
||||
error.add_exception(e)
|
||||
|
||||
error.raise_nonempty()
|
||||
|
Reference in New Issue
Block a user