diff options
Diffstat (limited to 'app')
13 files changed, 227 insertions, 40 deletions
diff --git a/app/assets/javascripts/environments/components/kubernetes_tabs.vue b/app/assets/javascripts/environments/components/kubernetes_tabs.vue index 7c699eec412..60b36596ef3 100644 --- a/app/assets/javascripts/environments/components/kubernetes_tabs.vue +++ b/app/assets/javascripts/environments/components/kubernetes_tabs.vue @@ -1,8 +1,9 @@ <script> import { GlTabs, GlTab, GlLoadingIcon, GlBadge, GlTable, GlPagination } from '@gitlab/ui'; import { __, s__ } from '~/locale'; +import { getAge } from '~/kubernetes_dashboard/helpers/k8s_integration_helper'; import k8sServicesQuery from '../graphql/queries/k8s_services.query.graphql'; -import { generateServicePortsString, getServiceAge } from '../helpers/k8s_integration_helper'; +import { generateServicePortsString } from '../helpers/k8s_integration_helper'; import { SERVICES_LIMIT_PER_PAGE } from '../constants'; import KubernetesSummary from './kubernetes_summary.vue'; @@ -62,7 +63,7 @@ export default { clusterIP: service?.spec?.clusterIP, externalIP: service?.spec?.externalIP, ports: generateServicePortsString(service?.spec?.ports), - age: getServiceAge(service?.metadata?.creationTimestamp), + age: getAge(service?.metadata?.creationTimestamp), }; }); }, diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql index 41f165ad1da..24898c2cadb 100644 --- a/app/assets/javascripts/environments/graphql/typedefs.graphql +++ b/app/assets/javascripts/environments/graphql/typedefs.graphql @@ -66,8 +66,15 @@ type k8sPodStatus { phase: String } +type k8sPodMetadata { + name: String + namespace: String + creationTimestamp: String +} + type LocalK8sPods { status: k8sPodStatus + metadata: k8sPodMetadata } input LocalConfiguration { diff --git a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js index 93a78e21dfb..a67c8b83eb6 100644 --- a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js +++ b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js @@ -1,4 +1,3 @@ -import { differenceInSeconds } from '~/lib/utils/datetime_utility'; import { CLUSTER_AGENT_ERROR_MESSAGES, STATUS_TRUE, STATUS_FALSE } from '../constants'; export function generateServicePortsString(ports) { @@ -12,30 +11,6 @@ export function generateServicePortsString(ports) { .join(', '); } -export function getServiceAge(creationTimestamp) { - if (!creationTimestamp) return ''; - - const timeDifference = differenceInSeconds(new Date(creationTimestamp), new Date()); - - const seconds = Math.floor(timeDifference); - const minutes = Math.floor(seconds / 60) % 60; - const hours = Math.floor(seconds / 60 / 60) % 24; - const days = Math.floor(seconds / 60 / 60 / 24); - - let ageString; - if (days > 0) { - ageString = `${days}d`; - } else if (hours > 0) { - ageString = `${hours}h`; - } else if (minutes > 0) { - ageString = `${minutes}m`; - } else { - ageString = `${seconds}s`; - } - - return ageString; -} - export function getDeploymentsStatuses(items) { const failed = []; const ready = []; diff --git a/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue b/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue new file mode 100644 index 00000000000..937b9684fa5 --- /dev/null +++ b/app/assets/javascripts/kubernetes_dashboard/components/workload_layout.vue @@ -0,0 +1,44 @@ +<script> +import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; +import WorkloadStats from './workload_stats.vue'; +import WorkloadTable from './workload_table.vue'; + +export default { + components: { + GlLoadingIcon, + GlAlert, + WorkloadStats, + WorkloadTable, + }, + props: { + loading: { + type: Boolean, + default: false, + required: false, + }, + errorMessage: { + type: String, + default: '', + required: false, + }, + stats: { + type: Array, + required: true, + }, + items: { + type: Array, + required: true, + }, + }, +}; +</script> +<template> + <gl-loading-icon v-if="loading" /> + <gl-alert v-else-if="errorMessage" variant="danger" :dismissible="false" class="gl-mb-5"> + {{ errorMessage }} + </gl-alert> + <div v-else> + <workload-stats :stats="stats" /> + <workload-table :items="items" /> + </div> +</template> diff --git a/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue b/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue new file mode 100644 index 00000000000..65cf00a3b85 --- /dev/null +++ b/app/assets/javascripts/kubernetes_dashboard/components/workload_table.vue @@ -0,0 +1,77 @@ +<script> +import { GlTable, GlBadge, GlPagination } from '@gitlab/ui'; +import { + WORKLOAD_STATUS_BADGE_VARIANTS, + PAGE_SIZE, + TABLE_HEADING_CLASSES, + DEFAULT_WORKLOAD_TABLE_FIELDS, +} from '../constants'; + +export default { + components: { + GlTable, + GlBadge, + GlPagination, + }, + props: { + items: { + type: Array, + required: true, + }, + fields: { + type: Array, + default: () => DEFAULT_WORKLOAD_TABLE_FIELDS, + required: false, + }, + }, + data() { + return { + currentPage: 1, + }; + }, + computed: { + tableFields() { + return this.fields.map((field) => { + return { + ...field, + thClass: TABLE_HEADING_CLASSES, + sortable: true, + }; + }); + }, + }, + PAGE_SIZE, + WORKLOAD_STATUS_BADGE_VARIANTS, + TABLE_CELL_CLASSES: 'gl-p-2', +}; +</script> + +<template> + <div class="gl-mt-8"> + <gl-table + :items="items" + :fields="tableFields" + :per-page="$options.PAGE_SIZE" + :current-page="currentPage" + stacked="md" + bordered + > + <template #cell(status)="{ item: { status } }"> + <gl-badge + :variant="$options.WORKLOAD_STATUS_BADGE_VARIANTS[status]" + size="sm" + class="gl-ml-2" + >{{ status }}</gl-badge + > + </template> + </gl-table> + + <gl-pagination + v-model="currentPage" + :per-page="$options.PAGE_SIZE" + :total-items="items.length" + align="center" + class="gl-mt-6" + /> + </div> +</template> diff --git a/app/assets/javascripts/kubernetes_dashboard/constants.js b/app/assets/javascripts/kubernetes_dashboard/constants.js index 2aeb2a4c113..cbb89dff1cf 100644 --- a/app/assets/javascripts/kubernetes_dashboard/constants.js +++ b/app/assets/javascripts/kubernetes_dashboard/constants.js @@ -11,3 +11,33 @@ export const STATUS_LABELS = { [PHASE_SUCCEEDED]: s__('KubernetesDashboard|Succeeded'), [PHASE_FAILED]: s__('KubernetesDashboard|Failed'), }; + +export const WORKLOAD_STATUS_BADGE_VARIANTS = { + [PHASE_RUNNING]: 'info', + [PHASE_PENDING]: 'warning', + [PHASE_SUCCEEDED]: 'success', + [PHASE_FAILED]: 'danger', +}; + +export const PAGE_SIZE = 20; + +export const TABLE_HEADING_CLASSES = 'gl-bg-gray-50! gl-font-weight-bold gl-white-space-nowrap'; + +export const DEFAULT_WORKLOAD_TABLE_FIELDS = [ + { + key: 'name', + label: s__('KubernetesDashboard|Name'), + }, + { + key: 'status', + label: s__('KubernetesDashboard|Status'), + }, + { + key: 'namespace', + label: s__('KubernetesDashboard|Namespace'), + }, + { + key: 'age', + label: s__('KubernetesDashboard|Age'), + }, +]; diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/client.js b/app/assets/javascripts/kubernetes_dashboard/graphql/client.js index 0b9de9c2a61..3a6e90640ae 100644 --- a/app/assets/javascripts/kubernetes_dashboard/graphql/client.js +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/client.js @@ -13,6 +13,11 @@ export const apolloProvider = () => { cache.writeQuery({ query: k8sPodsQuery, data: { + metadata: { + name: null, + namespace: null, + creationTimestamp: null, + }, status: { phase: null, }, diff --git a/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_pods.query.graphql b/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_pods.query.graphql index 17d264d32ec..0153d5e298f 100644 --- a/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_pods.query.graphql +++ b/app/assets/javascripts/kubernetes_dashboard/graphql/queries/k8s_dashboard_pods.query.graphql @@ -1,5 +1,10 @@ query getK8sDashboardPods($configuration: LocalConfiguration) { k8sPods(configuration: $configuration) @client { + metadata { + name + namespace + creationTimestamp + } status { phase } diff --git a/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js b/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js new file mode 100644 index 00000000000..0c6c0907000 --- /dev/null +++ b/app/assets/javascripts/kubernetes_dashboard/helpers/k8s_integration_helper.js @@ -0,0 +1,25 @@ +import { differenceInSeconds } from '~/lib/utils/datetime_utility'; + +export function getAge(creationTimestamp) { + if (!creationTimestamp) return ''; + + const timeDifference = differenceInSeconds(new Date(creationTimestamp), new Date()); + + const seconds = Math.floor(timeDifference); + const minutes = Math.floor(seconds / 60) % 60; + const hours = Math.floor(seconds / 60 / 60) % 24; + const days = Math.floor(seconds / 60 / 60 / 24); + + let ageString; + if (days > 0) { + ageString = `${days}d`; + } else if (hours > 0) { + ageString = `${hours}h`; + } else if (minutes > 0) { + ageString = `${minutes}m`; + } else { + ageString = `${seconds}s`; + } + + return ageString; +} diff --git a/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue b/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue index 5d2c3252c15..9cd759f335a 100644 --- a/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue +++ b/app/assets/javascripts/kubernetes_dashboard/pages/pods_page.vue @@ -1,6 +1,6 @@ <script> -import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; -import WorkloadStats from '../components/workload_stats.vue'; +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, @@ -12,9 +12,7 @@ import { export default { components: { - GlLoadingIcon, - GlAlert, - WorkloadStats, + WorkloadLayout, }, inject: ['configuration'], apollo: { @@ -26,7 +24,16 @@ export default { }; }, update(data) { - return data?.k8sPods || []; + return ( + data?.k8sPods?.map((pod) => { + return { + name: pod.metadata?.name, + namespace: pod.metadata?.namespace, + status: pod.status.phase, + age: getAge(pod.metadata?.creationTimestamp), + }; + }) || [] + ); }, error(err) { this.errorMessage = err?.message; @@ -35,6 +42,7 @@ export default { }, data() { return { + k8sPods: [], errorMessage: '', }; }, @@ -65,7 +73,7 @@ export default { }, methods: { countPodsByPhase(phase) { - const filteredPods = this.k8sPods?.filter((item) => item.status.phase === phase) || []; + const filteredPods = this.k8sPods?.filter((item) => item.status === phase) || []; return filteredPods.length; }, @@ -73,9 +81,10 @@ export default { }; </script> <template> - <gl-loading-icon v-if="loading" /> - <gl-alert v-else-if="errorMessage" variant="danger" :dismissible="false" class="gl-mb-5"> - {{ errorMessage }} - </gl-alert> - <workload-stats v-else :stats="podStats" /> + <workload-layout + :loading="loading" + :error-message="errorMessage" + :stats="podStats" + :items="k8sPods" + /> </template> diff --git a/app/models/bulk_imports/export_upload.rb b/app/models/bulk_imports/export_upload.rb index 00f8e8f1304..0560933ed93 100644 --- a/app/models/bulk_imports/export_upload.rb +++ b/app/models/bulk_imports/export_upload.rb @@ -11,6 +11,14 @@ module BulkImports mount_uploader :export_file, ExportUploader + # This causes CarrierWave v1 and v3 (but not v2) to upload the file to + # object storage *after* the database entry has been committed to the + # database. This avoids idling in a transaction. Similar to `ImportExportUpload`. + if Gitlab::Utils.to_boolean(ENV.fetch('ENABLE_STORE_EXPORT_FILE_AFTER_COMMIT', true)) + skip_callback :save, :after, :store_export_file! + set_callback :commit, :after, :store_export_file! + end + def retrieve_upload(_identifier, paths) Upload.find_by(model: self, path: paths) end diff --git a/app/uploaders/bulk_imports/export_uploader.rb b/app/uploaders/bulk_imports/export_uploader.rb index cd6e599054b..c1b6f1e0924 100644 --- a/app/uploaders/bulk_imports/export_uploader.rb +++ b/app/uploaders/bulk_imports/export_uploader.rb @@ -2,6 +2,6 @@ module BulkImports class ExportUploader < ImportExportUploader - EXTENSION_ALLOWLIST = %w[ndjson.gz].freeze + EXTENSION_ALLOWLIST = %w[ndjson.gz tar.gz gz].freeze end end diff --git a/app/workers/pages/deactivated_deployments_delete_cron_worker.rb b/app/workers/pages/deactivated_deployments_delete_cron_worker.rb index 7ee6327cea7..75905759761 100644 --- a/app/workers/pages/deactivated_deployments_delete_cron_worker.rb +++ b/app/workers/pages/deactivated_deployments_delete_cron_worker.rb @@ -12,6 +12,7 @@ module Pages def perform PagesDeployment.deactivated.each_batch do |deployments| # rubocop: disable Style/SymbolProc + deployments.each { |deployment| deployment.file.remove! } deployments.delete_all end end |