Skip to content
Snippets Groups Projects
Verified Commit 5dfce7d2 authored by Janis Altherr's avatar Janis Altherr :red_circle: Committed by GitLab
Browse files

Add default expiration to extra pages deployments


This commit adds an expire_at column to pages deployments
prefilled with the value set in admin settings

Changelog: added
EE: true

Signed-off-by: Janis Altherr's avatarjanis <jaltherr@gitlab.com>
parent 84c2c31b
No related branches found
No related tags found
1 merge request!162825Add a default expire_in for Pages extra versions
Showing
with 143 additions and 2 deletions
......@@ -37,6 +37,7 @@ export default {
deleteScheduledAtLabel: s__('Pages|Scheduled for deletion at'),
deleteBtnLabel: s__('Pages|Delete'),
restoreBtnLabel: s__('Pages|Restore'),
expiresAtLabel: s__('Pages|Expires at'),
},
static: {
SHORT_DATE_FORMAT_WITH_TIME,
......@@ -269,6 +270,22 @@ export default {
/>
</div>
</div>
<div
v-if="deployment.active && deployment.expiresAt"
class="gl-flex gl-flex-col gl-gap-2 gl-text-nowrap"
data-testid="deployment-expires-at"
>
<div class="gl-text-sm gl-text-secondary">
{{ $options.i18n.expiresAtLabel }}
</div>
<div>
<gl-icon name="remove" class="gl-mr-2 gl-text-secondary" />
<user-date
:date="deployment.expiresAt"
:date-format="$options.static.SHORT_DATE_FORMAT_WITH_TIME"
/>
</div>
</div>
<div v-if="!deployment.active" class="gl-flex gl-flex-col gl-gap-2 gl-text-nowrap">
<div class="gl-text-sm gl-text-secondary">
{{ $options.i18n.deleteScheduledAtLabel }}
......
......@@ -33,6 +33,7 @@ query GetProjectPagesDeployments(
ciBuildId
createdAt
deletedAt
expiresAt
fileCount
pathPrefix
size
......
......@@ -16,6 +16,8 @@ class PagesDeploymentType < BaseObject
description: 'Time the deployment was created.'
field :deleted_at, GraphQL::Types::ISO8601DateTime, null: true,
description: 'Time the deployment was deleted.'
field :expires_at, GraphQL::Types::ISO8601DateTime, null: true,
description: 'Time the deployment will expire.'
field :file_count, GraphQL::Types::Int, null: true,
description: 'Number of files that were published with the deployment.'
field :id, GraphQL::Types::ID, null: false,
......
......@@ -348,6 +348,7 @@ def visible_attributes
:plantuml_url,
:diagramsnet_enabled,
:diagramsnet_url,
:pages_extra_deployments_default_expiry_seconds,
:polling_interval_multiplier,
:project_export_enabled,
:prometheus_metrics_enabled,
......
......@@ -593,6 +593,7 @@ def self.kroki_formats_attributes
:notes_create_limit,
:package_registry_cleanup_policies_worker_capacity,
:packages_cleanup_package_file_worker_capacity,
:pages_extra_deployments_default_expiry_seconds,
:pipeline_limit_per_project_user_sha,
:project_api_limit,
:project_invited_groups_api_limit,
......@@ -730,6 +731,11 @@ def self.kroki_formats_attributes
validates :asciidoc_max_includes,
numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 64 }
jsonb_accessor :pages,
pages_extra_deployments_default_expiry_seconds: [:integer, { default: 86400 }]
validates :pages, json_schema: { filename: "application_setting_pages" }
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
......
......@@ -294,7 +294,8 @@ def defaults # rubocop:disable Metrics/AbcSize
nuget_skip_metadata_url_validation: false,
ai_action_api_rate_limit: 160,
code_suggestions_api_rate_limit: 60,
require_personal_access_token_expiry: true
require_personal_access_token_expiry: true,
pages_extra_deployments_default_expiry_seconds: 86400
}.tap do |hsh|
hsh.merge!(non_production_defaults) unless Rails.env.production?
end
......
......@@ -4,6 +4,7 @@
class PagesDeployment < ApplicationRecord
include GlobalID::Identification
include EachBatch
include FromUnion
include Sortable
include FileStoreMounter
include Gitlab::Utils::StrongMemoize
......@@ -27,6 +28,7 @@ class PagesDeployment < ApplicationRecord
scope :upload_ready, -> { where(upload_ready: true) }
scope :active, -> { upload_ready.where(deleted_at: nil) }
scope :expired, -> { where('expires_at < ?', Time.now.utc).order(:expires_at, :id) }
scope :deactivated, -> { where('deleted_at < ?', Time.now.utc) }
scope :versioned, -> { where.not(path_prefix: [nil, '']) }
scope :unversioned, -> { where(path_prefix: [nil, '']) }
......
......@@ -41,7 +41,7 @@ def execute
user: build.user
)
if deployment.path_prefix.present?
if extra_deployment?
track_internal_event(
'create_pages_extra_deployment',
project: project,
......@@ -60,6 +60,14 @@ def execute
private
def extra_deployment?
path_prefix.present?
end
def path_prefix
::Gitlab::Utils.slugify(build.pages&.fetch(:path_prefix, nil) || '')
end
def success
commit_status.success
publish_deployed_event
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Pages settings",
"type": "object",
"additionalProperties": false,
"properties": {
"pages_extra_deployments_default_expiry_seconds": {
"type": "integer",
"minimum": 0,
"description": "Default expiration for extra deployments in seconds."
}
}
}
......@@ -27,6 +27,12 @@
.form-text.text-muted
- link = link_to('', help_page_path('administration/pages/index', anchor: 'set-maximum-number-of-gitlab-pages-custom-domains-for-a-project'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more%{link_end}.'), tag_pair(link, :link_start, :link_end))
.form-group
= f.label :pages_extra_deployments_default_expiry_seconds, s_('AdminSettings|Default expiration time for extra deployments (in seconds)'), class: 'label-bold'
= f.number_field :pages_extra_deployments_default_expiry_seconds, class: 'form-control gl-form-input'
.form-text.text-muted
- link = link_to('', help_page_path('user/project/pages/index', anchor: 'create-multiple-deployments'), target: '_blank', rel: 'noopener noreferrer')
= safe_format(s_('AdminSettings|Set the default time after which extra deployments expire (0 for unlimited). %{link_start}What are extra deployments%{link_end}?'), tag_pair(link, :link_start, :link_end))
%h5
= s_("AdminSettings|Configure Let's Encrypt")
%p
......
......@@ -696,6 +696,15 @@
:weight: 1
:idempotent: true
:tags: []
- :name: cronjob:pages_deactivate_expired_deployments_cron
:worker_name: Pages::DeactivateExpiredDeploymentsCronWorker
:feature_category: :pages
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: cronjob:pages_deactivated_deployments_delete_cron
:worker_name: Pages::DeactivatedDeploymentsDeleteCronWorker
:feature_category: :pages
......
# frozen_string_literal: true
module Pages
class DeactivateExpiredDeploymentsCronWorker
include ApplicationWorker
include CronjobQueue # rubocop: disable Scalability/CronWorkerContext -- No relevant metadata
idempotent!
data_consistency :always # rubocop: disable SidekiqLoadBalancing/WorkerDataConsistency -- Job is performing writes
feature_category :pages
def perform
scope = PagesDeployment.expired
iterator = Gitlab::Pagination::Keyset::Iterator.new(scope: scope)
iterator.each_batch do |deployments|
deployments.each(&:deactivate)
end
end
end
end
......@@ -723,6 +723,9 @@
Settings.cron_jobs['ci_click_house_finished_pipelines_sync_worker']['cron'] ||= '*/4 * * * *'
Settings.cron_jobs['ci_click_house_finished_pipelines_sync_worker']['args'] ||= [1]
Settings.cron_jobs['ci_click_house_finished_pipelines_sync_worker']['job_class'] = 'Ci::ClickHouse::FinishedPipelinesSyncCronWorker'
Settings.cron_jobs['deactivate_expired_deployments_cron_worker'] ||= {}
Settings.cron_jobs['deactivate_expired_deployments_cron_worker']['cron'] ||= '*/10 * * * *'
Settings.cron_jobs['deactivate_expired_deployments_cron_worker']['job_class'] ||= 'Pages::DeactivateExpiredDeploymentsCronWorker'
Gitlab.ee do
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker'] ||= {}
......
# frozen_string_literal: true
class AddPagesSettingToApplicationSettings < Gitlab::Database::Migration[2.2]
milestone '17.4'
def change
add_column :application_settings,
:pages,
:jsonb,
default: {},
null: false
end
end
# frozen_string_literal: true
class AddExpiresAtToPagesDeployments < Gitlab::Database::Migration[2.2]
milestone '17.4'
def change
add_column :pages_deployments, :expires_at, :datetime_with_timezone, null: true
end
end
# frozen_string_literal: true
class AddIndexOnPagesDeploymentExpiresAt < Gitlab::Database::Migration[2.2]
milestone '17.4'
disable_ddl_transaction!
INDEX = 'index_pages_deployments_on_expires_at'
def up
add_concurrent_index :pages_deployments,
[:expires_at, :id],
where: 'expires_at IS NOT NULL',
name: INDEX
end
def down
remove_concurrent_index_by_name :pages_deployments, INDEX
end
end
3ab3d690f9043cdd7acaee6cfcd68508d4d0a7ae08d7cd635f701fd1d7d2ee5a
\ No newline at end of file
8e087e32dc9ab7da1041eb5a5c9839669399bb80e1f6003eb2c09cf9f08d897a
\ No newline at end of file
998036eb19e65e835fa1398731ddfbfff346689291face557a6d7564b735f6e1
\ No newline at end of file
......@@ -6022,6 +6022,7 @@ CREATE TABLE application_settings (
max_number_of_vulnerabilities_per_project integer,
cluster_agents jsonb DEFAULT '{}'::jsonb NOT NULL,
observability_backend_ssl_verification_enabled boolean DEFAULT true NOT NULL,
pages jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
......@@ -15228,6 +15229,7 @@ CREATE TABLE pages_deployments (
build_ref text,
deleted_at timestamp with time zone,
upload_ready boolean DEFAULT false,
expires_at timestamp with time zone,
CONSTRAINT check_4d04b8dc9a CHECK ((char_length(path_prefix) <= 128)),
CONSTRAINT check_5f9132a958 CHECK ((size IS NOT NULL)),
CONSTRAINT check_7e938c810a CHECK ((char_length(root_directory) <= 255)),
......@@ -29303,6 +29305,8 @@ CREATE INDEX index_pages_deployments_on_ci_build_id ON pages_deployments USING b
 
CREATE INDEX index_pages_deployments_on_deleted_at ON pages_deployments USING btree (deleted_at) WHERE (deleted_at IS NOT NULL);
 
CREATE INDEX index_pages_deployments_on_expires_at ON pages_deployments USING btree (expires_at, id) WHERE (expires_at IS NOT NULL);
CREATE INDEX index_pages_deployments_on_file_store_and_id ON pages_deployments USING btree (file_store, id);
 
CREATE INDEX index_pages_deployments_on_project_id ON pages_deployments USING btree (project_id);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment