def add_a_gridcell_to_gluster_pool(hostname): """Given a hostname, it attempts to add that hostname to the gluster trusted storage pool. If the command runs without an error, it returns a dict with the return status and the xml root """ d = None try: localhost = socket.getfqdn().strip() status_dict = None if hostname != localhost: cmd = "gluster peer probe %s --xml" % hostname # print 'executing gluster cmd' d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) else: raise Exception( "The GRIDCell %s is the localhost and hence already part of the pool" % hostname) except Exception, e: if hostname: return None, "Error adding GRIDCell %s to the storage pool : %s" % ( hostname, e) else: return None, "Error adding GRIDCell to the storage pool : %s" % (e)
def change_quota_status(vol_name, action): """Enable/disable quotas for a gluster volume If the command runs without an error, it returns True, else False vol_name - the volume name action - Either 'enable' or 'disable'. """ try: cmd = 'gluster --mode=script volume quota %s %s --xml' % (vol_name, action) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) if action == 'enable': cmd = 'gluster volume set %s quota-deem-statfs on --xml' % vol_name d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return False, 'Error changing volume quota status : %s' % (str(e))
def change_quota_status(vol_name, action): """Enable/disable quotas for a gluster volume If the command runs without an error, it returns True, else False vol_name - the volume name action - Either 'enable' or 'disable'. """ try: cmd = 'gluster --mode=script volume quota %s %s --xml' % ( vol_name, action) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) if action == 'enable': cmd = 'gluster volume set %s quota-deem-statfs on --xml' % vol_name d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return False, 'Error changing volume quota status : %s' % (str(e))
def remove_volume_dir_quota(vol_name, dir): """Removes a directory quota for a gluster volume If the command runs without an error, it returns True, else False vol_name - the volume name dir - the directory for which the quota need to be set """ try: cmd = 'gluster volume quota %s remove %s --xml' % (vol_name, dir) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return False, 'Error removing volume quota : %s' % str(e)
def activate_snapshot(snapshot_name): """Activate the snapshot with the given name If the command runs without an error, it returns a dict with the return status and the xml root snapshot_name - the name of the snapshot. """ d = None try: cmd = 'gluster --mode=script snapshot activate %s --xml' % snapshot_name d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return None, 'Error activating snapshot : %s' % str(e)
def activate_snapshot(snapshot_name): """Activate the snapshot with the given name If the command runs without an error, it returns a dict with the return status and the xml root snapshot_name - the name of the snapshot. """ d = None try: cmd = 'gluster --mode=script snapshot activate %s --xml' % snapshot_name d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return None, 'Error activating snapshot : %s' % str(e)
def remove_volume_dir_quota(vol_name, dir): """Removes a directory quota for a gluster volume If the command runs without an error, it returns True, else False vol_name - the volume name dir - the directory for which the quota need to be set """ try: cmd = 'gluster volume quota %s remove %s --xml' % (vol_name, dir) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return False, 'Error removing volume quota : %s' % str(e)
def set_volume_dir_quota(vol_name, dir, limit, unit): """Sets a directory or volume quota for a gluster volume. Setting the dir to '/' sets it for the whole volume. If the command runs without an error, it returns True, else False vol_name - the volume name dir - the directory for which the quota need to be set limit - a number specifying the quantity unit - GB/MB """ try: cmd = 'gluster volume quota %s limit-usage %s %s%s --xml' % ( vol_name, dir, limit, unit) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception except Exception, e: return False, 'Error setting volume quota : %s' % str(e)
def set_volume_dir_quota(vol_name, dir, limit, unit): """Sets a directory or volume quota for a gluster volume. Setting the dir to '/' sets it for the whole volume. If the command runs without an error, it returns True, else False vol_name - the volume name dir - the directory for which the quota need to be set limit - a number specifying the quantity unit - GB/MB """ try: cmd = 'gluster volume quota %s limit-usage %s %s%s --xml' % ( vol_name, dir, limit, unit) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception except Exception, e: return False, 'Error setting volume quota : %s' % str(e)
def get_volume_quotas(vol_name): """Get volume quotas for a volume If the command runs without an error, it returns a dict with the quota info, else False vol_name - the volume name """ quotas = None try: cmd = 'gluster volume quota %s list --xml /' % (vol_name) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) root = d["root"] quotas, err = xml_parse.get_vol_quotas(root) if err: raise Exception(err) except Exception, e: return None, 'Error getting volume quota : %s' % str(e)
def get_volume_quotas(vol_name): """Get volume quotas for a volume If the command runs without an error, it returns a dict with the quota info, else False vol_name - the volume name """ quotas = None try: cmd = 'gluster volume quota %s list --xml /' % (vol_name) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) root = d["root"] quotas, err = xml_parse.get_vol_quotas(root) if err: raise Exception(err) except Exception, e: return None, 'Error getting volume quota : %s' % str(e)
def get_peer_list(): """Get the list of all the gluster peers to this node. If the command runs without an error, it returns a list of peers """ peer_list = None try: cmd = '/usr/sbin/gluster peer status --xml' d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) peer_list = None if d and 'root' in d and d['root']: peer_list, err = xml_parse.get_peer_list(d["root"]) if err: raise Exception(err) except Exception, e: return None, 'Error getting peer list: %s' % str(e)
def create_snapshot(vol_name, snapshot_name): """Create a snapshot with the given name If the command runs without an error, it returns a dict with the return status and the xml root snapshot_name - the name of the snapshot. vol_name - the volume on which the snapshot needs to be taken. """ d = None try: if (not vol_name) or (not snapshot_name): raise Exception('Required parameter not provided') cmd = 'gluster snapshot create %s %s --xml' % ( snapshot_name, vol_name) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return None, 'Error creating snapshot: %s' % str(e)
def create_snapshot(vol_name, snapshot_name): """Create a snapshot with the given name If the command runs without an error, it returns a dict with the return status and the xml root snapshot_name - the name of the snapshot. vol_name - the volume on which the snapshot needs to be taken. """ d = None try: if (not vol_name) or (not snapshot_name): raise Exception('Required parameter not provided') cmd = 'gluster snapshot create %s %s --xml' % (snapshot_name, vol_name) d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: return None, 'Error creating snapshot: %s' % str(e)
def remove_a_gridcell_from_gluster_pool(hostname): """Given a hostname, it attempts to removes that hostname from the gluster trusted storage pool. If the command runs without an error, it returns a dict with the return status and the xml root """ d = None try: if not hostname: raise Exception('Required parameter not passed') localhost = socket.getfqdn().strip() if hostname != localhost: d = {} cmd = 'gluster peer detach %s --xml' % hostname d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception(err) except Exception, e: if hostname: return None, "Error removing GRIDCell %s from the storage pool : %s" % ( hostname, e) else: return None, "Error removing GRIDCell from the storage pool : %s" % ( e)
def create_volume(request): """ Used to actually create the volume""" return_dict = {} try: gluster_lck, err = lock.get_lock('gluster_commands') if err: raise Exception(err) if not gluster_lck: raise Exception( 'This action cannot be performed as an underlying storage command is being run. Please retry this operation after a few seconds.') return_dict['base_template'] = "volume_base.html" return_dict["page_title"] = 'Create a volume' return_dict['tab'] = 'view_volumes_tab' return_dict["error"] = 'Error creating a volume' if request.method != "POST": raise Exception("Invalid access method. Please use the menus.") if 'cmd' not in request.POST or 'dataset_list' not in request.POST: raise Exception('Required parameters not passed.') # cmd represents the actual gluster volume creation command built using # the wizard choices. cmd = request.POST['cmd'] # print cmd # dataset_list is a list of hostname:dataset components of the datasets # that need to br created on various gridcells. dsl = request.POST.getlist('dataset_list') dataset_dict = {} for ds in dsl: tl = ds.split(':') dataset_dict[tl[0]] = tl[1] iv_logging.info("create volume command %s" % cmd) # First create the datasets on which the bricks will reside. # revert_list will consist of the set of node:command components to # perform to undo dataset creation in case of some failures. client = salt.client.LocalClient() revert_list = [] errors = "" for node, dataset in dataset_dict.items(): dataset_cmd = 'zfs create %s' % dataset dataset_revert_cmd = 'zfs destroy %s' % dataset r1 = client.cmd(node, 'cmd.run_all', [dataset_cmd]) if r1: for node, ret in r1.items(): # print ret if ret["retcode"] != 0: errors += ", Error creating the underlying storage brick on %s" % node # print errors else: revert_list.append({node: dataset_revert_cmd}) if errors != "": # print errors if revert_list: # Undo the creation of the datasets for revert in revert_list: for node, dsr_cmd in revert.items(): r1 = client.cmd(node, 'cmd.run_all', [dsr_cmd]) if r1: for node, ret in r1.items(): # print ret if ret["retcode"] != 0: errors += ", Error undoing the creating the underlying storage brick on %s" % node raise Exception(errors) # Underlying storage created so now create the volume d, errors = xml_parse.run_gluster_command("%s force" % cmd) # print d, errors if not errors: # All ok so mount and change the owner and group of the volume to # integralstor (ret, rc), err = command.execute_with_rc("gluster volume set " + request.POST['vol_name'] + " storage.owner-gid 1000") if err: raise Exception('Error setting volume owner : %s' % err) # Now start the volume (ret, rc), err = command.execute_with_rc( "gluster volume start " + request.POST['vol_name']) if err: raise Exception('Error starting volume : %s' % err) ''' #Set the client side quorum count cmd = "gluster volume set %s quorum-count 2 --xml"%request.POST['vol_name'] d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception('Error setting volume client side quorum count : %s'%err) #Set the client side quorum type cmd = "gluster volume set %s quorum-type fixed --xml"%request.POST['vol_name'] d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception('Errot setting volume client side quorum type : %s'%err) ''' # Temporarily mount the volume (ret, rc), err = command.execute_with_rc( "mount -t glusterfs localhost:/" + request.POST['vol_name'] + " /mnt") if err: raise Exception(err) # Set the volume permissions (ret, rc), err = command.execute_with_rc("chmod 770 /mnt") if err: raise Exception(err) #..and unmount the volume (ret, rc), err = command.execute_with_rc("umount /mnt") if err: raise Exception(err) # If it is an ISCSI volume, then add it to the iscsi volume list.. # print request.POST['vol_access'] if request.POST["vol_access"] == "iscsi": ret, err = iscsi.add_iscsi_volume(request.POST["vol_name"]) if err: raise Exception(err) # Success so audit the change audit_str = "Create " if request.POST["vol_type"] in ["replicated"]: audit_str = audit_str + \ "replicated (count %d) " % int(request.POST["repl_count"]) else: audit_str = audit_str + "distributed " audit_str = audit_str + \ " volume named %s" % request.POST["vol_name"] ret, err = audit.audit("create_volume", audit_str, request) if err: raise Exception(err) else: # Volume creation itself failed so try and delete the underlying # datasets if they were created.. if not errors: errors = "" if revert_list: # Undo the creation of the datasets for revert in revert_list: for node, dsr_cmd in revert.items(): r1 = client.cmd(node, 'cmd.run_all', [dsr_cmd]) if r1: for node, ret in r1.items(): print ret if ret["retcode"] != 0: errors += ", Error undoing the creating the underlying storage brick on %s" % node if errors: raise Exception(errors) if request.POST['vol_type'] == 'replicated': return_dict['repl_count'] = request.POST['repl_count'] return_dict['vol_type'] = request.POST['vol_type'] return_dict['vol_name'] = request.POST['vol_name'] return_dict['node_list_str'] = request.POST['node_list_str'] return_dict['cmd'] = cmd return_dict['result_dict'] = d return django.shortcuts.render_to_response('vol_create_wiz_result.html', return_dict, context_instance=django.template.context.RequestContext(request)) except Exception, e: s = str(e) if "Another transaction is in progress".lower() in s.lower(): return_dict["error_details"] = "An underlying storage operation has locked a volume so we are unable to process this request. Please try after a couple of seconds" else: return_dict["error_details"] = "An error occurred when processing your request : %s" % s return django.shortcuts.render_to_response("logged_in_error.html", return_dict, context_instance=django.template.context.RequestContext(request))
def create_volume(request): """ Used to actually create the volume""" return_dict = {} try: gluster_lck, err = lock.get_lock('gluster_commands') if err: raise Exception(err) if not gluster_lck: raise Exception( 'This action cannot be performed as an underlying storage command is being run. Please retry this operation after a few seconds.' ) return_dict['base_template'] = "volume_base.html" return_dict["page_title"] = 'Create a volume' return_dict['tab'] = 'view_volumes_tab' return_dict["error"] = 'Error creating a volume' if request.method != "POST": raise Exception("Invalid access method. Please use the menus.") if 'cmd' not in request.POST or 'dataset_list' not in request.POST: raise Exception('Required parameters not passed.') # cmd represents the actual gluster volume creation command built using # the wizard choices. cmd = request.POST['cmd'] # print cmd # dataset_list is a list of hostname:dataset components of the datasets # that need to br created on various gridcells. dsl = request.POST.getlist('dataset_list') dataset_dict = {} for ds in dsl: tl = ds.split(':') dataset_dict[tl[0]] = tl[1] iv_logging.info("create volume command %s" % cmd) # First create the datasets on which the bricks will reside. # revert_list will consist of the set of node:command components to # perform to undo dataset creation in case of some failures. client = salt.client.LocalClient() revert_list = [] errors = "" for node, dataset in dataset_dict.items(): dataset_cmd = 'zfs create %s' % dataset dataset_revert_cmd = 'zfs destroy %s' % dataset r1 = client.cmd(node, 'cmd.run_all', [dataset_cmd]) if r1: for node, ret in r1.items(): # print ret if ret["retcode"] != 0: errors += ", Error creating the underlying storage brick on %s" % node # print errors else: revert_list.append({node: dataset_revert_cmd}) if errors != "": # print errors if revert_list: # Undo the creation of the datasets for revert in revert_list: for node, dsr_cmd in revert.items(): r1 = client.cmd(node, 'cmd.run_all', [dsr_cmd]) if r1: for node, ret in r1.items(): # print ret if ret["retcode"] != 0: errors += ", Error undoing the creating the underlying storage brick on %s" % node raise Exception(errors) # Underlying storage created so now create the volume d, errors = xml_parse.run_gluster_command("%s force" % cmd) # print d, errors if not errors: # All ok so mount and change the owner and group of the volume to # integralstor (ret, rc), err = command.execute_with_rc("gluster volume set " + request.POST['vol_name'] + " storage.owner-gid 1000") if err: raise Exception('Error setting volume owner : %s' % err) # Now start the volume (ret, rc), err = command.execute_with_rc("gluster volume start " + request.POST['vol_name']) if err: raise Exception('Error starting volume : %s' % err) ''' #Set the client side quorum count cmd = "gluster volume set %s quorum-count 2 --xml"%request.POST['vol_name'] d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception('Error setting volume client side quorum count : %s'%err) #Set the client side quorum type cmd = "gluster volume set %s quorum-type fixed --xml"%request.POST['vol_name'] d, err = xml_parse.run_gluster_command(cmd) if err: raise Exception('Errot setting volume client side quorum type : %s'%err) ''' # Temporarily mount the volume (ret, rc), err = command.execute_with_rc( "mount -t glusterfs localhost:/" + request.POST['vol_name'] + " /mnt") if err: raise Exception(err) # Set the volume permissions (ret, rc), err = command.execute_with_rc("chmod 770 /mnt") if err: raise Exception(err) #..and unmount the volume (ret, rc), err = command.execute_with_rc("umount /mnt") if err: raise Exception(err) # If it is an ISCSI volume, then add it to the iscsi volume list.. # print request.POST['vol_access'] if request.POST["vol_access"] == "iscsi": ret, err = iscsi.add_iscsi_volume(request.POST["vol_name"]) if err: raise Exception(err) # Success so audit the change audit_str = "Create " if request.POST["vol_type"] in ["replicated"]: audit_str = audit_str + \ "replicated (count %d) " % int(request.POST["repl_count"]) else: audit_str = audit_str + "distributed " audit_str = audit_str + \ " volume named %s" % request.POST["vol_name"] ret, err = audit.audit("create_volume", audit_str, request) if err: raise Exception(err) else: # Volume creation itself failed so try and delete the underlying # datasets if they were created.. if not errors: errors = "" if revert_list: # Undo the creation of the datasets for revert in revert_list: for node, dsr_cmd in revert.items(): r1 = client.cmd(node, 'cmd.run_all', [dsr_cmd]) if r1: for node, ret in r1.items(): print ret if ret["retcode"] != 0: errors += ", Error undoing the creating the underlying storage brick on %s" % node if errors: raise Exception(errors) if request.POST['vol_type'] == 'replicated': return_dict['repl_count'] = request.POST['repl_count'] return_dict['vol_type'] = request.POST['vol_type'] return_dict['vol_name'] = request.POST['vol_name'] return_dict['node_list_str'] = request.POST['node_list_str'] return_dict['cmd'] = cmd return_dict['result_dict'] = d return django.shortcuts.render_to_response( 'vol_create_wiz_result.html', return_dict, context_instance=django.template.context.RequestContext(request)) except Exception, e: s = str(e) if "Another transaction is in progress".lower() in s.lower(): return_dict[ "error_details"] = "An underlying storage operation has locked a volume so we are unable to process this request. Please try after a couple of seconds" else: return_dict[ "error_details"] = "An error occurred when processing your request : %s" % s return django.shortcuts.render_to_response( "logged_in_error.html", return_dict, context_instance=django.template.context.RequestContext(request))