From 245aff98e4028eb4f4741f0e6b999652dba59e3c Mon Sep 17 00:00:00 2001 From: Chad Woolley Date: Fri, 13 Sep 2024 20:25:16 -0700 Subject: [PATCH 1/2] Support workspace suspension - See https://gitlab.com/groups/gitlab-org/-/work_items/14910 Changelog: added --- ...dd_workspace_delayed_termination_fields.rb | 25 + ...rkspace_delayed_termination_constraints.rb | 34 + db/schema_migrations/20240913000001 | 1 + db/schema_migrations/20240913000002 | 1 + db/structure.sql | 5 + .../workspace/gitlab_agent_configuration.md | 60 ++ doc/user/workspace/index.md | 7 + .../workspaces_list/workspaces_table.vue | 18 - .../workspaces/user/pages/create.vue | 21 - .../remote_development_agent_config.rb | 8 +- ee/app/models/remote_development/workspace.rb | 2 +- .../workspaces_agent_config.rb | 34 +- .../agent_config_operations/updater.rb | 120 ++-- .../settings/default_settings.rb | 34 +- .../create/personal_access_token_creator.rb | 13 +- .../max_hours_before_termination.rb | 13 + .../workspace_operations/reconcile/main.rb | 1 + .../output/response_payload_builder.rb | 2 +- .../workspaces_from_agent_infos_updater.rb | 8 - .../workspaces_lifecycle_manager.rb | 81 +++ .../remote_development/workspaces_spec.rb | 257 +++++--- .../workspaces_list/workspaces_table_spec.js | 2 - .../workspaces/user/pages/create_spec.js | 40 +- .../agent_config_operations/updater_spec.rb | 172 ++--- .../settings/settings_initializer_spec.rb | 105 +-- .../personal_access_token_creator_spec.rb | 10 +- .../reconcile/main_integration_spec.rb | 60 +- .../reconcile/main_spec.rb | 1 + .../output/desired_config_generator_spec.rb | 10 +- .../reconcile/output/devfile_parser_spec.rb | 5 +- ...orkspaces_from_agent_infos_updater_spec.rb | 11 - .../workspaces_lifecycle_manager_spec.rb | 112 ++++ .../workspaces_agent_config_spec.rb | 68 +- .../remote_development/integration_spec.rb | 348 +++++----- .../integration_spec_helpers.rb | 596 ++++++++++++++---- .../remote_development_shared_contexts.rb | 6 +- locale/gitlab.pot | 3 - spec/fast_spec_helper.rb | 2 + 38 files changed, 1564 insertions(+), 732 deletions(-) create mode 100644 db/migrate/20240913000001_add_workspace_delayed_termination_fields.rb create mode 100644 db/migrate/20240913000002_add_workspace_delayed_termination_constraints.rb create mode 100644 db/schema_migrations/20240913000001 create mode 100644 db/schema_migrations/20240913000002 create mode 100644 ee/lib/remote_development/workspace_operations/max_hours_before_termination.rb create mode 100644 ee/lib/remote_development/workspace_operations/reconcile/persistence/workspaces_lifecycle_manager.rb create mode 100644 ee/spec/lib/remote_development/workspace_operations/reconcile/persistence/workspaces_lifecycle_manager_spec.rb diff --git a/db/migrate/20240913000001_add_workspace_delayed_termination_fields.rb b/db/migrate/20240913000001_add_workspace_delayed_termination_fields.rb new file mode 100644 index 00000000000000..2cee117bbe894a --- /dev/null +++ b/db/migrate/20240913000001_add_workspace_delayed_termination_fields.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddWorkspaceDelayedTerminationFields < Gitlab::Database::Migration[2.2] + milestone '17.5' + disable_ddl_transaction! + + def up + with_lock_retries do + # Default max_active_hours_before_stop to 1.5 days, so that workspace should usually + # stop outside of working hours, assuming it was last restarted during working hours. + add_column :workspaces_agent_configs, :max_active_hours_before_stop, :smallint, default: 36, null: false, + if_not_exists: true + # Default max_stopped_hours_before_termination to 1 month (31 days) + add_column :workspaces_agent_configs, :max_stopped_hours_before_termination, :smallint, default: 744, null: false, + if_not_exists: true + end + end + + def down + with_lock_retries do + remove_column :workspaces_agent_configs, :max_active_hours_before_stop, if_exists: true + remove_column :workspaces_agent_configs, :max_stopped_hours_before_termination, if_exists: true + end + end +end diff --git a/db/migrate/20240913000002_add_workspace_delayed_termination_constraints.rb b/db/migrate/20240913000002_add_workspace_delayed_termination_constraints.rb new file mode 100644 index 00000000000000..0e5cab703c6860 --- /dev/null +++ b/db/migrate/20240913000002_add_workspace_delayed_termination_constraints.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class AddWorkspaceDelayedTerminationConstraints < Gitlab::Database::Migration[2.2] + milestone "17.5" + disable_ddl_transaction! + + TABLE_NAME = :workspaces_agent_configs + + def constraint_1_name + check_constraint_name TABLE_NAME, + "max_active_hours_before_stop and max_stopped_hours_before_termination", "max_total_size_1_year" + end + + def constraint_2_name + check_constraint_name TABLE_NAME, :max_active_hours_before_stop, "min_size_0" + end + + def constraint_3_name + check_constraint_name TABLE_NAME, :max_stopped_hours_before_termination, "min_size_0" + end + + def up + add_check_constraint TABLE_NAME, + "(max_active_hours_before_stop + max_stopped_hours_before_termination) <= 8760", constraint_1_name + add_check_constraint TABLE_NAME, "max_active_hours_before_stop > 0", constraint_2_name + add_check_constraint TABLE_NAME, "max_stopped_hours_before_termination > 0", constraint_3_name + end + + def down + remove_check_constraint TABLE_NAME, constraint_1_name + remove_check_constraint TABLE_NAME, constraint_2_name + remove_check_constraint TABLE_NAME, constraint_3_name + end +end diff --git a/db/schema_migrations/20240913000001 b/db/schema_migrations/20240913000001 new file mode 100644 index 00000000000000..c4d464a12c1232 --- /dev/null +++ b/db/schema_migrations/20240913000001 @@ -0,0 +1 @@ +2fd7e382f30772901fecd8ef1e38cd1a2610673912813432654a6e088f8ce553 \ No newline at end of file diff --git a/db/schema_migrations/20240913000002 b/db/schema_migrations/20240913000002 new file mode 100644 index 00000000000000..91a8a944fed2e2 --- /dev/null +++ b/db/schema_migrations/20240913000002 @@ -0,0 +1 @@ +a923994ddf6244057a357ec96fe04900dba401e4c3fa0b6a3dafb663935b7a91 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index aec532237c3749..6fe99675759671 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -21986,9 +21986,14 @@ CREATE TABLE workspaces_agent_configs ( annotations jsonb DEFAULT '{}'::jsonb NOT NULL, labels jsonb DEFAULT '{}'::jsonb NOT NULL, image_pull_secrets jsonb DEFAULT '[]'::jsonb NOT NULL, + max_active_hours_before_stop smallint DEFAULT 36 NOT NULL, + max_stopped_hours_before_termination smallint DEFAULT 744 NOT NULL, + CONSTRAINT check_557e75a230 CHECK ((max_stopped_hours_before_termination > 0)), CONSTRAINT check_58759a890a CHECK ((char_length(dns_zone) <= 256)), + CONSTRAINT check_6d7baef494 CHECK (((max_active_hours_before_stop + max_stopped_hours_before_termination) <= 8760)), CONSTRAINT check_720388a28c CHECK ((char_length(default_runtime_class) <= 253)), CONSTRAINT check_dca877fba1 CHECK ((default_max_hours_before_termination <= 8760)), + CONSTRAINT check_df26c047a9 CHECK ((max_active_hours_before_stop > 0)), CONSTRAINT check_eab6e375ad CHECK ((max_hours_before_termination_limit <= 8760)), CONSTRAINT check_ee2464835c CHECK ((char_length(gitlab_workspaces_proxy_namespace) <= 63)) ); diff --git a/doc/user/workspace/gitlab_agent_configuration.md b/doc/user/workspace/gitlab_agent_configuration.md index 8c21ab5d968806..e3530cd6ce19e0 100644 --- a/doc/user/workspace/gitlab_agent_configuration.md +++ b/doc/user/workspace/gitlab_agent_configuration.md @@ -112,6 +112,8 @@ you can use any configured agent in `top-level-group` and in any of its subgroup | [`allow_privilege_escalation`](#allow_privilege_escalation) | No | `false` | Allow privilege escalation. | | [`annotations`](#annotations) | No | `{}` | Annotations to apply to Kubernetes objects. | | [`labels`](#labels) | No | `{}` | Labels to apply to Kubernetes objects. | +| [`max_active_hours_before_stop`](#max_active_hours_before_stop) | No | `36` | Maximum number of hours a workspace can be active before it is stopped. | +| [`max_stopped_hours_before_termination`](#max_stopped_hours_before_termination) | No | `744` | Maximum number of hours a workspace can be stopped before it is terminated. | NOTE: If a setting has an invalid value, it's not possible to update any setting until you fix that value. @@ -464,6 +466,64 @@ A valid label value: For more information about `labels`, see [Labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/). +### `max_active_hours_before_stop` + +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14910) in GitLab 17.6. + +Use this setting to automatically stop the agent's workspaces after the specified number of hours +have passed since the workspace last transitioned to an active state. +An "active state" is defined as any non-stopped or non-terminated state. + +The timer for this setting starts when the workspace is created, and is reset every time the +workspace is restarted. +It also applies even if the workspace is in an error or failure state. + +The default value is `36`, or one and a half days. This avoids stopping the workspace during +the user's normal working hours. + +**Example configuration:** + +```yaml +remote_development: + max_active_hours_before_stop: 60 +``` + +A valid value: + +- Is an integer. +- Is greater than or equal to `1`. +- Is less than or equal to `8760` (one year). +- `max_active_hours_before_stop` + `max_stopped_hours_before_termination` must be less than or equal to `8760`. + +The automatic stop is only triggered on a full reconciliation, which happens every hour. +This means that the workspace might be active for up to one hour longer than the configured value. + +### `max_stopped_hours_before_termination` + +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14910) in GitLab 17.6. + +Use this setting to automatically terminate the agent's workspaces after they have been in the stopped +state for the specified number of hours. + +The default value is `722`, or approximately one month. + +**Example configuration:** + +```yaml +remote_development: + max_stopped_hours_before_termination: 4332 +``` + +A valid value: + +- Is an integer. +- Is greater than or equal to `1`. +- Is less than or equal to `8760` (one year). +- `max_active_hours_before_stop` + `max_stopped_hours_before_termination` must be less than or equal to `8760`. + +The automatic termination is only triggered on a full reconciliation, which happens every hour. +This means that the workspace might be stopped for up to one hour longer than the configured value. + ## Configuring user access with remote development You can configure the `user_access` module to access the connected Kubernetes cluster with your GitLab credentials. diff --git a/doc/user/workspace/index.md b/doc/user/workspace/index.md index ee7303d1ff6fd6..0dc53a969a1e55 100644 --- a/doc/user/workspace/index.md +++ b/doc/user/workspace/index.md @@ -247,6 +247,13 @@ However, the volume provisioned for the workspace still exists. To delete the provisioned volume, you must terminate the workspace. +## Automatic workspace stop and termination + +1. A workspace will automatically stop 36 hours after it was last started or restarted. + For more details, see [the agent configuration setting documentation for `max_active_hours_before_stop`](gitlab_agent_configuration.md#max_active_hours_before_stop). +1. A workspace will automatically terminate 722 hours after it was last stopped. + For more details, see [the agent configuration setting documentation for `max_stopped_hours_before_termination`](gitlab_agent_configuration.md#max_stopped_hours_before_termination). + ## Arbitrary user IDs You can provide your own container image, which can run as any Linux user ID. diff --git a/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue b/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue index a4ead1ee31b78c..f373be423abd77 100644 --- a/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue +++ b/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue @@ -1,5 +1,4 @@