diff --git a/.gitpod.yml b/.gitpod.yml index 1a8a8e8555e..d83e5ff3e61 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -7,6 +7,7 @@ tasks: - init: | echo "$(date) – Copying GDK" | tee -a /workspace/startup.log + rm -r /workspace/.rvm mv $HOME/.rvm-workspace /workspace/.rvm cp -r $HOME/gitlab-development-kit /workspace/ ( diff --git a/Gemfile b/Gemfile index 213e5a86130..ff47974edc2 100644 --- a/Gemfile +++ b/Gemfile @@ -411,7 +411,7 @@ end group :test do gem 'fuubar', '~> 2.2.0' gem 'rspec-retry', '~> 0.6.1' - gem 'rspec_profiling', '~> 0.0.5' + gem 'rspec_profiling', '~> 0.0.6' gem 'rspec-parameterized', require: false gem 'capybara', '~> 3.33.0' diff --git a/Gemfile.lock b/Gemfile.lock index 027957f3471..21c36eb4c23 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1009,7 +1009,7 @@ GEM rspec-support (3.9.2) rspec_junit_formatter (0.4.1) rspec-core (>= 2, < 4, != 2.12.0) - rspec_profiling (0.0.5) + rspec_profiling (0.0.6) activerecord pg rails @@ -1467,7 +1467,7 @@ DEPENDENCIES rspec-rails (~> 4.0.0) rspec-retry (~> 0.6.1) rspec_junit_formatter - rspec_profiling (~> 0.0.5) + rspec_profiling (~> 0.0.6) rubocop (~> 0.82.0) rubocop-performance (~> 1.5.2) rubocop-rspec (~> 1.37.0) diff --git a/app/models/terraform/state.rb b/app/models/terraform/state.rb index 9d88db27449..c0579c7eedc 100644 --- a/app/models/terraform/state.rb +++ b/app/models/terraform/state.rb @@ -48,11 +48,11 @@ module Terraform self.lock_xid.present? end - def update_file!(data, version:) + def update_file!(data, version:, build:) if versioning_enabled? - create_new_version!(data: data, version: version) + create_new_version!(data: data, version: version, build: build) elsif latest_version.present? - migrate_legacy_version!(data: data, version: version) + migrate_legacy_version!(data: data, version: version, build: build) else self.file = data save! @@ -81,18 +81,18 @@ module Terraform # The code can be removed in the next major version (14.0), after # which any states that haven't been migrated will need to be # recreated: https://gitlab.com/gitlab-org/gitlab/-/issues/258960 - def migrate_legacy_version!(data:, version:) + def migrate_legacy_version!(data:, version:, build:) current_file = latest_version.file.read current_version = parse_serial(current_file) || version - 1 update!(versioning_enabled: true) reload_latest_version.update!(version: current_version, file: CarrierWaveStringFile.new(current_file)) - create_new_version!(data: data, version: version) + create_new_version!(data: data, version: version, build: build) end - def create_new_version!(data:, version:) - new_version = versions.build(version: version, created_by_user: locked_by_user) + def create_new_version!(data:, version:, build:) + new_version = versions.build(version: version, created_by_user: locked_by_user, build: build) new_version.assign_attributes(file: data) new_version.save! end diff --git a/app/models/terraform/state_version.rb b/app/models/terraform/state_version.rb index eff44485401..cc5d94b8e09 100644 --- a/app/models/terraform/state_version.rb +++ b/app/models/terraform/state_version.rb @@ -6,6 +6,7 @@ module Terraform belongs_to :terraform_state, class_name: 'Terraform::State', optional: false belongs_to :created_by_user, class_name: 'User', optional: true + belongs_to :build, class_name: 'Ci::Build', optional: true, foreign_key: :ci_build_id scope :ordered_by_version_desc, -> { order(version: :desc) } diff --git a/changelogs/unreleased/267168-set-build-on-terraform-state-version-creation.yml b/changelogs/unreleased/267168-set-build-on-terraform-state-version-creation.yml new file mode 100644 index 00000000000..a58cab0a6f8 --- /dev/null +++ b/changelogs/unreleased/267168-set-build-on-terraform-state-version-creation.yml @@ -0,0 +1,5 @@ +--- +title: Associate Terraform state versions with the CI job that created them +merge_request: 45347 +author: +type: added diff --git a/db/migrate/20201015231049_add_ci_build_id_to_terraform_state_versions.rb b/db/migrate/20201015231049_add_ci_build_id_to_terraform_state_versions.rb new file mode 100644 index 00000000000..539b2af5fc4 --- /dev/null +++ b/db/migrate/20201015231049_add_ci_build_id_to_terraform_state_versions.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class AddCiBuildIdToTerraformStateVersions < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_terraform_state_versions_on_ci_build_id' + + disable_ddl_transaction! + + def up + unless column_exists?(:terraform_state_versions, :ci_build_id) + add_column :terraform_state_versions, :ci_build_id, :bigint + end + + add_concurrent_index :terraform_state_versions, :ci_build_id, name: INDEX_NAME + add_concurrent_foreign_key :terraform_state_versions, :ci_builds, column: :ci_build_id, on_delete: :nullify + end + + def down + with_lock_retries do + remove_foreign_key_if_exists :terraform_state_versions, :ci_builds, column: :ci_build_id + end + + remove_concurrent_index_by_name :terraform_state_versions, INDEX_NAME + remove_column :terraform_state_versions, :ci_build_id + end +end diff --git a/db/schema_migrations/20201015231049 b/db/schema_migrations/20201015231049 new file mode 100644 index 00000000000..17a4147993a --- /dev/null +++ b/db/schema_migrations/20201015231049 @@ -0,0 +1 @@ +cae3c41e344f15fa5a9cf71546a0bf209ead964fd3efefba39aba79afd60e0be \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 6efa45850e6..b58d48d8c64 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -16454,6 +16454,7 @@ CREATE TABLE terraform_state_versions ( verified_at timestamp with time zone, verification_checksum bytea, verification_failure text, + ci_build_id bigint, CONSTRAINT check_0824bb7bbd CHECK ((char_length(file) <= 255)), CONSTRAINT tf_state_versions_verification_failure_text_limit CHECK ((char_length(verification_failure) <= 255)) ); @@ -21775,6 +21776,8 @@ CREATE INDEX index_term_agreements_on_term_id ON term_agreements USING btree (te CREATE INDEX index_term_agreements_on_user_id ON term_agreements USING btree (user_id); +CREATE INDEX index_terraform_state_versions_on_ci_build_id ON terraform_state_versions USING btree (ci_build_id); + CREATE INDEX index_terraform_state_versions_on_created_by_user_id ON terraform_state_versions USING btree (created_by_user_id); CREATE UNIQUE INDEX index_terraform_state_versions_on_state_id_and_version ON terraform_state_versions USING btree (terraform_state_id, version); @@ -22377,6 +22380,9 @@ ALTER TABLE ONLY clusters_applications_runners ALTER TABLE ONLY design_management_designs_versions ADD CONSTRAINT fk_03c671965c FOREIGN KEY (design_id) REFERENCES design_management_designs(id) ON DELETE CASCADE; +ALTER TABLE ONLY terraform_state_versions + ADD CONSTRAINT fk_04b91e4a9f FOREIGN KEY (ci_build_id) REFERENCES ci_builds(id) ON DELETE SET NULL; + ALTER TABLE ONLY ci_test_cases ADD CONSTRAINT fk_0526c30ded FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb index 4168cce21ef..ff6c931751c 100644 --- a/lib/api/terraform/state.rb +++ b/lib/api/terraform/state.rb @@ -52,7 +52,7 @@ module API no_content! if data.empty? remote_state_handler.handle_with_lock do |state| - state.update_file!(CarrierWaveStringFile.new(data), version: params[:serial]) + state.update_file!(CarrierWaveStringFile.new(data), version: params[:serial], build: current_authenticated_job) status :ok end end diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb index 3d3f7212053..f3975fe219a 100644 --- a/lib/gitlab/auth/auth_finders.rb +++ b/lib/gitlab/auth/auth_finders.rb @@ -83,6 +83,8 @@ module Gitlab return unless ::Gitlab::Auth::CI_JOB_USER == login job = find_valid_running_job_by_token!(password) + @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables + job.user end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 23cca889ab2..4acb6be8ae9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -28629,12 +28629,6 @@ msgstr "" msgid "UsageQuota|LFS Storage" msgstr "" -msgid "UsageQuota|Learn more about excess storage usage" -msgstr "" - -msgid "UsageQuota|Learn more about usage quotas" -msgstr "" - msgid "UsageQuota|Packages" msgstr "" @@ -28659,6 +28653,12 @@ msgstr "" msgid "UsageQuota|Storage" msgstr "" +msgid "UsageQuota|This is the total amount of storage used across your projects within this namespace." +msgstr "" + +msgid "UsageQuota|This is the total amount of storage used by projects above the free %{actualRepositorySizeLimit} storage limit." +msgstr "" + msgid "UsageQuota|This namespace contains locked projects" msgstr "" diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb index 2ebde145bfd..3c19ef0bd1b 100644 --- a/spec/lib/gitlab/auth/auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/auth_finders_spec.rb @@ -607,6 +607,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do set_basic_auth_header(username, build.token) is_expected.to eq user + expect(@current_authenticated_job).to eq build end it 'raises error with invalid token' do diff --git a/spec/models/terraform/state_spec.rb b/spec/models/terraform/state_spec.rb index 608c5bdf03a..ca8fe4cca3b 100644 --- a/spec/models/terraform/state_spec.rb +++ b/spec/models/terraform/state_spec.rb @@ -97,10 +97,11 @@ RSpec.describe Terraform::State do end describe '#update_file!' do - let(:version) { 3 } - let(:data) { Hash[terraform_version: '0.12.21'].to_json } + let_it_be(:build) { create(:ci_build) } + let_it_be(:version) { 3 } + let_it_be(:data) { Hash[terraform_version: '0.12.21'].to_json } - subject { terraform_state.update_file!(CarrierWaveStringFile.new(data), version: version) } + subject { terraform_state.update_file!(CarrierWaveStringFile.new(data), version: version, build: build) } context 'versioning is enabled' do let(:terraform_state) { create(:terraform_state) } @@ -109,6 +110,7 @@ RSpec.describe Terraform::State do expect { subject }.to change { Terraform::StateVersion.count } expect(terraform_state.latest_version.version).to eq(version) + expect(terraform_state.latest_version.build).to eq(build) expect(terraform_state.latest_version.file.read).to eq(data) end end diff --git a/spec/models/terraform/state_version_spec.rb b/spec/models/terraform/state_version_spec.rb index cc5ea87159d..97ac77d5e7b 100644 --- a/spec/models/terraform/state_version_spec.rb +++ b/spec/models/terraform/state_version_spec.rb @@ -7,6 +7,7 @@ RSpec.describe Terraform::StateVersion do it { is_expected.to belong_to(:terraform_state).required } it { is_expected.to belong_to(:created_by_user).class_name('User').optional } + it { is_expected.to belong_to(:build).class_name('Ci::Build').optional } describe 'scopes' do describe '.ordered_by_version_desc' do diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb index aff41ff5974..21cc578b1eb 100644 --- a/spec/requests/api/terraform/state_spec.rb +++ b/spec/requests/api/terraform/state_spec.rb @@ -113,7 +113,7 @@ RSpec.describe API::Terraform::State do end describe 'POST /projects/:id/terraform/state/:name' do - let(:params) { { 'instance': 'example-instance', 'serial': '1' } } + let(:params) { { 'instance': 'example-instance', 'serial': state.latest_version.version + 1 } } subject(:request) { post api(state_path), headers: auth_header, as: :json, params: params } @@ -198,6 +198,18 @@ RSpec.describe API::Terraform::State do end end end + + context 'when using job token authentication' do + let(:job) { create(:ci_build, status: :running, project: project, user: maintainer) } + let(:auth_header) { job_basic_auth_header(job) } + + it 'associates the job with the newly created state version' do + expect { request }.to change { state.versions.count }.by(1) + + expect(response).to have_gitlab_http_status(:ok) + expect(state.reload_latest_version.build).to eq(job) + end + end end describe 'DELETE /projects/:id/terraform/state/:name' do