]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard : Add Cert Status column to services page 66949/head
authorAbhishek Desai <abhishek.desai1@ibm.com>
Fri, 16 Jan 2026 14:31:54 +0000 (20:01 +0530)
committerAbhishek Desai <abhishek.desai1@ibm.com>
Tue, 20 Jan 2026 20:38:40 +0000 (02:08 +0530)
fixes : https://tracker.ceph.com/issues/74411
Signed-off-by: Abhishek Desai <abhishek.desai1@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/models/service.interface.ts

index 042b180d1ba67aee6825acb14a93e61670d9d383..07380d6a169c5d40302747ceef0e9795a853fc19 100644 (file)
   </ng-container>
   <ng-template #noUrl>{{row.service_name}}</ng-template>
 </ng-template>
+
+<ng-template #certificateStatusTpl
+             let-row="data.row">
+  @if (row.certificate) {
+    {{ formatCertificateStatus(row.certificate) }}
+  } @else {
+    -
+  }
+</ng-template>
index 7a5e8ee54b75d0d1cff67e3469e65b9931fa4294..782650c8eafc4952b11d1807c6e789429fedd6a2 100644 (file)
@@ -1,3 +1,4 @@
+import { DatePipe } from '@angular/common';
 import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
 import { Router } from '@angular/router';
 
@@ -18,7 +19,11 @@ import { FinishedTask } from '~/app/shared/models/finished-task';
 import { OrchestratorFeature } from '~/app/shared/models/orchestrator.enum';
 import { OrchestratorStatus } from '~/app/shared/models/orchestrator.interface';
 import { Permissions } from '~/app/shared/models/permissions';
-import { CephServiceSpec } from '~/app/shared/models/service.interface';
+import {
+  CephCertificateStatus,
+  CephServiceCertificate,
+  CephServiceSpec
+} from '~/app/shared/models/service.interface';
 import { RelativeDatePipe } from '~/app/shared/pipes/relative-date.pipe';
 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
@@ -35,7 +40,7 @@ const BASE_URL = 'services';
   selector: 'cd-services',
   templateUrl: './services.component.html',
   styleUrls: ['./services.component.scss'],
-  providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }],
+  providers: [DatePipe, { provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }],
   standalone: false
 })
 export class ServicesComponent extends ListWithDetails implements OnChanges, OnInit {
@@ -45,6 +50,8 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
   public runningTpl: TemplateRef<any>;
   @ViewChild('urlTpl', { static: true })
   public urlTpl: TemplateRef<any>;
+  @ViewChild('certificateStatusTpl', { static: true })
+  public certificateStatusTpl: TemplateRef<any>;
 
   @Input() hostname: string;
 
@@ -86,7 +93,8 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
     private taskWrapperService: TaskWrapperService,
     private router: Router,
     private settingsService: SettingsService,
-    private cdsModalService: ModalCdsService
+    private cdsModalService: ModalCdsService,
+    private datePipe: DatePipe
   ) {
     super();
     this.permissions = this.authStorageService.getPermissions();
@@ -185,6 +193,12 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
           undefined: '-',
           '': '-'
         }
+      },
+      {
+        name: $localize`Certificate Status`,
+        prop: 'certificate.status',
+        flexGrow: 2,
+        cellTemplate: this.certificateStatusTpl
       }
     ];
 
@@ -300,4 +314,30 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
       this.serviceUrls[serviceType] = url;
     });
   }
+
+  formatCertificateStatus(cert: CephServiceCertificate): string {
+    if (!cert || !cert.requires_certificate || !cert.status) {
+      return '-';
+    }
+
+    const formattedDate = cert.expiry_date
+      ? this.datePipe.transform(cert.expiry_date, 'dd MMM y')
+      : null;
+
+    switch (cert.status) {
+      case CephCertificateStatus.valid:
+        return formattedDate ? $localize`Valid - ${formattedDate}` : $localize`Valid`;
+      case CephCertificateStatus.expiring:
+      case CephCertificateStatus.expiringSoon:
+        return formattedDate
+          ? $localize`Expiring soon - ${formattedDate}`
+          : $localize`Expiring soon`;
+      case CephCertificateStatus.expired:
+        return formattedDate ? $localize`Expired - ${formattedDate}` : $localize`Expired`;
+      case CephCertificateStatus.notConfigured:
+        return '-';
+      default:
+        return formattedDate ? `${cert.status} - ${formattedDate}` : cert.status;
+    }
+  }
 }
index c79a9cb4e74a1c2b74712900a10d7e33069c1e98..6ee238e76fea955d91d47f0f1c54c4c2aea34a36 100644 (file)
@@ -7,6 +7,27 @@ export interface CephServiceStatus {
   created: Date;
 }
 
+export enum CephCertificateStatus {
+  valid = 'valid',
+  expired = 'expired',
+  expiring = 'expiring',
+  expiringSoon = 'expiring_soon',
+  notConfigured = 'not_configured',
+  invalid = 'invalid'
+}
+
+export interface CephServiceCertificate {
+  cert_name: string;
+  scope: string;
+  requires_certificate: boolean;
+  status: CephCertificateStatus | string;
+  days_to_expiration: number;
+  signed_by: string;
+  has_certificate: boolean;
+  certificate_source: string;
+  expiry_date: string;
+}
+
 // This will become handy when creating arbitrary services
 export interface CephServiceSpec {
   service_name: string;
@@ -14,6 +35,7 @@ export interface CephServiceSpec {
   service_id: string;
   unmanaged: boolean;
   status: CephServiceStatus;
+  certificate?: CephServiceCertificate;
   spec: CephServiceAdditionalSpec;
   placement: CephServicePlacement;
 }