diff --git a/ee/lib/remote_development/workspaces/create/editor_component_injector.rb b/ee/lib/remote_development/workspaces/create/editor_component_injector.rb index bd2517266e29f41d76490c26127471a9cdbba06e..6a0f85ca01583bb1181ccd3f2ae9f26dee429cf6 100644 --- a/ee/lib/remote_development/workspaces/create/editor_component_injector.rb +++ b/ee/lib/remote_development/workspaces/create/editor_component_injector.rb @@ -15,10 +15,7 @@ def self.inject(value) # params: Hash => params # NOTE: Params is currently unused until we use the editor entry } volume_mounts => { data_volume: Hash => data_volume } - data_volume => { - name: String => volume_name, - path: String => volume_path, - } + data_volume => { path: String => volume_path } # NOTE: Editor is currently unused # editor = params[:editor] @@ -27,19 +24,18 @@ def self.inject(value) ssh_port = 60022 editor_component = processed_devfile['components'].find { |c| c.dig('attributes', 'gl/inject-editor') } - override_main_container(editor_component, volume_name, volume_path, editor_port, ssh_port) if editor_component - inject_editor_component(processed_devfile, volume_name, volume_path) + override_main_container(editor_component, volume_path, editor_port, ssh_port) if editor_component + inject_editor_component(processed_devfile, volume_path) value end # @param [Hash] component - # @param [String] volume_name # @param [String] volume_path # @param [Integer] editor_port # @param [Integer] ssh_port # @return [Hash] - def self.override_main_container(component, volume_name, volume_path, editor_port, ssh_port) + def self.override_main_container(component, volume_path, editor_port, ssh_port) # This overrides the main container's command # Open issue to support both starting the editor and running the default command: # https://gitlab.com/gitlab-org/gitlab/-/issues/392853 @@ -55,13 +51,7 @@ def self.override_main_container(component, volume_name, volume_path, editor_por SH component['container']['command'] = %w[/bin/sh -c] component['container']['args'] = [container_args] - - component['container']['volumeMounts'] = [] if component['container']['volumeMounts'].nil? - - component['container']['volumeMounts'] += [{ 'name' => volume_name, 'path' => volume_path }] - component['container']['env'] = [] if component['container']['env'].nil? - component['container']['env'] += [ { 'name' => 'GL_EDITOR_VOLUME_DIR', @@ -82,7 +72,6 @@ def self.override_main_container(component, volume_name, volume_path, editor_por ] component['container']['endpoints'] = [] if component['container']['endpoints'].nil? - component['container']['endpoints'].append( { 'name' => 'editor-server', @@ -102,11 +91,10 @@ def self.override_main_container(component, volume_name, volume_path, editor_por end # @param [Hash] processed_devfile - # @param [String] volume_name # @param [String] volume_path # @return [Array] - def self.inject_editor_component(processed_devfile, volume_name, volume_path) - processed_devfile['components'] += editor_components(volume_name, volume_path) + def self.inject_editor_component(processed_devfile, volume_path) + processed_devfile['components'] += editor_components(volume_path) processed_devfile['commands'] = [] if processed_devfile['commands'].nil? processed_devfile['commands'] += [{ @@ -121,10 +109,9 @@ def self.inject_editor_component(processed_devfile, volume_name, volume_path) processed_devfile['events']['preStart'] += ['gl-editor-injector-command'] end - # @param [String] volume_name # @param [String] volume_path # @return [Array] - def self.editor_components(volume_name, volume_path) + def self.editor_components(volume_path) # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/409775 - choose image based on which editor is passed. image_name = 'registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/web-ide-injector' image_tag = '5' @@ -134,7 +121,6 @@ def self.editor_components(volume_name, volume_path) 'name' => 'gl-editor-injector', 'container' => { 'image' => "#{image_name}:#{image_tag}", - 'volumeMounts' => [{ 'name' => volume_name, 'path' => volume_path }], 'env' => [ { 'name' => 'GL_EDITOR_VOLUME_DIR', diff --git a/ee/lib/remote_development/workspaces/create/main.rb b/ee/lib/remote_development/workspaces/create/main.rb index 89d7f33a985428af91f7695c0751d5efcdbf7076..d499a4525557c969d1f2f8bce9f1d9626e02cb48 100644 --- a/ee/lib/remote_development/workspaces/create/main.rb +++ b/ee/lib/remote_development/workspaces/create/main.rb @@ -23,9 +23,9 @@ def self.main(value) .and_then(DevfileFlattener.method(:flatten)) .and_then(PostFlattenDevfileValidator.method(:validate)) .map(VolumeDefiner.method(:define)) - .map(VolumeComponentInjector.method(:inject)) .map(EditorComponentInjector.method(:inject)) .map(ProjectClonerComponentInjector.method(:inject)) + .map(VolumeComponentInjector.method(:inject)) .and_then(Creator.method(:create)) # rubocop:disable Lint/DuplicateBranch -- Rubocop doesn't know the branches are different due to destructuring diff --git a/ee/lib/remote_development/workspaces/create/project_cloner_component_injector.rb b/ee/lib/remote_development/workspaces/create/project_cloner_component_injector.rb index 0554d563b3eda6314eaa6d7c6ec823a98c2c4198..36b4f11bce16a18d9f7a84298a122a2e1f372d8e 100644 --- a/ee/lib/remote_development/workspaces/create/project_cloner_component_injector.rb +++ b/ee/lib/remote_development/workspaces/create/project_cloner_component_injector.rb @@ -15,12 +15,8 @@ def self.inject(value) params: Hash => params } volume_mounts => { data_volume: Hash => data_volume } - data_volume => { - name: String => volume_name, - path: String => volume_path, - } - - params => {project: Project => project} + data_volume => { path: String => volume_path } + params => { project: Project => project } # 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 @@ -52,7 +48,6 @@ def self.inject(value) 'name' => 'gl-cloner-injector', 'container' => { 'image' => "#{image_name}:#{image_tag}", - 'volumeMounts' => [{ 'name' => volume_name, 'path' => volume_path }], 'args' => [container_args], # command has been overridden here as the default command in the alpine/git # container invokes git directly diff --git a/ee/lib/remote_development/workspaces/create/volume_component_injector.rb b/ee/lib/remote_development/workspaces/create/volume_component_injector.rb index 2d54aad5c678c3455e44a32498035b1161277906..9ebebeb02acfaa6ccca9bd9f7dcf7c4c0f40e8ce 100644 --- a/ee/lib/remote_development/workspaces/create/volume_component_injector.rb +++ b/ee/lib/remote_development/workspaces/create/volume_component_injector.rb @@ -11,16 +11,25 @@ class VolumeComponentInjector def self.inject(value) value => { processed_devfile: Hash => processed_devfile, volume_mounts: Hash => volume_mounts } volume_mounts => { data_volume: Hash => data_volume } - data_volume => { name: String => volume_name } + data_volume => { + name: String => volume_name, + path: String => volume_path, + } - component = { + volume_component = { 'name' => volume_name, 'volume' => { 'size' => '15Gi' } } - processed_devfile['components'] << component + processed_devfile['components'] << volume_component + processed_devfile['components'].each do |component| + next if component['container'].nil? + + component['container']['volumeMounts'] = [] if component['container']['volumeMounts'].nil? + component['container']['volumeMounts'] += [{ 'name' => volume_name, 'path' => volume_path }] + end value end diff --git a/ee/spec/fixtures/remote_development/example.devfile.yaml b/ee/spec/fixtures/remote_development/example.devfile.yaml index b0b397aef5458a97acac74eef849c7f4f95ebbd0..cae2fcd1d74330ef65db39dac570337b3be93ff3 100644 --- a/ee/spec/fixtures/remote_development/example.devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.devfile.yaml @@ -6,3 +6,10 @@ components: gl/inject-editor: true container: image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo + - name: database-container + container: + image: mysql + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + diff --git a/ee/spec/fixtures/remote_development/example.editor-injected-devfile.yaml b/ee/spec/fixtures/remote_development/example.editor-injected-devfile.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e3790a3f15c490ea64bd66e09bf50df33a0f0350 --- /dev/null +++ b/ee/spec/fixtures/remote_development/example.editor-injected-devfile.yaml @@ -0,0 +1,68 @@ +--- +schemaVersion: 2.2.0 +metadata: {} +components: + - name: tooling-container + attributes: + gl/inject-editor: true + container: + image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo + args: + - |- + sshd_path=$(which sshd) + if [ -x "$sshd_path" ]; then + echo "Starting sshd on port ${GL_SSH_PORT}" + $sshd_path -D -p $GL_SSH_PORT & + else + echo "'sshd' not found in path. Not starting SSH server." + fi + /projects/.gl-editor/start_server.sh + command: + - "/bin/sh" + - "-c" + env: + - name: GL_EDITOR_VOLUME_DIR + value: "/projects/.gl-editor" + - name: GL_EDITOR_LOG_LEVEL + value: "info" + - name: GL_EDITOR_PORT + value: "60001" + - name: GL_SSH_PORT + value: "60022" + endpoints: + - name: editor-server + targetPort: 60001 + exposure: public + secure: true + protocol: https + - name: ssh-server + targetPort: 60022 + exposure: internal + secure: true + dedicatedPod: false + mountSources: true + - name: database-container + container: + image: mysql + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + dedicatedPod: false + mountSources: true + - name: gl-editor-injector + container: + image: registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/web-ide-injector:5 + env: + - name: GL_EDITOR_VOLUME_DIR + value: "/projects/.gl-editor" + memoryLimit: 256Mi + memoryRequest: 128Mi + cpuLimit: 500m + cpuRequest: 100m +events: + preStart: + - gl-editor-injector-command +commands: + - id: gl-editor-injector-command + apply: + component: gl-editor-injector diff --git a/ee/spec/fixtures/remote_development/example.flattened-devfile.yaml b/ee/spec/fixtures/remote_development/example.flattened-devfile.yaml index 4b8559d875a2fca02d0ed6076c1f52fe465382cd..397a5b7e9be0bd0e2321a5d9ce608ffe4fba6e44 100644 --- a/ee/spec/fixtures/remote_development/example.flattened-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.flattened-devfile.yaml @@ -9,3 +9,11 @@ components: dedicatedPod: false mountSources: true image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo + - name: database-container + container: + dedicatedPod: false + mountSources: true + image: mysql + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" 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 7c9d5684eac056013bccd7433fd08208a512d59e..b3cef27da8d6e09de356e9a8455baf5dc5a6d5d3 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile-v2.yaml @@ -44,9 +44,17 @@ components: secure: true dedicatedPod: false mountSources: true - - name: gl-workspace-data - volume: - size: 15Gi + - name: database-container + container: + image: mysql + volumeMounts: + - name: gl-workspace-data + path: /projects + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + dedicatedPod: false + mountSources: true - name: gl-editor-injector container: image: registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/web-ide-injector:5 @@ -79,6 +87,9 @@ components: memoryRequest: 128Mi cpuLimit: 500m cpuRequest: 100m + - name: gl-workspace-data + volume: + size: 15Gi events: preStart: - gl-editor-injector-command diff --git a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml index 7c9d5684eac056013bccd7433fd08208a512d59e..b3cef27da8d6e09de356e9a8455baf5dc5a6d5d3 100644 --- a/ee/spec/fixtures/remote_development/example.processed-devfile.yaml +++ b/ee/spec/fixtures/remote_development/example.processed-devfile.yaml @@ -44,9 +44,17 @@ components: secure: true dedicatedPod: false mountSources: true - - name: gl-workspace-data - volume: - size: 15Gi + - name: database-container + container: + image: mysql + volumeMounts: + - name: gl-workspace-data + path: /projects + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + dedicatedPod: false + mountSources: true - name: gl-editor-injector container: image: registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/web-ide-injector:5 @@ -79,6 +87,9 @@ components: memoryRequest: 128Mi cpuLimit: 500m cpuRequest: 100m + - name: gl-workspace-data + volume: + size: 15Gi events: preStart: - gl-editor-injector-command 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 new file mode 100644 index 0000000000000000000000000000000000000000..b31fe434fe76d93f18cdee0e2f16acba01afe6f6 --- /dev/null +++ b/ee/spec/fixtures/remote_development/example.project-cloner-injected-devfile.yaml @@ -0,0 +1,88 @@ +--- +schemaVersion: 2.2.0 +metadata: {} +components: + - name: tooling-container + attributes: + gl/inject-editor: true + container: + image: quay.io/mloriedo/universal-developer-image:ubi8-dw-demo + args: + - |- + sshd_path=$(which sshd) + if [ -x "$sshd_path" ]; then + echo "Starting sshd on port ${GL_SSH_PORT}" + $sshd_path -D -p $GL_SSH_PORT & + else + echo "'sshd' not found in path. Not starting SSH server." + fi + /projects/.gl-editor/start_server.sh + command: + - "/bin/sh" + - "-c" + env: + - name: GL_EDITOR_VOLUME_DIR + value: "/projects/.gl-editor" + - name: GL_EDITOR_LOG_LEVEL + value: "info" + - name: GL_EDITOR_PORT + value: "60001" + - name: GL_SSH_PORT + value: "60022" + endpoints: + - name: editor-server + targetPort: 60001 + exposure: public + secure: true + protocol: https + - name: ssh-server + targetPort: 60022 + exposure: internal + secure: true + dedicatedPod: false + mountSources: true + - name: database-container + container: + image: mysql + env: + - name: MYSQL_ROOT_PASSWORD + value: "my-secret-pw" + dedicatedPod: false + mountSources: true + - name: gl-editor-injector + container: + image: registry.gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork/web-ide-injector:5 + env: + - name: GL_EDITOR_VOLUME_DIR + value: "/projects/.gl-editor" + memoryLimit: 256Mi + memoryRequest: 128Mi + cpuLimit: 500m + cpuRequest: 100m + - name: gl-cloner-injector + container: + image: alpine/git:2.36.3 + args: + - |- + if [ ! -d '/projects/test-project' ]; + then + git clone --branch master http://localhost/test-group/test-project.git /projects/test-project; + fi + command: + - "/bin/sh" + - "-c" + memoryLimit: 256Mi + memoryRequest: 128Mi + cpuLimit: 500m + cpuRequest: 100m +events: + preStart: + - gl-editor-injector-command + - gl-cloner-injector-command +commands: + - id: gl-editor-injector-command + apply: + component: gl-editor-injector + - id: gl-cloner-injector-command + apply: + component: gl-cloner-injector diff --git a/ee/spec/lib/remote_development/workspaces/create/editor_component_injector_spec.rb b/ee/spec/lib/remote_development/workspaces/create/editor_component_injector_spec.rb index 4789696632fc61034b8b286fe7160ed80f6ba725..c5466c4e242557407c8dcf5768119169f3bbe754 100644 --- a/ee/spec/lib/remote_development/workspaces/create/editor_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspaces/create/editor_component_injector_spec.rb @@ -5,20 +5,19 @@ RSpec.describe RemoteDevelopment::Workspaces::Create::EditorComponentInjector, feature_category: :remote_development do include_context 'with remote development shared fixtures' - let(:flattened_devfile_name) { 'example.flattened-devfile.yaml' } - let(:processed_devfile) { YAML.safe_load(read_devfile(flattened_devfile_name)).to_h } - let(:expected_processed_devfile) { YAML.safe_load(example_processed_devfile) } - let(:component_name) { "gl-editor-injector" } - let(:volume_name) { "gl-workspace-data" } + let(:agent) { create(:ee_cluster_agent, :with_remote_development_agent_config) } + let(:input_processed_devfile_name) { 'example.flattened-devfile.yaml' } + let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } + let(:expected_processed_devfile_name) { 'example.editor-injected-devfile.yaml' } + let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } let(:value) do { params: { editor: "editor" # NOTE: Currently unused }, - processed_devfile: processed_devfile, + processed_devfile: input_processed_devfile, volume_mounts: { data_volume: { - name: volume_name, path: "/projects" } } @@ -30,12 +29,6 @@ end it "injects the editor injector component" do - components = returned_value.dig(:processed_devfile, "components") - editor_injector_component = components.find { |component| component.fetch("name") == component_name } - processed_devfile_components = expected_processed_devfile.fetch("components") - expected_volume_component = processed_devfile_components.find do |component| - component.fetch("name") == component_name - end - expect(editor_injector_component).to eq(expected_volume_component) + expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) end end diff --git a/ee/spec/lib/remote_development/workspaces/create/project_cloner_component_injector_spec.rb b/ee/spec/lib/remote_development/workspaces/create/project_cloner_component_injector_spec.rb index 7362e23a9e88c12c36d740899b07f67d3f9af92c..6edc8a8c12878ae0d6cd460de021626d5ae0cb6f 100644 --- a/ee/spec/lib/remote_development/workspaces/create/project_cloner_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspaces/create/project_cloner_component_injector_spec.rb @@ -10,20 +10,19 @@ create(:project, :in_group, :repository, path: "test-project", namespace: group) end - let(:flattened_devfile_name) { 'example.flattened-devfile.yaml' } - let(:processed_devfile) { YAML.safe_load(read_devfile(flattened_devfile_name)) } - let(:expected_processed_devfile) { YAML.safe_load(example_processed_devfile) } + let(:input_processed_devfile_name) { 'example.editor-injected-devfile.yaml' } + let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } + let(:expected_processed_devfile_name) { 'example.project-cloner-injected-devfile.yaml' } + let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } let(:component_name) { "gl-cloner-injector" } - let(:volume_name) { "gl-workspace-data" } let(:value) do { params: { project: project }, - processed_devfile: processed_devfile, + processed_devfile: input_processed_devfile, volume_mounts: { data_volume: { - name: volume_name, path: "/projects" } } @@ -35,12 +34,6 @@ end it "injects the project cloner component" do - components = returned_value.dig(:processed_devfile, "components") - project_cloner_component = components.find { |component| component.fetch("name") == component_name } - expected_components = expected_processed_devfile.fetch("components") - expected_volume_component = expected_components.find do |component| - component.fetch("name") == component_name - end - expect(project_cloner_component).to eq(expected_volume_component) + expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) end end diff --git a/ee/spec/lib/remote_development/workspaces/create/volume_component_injector_spec.rb b/ee/spec/lib/remote_development/workspaces/create/volume_component_injector_spec.rb index 442ecfd894e3727595cdadcdb650d9b9e1242f88..eff3e5dce3717c53843787cab401154f0965eab9 100644 --- a/ee/spec/lib/remote_development/workspaces/create/volume_component_injector_spec.rb +++ b/ee/spec/lib/remote_development/workspaces/create/volume_component_injector_spec.rb @@ -5,14 +5,15 @@ RSpec.describe RemoteDevelopment::Workspaces::Create::VolumeComponentInjector, feature_category: :remote_development do include_context 'with remote development shared fixtures' - let(:flattened_devfile_name) { 'example.flattened-devfile.yaml' } - let(:processed_devfile) { YAML.safe_load(read_devfile(flattened_devfile_name)).to_h } - let(:expected_processed_devfile) { YAML.safe_load(example_processed_devfile) } + let(:input_processed_devfile_name) { 'example.project-cloner-injected-devfile.yaml' } + let(:input_processed_devfile) { YAML.safe_load(read_devfile(input_processed_devfile_name)).to_h } + let(:expected_processed_devfile_name) { 'example.processed-devfile.yaml' } + let(:expected_processed_devfile) { YAML.safe_load(read_devfile(expected_processed_devfile_name)).to_h } let(:component_name) { "gl-workspace-data" } let(:volume_name) { "gl-workspace-data" } let(:value) do { - processed_devfile: processed_devfile, + processed_devfile: input_processed_devfile, volume_mounts: { data_volume: { name: volume_name, @@ -27,12 +28,6 @@ end it "injects the workspace volume component" do - components = returned_value.dig(:processed_devfile, "components") - volume_component = components.find { |component| component.fetch("name") == component_name } - expected_components = expected_processed_devfile.fetch("components") - expected_volume_component = expected_components.find do |component| - component.fetch("name") == component_name - end - expect(volume_component).to eq(expected_volume_component) + expect(returned_value[:processed_devfile]).to eq(expected_processed_devfile) end end 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 6b52e536a9880cf9f15e654da297a98107af4716..b974a278e7609adf976c28ece0a426c38746e4d1 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 @@ -666,6 +666,49 @@ def workspace_deployment( } } ] + }, + { + env: [ + { + name: "MYSQL_ROOT_PASSWORD", + value: "my-secret-pw" + }, + { + name: "PROJECTS_ROOT", + value: "/projects" + }, + { + name: "PROJECT_SOURCE", + value: "/projects" + } + ], + image: "mysql", + imagePullPolicy: "Always", + name: "database-container", + resources: default_resources_per_workspace_container, + volumeMounts: [ + { + mountPath: "/projects", + name: "gl-workspace-data" + }, + { + name: "gl-workspace-variables", + mountPath: variables_file_mount_path.to_s + } + ], + securityContext: { + allowPrivilegeEscalation: false, + privileged: false, + runAsNonRoot: true, + runAsUser: 5001 + }, + envFrom: [ + { + secretRef: { + name: "#{workspace_name}-env-var" + } + } + ] } ], initContainers: [