Best Python code snippet using autotest_python
retrieve_files.py
Source:retrieve_files.py  
1""" Process requests from users into a storage-D tape requests.2 This script makes sure all the storage-D queue slots are loaded with requests.3 Then starts a single storage-D request. Other instances of this script make this run in parallel.4 The storage-D retrieve log is monitored to note when files are moved onto disk.5 This is designed to be used via the django-extensions runscript command:6 ``$ python manage.py runscript queue_requests``7"""8#9# SJP 2016-02-0910# NRM 2017-01-2511# import nla objects12from nla_control.models import *13from nla_control.settings import *14import nla_control15from django.core.mail import send_mail16from django.db.models import Q17import subprocess18import datetime19import time20import re21import socket22from pytz import utc23import sys, os24from ceda_elasticsearch_tools.index_tools import CedaFbi, CedaEo25def get_restore_disk(slot):26    """Get the next restore disk with enough free space to store all the files in the request.27       :param integer slot: slot number28       :return: the mountpoint of the first restore disk with enough space to store the request29       :rtype: string30       """31    restore_disks = RestoreDisk.objects.all()32    # get the size of the files in the request33    files = slot.tape_request.files.filter(stage=TapeFile.ONTAPE)34    # if no files then just return35    if len(files) == 0:36        return restore_disks[0]37    # add up the filesize38    total_request_size = 039    for f in files:40        # have to go via the TapeFile41        total_request_size += TapeFile.objects.filter(logical_path=f.logical_path)[0].size42    # loop over the restore_disks43    target_disk = None44    for td in restore_disks:45        # find a disk with enough free space46        if td.allocated_bytes - td.used_bytes > total_request_size:47            target_disk = td48            break49    # if a disk not found then print an error and return None50    if type(target_disk) == type(None):51        return None52    # create the directory if it doesn't exist53    if not os.path.exists(target_disk.mountpoint):54        os.makedirs(target_disk.mountpoint)55    return target_disk56def send_start_email(slot):57    """Send an email to the user to notify that the request has started.  The email address is stored in58       ``notify_on_first_file`` in the *TapeRequest*.59       :param integer slot: slot number60    """61    if not slot.tape_request.notify_on_first_file:62        return63    # to address is notify_on_first64    toaddrs = [slot.tape_request.notify_on_first_file]65    # from address is just a dummy address66    fromaddr = "support@ceda.ac.uk"67    # subject68    subject = "[NLA] - Tape request %i has started" % slot.tape_request.id69    msg = "Request contains files: "70    for f in slot.tape_request.files.all():71        msg += "\n" + f.logical_path72    send_mail(subject, msg, fromaddr, toaddrs, fail_silently=False)73def send_end_email(slot):74    """Send an email to the user to notify that the request has finished. The email address is stored in75       ``notify_on_last_file`` in the *TapeRequest*.76       :param integer slot: slot number77    """78    if not slot.tape_request.notify_on_last_file:79        return80    # to address is notify_on_last81    toaddrs = [slot.tape_request.notify_on_last_file]82    # from address is just a dummy address83    fromaddr = "support@ceda.ac.uk"84    # subject85    subject = "[NLA] - Tape request %i has finished" % slot.tape_request.id86    msg = "Request contains files: "87    for f in slot.tape_request.files.all():88        msg += "\n" + f.logical_path89    send_mail(subject, msg, fromaddr, toaddrs, fail_silently=False)90def get_spot_contents(spot_name):91    """Get a list of the files in the spot `spot_name`"""92    sd_cmd = ["/usr/bin/python2.7", "/usr/bin/sd_ls", "-s", spot_name, "-L", "file"]93    try:94        output = subprocess.check_output(sd_cmd).decode("utf-8")95    except subprocess.CalledProcessError:96        return []97    out_lines = output.split("\n")98    spot_files = []99    for out_item in out_lines:100        out_file = out_item.split()101        if len(out_file) == 11:102            file_name = out_file[10]103            size = out_file[1]104            status = out_file[2]105            spot_files.append({os.path.basename(file_name) : (file_name, size, status,)})106    return spot_files107def create_retrieve_listing(slot, target_disk):108    """Create a text file (``file_listing_filename``) containing the names of the files to retrieve from StorageD.109    This text file is saved to the mountpoint of the restore disk that has been allocated for this retrieval by110    ``get_restore_disk``. The function also builds a mapping (``retrieved_to_file_map``) between a files spot name111    (physical location) and TapeFile, which includes a files logical path (symbolic link to the file from the archive112    filespace).113    :param integer slot: slot number114    :param RestoreDisk target_disk: *RestoreDisk* object containing the mountpoint where files will be written to115    :return: file_listing_filename, retrieved_to_file_map116    :rtype: Tuple(string, Dictionary[string:TapeFile])117    """118    # files to retrieve119    files = slot.tape_request.files.filter(stage=TapeFile.ONTAPE)120    # make files to retrieve in a listing file and mark files as restoring.121    file_listing_filename = os.path.join(target_disk.mountpoint, "retrieve_listing_%s.txt" % slot.tape_request.id)122    file_listing = open(file_listing_filename, "w")123    retrieved_to_file_map = {}124    spot_list = {}125    for f in files:126        try:127            spot_logical_path, spot_name = f.spotname()128        except:129            print("Spotname name not found for file: {}".format(f))130       	    continue131        # get a list of files in the spot if not already got132        if spot_name not in spot_list:133            spot_list[spot_name] = get_spot_contents(spot_name)134        if TEST_VERSION:135            to_retrieve = f.logical_path136        else:137            to_retrieve = f.logical_path.replace(spot_logical_path, "/archive/%s" % spot_name)138        to_check = os.path.basename(to_retrieve)139        # check it's in the spot on sd140        # spot list is now a list of dictionaries with the file name to check as the key141        spot_list_keys = [list(s.keys())[0] for s in spot_list[spot_name]]142        if to_check in spot_list_keys:143            retrieved_to_file_map[to_retrieve] = f144            file_listing.write(to_retrieve + "\n")145            f.stage = TapeFile.RESTORING146            f.restore_disk = target_disk147            f.save()148    file_listing.close()149    return file_listing_filename, retrieved_to_file_map150def start_sd_get(slot, file_listing_filename, target_disk):151    """152    Start the process of retrieving files from StorageD by calling (the command line program) sd_get, with the153    list of files created by ``create_retrieve_listing`` as input, for a single slot.  The process id of the instance154    of sd_get running for the slot is returned.  A logfile is also created, with output from sd_get being appended to155    the logfile.156    :param integer slot: slot number157    :param string file_listing_filename: the name of the text file containing the names of the files to retrieve from158        StorageD.  This file listing is created by ``create_retrieve_listing``.159    :param RestoreDisk target_disk: *RestoreDisk* object containing the mountpoint where files will be written to160    :return: process id of the instance of ``sd_get``, the name of the output log file161    :rtype: Tuple(integer, string)162    """163    # start an sd_get to retrieval cache164    log_file_name = os.path.join(target_disk.mountpoint, "retrieve_log_%s.txt" % slot.tape_request.id)165    if os.path.exists(log_file_name):  # make sure old log is removed as this may get picked up by current request166        os.unlink(log_file_name)167    # build the arg string for sd_get168    sd_get_args = ["-v", "-l", log_file_name, "-h", SD_HOST, "-r", target_disk.mountpoint, "-f", file_listing_filename]169    if TEST_VERSION:170        # get the current python running via sys.executable and the sd_get_emulator command from171        # the current PROJECT_DIR / BASE_DIR172        pth = os.path.dirname(nla_control.__file__)173        sd_get_cmd = [sys.executable, pth, "/bin/sd_get_emulator"]174        sd_get_cmd.extend(sd_get_args)175    else:176        # this is a bit hacky but sd_get uses the system python2.7, rather than the venv one177        sd_get_cmd = ["/usr/bin/python2.7", "/usr/bin/sd_get"]178        sd_get_cmd.extend(sd_get_args)179    # mark request as started180    slot.tape_request.storaged_request_start = datetime.datetime.utcnow()181    slot.tape_request.save()182    # start storage-D process and record pid and host183    p = subprocess.Popen(sd_get_cmd)184    print("Starting retrieval of file listing : {}".format(185        file_listing_filename)186    )187    slot.host_ip = socket.gethostbyname(socket.gethostname())188    slot.pid = p.pid189    slot.save()190    return p, log_file_name191def wait_sd_get(p, slot, log_file_name, target_disk, retrieved_to_file_map):192    """193    Wait for the ``sd_get`` process for a slot to finish.  The function monitors the log file (``log_file_name``)194    for reports of file restores from StorageD (carried out by ``sd_get``.  When a restored file is found, a symbolic195    link is created from its place in the restore area (*RestoreDisk* ``target_disk``) to the original logical_file_path196    location in the archive.197    :param integer p: process id of the instance of ``sd_get``198    :param integer slot: slot number199    :param string log_file_name: name of log file to append to200    :param RestoreDisk target_disk: *RestoreDisk* object containing the mountpoint where files will be written to201    :param retrieved_to_file_map: Mapping of spot filepaths to logical file paths, created by ``create_retrieve_listing``202    """203    """ """204    # setup log file to read205    files_retrieved = 0206    log_file = None207    ended = False208    while True:209        # sleep first, to allow process to start210        time.sleep(10)211        # see if process has ended212        if p.poll() is not None:213            ended = True214        # see is logfile is available yet. if not then wait a second and try again.215        if log_file is None:216            if os.path.exists(log_file_name):217                log_file = open(log_file_name)218            else:219                if ended:220                    break221                time.sleep(1)222                continue223        # check the log file for reports of file restores...224        lines = log_file.readlines()225        # keep a list of restored filenames226        restored_files = []227        for line in lines:228            # look for line with right pattern to know its finished229            if TEST_VERSION:230                m = re.search('Copying file: (.*) to (.*)', line)231            else:232                m = re.search('Saving (.*) into local file (.*)', line)233            if m:234                restored_archive_file_path = m.groups()[0]235                local_restored_path = m.groups()[1]236                files_retrieved += 1237                # move the retrieved file back to archive area.238                f = retrieved_to_file_map[restored_archive_file_path]239                # link file to final archive location240                try:241                    if os.path.exists(f.logical_path):242                        if os.path.islink(f.logical_path):243                            os.unlink(f.logical_path)244                            os.symlink(local_restored_path, f.logical_path)245                        else:246                            raise Exception("File exists and is not a link".format(f.logical_path))247                    else:248                        os.symlink(local_restored_path, f.logical_path)249                except:250                    print("Could not create symlink from {} to {}".format(f.logical_path, local_restored_path))251                else:252                    # set the first files on disk if not already set253                    if slot.tape_request.first_files_on_disk is None:254                        slot.tape_request.first_files_on_disk = datetime.datetime.utcnow()255                    f.stage = TapeFile.RESTORED256                    f.save()257                # update the restore_disk258                target_disk.update()259                # add the filename to the restored filenames260                restored_files.append(f.logical_path.encode("utf-8"))261        # modify the restored files in elastic search262        try:263            if len(restored_files) > 0:264                fbi = CedaFbi(265                        headers = {266                            'x-api-key': CEDA_FBI_API_KEY267                        }268                      )269                fbi.update_file_location(file_list=restored_files, on_disk=True)270                #print "Updated Elastic Search index for files ",271                #for f in restored_files:272                #    print " - " + str(f)273        except Exception as e:274            print("Failed updating Elastic Search Index ",)275            print(e, restored_files)276        log_file.close()277        log_file = None278        # checking to see if the process ended before we searched the log file279        if ended:280            break281def complete_request(slot):282    """Tidy up slot after a completed request.  This involves setting dates for the storaged_request_end283    and last_files_on_disk members, setting the active_request to False and clearing the slot.284       :param integer slot: slot number285    """286    print("Completing request {} on slot {}".format(287        slot.tape_request, slot.pk)288    )289    # request ended - mark request as finished290    slot.tape_request.storaged_request_end = datetime.datetime.utcnow()291    slot.tape_request.last_files_on_disk = datetime.datetime.utcnow()292    slot.tape_request.save()293    # reset slot294    slot.pid = None295    slot.host_ip = None296    slot.tape_request = None297    slot.save()298def start_retrieval(slot):299    """Function to run the storage-D retrieve for a tape request.300    This function takes a slot with an attached tape request, creates a working directory for the retrival listing,301    log file and retrieved data. It starts an sd_get command as a subprocess and monitors its progress by monitoring302    the log file and polling to see if the process is completed.303    :param integer slot: slot number to strat the request in304    """305    # don't call this if slot not filled or already started.306    assert slot.tape_request is not None, "ERROR: Can only call watch_sd_get with a full slot"307    # files to retrieve308    files = slot.tape_request.files.filter(stage=TapeFile.ONTAPE)309    # if no files need retrieving then just mark up as if finished310    if len(files) == 0:311        slot.tape_request.storaged_request_start = datetime.datetime.utcnow()312        complete_request(slot)313        return False314    # get the next free restore disk315    target_disk = get_restore_disk(slot)316    # error check - no room on the disk returns None317    if target_disk is None:318        print("ERROR: No RestoreDisks exist with enough space to hold the request")319        return False320    # create the retrieve listing file and get the mapping between the retrieve listing and the spot filename321    file_listing_filename, retrieved_to_file_map = create_retrieve_listing(slot, target_disk)322    # check whether any files actually need to be downloaded323    if len(retrieved_to_file_map) != 0:324        print("  Start request for %s on slot %s" % (slot.tape_request, slot.pk))325        # send start notification email if no files retrieved326        if slot.tape_request.files.filter(stage=TapeFile.RESTORED).count() == 0:327            send_start_email(slot)328        # start the sd_get_process329        p, log_file_name = start_sd_get(slot, file_listing_filename, target_disk)330        wait_sd_get(p, slot, log_file_name, target_disk, retrieved_to_file_map)331        # request ended - send ended email if there are no files in the request left ONTAPE or RESTORING332        if slot.tape_request.files.filter(Q(stage=TapeFile.ONTAPE) | Q(stage=TapeFile.RESTORING)).count() == 0:333            send_end_email(slot)334        # if got all the files then mark slot as empty335        if slot.tape_request.files.filter(stage=TapeFile.RESTORING).count() == 0:336            complete_request(slot)337        else:338            print("Request finished on StorageD, but all files in request not retrieved yet")339            redo_request(slot)          # mark the request to reattempt later340        return True341    else:342        # Deactivate request and make slot available to others343        slot.tape_request.save()344        slot.tape_request = None345        slot.save()346        return False347def redo_request(slot):348    """Reset a tape request so that it will be restarted.  This is used for requests with files that are stuck349       in the RESTORING stage.350       - Mark all files with stage RESTORING as ONTAPE (i.e. reset them to previous state)351       - Reset all the information in the request so that it is marked as not started352       :param integer slot: slot number to redo the request for353    """354    print("Redoing request {} on slot {}".format(355        slot.tape_request, slot.pk)356    )357    # mark unrestored files as on tape358    for f in slot.tape_request.files.filter(stage=TapeFile.RESTORING):359        f.stage = TapeFile.ONTAPE360        f.save()361    # mark tape request as not started362    slot.tape_request.storaged_request_start = None363    slot.tape_request.storaged_request_end = None364    slot.tape_request.save()365    # reset slot366    slot.pid = None367    slot.host_ip = None368    slot.tape_request = None369    slot.save()370def check_happy(slot):371    """Check the progress of the requests in each slot.  Several scenarios are accounted for:372       - The request hasn't started yet (do nothing)373       - The request is stuck in the RESTORING phase (restart the request via ``redo_requests``)374       - This script has been run from a different host (do nothing)375       - The ``sd_get`` process is still running (do nothing)376       - The ``sd_get`` process is not running but the request has started (restart the request via ``redo_requests``)377       :param integer slot: slot number to check378       """379    print("Checking slot %s" % slot)380    if slot.tape_request.storaged_request_start is None:381        # no need to tidy up an unstarted process382        print("No need to correct: not started yet.")383        return384    # look for files stuck in RESTORING state385    if slot.pid is None or slot.host_ip is None:386        start_time = slot.tape_request.storaged_request_start.replace(tzinfo=utc)387        if start_time < datetime.datetime.now(utc) + datetime.timedelta(seconds=120):388            # no port or host ip and not started389            print("Reset request: pid or host not set and not started for 120s.")390            redo_request(slot)391            return392        else:393            # wait for rest after 20 seconds394            print("No need to correct: pid or host not sec, but less than 20s old.")395            return396    if slot.host_ip != socket.gethostbyname(socket.gethostname()):397        # can't reset from different machine398        print("No need to correct: Not on right host.")399        return400    # need to test pid on this machine401    if os.path.exists("/proc/{}".format(slot.pid)):402        print("No need to correct: pid still running.")403        return404    else:405        print("Reset request: pid not running.")406        redo_request(slot)407        return408def run():409    """ Entry point for the Django script run via ``./manage.py retrieve_files``410        The algorithm / order to run the above functions is411          - **for each** slot:412            - **if** no request in the slot **then** continue to next slot413            - **if** request already active in the slot **then** check the progress of the request (``check_happy``)414            - **if** there is a new request in the slot **then**415              - load the storage paths (``TapeFile.load_storage_paths``)416              - start the retrieval of the file(s) in the request and create an active request in this slot (``start_retrieval``)417    """418    # First of all check if the process is running - if it is then don't start running again419    try:420        lines = subprocess.check_output(["ps", "-f", "-u", "badc"]).decode("utf-8").split("\n")421        n_processes = 0422        for l in lines:423            if "retrieve_files" in l and not "/bin/sh" in l:424                n_processes += 1425    except:426        n_processes = 1427    if n_processes > MAX_RETRIEVALS+1:   # this process counts as one process_requests processx428        print("Process already running {} transfers, exiting".format(MAX_RETRIEVALS))429        sys.exit()430    # flag whether storage paths are loaded431    spaths_loaded = False432    print("Start retrieval runs for a slot")433    for slot in StorageDSlot.objects.all():434        if slot.tape_request is None:435            print("  No request for slot %s" % slot.pk)436            continue437        elif slot.pid is not None:438            print("  Request for %s already active on slot %s" % (slot.tape_request, slot.pk))439            check_happy(slot)440            continue441        else:442            # load storage paths to do path translation to from logical to storage paths.443            print("  Process slot %s" % slot.pk)444            if not spaths_loaded:445                print("Load storage paths")446                TapeFile.load_storage_paths()447                spaths_loaded = True448            if start_retrieval(slot):449               break...tidy_requests.py
Source:tidy_requests.py  
1""" Tidy up files from requests where the retention time is in the past.2    Files are checked to see if they are part of another request, have been deleted or modified. If not then3    they are removed and flagged as back on tape.4    This is designed to be used via the django-extentions runscript command:5    ``$ python manage.py runscript tidy_requests``6"""7# SJP 2016-02-098from nla_control.models import TapeFile, TapeRequest9import datetime10import sys11from pytz import utc12from nla_control.settings import *13from nla_control.scripts.process_requests import update_requests14from ceda_elasticsearch_tools.index_tools import CedaFbi, CedaEo15import subprocess16__author__ = 'sjp23'17def in_other_request(tr, f):18    # check that file is not in another request19    in_other_req = False20    now = datetime.datetime.now(utc)21    active_tape_requests = TapeRequest.objects.filter(retention__gte=now)22    file_in_requests = active_tape_requests.filter(files__id__exact = f.id)23    in_other_req = (file_in_requests.count() > 0)24    if (in_other_req):25        if (f.stage == TapeFile.RESTORED or f.stage == TapeFile.RESTORING26            or f.stage == TapeFile.ONDISK):27            print("In other request {} {} {}".format(tr, f, file_in_requests))28            return True29    return False30def tidy_requests():31    """Run the tidying up of the TapeRequests.32    The algorithm is:33    - **for each** TapeRequest object whose retention time < currrent time (i.e. in the past):34      - **for each** file in the TapeRequest:35        - **if** the file does not exist on the disk but **and** a stage of RESTORED **then** delete the file36          (``move_files_to_nla.py`` will add the file back into the NLA if it is still archived on tape)37        - **if** the file has been modified **then** reset its stage to UNVERIFIED38        - **if** the file is in another request **then** move onto the next file **else**:39          - Unlink the file (delete)40          - Mark the stage of the file as ONTAPE41          - Update the restore disk to reflect that space has been freed42    """43    # Update the files portion of the tape request with those present in the NLA44    now = datetime.datetime.now(utc)45    print("Searching for expired tape requests")46    tape_requests = TapeRequest.objects.filter(retention__lt=now)47    print("Number of tape requests: ", tape_requests.count())48    print("Updating tape requests")49    for tr in tape_requests:50        print("Tape request: {}".format(tr))51        request_files = tr.request_files.split()52        n_rf = len(request_files)53        # split the request files up into batches of 100054        n_per_batch = 10000055        tr.files.clear()56        for i in range(0, int(n_rf/n_per_batch+1)):57            batch_files = request_files[i*n_per_batch:(i+1)*n_per_batch]58            print("Processing {}/{}".format(i*len(batch_files), n_rf))59            present_tape_files = TapeFile.objects.filter(logical_path__in=batch_files)60            if len(present_tape_files) != 0:61                pf = list(present_tape_files.all())62                tr.files.add(*pf)63                tr.save()64    # list of restore disks used - cache them so that they only need to be updated once65    restore_disks = []66    print("Tidying tape requests: find tape requests...")67    for tr in tape_requests:68        # make list of files to tidy69        print(tr)70        to_remove = []71        for f in tr.files.all():72            # Check if the file does not exist on the disk anymore - but only remove it if it is still in a restored state73            if not os.path.exists(f.logical_path):74                if f.stage == TapeFile.RESTORED:75                    print("File requests exists, but file is not on the disk. Removing file from NLA:", f.logical_path)76                    #f.delete()77                continue78            file_mod = datetime.datetime.fromtimestamp(os.path.getmtime(f.logical_path), utc)79            if f.verified:80                tr_f_mod = f.verified.replace(tzinfo=file_mod.tzinfo)81                if not os.path.islink(f.logical_path) and file_mod > tr_f_mod:82                    print("File has been modified after the time it was verified. Leave it alone.")83                    print("Leaving file, but resetting as unverified %s" % f)84                    f.verified = None85                    f.stage = TapeFile.UNVERIFIED86                    f.restore_disk = None87                    f.save()88                    continue89            # check that file is not in another request90            if in_other_request(tr, f):91                continue92            # if we get here then the file exists, has not been modified since checked and is not in another request93            to_remove.append(f)94        print("Removing %s files from restored area:" % len(to_remove))95        # list of files to modify in elastic search96        removed_files = []97        for f in to_remove:98            print("     -  %s" % f)99            logical_dir = os.path.dirname(f.logical_path)100            sign_post = os.path.join(logical_dir, "00FILES_ON_TAPE")101            try:102                if not os.path.exists(sign_post):103                    if not TEST_VERSION:104                        os.symlink("/badc/ARCHIVE_INFO/FILES_ON_TAPE.txt", sign_post)105            except Exception as e:106                print("Could not create signpost: ", sign_post)107            # Commented out deletion of files for testing safety108            if f.stage == TapeFile.RESTORED:109                try:110                    f.stage = TapeFile.ONTAPE111                    # get the restore disk and update112                    if f.restore_disk and not f in restore_disks:113                        restore_disks.append(f.restore_disk)114                    # set no restore disk115                    f.restore_disk = None116                    f.save()117                    # remove link and datafile in restore cache118                    os.unlink(os.readlink(f.logical_path))119                    os.unlink(f.logical_path)120                except Exception as e:121                    print("Could not remove from restored area: ", f.logical_path)122            else:123                # removing for the first time or deleted or unverified124                try:125                    f.stage = TapeFile.ONTAPE126                    # get the restore disk and update127                    if f.restore_disk and not f in restore_disks:128                        restore_disks.append(f.restore_disk)129                    # set no restore disk130                    f.restore_disk = None131                    f.save()132                    os.unlink(f.logical_path)133                except Exception as e:134                    print("Could not remove from archive: ", f.logical_path)135            # add to list of files to be altered in Elastic Search136            removed_files.append(f.logical_path.encode("utf-8"))137        print("Setting status of files in Elastic Search to not on disk")138        try:139            # Open connection to index and update files140            if len(removed_files) > 0:141                fbi = CedaFbi(142                          headers = {143                              'x-api-key' : CEDA_FBI_API_KEY144                        }145                      )146                fbi.update_file_location(file_list=removed_files, on_disk=False)147            print("Updated Elastic Search index for files ",)148            for f in removed_files:149                print(" - " + str(f))150        except Exception as e:151            print("Failed updating Elastic Search Index ",)152            print(e, removed_files)153        print("Remove request %s" % tr)154        tr.delete()155    # update the restore disk used156    print("Updating restore disk")157    for rd in restore_disks:158        rd.update()159def run():160    """Entry point for the Django script run via ``./manage.py runscript``"""161    # First of all check if the process is running - if it is then don't start running again162    print("Starting tidy_requests")163    try:164        lines = subprocess.check_output(["ps", "-f", "-u", "badc"]).decode("utf-8").split("\n")165        n_processes = 0166        for l in lines:167            if "tidy_requests" in l and not "/bin/sh" in l:168                print(l)169                n_processes += 1170    except:171        n_processes = 1172    if n_processes > 1:173        print("Process already running, exiting")174        sys.exit()175    # otherwise run176    tidy_requests()...__init__.py
Source:__init__.py  
1import json, subprocess2from ... pyaz_utils import get_cli_name, get_params3def restore_disks(resource_group, vault_name, container_name, item_name, rp_name, storage_account, target_resource_group=None, restore_to_staging_storage_account=None, restore_only_osdisk=None, diskslist=None, restore_as_unmanaged_disks=None, use_secondary_region=None, rehydration_duration=None, rehydration_priority=None, disk_encryption_set_id=None, mi_system_assigned=None, mi_user_assigned=None):4    params = get_params(locals())   5    command = "az backup restore restore-disks " + params6    print(command)7    output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)8    stdout =  output.stdout.decode("utf-8")9    stderr = output.stderr.decode("utf-8")10    if stdout:11        return json.loads(stdout)12        print(stdout)13    else:14        raise Exception(stderr)15        print(stderr)  16def restore_azurefileshare(resource_group, vault_name, rp_name, container_name, item_name, restore_mode, resolve_conflict, target_storage_account=None, target_file_share=None, target_folder=None):17    params = get_params(locals())   ...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
