1
#!/usr/bin/python
import os

from os import getpid

import multiprocessing


build="613719"
file1=open('/auto/home/venkam11/python/install-script/build-ddr-file.txt', 'r')

def installation(model,ddr,build):

    cli = "/auto/tools/qa/shared/qa-branch/util/install.pl -durham -restart -silentinstall -model %s -branch 6.2A %s %s"  %(model, ddr, build)

    print cli
    os.popen2(cli)
    print "installation has started on %s \n" %ddr

if name == 'main':

pid=getpid()

print("parent process id :{}".format(getpid()))

for ddr in file1:
    print ddr.rstrip()
    if 'dd4500' in ddr:
        print "dd4500"
        model = "dd4500"
    elif ('apollo' or 'apolloplus') in ddr:
        print "dd9500"
        model = "dd9500"
    elif 'dd2500' in ddr:
        print "dd2500"
        model = "dd2500"
    elif 'dd7200' in ddr:
        print "dd7200"
        model = "dd7200"
    elif 'jupiter' in ddr:
        print "dd9800"
        model = "dd9800"
    ddr = ddr.rstrip()
    ins=multiprocessing.Process(target=installation, args=(model,ddr,build))
    ins.start()

Basically iam trying to read the file which has the machine names and using multiprocessing, I want to insatll the OS on the machines which I have read.

Above is my code, when I run, it starts installing on all the machines at once and the main program terminates.

But I want the main program not to terminate, it has to wait until the child process finish the job, also return the output saying the child process job is complete.

Install make take anytime 1 hr or 2 hrs, but I want the message saying that all the process jobs are completed.

Can anyone please help here.

Sreekiran A R
  • 3,123
  • 2
  • 20
  • 41
Mohan
  • 59
  • 8

2 Answers2

1

Populate a list of processes and use join() to join them with the parent process and then print the message. This way, the parent waits till the children are done with their tasks before executing the lines that follow.

The code for the same should look something like this:

#!/usr/bin/python
import os
import multiprocessing
import subprocess
import time
import sys

from os import getpid

file1 = open('/auto/home/venkam11/python/install-script/build-ddr-file.txt', 'w+')
print ("enter the ddr names one by one in each line and press ctrl-d twice")
userInput = sys.stdin.readlines()
file1.writelines(userInput)
file1.close()
build = input("\nenter the build number : \n")
branch = raw_input("enter the branch name  : " )
file1 = open('/auto/home/venkam11/python/install-script/build-ddr-file.txt', 'r')

def installation(model, branch, ddr, build, shared_dict):
        cli = "/auto/tools/qa/shared/qa-branch/util/install.pl -durham -restart -silentinstall -model %s -branch %s %s %s"  %(model, branch, ddr, build)
        print cli
        print "installation has started on %s \n" % ddr
        time.sleep(20)
        try:
            subprocess.check_call(cli, shell=True)
            shared_dict[ddr] = True
        except subprocess.CalledProcessError:
            shared_dict[ddr] = False

