Browse Source

roles/lib_openshift: Handle /usr/local/bin/oc with sudo

The real changes here are in `src/lib/{base,import}.py` remember, the rest is
committed to git rather than built for some reason.

This is tested on CentOS AH (python2), I haven't yet tested the Python 3 path
here. I tried the suggestion in the PR for using Ansible's `module` but AFAICS
that would require passing down the `module` variable pretty far down into this
code. This implementation seems OK too.

Closes: https://github.com/openshift/openshift-ansible/issues/3410
Colin Walters 8 years ago
parent
commit
4b8328fe94

+ 16 - 4
roles/lib_openshift/library/oadm_manage_node.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -963,10 +964,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -982,7 +991,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_edit.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -991,10 +992,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -1010,7 +1019,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_env.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -958,10 +959,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -977,7 +986,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_label.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -967,10 +968,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -986,7 +995,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_obj.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -970,10 +971,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -989,7 +998,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_process.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -959,10 +960,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -978,7 +987,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_route.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -1001,10 +1002,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -1020,7 +1029,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_scale.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -945,10 +946,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -964,7 +973,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_secret.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -991,10 +992,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -1010,7 +1019,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_service.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -997,10 +998,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -1016,7 +1025,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_serviceaccount.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -943,10 +944,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -962,7 +971,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_serviceaccount_secret.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -943,10 +944,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -962,7 +971,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 16 - 4
roles/lib_openshift/library/oc_version.py

@@ -36,6 +36,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess
@@ -915,10 +916,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -934,7 +943,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 15 - 4
roles/lib_openshift/src/lib/base.py

@@ -224,10 +224,18 @@ class OpenShiftCLI(object):
     def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
         '''Base command for oc '''
         cmds = []
-        if oadm:
-            cmds = ['oadm']
+        basecmd = 'oadm' if oadm else 'oc'
+        # https://github.com/openshift/openshift-ansible/issues/3410
+        # oc can be in /usr/local/bin in some cases, but that may not
+        # be in $PATH due to ansible/sudo
+        if sys.version_info[0] == 3:
+            basepath = shutil.which(basecmd) # pylint: disable=no-member
         else:
-            cmds = ['oc']
+            import distutils.spawn
+            basepath = distutils.spawn.find_executable(basecmd) # pylint: disable=no-name-in-module
+        if basepath is None and os.path.isfile('/usr/local/bin/' + basecmd):
+            basecmd = '/usr/local/bin/' + basecmd
+        cmds.append(basecmd)
 
         if self.all_namespaces:
             cmds.extend(['--all-namespaces'])
@@ -243,7 +251,10 @@ class OpenShiftCLI(object):
         if self.verbose:
             print(' '.join(cmds))
 
-        returncode, stdout, stderr = self._run(cmds, input_data)
+        try:
+            returncode, stdout, stderr = self._run(cmds, input_data)
+        except OSError as ex:
+            returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex)
 
         rval = {"returncode": returncode,
                 "results": results,

+ 1 - 0
roles/lib_openshift/src/lib/import.py

@@ -10,6 +10,7 @@ import atexit
 import copy
 import json
 import os
+import sys
 import re
 import shutil
 import subprocess