def read(self, param): try: with open(os.path.join(self.path, param)) as f: for line in f.readlines(): yield line.split() except IOError, e: msg = "Cgroup read error: %s/%s: %s" % (self.path, param, e) logger.error(msg)
def write(self, param, value): try: with open(os.path.join(self.path, param), 'w') as f: f.write(value) logger.info("Writing cgroup: %s: %s" % (param, value)) except IOError, e: msg = "Cgroup write error: %s/%s: %s" % (self.path, param, e) logger.error(msg)
def remove(self, path): for i in range(0, 10): try: return execute('lvremove', path, force=None) except ProcessError: sleep(1) continue logger.error("Failed to delete volume '%s' after 10 tries" % path) raise
def _assign_node(self, volume, backup, source, nodes): """ Assigns the new volume to a node. :returns: dict, node response on successful placement :raises: HTTPError """ request_params = { 'account': self.account_id, 'size': volume.size, 'read_iops': volume.volume_type.read_iops, 'write_iops': volume.volume_type.write_iops, } if volume.image_id: request_params['image_id'] = volume.image_id if backup: request_params['backup_source_volume_id'] = backup.volume.name request_params['backup_id'] = backup.id volume.restore_of = backup.id if source: request_params['source_volume_id'] = source.name request_params['source_host'] = source.node.hostname request_params['source_port'] = source.node.port last_node_error = None for node in nodes: volume.node = node self.db.commit() # prevent duplicate/lost volumes try: path = '/volumes/%s' % volume.name return self.node_request(node, 'PUT', path, **request_params) except NodeError, e: last_node_error = e # log server errors and continue if (e.code // 100) == 5: logger.error(str(e)) continue # pass client error up to user, immediately break
def get_registration_exceptions(local_info, node_info): exceptions = {} for k, v in local_info.items(): if 'hostname' in k and node_info[k] != v: try: node_value = socket.gethostbyname(node_info[k]) except socket.error: # skip hostname translation on failure pass else: try: node_value = node_info[k] except KeyError, e: logger.error("During registration; missing '%s' key in api " "server response" % k) continue if node_value != v: logger.warning("Invalid '%s' registered " "as %r != %r" % (k, node_value, v)) exceptions[k] = v else: logger.info("Verified '%s' registered as '%s'" % (k, v))
def create_clone(self, volume_id, clone_id, iqn, iscsi_ip, iscsi_port, callback=None, lock=None, cinder=None): volume = self.get(volume_id) size = volume['size'] / 1024 / 1024 / 1024 logger.info("Cloning source '%s' to volume '%s'" % (volume_id, clone_id)) snapshot_name = uuid.uuid4() snapshot = self.create_snapshot(volume_id, snapshot_name, clone_id=clone_id, type_='clone') logger.info("Snapshot to clone id: '%s'" % snapshot['id']) try: new_volume = ISCSIDevice(iqn, iscsi_ip, iscsi_port) new_volume.connect() except (ISCSILoginFailed, ISCSINotConnected): msg = "Unable to open iscsi connection to %s:%s - %s" % \ (iscsi_ip, iscsi_port, iqn) logger.error(msg) self.delete(snapshot['id']) raise ServiceUnavailable(msg) spawn(lock, self._copy_clone, snapshot, clone_id, size, new_volume, cinder, callback=callback, skip_fork=self.skip_fork)
def __call__(self, request): """Handle WSGI request.""" try: try: # Call the implementation to handle the action return self.encode_response(self.call(request)) except HTTPException: raise except Exception, e: logger.exception("Caught unknown exception, traceback dumped") raise HTTPInternalServerError("Internal controller error") except HTTPException, e: # Avoid logging HTTPOk Exceptions if isinstance(e, HTTPError): logger.error("%s" % e) # (thrawn01) returning a HTTPError exception to WSGI # container would result in a text/html content type # provided by webob, this is not desired body = { 'reason': e.detail, 'request-id': request.headers.get('x-request-id', '-') } return self.encode_response(Response(body=body, status=e.status))
def _do_create(self, volume_id, size_str, tag, backup_source_volume_id=None): try: out = execute('lvcreate', self.volume_group, name=volume_id, size=size_str, addtag=tag) except ProcessError, e: if not e.errcode == 5 and 'already exists' not in e.err: raise # We ran out of space on the storage node! if "Insufficient free extents" in e.err \ or "insufficient free space" in e.err: logger.error(e.err) raise ServiceUnavailable("LVM reports insufficient " "free space on drive") # If we are requesting a restore, and the existing volume is this # same failed restore, it's not an error. if backup_source_volume_id and backup_source_volume_id == \ self.get(volume_id).get('backup_source_volume_id', False): logger.info("Restarting failed restore on '%s'" % volume_id) else: raise AlreadyExists("Unable to create a new volume named " "'%s' because one already exists." % volume_id)
path = '/volumes/%s/clones/%s' % (source['id'], volume['id']) node_params = { 'account': req.params.get('account', ''), 'iqn': export['name'], 'iscsi_ip': self.helper.storage_host, 'iscsi_port': self.helper.storage_port, # First dirty method to close the export. 'mgmt_host': self.helper.management_host, 'mgmt_port': self.helper.management_port, 'cinder_host': self.helper.cinder_host, } try: self.helper.node_request(source['host'], source['port'], 'PUT', path, **node_params) except NodeError, e: logger.error('Clone node request failed: %s' % e) self.helper.exports.delete(volume['id']) self.helper.volumes.delete(volume['id'], lock=lock) raise volume['status'] = 'CLONING' # Create from image elif req.params.get('image_id'): image_id = params['image_id'] = req.params['image_id'] account = params['account'] = req.params.get('account') params['callback'] = self._create_from_image_cb(req, iops) params['scrub_callback'] = self._post_scrub_cb() try: self.helper.volumes.create(self.id, **params) except InvalidImage, e:
else: convert_gbs = self.convert_gbs tmp_vol = self.create_convert_scratch(image, convert_gbs) except GlanceError, e: logger.warning("Error fetching glance image: %s" % e) raise InvalidImage("Error fetching image: %s" % image_id) # Create a tag to apply to the lvm volume tag = encode_tag(backup_source_volume_id=backup_source_volume_id, backup_id=backup_id) try: self._do_create(volume_id, size_str, tag, backup_source_volume_id) except Exception, e: # If we ran out of space due to the tmp_vol logger.error('Failed to create volume: %s' % e) # Update cinder immediately. if callback: callback() if tmp_vol: spawn(NullResource(), self.remove_lvm_volume, tmp_vol, callback=scrub_callback, skip_fork=self.skip_fork) raise def log_duration(): duration = time() - op_start parts = ['STAT: Create Volume'] if volume_id: parts.append('Volume_ID: %s' % (volume_id,)) if backup_id:
class CgroupHelper(object): cgroup_parameters = [ 'blkio.throttle.read_iops_device', 'blkio.throttle.write_iops_device', ] def __init__(self, conf): sys_fs_path = conf.string('cgroup', 'cgroup_path', '/sys/fs/cgroup/blkio/sysdefault') self.cgroup_fs = CgroupFs(sys_fs_path) run_dir = conf.string('storage', 'run_dir', conf.path('run')) self.cgroups_path = os.path.join(run_dir, 'cgroups') def _updates_path(self): return os.path.join(self.cgroups_path, 'updates') def all_cgroups(self): data = defaultdict(dict) for name in self.cgroup_parameters: for device, throttle in self.cgroup_fs.read(name): data[name][device] = throttle return data def get(self, volume): device = volume['device_number'] data = {} cgroups = self.all_cgroups() for name, device_map in cgroups.items(): if device in device_map: data[name] = device_map[device] return data def set_read_iops(self, volume, throttle): self.set(volume, throttle, 'blkio.throttle.read_iops_device') def set_write_iops(self, volume, throttle): self.set(volume, throttle, 'blkio.throttle.write_iops_device') def set(self, volume, throttle, param=None): if not param: params = self.cgroup_parameters else: params = [param] throttle = int(throttle) if throttle < 0: raise ValueError("Throttle cannot be negative") device = volume['device_number'] for name in params: value = "%s %s" % (device, throttle) self.cgroup_fs.write(name, value) self.save_update(volume, name, throttle) def save_update(self, volume, name, throttle): try: os.makedirs(self.cgroups_path) except OSError, e: if e.errno != errno.EEXIST: raise try: with open(self._updates_path(), 'a') as f: fcntl.lockf(f.fileno(), fcntl.LOCK_EX) entry = '%s %s %s\n' % (volume['id'], name, throttle) f.write(entry) except IOError, e: logger.error('Failed writing cgroup update: %s' % e)
else: convert_gbs = self.convert_gbs tmp_vol = self.create_convert_scratch(image, convert_gbs) except GlanceError, e: logger.warning("Error fetching glance image: %s" % e) raise InvalidImage("Error fetching image: %s" % image_id) # Create a tag to apply to the lvm volume tag = encode_tag(backup_source_volume_id=backup_source_volume_id, backup_id=backup_id) try: self._do_create(volume_id, size_str, tag, backup_source_volume_id) except Exception, e: # If we ran out of space due to the tmp_vol logger.error('Failed to create volume: %s' % e) # Update cinder immediately. if callback: callback() if tmp_vol: spawn(NullResource(), self.remove_lvm_volume, tmp_vol, callback=scrub_callback, skip_fork=self.skip_fork) raise def log_duration(): duration = time() - op_start parts = ['STAT: Create Volume']