if __name__ == '__main__':
    #pid=getpid()
    #print("parent process id : {}".format(getpid()))
    processes = []
    manager = multiprocessing.Manager()
    shared_dict = manager.dict()
    for ddr in file1:
        print ddr.rstrip()
        if 'dd4500' in ddr:
            print "dd4500"
            model = "dd4500"
        elif ('apollo' or 'apolloplus') in ddr:
            print "dd9500"
            model = "dd9500"
        elif 'dd2500' in ddr:
            print "dd2500"
            model = "dd2500"
        elif 'dd7200' in ddr:
            print "dd7200"
            model = "dd7200"
        elif 'jupiter' in ddr:
            print "dd9800"
            model = "dd9800"

        ddr = ddr.rstrip()
        ins = multiprocessing.Process(target=installation, args=(model, branch, ddr, build, shared_dict))
        ins.start()
        processes.append(ins)

    for process in processes:
        process.join()

    print('All the installations are complete')
    print('Details: ')
    for ddr, success in shared_dict.items():
        if success:
            print('Installation on {} successful'.format(ddr))
        else:
            print('Installation on {} unsuccessful'.format(ddr))
  • 1
    Hi Vignesh, It worked for me. I had used the steps which you had told, but not placed in the correct place. Thanks a lot for the help. – Mohan Feb 08 '19 at 10:52
  • Hi Vignesh, Also, is there a way to read the output of process, like installation log. So that I should read the log and check for the successful or fail message in the log and print as machine installation is successful or failed. – Mohan Feb 08 '19 at 11:09
  • As you said, you can write the status into a log file and read from it when exiting from the parent. But here, you'll have to write to the file from your perl script, the reading part can be done in your python script. – Vignesh Bayari R. Feb 08 '19 at 11:19
  • Or, as @holdenweb says, you can use `subprocess`, specifically, `check_call` to see if it executes successfully, if not, print failure message. – Vignesh Bayari R. Feb 08 '19 at 11:41
  • Hi Vignesh, It works but, installation on one machine may happen faster and other takes more time. So the problem is, as soon as the installation over, it displays the message as below [2019-02-08 08:11:58] DEBUG: Log file was saved to /tmp/install-dd4500-103-613719_16.log [2019-02-08 08:11:58] DEBUG: Closing console session [2019-02-08 08:11:58] DEBUG: Installation successful, returning exit code 0. Perl exited with active threads: 0 running and unjoined 1 finished and unjoined 0 running and detached installation on dd4500-103.datadomain.com successful – Mohan Feb 08 '19 at 17:46
  • but after the first machine install is complete, we get the message at that point and the installation monitor screen continues for the other machines. at last after last machine install completes, getting the following message 0 running and detached, installation on apollo208.datadomain.com unsuccessful! All the installations are complete. Problem here is, cant I see the output of install success or failure of all the machines at last, after all the machines install completes. At last iam seeing only, last machines message and all installations are complete message. – Mohan Feb 08 '19 at 17:49
  • Since they're separate processes, in the above code, you might have to write the message to a log file instead of printing it on the console. Later, after all the children are done executing, read the messages from the file and print them. – Vignesh Bayari R. Feb 09 '19 at 08:20
  • Instead of reading from file, there is no way to print all the process output at once ? Also Cant we hide the kernel messages that we see on console ? And see only install started message and install sucees or fail message – Mohan Feb 09 '19 at 08:40
  • Since they're running as separate processes, writing to a file is the approach I can think of. As for the console problem, from `subprocess` documentation, I see that stdout and stderr can be passed as arguments to the `check_call()` method. – Vignesh Bayari R. Feb 09 '19 at 08:46
  • @Mohan Apparently, `multiprocessing`'s `Manager` allows for the use of a shared dictionary between the processes, I've edited my code to make use of the same. With a shared `dict`, there is no need for logging messages and things like that. – Vignesh Bayari R. Feb 09 '19 at 09:17
0

Welcome to Stackoverflow. Much like threads, the easiest way to synchronise with your subprocesses is to join() them, most usually in the creating thread/process. The os.popen2 call was deprecated when the subprocess module was introduced, as it does not give the necessary degree of control over and communication with the started subprocess. For that you have correctly deduced you can use the multiprocessing module.

The technical answer to your question using multiprocessing is already covered well in another answer, as well as in this question, which explains how the calling entity can synchronise with its child processes. It's quite permissible to deal with an unknown number of subprocesses by storing each one in a list, for example, like this

for p in my_processes:
    p.join()

A more useful answer might be that the subprocess module allows creation and monitoring of other processes without the overhead and complexity of multiprocessing, which has advanced features for inter-process communication that you do not (yet) appear to need. Its documentation has quite good examples of how older and/or less appropriate Python code can be adapted to use the new module, so it could be worth a look.

holdenweb
  • 33,305
  • 7
  • 57
  • 77
  • Hi, thanks for the answer. I have another question. Also, is there a way to read the output of process, like installation log. So that I should read the log and check for the successful or fail message in the log and print as machine installation is successful or failed – Mohan Feb 08 '19 at 11:14
  • For that kind of thing you should definitely search for `subprocess` examples (there will be lots, many from stackoverflow, I imagine). But do look at the examples in the docs first, since there are many good ideas in there. – holdenweb Feb 08 '19 at 12:56
  • Hi, Thanks for the answer. I will go through the examples. – Mohan Feb 08 '19 at 17:54