From a9ed692df973df0a114ed8aa5d4133d9d88cb334 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Wed, 19 Apr 2017 11:45:02 +0200 Subject: [PATCH 1/9] added .gitlab-ci.yml --- .gitlab-ci.yml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..75406ad4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,44 @@ +stages: + - test + - cleanup + +travis_ci_tests: + stage: test + script: + # ADAPT THIS VARIABLE TO YOUR PROJECT: + # Set here the location of the project folder inside the VM. + # This should be in the form /build// + - project_folder=/build/mkean/shifter + # create virtual machine + - cd .. + - rm -rf travis-for-gitlab-vm + - git clone https://madra.cscs.ch/mkean/travis-for-gitlab.git travis-for-gitlab-vm + - cd travis-for-gitlab-vm + - vagrant up + # convert .travis.yml to bash script + - vagrant ssh -c "cd $project_folder && printf 'y\\n' | travis lint" + - vagrant ssh -c "cd $project_folder && printf 'y\\n' | travis compile >travis.yml.sh" + - vagrant ssh -c "cd $project_folder && chmod 775 travis.yml.sh" + # modify travis bash script (remove python virtualenv, otherwise the tests executed as vagrant user + # would have a different environment from the tests executed as root) + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^if \\[\\[ ! -f ~\\/virtualenv/,/^fi/d'" + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/travis_cmd source\\\\ \\\\~\\/virtualenv/d'" + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e 's/travis_cmd pip\\\\ install/travis_cmd sudo\\\\ pip\\\\ install/'" + # modify travis bash script (dont't changedir, we will set the right working directory on our own) + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^mkdir -p \\\$HOME/,+1d'" + # modify travis bash script (get rid of git clone, checkout, etc. Gitlab has already taken care of + # creating a fresh checkout of the project to be tested. It is mounted under /build) + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^travis_fold start git.checkout/,/^travis_fold end/d'" + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^if \\[\\[ -f .gitmodules/,/^fi/d'" + # modify travis bash script (get rid of network reconfigurations) + - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^echo \"options rotate/,/^done/d'" + # execute travis bash script (all child processes are killed at the end of the execution, otherwise + # the ssh command could hang and never terminate. That happens if any child process keeps stdin, stdout or stderr open) + - vagrant ssh -c "cd $project_folder && ./travis.yml.sh; RET=\$?; ps -o pid,cmd -g \$\$ | sed 1d | grep -v -w ps | grep -v -e -bash | grep -v -w sed | grep -v -w awk | grep -v -w xargs | awk '{print \$1}' | xargs sudo kill -9; exit \$RET" + +delete_travis_vm: + stage: cleanup + script: + - cd ../travis-for-gitlab-vm && vagrant destroy -f + - rm -rf ../travis-for-gitlab-vm + when: always From 85ce436bf2cee8f34c9a36dcdbdec9b88d1f26f6 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Wed, 8 Mar 2017 09:31:46 +0100 Subject: [PATCH 2/9] ImageGW: increased sleep times to fix tests --- imagegw/test/imagemngr_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imagegw/test/imagemngr_test.py b/imagegw/test/imagemngr_test.py index c330303f..6db85cac 100644 --- a/imagegw/test/imagemngr_test.py +++ b/imagegw/test/imagemngr_test.py @@ -912,7 +912,7 @@ def test_expire_remote(self): er = {'system': system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er, testmode=1) # ,delay=False) assert rec is not None - time.sleep(2) + time.sleep(4) state = self.m.get_state(id) assert state == 'EXPIRED' assert os.path.exists(file) is False @@ -933,7 +933,7 @@ def test_expire_local(self): er = {'system': system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er) # ,delay=False) assert rec is not None - time.sleep(2) + time.sleep(4) state = self.m.get_state(id) assert state == 'EXPIRED' assert os.path.exists(file) is False @@ -952,7 +952,7 @@ def test_expire_noadmin(self): er = {'system': self.system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er, testmode=1) # ,delay=False) assert rec is not None - time.sleep(2) + time.sleep(4) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True @@ -1010,7 +1010,7 @@ def test_autoexpire_dontexpire(self): self.format) session = self.m.new_session(self.authadmin, self.system) self.m.autoexpire(session, self.system, testmode=1) # ,delay=False) - time.sleep(2) + time.sleep(4) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True @@ -1029,7 +1029,7 @@ def test_autoexpire_othersystem(self): self.format) session = self.m.new_session(self.authadmin, self.system) self.m.autoexpire(session, self.system, testmode=1) # ,delay=False) - time.sleep(2) + time.sleep(4) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True From aff831ab41b71b4a619e4e21cf548a797bee63f3 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Mon, 6 Mar 2017 13:51:03 +0100 Subject: [PATCH 3/9] Mount of siteFs: fixed mkdir I replaced mkdir with mkdir_p, which is equivalent to issuing the bash command "mkdir -p", i.e. creates parent directories if they don't exist yet. --- src/shifter_core.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/shifter_core.c b/src/shifter_core.c index a1ad10cb..dd7c7c82 100644 --- a/src/shifter_core.c +++ b/src/shifter_core.c @@ -1717,25 +1717,37 @@ int setupVolumeMapMounts( if (createToDev) { int okToMkdir = 0; + /* search the first existing parent folder and check that it is on the device + where we are authorized to create stuff */ char *ptr = strrchr(to_buffer, '/'); - if (ptr) { - /* get parent path of intended dir */ - *ptr = '\0'; - - /* if parent path is on the same device as is authorized by createToDev - then ok the mkdir operation */ - if (lstat(to_buffer, &statData) == 0) { - if (statData.st_dev == createToDev) { + *ptr = '\0'; + while (1) { + int parent_folder_exists = (lstat(to_buffer, &statData) == 0); + if (parent_folder_exists) { + int is_parent_folder_on_authorized_device = (statData.st_dev == createToDev); + if (is_parent_folder_on_authorized_device) { okToMkdir = 1; } + *ptr = '/'; + break; } - /* reset to target path */ - *ptr = '/'; + /* move to next parent folder */ + char *old_ptr = ptr; + ptr = strrchr(to_buffer, '/'); + *old_ptr = '/'; + *ptr = '\0'; + + int went_through_all_parent_folders = (ptr == to_buffer); + if(went_through_all_parent_folders) + { + *ptr = '/'; + break; + } } if (okToMkdir) { - mkdir(to_buffer, 0755); + mkdir_p(to_buffer, 0755); if (lstat(to_buffer, &statData) != 0) { fprintf(stderr, "FAILED to find volume \"to\": %s\n", to_buffer); From a3bb12e4c55b4f5d9bb1c4252c8f66e4d3f9272e Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Tue, 7 Mar 2017 15:18:08 +0100 Subject: [PATCH 4/9] bindImageIntoUDI: warn when image's file/folders are overridden --- src/shifter_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shifter_core.c b/src/shifter_core.c index dd7c7c82..797dd6a4 100644 --- a/src/shifter_core.c +++ b/src/shifter_core.c @@ -179,6 +179,11 @@ int bindImageIntoUDI( mntBuffer[PATH_MAX-1] = 0; if (lstat(mntBuffer, &statData) == 0) { /* exists in UDI, skip */ + fprintf(stderr, "WARNING: skipping mount of image's %s/%s. The file or directory already" + " exists in the container and will not be bind mounted from the image. This" + " could happen because the system administrator configured Shifter to create" + " or mount resources in the container whose path conflicts with the contents" + " of the image.\n", relpath, itemname); free(itemname); itemname = NULL; continue; From 1142f5a946aea71823430e789a02f2b331d71681 Mon Sep 17 00:00:00 2001 From: Alberto Madonna Date: Tue, 7 Mar 2017 15:48:23 +0100 Subject: [PATCH 5/9] Added warnings about siteFs effects on Sphinx documentation manual install page --- doc/install/manualinstallgpu.rst | 9 +++++++++ udiRoot.conf.example.in | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/install/manualinstallgpu.rst b/doc/install/manualinstallgpu.rst index da7a62ab..c0cda847 100644 --- a/doc/install/manualinstallgpu.rst +++ b/doc/install/manualinstallgpu.rst @@ -101,8 +101,17 @@ To illustrate the configuration process, consider the following parameters that * **autoLoadKernelModule=0** Flag to determine if kernel modules will be loaded by Shifter if required. This is limited to loop, squashfs, ext4 (and dependencies). *Recommend value 0* if kernel modules (loop, squashfs, and ext4) are already loaded as part of the node boot process, otherwise use *value 1* to let Shifter load the kernel modules. * **system=greina** The name of the computer cluster where shifter is deployed. It is **important for this to match the platform name in the json configuration file** for the Image Manager. * **imageGateway=http://greina9:5000** Space separated URLs for where the Image Gateway can be reached. +* **siteFs=/home;/scratch** Semicolon seperated list of paths to be automatically bind-mounted from the host system into the container. This is typically used to make network filesystems accessible within the container, but could be used to allow certain other facilities. * **siteResources=/opt/shifter/site-resources** Absolute path to where site-specific resources will be bind-mounted inside the container to enable features like native MPI or GPU support. This configuration only affects the container. The specified path will be automatically created inside the container. The specified path doesn't need to exist on the host. +.. warning:: + If a path specified in ``siteFs`` contains a parent directory that also exists in + the image, mount precedence will be given to the host path, and the resources + from the image will be skipped. + + For example: if ``/var/spool/alps`` is in ``siteFs``, and the image contains + ``/var/spool/``, the image directory will not be mounted. + Shifter Startup +++++++++++++++ diff --git a/udiRoot.conf.example.in b/udiRoot.conf.example.in index 5b7ce068..17f510d9 100644 --- a/udiRoot.conf.example.in +++ b/udiRoot.conf.example.in @@ -204,7 +204,7 @@ rootfsType=@ROOTFS_TYPE@ #siteFs # -# Semicolon seperated list of paths to be automatically bind-mounted into the +# Semicolon separated list of paths to be automatically bind-mounted into the # container. This is typically used to make network filesystems accessible # within the container, but could be used to allow certain other facilities, # like /var/run or /var/spool/alps to be accessible within the image (depending @@ -215,6 +215,13 @@ rootfsType=@ROOTFS_TYPE@ # # It is OK to perform this under /var or /opt or a novel path that your site # maintains (e.g., for NERSC, /global). +# +# **WARNING**: If a path on this list contains a parent directory that also exists in +# the image, mount precedence will be given to the host path specified here, and +# the resources from the image will be skipped. +# For example: if /var/spool/alps is in siteFs, and the image contains /var/spool/, +# the image directory will not be mounted. +# siteFs=/home:/home From f0fe805b64fcd6815ed22828adcf97a1fb495bfe Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Tue, 7 Mar 2017 17:12:42 +0100 Subject: [PATCH 6/9] bindImageIntoUDI: filtered some warnings about skipped mounts --- src/shifter_core.c | 41 ++++++++++++++++++++++++++++++++++------- src/utility.c | 25 +++++++++++++++++++++++++ src/utility.h | 1 + 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/shifter_core.c b/src/shifter_core.c index 797dd6a4..fe291025 100644 --- a/src/shifter_core.c +++ b/src/shifter_core.c @@ -174,16 +174,43 @@ int bindImageIntoUDI( continue; } - /* check to see if UDI version already exists */ + /* check to see if UDI version already exists, + * skip if UDI already contains the file or folder */ snprintf(mntBuffer, PATH_MAX, "%s/%s/%s", udiRoot, relpath, itemname); mntBuffer[PATH_MAX-1] = 0; if (lstat(mntBuffer, &statData) == 0) { - /* exists in UDI, skip */ - fprintf(stderr, "WARNING: skipping mount of image's %s/%s. The file or directory already" - " exists in the container and will not be bind mounted from the image. This" - " could happen because the system administrator configured Shifter to create" - " or mount resources in the container whose path conflicts with the contents" - " of the image.\n", relpath, itemname); + + /* print warning if we are skipping potentially important image's data */ + snprintf(srcBuffer, PATH_MAX, "%s/%s/%s", imgRoot, relpath, itemname); + srcBuffer[PATH_MAX-1] = 0; + char relBuffer[PATH_MAX]; + snprintf(relBuffer, PATH_MAX, "%s/%s", relpath, itemname); + relBuffer[PATH_MAX-1] = 0; + + int is_top_level_directory = strcmp(relpath, "/")==0 && is_existing_directory(srcBuffer); + if(!is_top_level_directory) { + int is_file = is_existing_file(srcBuffer) && !is_existing_directory(srcBuffer); + int is_non_empty_directory = (is_existing_directory(srcBuffer) + && !is_empty_directory(srcBuffer)); + // we consider fine to skip the following directories: + // - /etc: is specially handled somewhere else (recursive copy, instead of mount) + // - /var/run: we don't care about the old container's runtime data + // - /var/spool: we don't care about the old container's spool data + // - /var/tmp: we prefer the site's /var/tmp so we can create/modify data (image is read-only) + int has_important_parent_folder = (strncmp(relBuffer, "/etc", 4) != 0 + && strncmp(relBuffer, "/var/run", 8) != 0 + && strncmp(relBuffer, "/var/spool", 10) != 0 + && strncmp(relBuffer, "/var/tmp", 8) != 0); + if((is_file || is_non_empty_directory) && has_important_parent_folder) + { + fprintf(stderr, "WARNING: skipping mount of image's %s. The file or directory already" + " exists in the container and will not be bind mounted from the image. This" + " could happen because the system administrator configured Shifter to create" + " or mount resources in the container whose path conflicts with the contents" + " of the image.\n", relBuffer); + } + } + free(itemname); itemname = NULL; continue; diff --git a/src/utility.c b/src/utility.c index 2381272f..c464a328 100644 --- a/src/utility.c +++ b/src/utility.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "utility.h" @@ -532,3 +533,27 @@ int is_existing_directory(const char* path) { struct stat sb; return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode); } + +/** + * Returns 1 if the specified directory is empty. + */ +int is_empty_directory(const char* path) { + DIR *dir = opendir(path); + if(dir == NULL) { + return 1; + } + + struct dirent *entry = NULL; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + { + continue; + } + closedir(dir); + return 0; + } + + closedir(dir); + return 1; +} diff --git a/src/utility.h b/src/utility.h index c0df17e1..ea1f3609 100644 --- a/src/utility.h +++ b/src/utility.h @@ -66,6 +66,7 @@ char *userInputPathFilter(const char *input, int allowSlash); int mkdir_p(const char* path, mode_t mode); int is_existing_file(const char* path); int is_existing_directory(const char* path); +int is_empty_directory(const char* path); #ifdef __cplusplus } From 117bba567fe90f90479b71e1989af11705c4d4b4 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Wed, 8 Mar 2017 11:27:42 +0100 Subject: [PATCH 7/9] bindImageIntoUDI: cleaned filtering of warnings Made code cleaner. --- src/shifter_core.c | 51 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/shifter_core.c b/src/shifter_core.c index fe291025..df74bc04 100644 --- a/src/shifter_core.c +++ b/src/shifter_core.c @@ -184,31 +184,36 @@ int bindImageIntoUDI( snprintf(srcBuffer, PATH_MAX, "%s/%s/%s", imgRoot, relpath, itemname); srcBuffer[PATH_MAX-1] = 0; char relBuffer[PATH_MAX]; - snprintf(relBuffer, PATH_MAX, "%s/%s", relpath, itemname); + if(strcmp(relpath, "/") == 0) { + snprintf(relBuffer, PATH_MAX, "/%s", itemname); + } + else { + snprintf(relBuffer, PATH_MAX, "%s/%s", relpath, itemname); + } relBuffer[PATH_MAX-1] = 0; - int is_top_level_directory = strcmp(relpath, "/")==0 && is_existing_directory(srcBuffer); - if(!is_top_level_directory) { - int is_file = is_existing_file(srcBuffer) && !is_existing_directory(srcBuffer); - int is_non_empty_directory = (is_existing_directory(srcBuffer) - && !is_empty_directory(srcBuffer)); - // we consider fine to skip the following directories: - // - /etc: is specially handled somewhere else (recursive copy, instead of mount) - // - /var/run: we don't care about the old container's runtime data - // - /var/spool: we don't care about the old container's spool data - // - /var/tmp: we prefer the site's /var/tmp so we can create/modify data (image is read-only) - int has_important_parent_folder = (strncmp(relBuffer, "/etc", 4) != 0 - && strncmp(relBuffer, "/var/run", 8) != 0 - && strncmp(relBuffer, "/var/spool", 10) != 0 - && strncmp(relBuffer, "/var/tmp", 8) != 0); - if((is_file || is_non_empty_directory) && has_important_parent_folder) - { - fprintf(stderr, "WARNING: skipping mount of image's %s. The file or directory already" - " exists in the container and will not be bind mounted from the image. This" - " could happen because the system administrator configured Shifter to create" - " or mount resources in the container whose path conflicts with the contents" - " of the image.\n", relBuffer); - } + int is_file = is_existing_file(srcBuffer) && !is_existing_directory(srcBuffer); + int is_non_empty_directory = (is_existing_directory(srcBuffer) + && !is_empty_directory(srcBuffer)); + /* We consider not important, i.e. ok to skip, the following items: + * - /etc and children: /etc is specially handled (recursive copy to merge image's /etc with site /etc) + * - /var: is specially handled (this function is also explicitely called to mount the first-level contents of /var) + * - /var/run and children: we don't care about the old container's runtime data + * - /var/spool and children: we don't care about the old container's spool data + * - /var/tmp and children: we want the site's /var/tmp so we can create/modify data (image's /var/tmp is read-only) + */ + int is_important = (strncmp(relBuffer, "/etc", 4) != 0 + && strcmp(relBuffer, "/var") != 0 + && strncmp(relBuffer, "/var/run", 8) != 0 + && strncmp(relBuffer, "/var/spool", 10) != 0 + && strncmp(relBuffer, "/var/tmp", 8) != 0); + if((is_file || is_non_empty_directory) && is_important) + { + fprintf(stderr, "WARNING: skipping mount of image's %s. The file or directory already" + " exists in the container and will not be bind mounted from the image. This" + " could happen because the system administrator configured Shifter to create" + " or mount resources in the container whose path conflicts with the contents" + " of the image.\n", relBuffer); } free(itemname); From 9f6459e8c8b51931362498f39e2f3bdb5a8ad98e Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Fri, 28 Apr 2017 08:28:58 +0200 Subject: [PATCH 8/9] Revert "ImageGW: increased sleep times to fix tests" This reverts commit 450377241267a0c13c4fd3c2c9a625e7e3033565. --- imagegw/test/imagemngr_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imagegw/test/imagemngr_test.py b/imagegw/test/imagemngr_test.py index 6db85cac..c330303f 100644 --- a/imagegw/test/imagemngr_test.py +++ b/imagegw/test/imagemngr_test.py @@ -912,7 +912,7 @@ def test_expire_remote(self): er = {'system': system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er, testmode=1) # ,delay=False) assert rec is not None - time.sleep(4) + time.sleep(2) state = self.m.get_state(id) assert state == 'EXPIRED' assert os.path.exists(file) is False @@ -933,7 +933,7 @@ def test_expire_local(self): er = {'system': system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er) # ,delay=False) assert rec is not None - time.sleep(4) + time.sleep(2) state = self.m.get_state(id) assert state == 'EXPIRED' assert os.path.exists(file) is False @@ -952,7 +952,7 @@ def test_expire_noadmin(self): er = {'system': self.system, 'tag': self.tag, 'itype': self.itype} rec = self.m.expire(session, er, testmode=1) # ,delay=False) assert rec is not None - time.sleep(4) + time.sleep(2) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True @@ -1010,7 +1010,7 @@ def test_autoexpire_dontexpire(self): self.format) session = self.m.new_session(self.authadmin, self.system) self.m.autoexpire(session, self.system, testmode=1) # ,delay=False) - time.sleep(4) + time.sleep(2) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True @@ -1029,7 +1029,7 @@ def test_autoexpire_othersystem(self): self.format) session = self.m.new_session(self.authadmin, self.system) self.m.autoexpire(session, self.system, testmode=1) # ,delay=False) - time.sleep(4) + time.sleep(2) state = self.m.get_state(id) assert state == 'READY' assert os.path.exists(file) is True From 56715402fc7d91ff6fd87580e619ebfbd7c16553 Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Fri, 28 Apr 2017 08:16:29 +0200 Subject: [PATCH 9/9] removed .gitlab-ci.yml --- .gitlab-ci.yml | 44 -------------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 75406ad4..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,44 +0,0 @@ -stages: - - test - - cleanup - -travis_ci_tests: - stage: test - script: - # ADAPT THIS VARIABLE TO YOUR PROJECT: - # Set here the location of the project folder inside the VM. - # This should be in the form /build// - - project_folder=/build/mkean/shifter - # create virtual machine - - cd .. - - rm -rf travis-for-gitlab-vm - - git clone https://madra.cscs.ch/mkean/travis-for-gitlab.git travis-for-gitlab-vm - - cd travis-for-gitlab-vm - - vagrant up - # convert .travis.yml to bash script - - vagrant ssh -c "cd $project_folder && printf 'y\\n' | travis lint" - - vagrant ssh -c "cd $project_folder && printf 'y\\n' | travis compile >travis.yml.sh" - - vagrant ssh -c "cd $project_folder && chmod 775 travis.yml.sh" - # modify travis bash script (remove python virtualenv, otherwise the tests executed as vagrant user - # would have a different environment from the tests executed as root) - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^if \\[\\[ ! -f ~\\/virtualenv/,/^fi/d'" - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/travis_cmd source\\\\ \\\\~\\/virtualenv/d'" - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e 's/travis_cmd pip\\\\ install/travis_cmd sudo\\\\ pip\\\\ install/'" - # modify travis bash script (dont't changedir, we will set the right working directory on our own) - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^mkdir -p \\\$HOME/,+1d'" - # modify travis bash script (get rid of git clone, checkout, etc. Gitlab has already taken care of - # creating a fresh checkout of the project to be tested. It is mounted under /build) - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^travis_fold start git.checkout/,/^travis_fold end/d'" - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^if \\[\\[ -f .gitmodules/,/^fi/d'" - # modify travis bash script (get rid of network reconfigurations) - - vagrant ssh -c "sed -i $project_folder/travis.yml.sh -e '/^echo \"options rotate/,/^done/d'" - # execute travis bash script (all child processes are killed at the end of the execution, otherwise - # the ssh command could hang and never terminate. That happens if any child process keeps stdin, stdout or stderr open) - - vagrant ssh -c "cd $project_folder && ./travis.yml.sh; RET=\$?; ps -o pid,cmd -g \$\$ | sed 1d | grep -v -w ps | grep -v -e -bash | grep -v -w sed | grep -v -w awk | grep -v -w xargs | awk '{print \$1}' | xargs sudo kill -9; exit \$RET" - -delete_travis_vm: - stage: cleanup - script: - - cd ../travis-for-gitlab-vm && vagrant destroy -f - - rm -rf ../travis-for-gitlab-vm - when: always