diff --git a/.rubocop.yml b/.rubocop.yml index bd98f99ad24..b87752aec3b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1110,3 +1110,12 @@ Database/AvoidUsingPluckWithoutLimit: - 'spec/**/*.rb' - 'ee/spec/**/*.rb' - 'qa/qa/specs/**/*.rb' + +Style/SymbolProc: + AllowedMethods: + - define_method + - mail + - respond_to + # See https://gitlab.com/gitlab-org/gitlab/-/issues/434151 + - each_batch + - each_sub_batch diff --git a/.rubocop_todo/style/symbol_proc.yml b/.rubocop_todo/style/symbol_proc.yml index 1808bb7fbb6..52020404660 100644 --- a/.rubocop_todo/style/symbol_proc.yml +++ b/.rubocop_todo/style/symbol_proc.yml @@ -11,7 +11,6 @@ Style/SymbolProc: - 'app/models/integrations/prometheus.rb' - 'app/models/label_note.rb' - 'app/models/members/project_member.rb' - - 'app/models/namespace.rb' - 'app/models/preloaders/merge_request_diff_preloader.rb' - 'app/models/release.rb' - 'app/models/remote_mirror.rb' @@ -45,14 +44,12 @@ Style/SymbolProc: - 'app/services/ci/find_exposed_artifacts_service.rb' - 'app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb' - 'app/services/ci/update_build_state_service.rb' - - 'app/services/clusters/agents/delete_expired_events_service.rb' - 'app/services/feature_flags/update_service.rb' - 'app/services/merge_requests/base_service.rb' - 'app/services/notes/destroy_service.rb' - 'app/services/packages/debian/generate_distribution_service.rb' - 'app/services/resource_events/synthetic_label_notes_builder_service.rb' - 'app/services/two_factor/destroy_service.rb' - - 'app/workers/bulk_import_worker.rb' - 'app/workers/bulk_imports/stuck_import_worker.rb' - 'app/workers/ci/build_trace_chunk_flush_worker.rb' - 'app/workers/gitlab/import/stuck_import_job.rb' @@ -63,7 +60,6 @@ Style/SymbolProc: - 'config/initializers/doorkeeper_openid_connect.rb' - 'config/initializers/mail_encoding_patch.rb' - 'config/settings.rb' - - 'ee/app/helpers/ee/mirror_helper.rb' - 'ee/app/helpers/ee/registrations_helper.rb' - 'ee/app/models/concerns/epic_tree_sorting.rb' - 'ee/app/models/ee/issue.rb' @@ -76,10 +72,8 @@ Style/SymbolProc: - 'ee/app/serializers/integrations/jira_serializers/issue_entity.rb' - 'ee/app/serializers/linked_epic_entity.rb' - 'ee/app/services/analytics/cycle_analytics/data_loader_service.rb' - - 'ee/app/services/geo/verification_state_backfill_service.rb' - 'ee/app/services/security/scanned_resources_counting_service.rb' - 'ee/app/services/timebox_report_service.rb' - - 'ee/app/services/vulnerabilities/historical_statistics/deletion_service.rb' - 'ee/app/workers/geo/sync_timeout_cron_worker.rb' - 'ee/app/workers/geo/verification_cron_worker.rb' - 'ee/lib/api/entities/pending_member.rb' @@ -107,10 +101,8 @@ Style/SymbolProc: - 'lib/api/entities/issuable_references.rb' - 'lib/api/entities/merge_request_approvals.rb' - 'lib/api/entities/package.rb' - - 'lib/api/entities/protected_ref_access.rb' - 'lib/api/go_proxy.rb' - 'lib/api/helpers/internal_helpers.rb' - - 'lib/api/package_files.rb' - 'lib/atlassian/jira_connect/serializers/base_entity.rb' - 'lib/bulk_imports/common/pipelines/entity_finisher.rb' - 'lib/bulk_imports/ndjson_pipeline.rb' @@ -118,7 +110,6 @@ Style/SymbolProc: - 'lib/container_registry/gitlab_api_client.rb' - 'lib/gitlab/analytics/cycle_analytics/stage_events.rb' - 'lib/gitlab/auth/o_auth/auth_hash.rb' - - 'lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings.rb' - 'lib/gitlab/blob_helper.rb' - 'lib/gitlab/cache/ci/project_pipeline_status.rb' - 'lib/gitlab/checks/changes_access.rb' @@ -127,7 +118,6 @@ Style/SymbolProc: - 'lib/gitlab/config/entry/node.rb' - 'lib/gitlab/database/async_indexes/migration_helpers.rb' - 'lib/gitlab/database/consistency_checker.rb' - - 'lib/gitlab/database/migrations/background_migration_helpers.rb' - 'lib/gitlab/database/migrations/instrumentation.rb' - 'lib/gitlab/diff/file_collection/base.rb' - 'lib/gitlab/diff/rendered/notebook/diff_file_helper.rb' @@ -145,18 +135,12 @@ Style/SymbolProc: - 'lib/gitlab/slash_commands/deploy.rb' - 'lib/gitlab/ssh_public_key.rb' - 'lib/gitlab/suggestions/suggestion_set.rb' - - 'lib/gitlab/task_helpers.rb' - 'lib/tasks/gitlab/praefect.rake' - - 'qa/qa/ee/page/group/settings/general.rb' - - 'qa/qa/ee/page/operations_dashboard.rb' - 'qa/qa/page/group/settings/package_registries.rb' - 'qa/qa/page/profile/two_factor_auth.rb' - - 'qa/qa/resource/project_snippet.rb' - 'qa/qa/runtime/ip_address.rb' - 'qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb' - - 'qa/qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb' - 'qa/qa/specs/features/ee/browser_ui/3_create/merge_request/approval_rules_spec.rb' - - 'qa/qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb' - 'qa/qa/specs/features/ee/browser_ui/4_verify/pipeline_subscription_with_group_owned_project_spec.rb' - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' - 'rubocop/cop/gitlab/namespaced_class.rb' @@ -184,8 +168,6 @@ Style/SymbolProc: - 'spec/helpers/instance_configuration_helper_spec.rb' - 'spec/helpers/members_helper_spec.rb' - 'spec/lib/backup/gitaly_backup_spec.rb' - - 'spec/lib/gitlab/database/dynamic_model_helpers_spec.rb' - - 'spec/lib/gitlab/database/loose_foreign_keys_spec.rb' - 'spec/lib/gitlab/database/migration_helpers/loose_foreign_key_helpers_spec.rb' - 'spec/lib/gitlab/git/commit_spec.rb' - 'spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb' @@ -193,7 +175,6 @@ Style/SymbolProc: - 'spec/lib/gitlab/graphql/markdown_field_spec.rb' - 'spec/lib/gitlab/instrumentation/redis_spec.rb' - 'spec/lib/gitlab/optimistic_locking_spec.rb' - - 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/query_builder_spec.rb' - 'spec/lib/gitlab/quick_actions/dsl_spec.rb' - 'spec/lib/gitlab/relative_positioning/item_context_spec.rb' - 'spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb' diff --git a/Gemfile b/Gemfile index 1dff5c15b83..c874c7a7ab9 100644 --- a/Gemfile +++ b/Gemfile @@ -386,7 +386,7 @@ gem 'snowplow-tracker', '~> 0.8.0' # rubocop:todo Gemfile/MissingFeatureCategory # Metrics gem 'webrick', '~> 1.8.1', require: false # rubocop:todo Gemfile/MissingFeatureCategory -gem 'prometheus-client-mmap', '~> 1.0', '>= 1.0.1', require: 'prometheus/client' # rubocop:todo Gemfile/MissingFeatureCategory +gem 'prometheus-client-mmap', '~> 1.0', '>= 1.0.2', require: 'prometheus/client' # rubocop:todo Gemfile/MissingFeatureCategory gem 'warning', '~> 1.3.0' # rubocop:todo Gemfile/MissingFeatureCategory diff --git a/Gemfile.checksum b/Gemfile.checksum index 4a39309d863..403eb642b25 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -457,11 +457,11 @@ {"name":"prime","version":"0.1.2","platform":"ruby","checksum":"d4e956cadfaf04de036dc7dc74f95bf6a285a62cc509b28b7a66b245d19fe3a4"}, {"name":"prism","version":"0.18.0","platform":"ruby","checksum":"bae73ccaed950e830e136be38cdb9461f9f645f8ef306217ff1d66ff83eb589c"}, {"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"}, -{"name":"prometheus-client-mmap","version":"1.0.1","platform":"aarch64-linux","checksum":"12eedc9e0915686a00aa65a03e3a36f42c7d4d26803ba7fe5826441a2c3b7471"}, -{"name":"prometheus-client-mmap","version":"1.0.1","platform":"arm64-darwin","checksum":"ff8d4577e761b0dc8b4b706bce1034d587df021a6216a218b015bdb1c0ef87e6"}, -{"name":"prometheus-client-mmap","version":"1.0.1","platform":"ruby","checksum":"d894cc6aa68044d8018252971793763c855234b75dc51e2bc51abc42df0c00c5"}, -{"name":"prometheus-client-mmap","version":"1.0.1","platform":"x86_64-darwin","checksum":"c482d5b00b7dcae95e61971e27133145712f6f3e036f745acff170c20f8ccdf2"}, -{"name":"prometheus-client-mmap","version":"1.0.1","platform":"x86_64-linux","checksum":"612df1eafdb2eefda7d0dd69b8400fe9139dfca74a6678527d42334dbd33b2b4"}, +{"name":"prometheus-client-mmap","version":"1.0.2","platform":"aarch64-linux","checksum":"1cec0954f54e47760f56c4fb9cf98de30e5a80f1a803726239590d008c976847"}, +{"name":"prometheus-client-mmap","version":"1.0.2","platform":"arm64-darwin","checksum":"a9911e1963bbdb170f07af125efa2f1fb38aa6f49b442ac31abd2e13cf3599b4"}, +{"name":"prometheus-client-mmap","version":"1.0.2","platform":"ruby","checksum":"f88ef1d375f24b651970bef567101a53edcedd1f5c21922c0c0b3fbec623def5"}, +{"name":"prometheus-client-mmap","version":"1.0.2","platform":"x86_64-darwin","checksum":"17b6266135394fa187d939ab900263837f8b50240ea4fd7946d6ede825511e00"}, +{"name":"prometheus-client-mmap","version":"1.0.2","platform":"x86_64-linux","checksum":"f03c746b1afbd583902e249b347297a8065ec0db06dae61da4c9952dcedc65d5"}, {"name":"protocol","version":"2.0.0","platform":"ruby","checksum":"dcd7c509e53b8cd6284e965a2e2e71d5291ca9e2d50acfa3d7ee0561c0df16b9"}, {"name":"pry","version":"0.14.2","platform":"java","checksum":"fd780670977ba04ff7ee32dabd4d02fe4bf02e977afe8809832d5dca1412862e"}, {"name":"pry","version":"0.14.2","platform":"ruby","checksum":"c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d"}, diff --git a/Gemfile.lock b/Gemfile.lock index f347caac339..b71390671ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1251,7 +1251,7 @@ GEM coderay parser unparser - prometheus-client-mmap (1.0.1) + prometheus-client-mmap (1.0.2) rb_sys (~> 0.9) protocol (2.0.0) ruby_parser (~> 3.0) @@ -2006,7 +2006,7 @@ DEPENDENCIES pg_query (~> 4.2.3) png_quantizator (~> 0.2.1) premailer-rails (~> 1.10.3) - prometheus-client-mmap (~> 1.0, >= 1.0.1) + prometheus-client-mmap (~> 1.0, >= 1.0.2) pry-byebug pry-rails (~> 0.3.9) pry-shell (~> 0.6.4) diff --git a/app/assets/javascripts/environments/components/kubernetes_pods.vue b/app/assets/javascripts/environments/components/kubernetes_pods.vue index 2015355f794..cd21c4d65dc 100644 --- a/app/assets/javascripts/environments/components/kubernetes_pods.vue +++ b/app/assets/javascripts/environments/components/kubernetes_pods.vue @@ -2,10 +2,10 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { s__ } from '~/locale'; import { - PHASE_RUNNING, - PHASE_PENDING, - PHASE_SUCCEEDED, - PHASE_FAILED, + STATUS_RUNNING, + STATUS_PENDING, + STATUS_SUCCEEDED, + STATUS_FAILED, STATUS_LABELS, } from '~/kubernetes_dashboard/constants'; import WorkloadStats from '~/kubernetes_dashboard/components/workload_stats.vue'; @@ -58,20 +58,20 @@ export default { return [ { - value: this.countPodsByPhase(PHASE_RUNNING), - title: STATUS_LABELS[PHASE_RUNNING], + value: this.countPodsByPhase(STATUS_RUNNING), + title: STATUS_LABELS[STATUS_RUNNING], }, { - value: this.countPodsByPhase(PHASE_PENDING), - title: STATUS_LABELS[PHASE_PENDING], + value: this.countPodsByPhase(STATUS_PENDING), + title: STATUS_LABELS[STATUS_PENDING], }, { - value: this.countPodsByPhase(PHASE_SUCCEEDED), - title: STATUS_LABELS[PHASE_SUCCEEDED], + value: this.countPodsByPhase(STATUS_SUCCEEDED), + title: STATUS_LABELS[STATUS_SUCCEEDED], }, { - value: this.countPodsByPhase(PHASE_FAILED), - title: STATUS_LABELS[PHASE_FAILED], + value: this.countPodsByPhase(STATUS_FAILED), + title: STATUS_LABELS[STATUS_FAILED], }, ]; }, @@ -83,7 +83,7 @@ export default { countPodsByPhase(phase) { const filteredPods = this.k8sPods.filter((item) => item.status.phase === phase); - const hasFailedState = Boolean(phase === PHASE_FAILED && filteredPods.length); + const hasFailedState = Boolean(phase === STATUS_FAILED && filteredPods.length); this.$emit('update-failed-state', { pods: hasFailedState }); return filteredPods.length; diff --git a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js index ed14aa3169e..04a42bed416 100644 --- a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js +++ b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js @@ -1,5 +1,8 @@ -import { calculateDeploymentStatus } from '~/kubernetes_dashboard/helpers/k8s_integration_helper'; -import { PHASE_READY, PHASE_FAILED } from '~/kubernetes_dashboard/constants'; +import { + calculateDeploymentStatus, + calculateStatefulSetStatus, +} from '~/kubernetes_dashboard/helpers/k8s_integration_helper'; +import { STATUS_READY, STATUS_FAILED } from '~/kubernetes_dashboard/constants'; import { CLUSTER_AGENT_ERROR_MESSAGES } from '../constants'; export function generateServicePortsString(ports) { @@ -22,10 +25,10 @@ export function getDeploymentsStatuses(items) { const status = calculateDeploymentStatus(item); switch (status) { - case PHASE_READY: + case STATUS_READY: ready.push(item); break; - case PHASE_FAILED: + case STATUS_FAILED: failed.push(item); break; default: @@ -63,10 +66,10 @@ export function getDaemonSetStatuses(items) { export function getStatefulSetStatuses(items) { const failed = items.filter((item) => { - return item.status?.readyReplicas < item.spec?.replicas; + return calculateStatefulSetStatus(item) === STATUS_FAILED; }); const ready = items.filter((item) => { - return item.status?.readyReplicas === item.spec?.replicas; + return calculateStatefulSetStatus(item) === STATUS_READY; }); return { diff --git a/app/assets/javascripts/kubernetes_dashboard/constants.js b/app/assets/javascripts/kubernetes_dashboard/constants.js index bbbc8a33675..b93740aec90 100644 --- a/app/assets/javascripts/kubernetes_dashboard/constants.js +++ b/app/assets/javascripts/kubernetes_dashboard/constants.js @@ -1,25 +1,25 @@ import { s__ } from '~/locale'; -export const PHASE_RUNNING = 'Running'; -export const PHASE_PENDING = 'Pending'; -export const PHASE_SUCCEEDED = 'Succeeded'; -export const PHASE_FAILED = 'Failed'; -export const PHASE_READY = 'Ready'; +export const STATUS_RUNNING = 'Running'; +export const STATUS_PENDING = 'Pending'; +export const STATUS_SUCCEEDED = 'Succeeded'; +export const STATUS_FAILED = 'Failed'; +export const STATUS_READY = 'Ready'; export const STATUS_LABELS = { - [PHASE_RUNNING]: s__('KubernetesDashboard|Running'), - [PHASE_PENDING]: s__('KubernetesDashboard|Pending'), - [PHASE_SUCCEEDED]: s__('KubernetesDashboard|Succeeded'), - [PHASE_FAILED]: s__('KubernetesDashboard|Failed'), - [PHASE_READY]: s__('KubernetesDashboard|Ready'), + [STATUS_RUNNING]: s__('KubernetesDashboard|Running'), + [STATUS_PENDING]: s__('KubernetesDashboard|Pending'), + [STATUS_SUCCEEDED]: s__('KubernetesDashboard|Succeeded'), + [STATUS_FAILED]: s__('KubernetesDashboard|Failed'), + [STATUS_READY]: s__('KubernetesDashboard|Ready'), }; export const WORKLOAD_STATUS_BADGE_VARIANTS = { - [PHASE_RUNNING]: 'info', - [PHASE_PENDING]: 'warning', - [PHASE_SUCCEEDED]: 'success', - [PHASE_FAILED]: 'danger', - [PHASE_READY]: 'success', + [STATUS_RUNNING]: 'info', + [STATUS_PENDING]: 'warning', + [STATUS_SUCCEEDED]: 'success', + [STATUS_FAILED]: 'danger', + [STATUS_READY]: 'success', }; export const PAGE_SIZE = 20; diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/client.js b/app/assets/javascripts/kubernetes_dashboard/graphql/client.js index a058fefd0e2..a3ad75eacf5 100644 --- a/app/assets/javascripts/kubernetes_dashboard/graphql/client.js +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/client.js @@ -3,6 +3,7 @@ import createDefaultClient from '~/lib/graphql'; import typeDefs from '~/environments/graphql/typedefs.graphql'; import k8sPodsQuery from './queries/k8s_dashboard_pods.query.graphql'; import k8sDeploymentsQuery from './queries/k8s_dashboard_deployments.query.graphql'; +import k8sStatefulSetsQuery from './queries/k8s_dashboard_stateful_sets.query.graphql'; import { resolvers } from './resolvers'; export const apolloProvider = () => { @@ -43,6 +44,25 @@ export const apolloProvider = () => { }, }); + cache.writeQuery({ + query: k8sStatefulSetsQuery, + data: { + metadata: { + name: null, + namespace: null, + creationTimestamp: null, + labels: null, + annotations: null, + }, + status: { + readyReplicas: null, + }, + spec: { + replicas: null, + }, + }, + }); + return new VueApollo({ defaultClient, }); diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/helpers/resolver_helpers.js b/app/assets/javascripts/kubernetes_dashboard/graphql/helpers/resolver_helpers.js index f034036287a..47c2f543357 100644 --- a/app/assets/javascripts/kubernetes_dashboard/graphql/helpers/resolver_helpers.js +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/helpers/resolver_helpers.js @@ -25,6 +25,24 @@ export const mapWorkloadItem = (item) => { return { status: item.status }; }; +export const mapSetItem = (item) => { + const status = { + ...item.status, + readyReplicas: item.status?.readyReplicas || null, + }; + + const metadata = + { + ...item.metadata, + annotations: item.metadata?.annotations || {}, + labels: item.metadata?.labels || {}, + } || null; + + const spec = item.spec || null; + + return { status, metadata, spec }; +}; + export const watchWorkloadItems = ({ client, query, @@ -32,6 +50,7 @@ export const watchWorkloadItems = ({ namespace, watchPath, queryField, + mapFn = mapWorkloadItem, }) => { const config = new Configuration(configuration); const watcherApi = new WatchApi(config); @@ -42,7 +61,7 @@ export const watchWorkloadItems = ({ let result = []; watcher.on(EVENT_DATA, (data) => { - result = data.map(mapWorkloadItem); + result = data.map(mapFn); client.writeQuery({ query, diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_stateful_sets.query.graphql b/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_stateful_sets.query.graphql new file mode 100644 index 00000000000..ab1b9e1e472 --- /dev/null +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_stateful_sets.query.graphql @@ -0,0 +1,17 @@ +query getK8sDashboardStatefulSets($configuration: LocalConfiguration) { + k8sStatefulSets(configuration: $configuration) @client { + metadata { + name + namespace + creationTimestamp + labels + annotations + } + status { + readyReplicas + } + spec { + replicas + } + } +} diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/resolvers/kubernetes.js b/app/assets/javascripts/kubernetes_dashboard/graphql/resolvers/kubernetes.js index 6a064d881e7..e61545c9b45 100644 --- a/app/assets/javascripts/kubernetes_dashboard/graphql/resolvers/kubernetes.js +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/resolvers/kubernetes.js @@ -4,11 +4,13 @@ import { getK8sPods, handleClusterError, mapWorkloadItem, + mapSetItem, buildWatchPath, watchWorkloadItems, } from '../helpers/resolver_helpers'; import k8sDashboardPodsQuery from '../queries/k8s_dashboard_pods.query.graphql'; import k8sDashboardDeploymentsQuery from '../queries/k8s_dashboard_deployments.query.graphql'; +import k8sDashboardStatefulSetsQuery from '../queries/k8s_dashboard_stateful_sets.query.graphql'; export default { k8sPods(_, { configuration }, { client }) { @@ -52,4 +54,41 @@ export default { } }); }, + + k8sStatefulSets(_, { configuration, namespace = '' }, { client }) { + const config = new Configuration(configuration); + + const appsV1api = new AppsV1Api(config); + const deploymentsApi = namespace + ? appsV1api.listAppsV1NamespacedStatefulSet({ namespace }) + : appsV1api.listAppsV1StatefulSetForAllNamespaces(); + return deploymentsApi + .then((res) => { + const watchPath = buildWatchPath({ + resource: 'statefulsets', + api: 'apis/apps/v1', + namespace, + }); + watchWorkloadItems({ + client, + query: k8sDashboardStatefulSetsQuery, + configuration, + namespace, + watchPath, + queryField: 'k8sStatefulSets', + mapFn: mapSetItem, + }); + + const data = res?.items || []; + + return data.map(mapSetItem); + }) + .catch(async (err) => { + try { + await handleClusterError(err); + } catch (error) { + throw new Error(error.message); + } + }); + }, }; diff --git a/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js b/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js index d55a57f0ab7..17f1ebdc013 100644 --- a/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js +++ b/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js @@ -1,5 +1,11 @@ import { differenceInSeconds } from '~/lib/utils/datetime_utility'; -import { STATUS_TRUE, STATUS_FALSE, PHASE_PENDING, PHASE_READY, PHASE_FAILED } from '../constants'; +import { + STATUS_TRUE, + STATUS_FALSE, + STATUS_PENDING, + STATUS_READY, + STATUS_FAILED, +} from '../constants'; export function getAge(creationTimestamp) { if (!creationTimestamp) return ''; @@ -28,10 +34,17 @@ export function getAge(creationTimestamp) { export function calculateDeploymentStatus(item) { const [available, progressing] = item.status?.conditions ?? []; if (available?.status === STATUS_TRUE) { - return PHASE_READY; + return STATUS_READY; } if (available?.status === STATUS_FALSE && progressing?.status !== STATUS_TRUE) { - return PHASE_FAILED; + return STATUS_FAILED; } - return PHASE_PENDING; + return STATUS_PENDING; +} + +export function calculateStatefulSetStatus(item) { + if (item.status?.readyReplicas === item.spec?.replicas) { + return STATUS_READY; + } + return STATUS_FAILED; } diff --git a/app/assets/javascripts/kubernetes_dashboard/pages/deployments_page.vue b/app/assets/javascripts/kubernetes_dashboard/pages/deployments_page.vue index 2e08d9f0c03..c5472966539 100644 --- a/app/assets/javascripts/kubernetes_dashboard/pages/deployments_page.vue +++ b/app/assets/javascripts/kubernetes_dashboard/pages/deployments_page.vue @@ -3,7 +3,7 @@ import { s__ } from '~/locale'; import { getAge, calculateDeploymentStatus } from '../helpers/k8s_integration_helper'; import WorkloadLayout from '../components/workload_layout.vue'; import k8sDeploymentsQuery from '../graphql/queries/k8s_dashboard_deployments.query.graphql'; -import { PHASE_FAILED, PHASE_READY, PHASE_PENDING, STATUS_LABELS } from '../constants'; +import { STATUS_FAILED, STATUS_READY, STATUS_PENDING, STATUS_LABELS } from '../constants'; export default { components: { @@ -48,16 +48,16 @@ export default { deploymentsStats() { return [ { - value: this.countDeploymentsByStatus(PHASE_READY), - title: STATUS_LABELS[PHASE_READY], + value: this.countDeploymentsByStatus(STATUS_READY), + title: STATUS_LABELS[STATUS_READY], }, { - value: this.countDeploymentsByStatus(PHASE_FAILED), - title: STATUS_LABELS[PHASE_FAILED], + value: this.countDeploymentsByStatus(STATUS_FAILED), + title: STATUS_LABELS[STATUS_FAILED], }, { - value: this.countDeploymentsByStatus(PHASE_PENDING), - title: STATUS_LABELS[PHASE_PENDING], + value: this.countDeploymentsByStatus(STATUS_PENDING), + title: STATUS_LABELS[STATUS_PENDING], }, ]; }, diff --git a/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue b/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue index 3025f52c325..4be40fdde62 100644 --- a/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue +++ b/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue @@ -4,10 +4,10 @@ import { getAge } from '../helpers/k8s_integration_helper'; import WorkloadLayout from '../components/workload_layout.vue'; import k8sPodsQuery from '../graphql/queries/k8s_dashboard_pods.query.graphql'; import { - PHASE_RUNNING, - PHASE_PENDING, - PHASE_SUCCEEDED, - PHASE_FAILED, + STATUS_RUNNING, + STATUS_PENDING, + STATUS_SUCCEEDED, + STATUS_FAILED, STATUS_LABELS, } from '../constants'; @@ -54,20 +54,20 @@ export default { podStats() { return [ { - value: this.countPodsByPhase(PHASE_RUNNING), - title: STATUS_LABELS[PHASE_RUNNING], + value: this.countPodsByPhase(STATUS_RUNNING), + title: STATUS_LABELS[STATUS_RUNNING], }, { - value: this.countPodsByPhase(PHASE_PENDING), - title: STATUS_LABELS[PHASE_PENDING], + value: this.countPodsByPhase(STATUS_PENDING), + title: STATUS_LABELS[STATUS_PENDING], }, { - value: this.countPodsByPhase(PHASE_SUCCEEDED), - title: STATUS_LABELS[PHASE_SUCCEEDED], + value: this.countPodsByPhase(STATUS_SUCCEEDED), + title: STATUS_LABELS[STATUS_SUCCEEDED], }, { - value: this.countPodsByPhase(PHASE_FAILED), - title: STATUS_LABELS[PHASE_FAILED], + value: this.countPodsByPhase(STATUS_FAILED), + title: STATUS_LABELS[STATUS_FAILED], }, ]; }, diff --git a/app/assets/javascripts/kubernetes_dashboard/pages/stateful_sets_page.vue b/app/assets/javascripts/kubernetes_dashboard/pages/stateful_sets_page.vue new file mode 100644 index 00000000000..bcdce41b433 --- /dev/null +++ b/app/assets/javascripts/kubernetes_dashboard/pages/stateful_sets_page.vue @@ -0,0 +1,81 @@ + + diff --git a/app/assets/javascripts/kubernetes_dashboard/router/constants.js b/app/assets/javascripts/kubernetes_dashboard/router/constants.js index d2db2e616fd..34bb4e8f42f 100644 --- a/app/assets/javascripts/kubernetes_dashboard/router/constants.js +++ b/app/assets/javascripts/kubernetes_dashboard/router/constants.js @@ -1,5 +1,7 @@ export const PODS_ROUTE_NAME = 'pods'; export const DEPLOYMENTS_ROUTE_NAME = 'deployments'; +export const STATEFUL_SETS_ROUTE_NAME = 'statefulSets'; export const PODS_ROUTE_PATH = '/pods'; export const DEPLOYMENTS_ROUTE_PATH = '/deployments'; +export const STATEFUL_SETS_ROUTE_PATH = '/statefulsets'; diff --git a/app/assets/javascripts/kubernetes_dashboard/router/routes.js b/app/assets/javascripts/kubernetes_dashboard/router/routes.js index 639f41df926..96e7a35bfe2 100644 --- a/app/assets/javascripts/kubernetes_dashboard/router/routes.js +++ b/app/assets/javascripts/kubernetes_dashboard/router/routes.js @@ -1,11 +1,14 @@ import { s__ } from '~/locale'; import PodsPage from '../pages/pods_page.vue'; import DeploymentsPage from '../pages/deployments_page.vue'; +import StatefulSetsPage from '../pages/stateful_sets_page.vue'; import { PODS_ROUTE_NAME, PODS_ROUTE_PATH, DEPLOYMENTS_ROUTE_NAME, DEPLOYMENTS_ROUTE_PATH, + STATEFUL_SETS_ROUTE_NAME, + STATEFUL_SETS_ROUTE_PATH, } from './constants'; export default [ @@ -25,4 +28,12 @@ export default [ title: s__('KubernetesDashboard|Deployments'), }, }, + { + name: STATEFUL_SETS_ROUTE_NAME, + path: STATEFUL_SETS_ROUTE_PATH, + component: StatefulSetsPage, + meta: { + title: s__('KubernetesDashboard|StatefulSets'), + }, + }, ]; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue index 524f2c045e6..d153c17ea1e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue @@ -293,7 +293,7 @@ export default { :multiple-approval-rules-available="mr.multipleApprovalRulesAvailable" /> -
+