diff --git a/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb b/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb index aba91a1c5146a91959576589f5e943a001d81ca6..1813da2d51d4097ef6ae2b5e8f6ebd22a3a636a5 100644 --- a/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb +++ b/ee/lib/remote_development/workspace_operations/create/project_cloner_component_injector.rb @@ -24,6 +24,7 @@ def self.inject(context) settings => { project_cloner_image: String => image, } + project_cloning_successful_file = "#{volume_path}/.gl_project_cloning_successful" # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/408448 # replace the alpine/git docker image with one that is published by gitlab for security / reliability @@ -31,17 +32,37 @@ def self.inject(context) clone_dir = "#{volume_path}/#{project.path}" project_url = project.http_url_to_repo - # The project is cloned only if one doesn't exist already. - # This done to avoid resetting user's modifications to the workspace. - # After cloning the project, set the user's git configuration - name and email. - # The name and email are read from environment variable because we do not want to - # store PII in the processed devfile in the database. - # The environment variables are injected into the gl-cloner-injector container component - # when the Kubernetes resources are generated. + # The project should be cloned only if one is not cloned successfully already. + # This is required to avoid resetting user's modifications to the files. + # This is achieved by checking for the existence of a file before cloning. + # If the file does not exist, clone the project. + # To accommodate for scenarios where the project cloning failed midway in the previous attempt, + # remove the directory before cloning. + # Once cloning is successful, create the file which is used in the check above. + # This will ensure the project is not cloned again on restarts. container_args = <<~SH.chomp - if [ ! -d '#{clone_dir}' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; then - git clone --branch #{Shellwords.shellescape(devfile_ref)} #{Shellwords.shellescape(project_url)} #{Shellwords.shellescape(clone_dir)}; + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "#{Shellwords.shellescape(clone_dir)}" ]; + then + echo "Removing unsuccessfully cloned project directory"; + rm -rf "#{Shellwords.shellescape(clone_dir)}"; + fi + echo "Cloning project"; + git clone --branch "#{Shellwords.shellescape(devfile_ref)}" "#{Shellwords.shellescape(project_url)}" "#{Shellwords.shellescape(clone_dir)}"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi SH @@ -56,6 +77,12 @@ def self.inject(context) # command has been overridden here as the default command in the alpine/git # container invokes git directly 'command' => %w[/bin/sh -c], + 'env' => [ + { + 'name' => 'GL_PROJECT_CLONING_SUCCESSFUL_FILE', + 'value' => project_cloning_successful_file + } + ], 'memoryLimit' => '512Mi', 'memoryRequest' => '256Mi', 'cpuLimit' => '500m', diff --git a/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml b/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml index aa811ef69bf13bc470471a8ffbebe5671c6cb520..2da26d74745943c2ff6053eab34679088680476c 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml @@ -76,11 +76,33 @@ components: volumeMounts: - name: gl-workspace-data path: "/projects" + env: + - name: GL_PROJECT_CLONING_SUCCESSFUL_FILE + value: "/projects/.gl_project_cloning_successful" args: - |- - if [ ! -d '/projects/test-project' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; + then + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "/projects/test-project" ]; then - git clone --branch master http://localhost/test-group/test-project.git /projects/test-project; + echo "Removing unsuccessfully cloned project directory"; + rm -rf "/projects/test-project"; + fi + echo "Cloning project"; + git clone --branch "master" "http://localhost/test-group/test-project.git" "/projects/test-project"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi command: - "/bin/sh" diff --git a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml index aa811ef69bf13bc470471a8ffbebe5671c6cb520..2da26d74745943c2ff6053eab34679088680476c 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml @@ -76,11 +76,33 @@ components: volumeMounts: - name: gl-workspace-data path: "/projects" + env: + - name: GL_PROJECT_CLONING_SUCCESSFUL_FILE + value: "/projects/.gl_project_cloning_successful" args: - |- - if [ ! -d '/projects/test-project' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; + then + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "/projects/test-project" ]; then - git clone --branch master http://localhost/test-group/test-project.git /projects/test-project; + echo "Removing unsuccessfully cloned project directory"; + rm -rf "/projects/test-project"; + fi + echo "Cloning project"; + git clone --branch "master" "http://localhost/test-group/test-project.git" "/projects/test-project"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi command: - "/bin/sh" diff --git a/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml b/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml index f2a45bcab47522e794406744ac92193c6d9dd8eb..4c4fe5f155207431227547c1984a4d356a524d1d 100644 --- a/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-marketplace-disabled-devfile.yaml @@ -68,11 +68,33 @@ components: volumeMounts: - name: gl-workspace-data path: "/projects" + env: + - name: GL_PROJECT_CLONING_SUCCESSFUL_FILE + value: "/projects/.gl_project_cloning_successful" args: - |- - if [ ! -d '/projects/test-project' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; + then + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "/projects/test-project" ]; then - git clone --branch master http://localhost/test-group/test-project.git /projects/test-project; + echo "Removing unsuccessfully cloned project directory"; + rm -rf "/projects/test-project"; + fi + echo "Cloning project"; + git clone --branch "master" "http://localhost/test-group/test-project.git" "/projects/test-project"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi command: - "/bin/sh" diff --git a/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml b/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml index 38f8945db24dcd7bfc17005713c4a98a42d67edb..5bc3995b2ea4a0c71f8419d3c977c1b83de61018 100644 --- a/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml @@ -64,11 +64,33 @@ components: - name: gl-cloner-injector container: image: alpine/git:2.45.2 + env: + - name: GL_PROJECT_CLONING_SUCCESSFUL_FILE + value: "/projects/.gl_project_cloning_successful" args: - |- - if [ ! -d '/projects/test-project' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; + then + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "/projects/test-project" ]; then - git clone --branch master http://localhost/test-group/test-project.git /projects/test-project; + echo "Removing unsuccessfully cloned project directory"; + rm -rf "/projects/test-project"; + fi + echo "Cloning project"; + git clone --branch "master" "http://localhost/test-group/test-project.git" "/projects/test-project"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi command: - "/bin/sh" diff --git a/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb b/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb index ee0ece47be943df5d863307834b6ce7e43aa9058..41145554ed69e8760e41676950064751720bc7e4 100644 --- a/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb +++ b/ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb @@ -747,14 +747,37 @@ def workspace_deployment( { args: [ <<~ARGS.chomp - if [ ! -d '/projects/test-project' ]; + if [ -f "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}" ]; then - git clone --branch master #{root_url}test-group/test-project.git /projects/test-project; + echo "Project cloning was already successful"; + exit 0; + fi + if [ -d "/projects/test-project" ]; + then + echo "Removing unsuccessfully cloned project directory"; + rm -rf "/projects/test-project"; + fi + echo "Cloning project"; + git clone --branch "master" "#{root_url}test-group/test-project.git" "/projects/test-project"; + exit_code=$? + if [ "${exit_code}" -eq 0 ]; + then + echo "Project cloning successful"; + touch "${GL_PROJECT_CLONING_SUCCESSFUL_FILE}"; + echo "Updated file to indicate successful project cloning"; + exit 0; + else + echo "Project cloning failed with exit code: ${exit_code}"; + exit "${exit_code}"; fi ARGS ], command: %w[/bin/sh -c], env: [ + { + name: "GL_PROJECT_CLONING_SUCCESSFUL_FILE", + value: "/projects/.gl_project_cloning_successful" + }, { name: "PROJECTS_ROOT", value: "/projects"