File

src/app/ceph/cluster/osd/osd-list/osd-list.component.ts

Implements

OnInit

Metadata

selector cd-osd-list
styleUrls ./osd-list.component.scss
templateUrl ./osd-list.component.html

Index

Properties
Methods
Accessors

Constructor

constructor(authStorageService: AuthStorageService, osdService: OsdService, dimlessBinaryPipe: DimlessBinaryPipe, modalService: BsModalService, i18n: I18n)
Parameters :
Name Type Optional
authStorageService AuthStorageService No
osdService OsdService No
dimlessBinaryPipe DimlessBinaryPipe No
modalService BsModalService No
i18n I18n No

Methods

Protected Static collectStates
collectStates(osd)
Parameters :
Name Optional
osd No
Returns : {}
configureClusterAction
configureClusterAction()
Returns : void
configureQosParamsAction
configureQosParamsAction()
Returns : void
getOsdList
getOsdList()
Returns : void
isNotSelectedOrInState
isNotSelectedOrInState(state: "in" | "up" | "down" | "out")

Returns true if no row is selected or if the selected row is in the given state. Useful for deactivating the corresponding menu entry.

Parameters :
Name Type Optional
state "in" | "up" | "down" | "out" No
Returns : boolean
ngOnInit
ngOnInit()
Returns : void
reweight
reweight()
Returns : void
scrubAction
scrubAction(deep)
Parameters :
Name Optional
deep No
Returns : void
showConfirmationModal
showConfirmationModal(markAction: string, onSubmit: (id: number) => void)
Parameters :
Name Type Optional
markAction string No
onSubmit function No
Returns : void
showCriticalConfirmationModal
showCriticalConfirmationModal(actionDescription: string, itemDescription: string, templateItemDescription: string, action: (id: number) => void)
Parameters :
Name Type Optional
actionDescription string No
itemDescription string No
templateItemDescription string No
action function No
Returns : void
updateSelection
updateSelection(selection: CdTableSelection)
Parameters :
Name Type Optional
selection CdTableSelection No
Returns : void

Properties

bsModalRef
Type : BsModalRef
columns
Type : CdTableColumn[]
criticalConfirmationTpl
Type : TemplateRef<any>
Decorators :
@ViewChild('criticalConfirmationTpl')
markOsdConfirmationTpl
Type : TemplateRef<any>
Decorators :
@ViewChild('markOsdConfirmationTpl')
osds
Type : []
Default value : []
osdUsageTpl
Type : TemplateRef<any>
Decorators :
@ViewChild('osdUsageTpl')
permissions
Type : Permissions
reweightBodyTpl
Type : TemplateRef<any>
Decorators :
@ViewChild('reweightBodyTpl')
safeToDestroyBodyTpl
Type : TemplateRef<any>
Decorators :
@ViewChild('safeToDestroyBodyTpl')
selection
Default value : new CdTableSelection()
statusColor
Type : TemplateRef<any>
Decorators :
@ViewChild('statusColor')
tableActions
Type : CdTableAction[]
tableComponent
Type : TableComponent
Decorators :
@ViewChild(TableComponent)

Accessors

hasOsdSelected
gethasOsdSelected()
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';

import { I18n } from '@ngx-translate/i18n-polyfill';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
import { Observable } from 'rxjs';

import { OsdService } from '../../../../shared/api/osd.service';
import { ConfirmationModalComponent } from '../../../../shared/components/confirmation-modal/confirmation-modal.component';
import { CriticalConfirmationModalComponent } from '../../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
import { TableComponent } from '../../../../shared/datatable/table/table.component';
import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
import { CdTableAction } from '../../../../shared/models/cd-table-action';
import { CdTableColumn } from '../../../../shared/models/cd-table-column';
import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
import { Permissions } from '../../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe';
import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
import { OsdFlagsModalComponent } from '../osd-flags-modal/osd-flags-modal.component';
import { OsdRecvSpeedModalComponent } from '../osd-recv-speed-modal/osd-recv-speed-modal.component';
import { OsdReweightModalComponent } from '../osd-reweight-modal/osd-reweight-modal.component';
import { OsdScrubModalComponent } from '../osd-scrub-modal/osd-scrub-modal.component';

@Component({
  selector: 'cd-osd-list',
  templateUrl: './osd-list.component.html',
  styleUrls: ['./osd-list.component.scss']
})
export class OsdListComponent implements OnInit {
  @ViewChild('statusColor')
  statusColor: TemplateRef<any>;
  @ViewChild('osdUsageTpl')
  osdUsageTpl: TemplateRef<any>;
  @ViewChild('markOsdConfirmationTpl')
  markOsdConfirmationTpl: TemplateRef<any>;
  @ViewChild('criticalConfirmationTpl')
  criticalConfirmationTpl: TemplateRef<any>;
  @ViewChild(TableComponent)
  tableComponent: TableComponent;
  @ViewChild('reweightBodyTpl')
  reweightBodyTpl: TemplateRef<any>;
  @ViewChild('safeToDestroyBodyTpl')
  safeToDestroyBodyTpl: TemplateRef<any>;

  permissions: Permissions;
  tableActions: CdTableAction[];
  bsModalRef: BsModalRef;
  columns: CdTableColumn[];

  osds = [];
  selection = new CdTableSelection();

  protected static collectStates(osd) {
    return [osd['in'] ? 'in' : 'out', osd['up'] ? 'up' : 'down'];
  }

  constructor(
    private authStorageService: AuthStorageService,
    private osdService: OsdService,
    private dimlessBinaryPipe: DimlessBinaryPipe,
    private modalService: BsModalService,
    private i18n: I18n
  ) {
    this.permissions = this.authStorageService.getPermissions();
    this.tableActions = [
      {
        name: this.i18n('Scrub'),
        permission: 'update',
        icon: 'fa-stethoscope',
        click: () => this.scrubAction(false),
        disable: () => !this.hasOsdSelected
      },
      {
        name: this.i18n('Deep Scrub'),
        permission: 'update',
        icon: 'fa-cog',
        click: () => this.scrubAction(true),
        disable: () => !this.hasOsdSelected
      },
      {
        name: this.i18n('Reweight'),
        permission: 'update',
        click: () => this.reweight(),
        disable: () => !this.hasOsdSelected,
        icon: 'fa-balance-scale'
      },
      {
        name: this.i18n('Mark Out'),
        permission: 'update',
        click: () => this.showConfirmationModal(this.i18n('out'), this.osdService.markOut),
        disable: () => this.isNotSelectedOrInState('out'),
        icon: 'fa-arrow-left'
      },
      {
        name: this.i18n('Mark In'),
        permission: 'update',
        click: () => this.showConfirmationModal(this.i18n('in'), this.osdService.markIn),
        disable: () => this.isNotSelectedOrInState('in'),
        icon: 'fa-arrow-right'
      },
      {
        name: this.i18n('Mark Down'),
        permission: 'update',
        click: () => this.showConfirmationModal(this.i18n('down'), this.osdService.markDown),
        disable: () => this.isNotSelectedOrInState('down'),
        icon: 'fa-arrow-down'
      },
      {
        name: this.i18n('Mark Lost'),
        permission: 'delete',
        click: () =>
          this.showCriticalConfirmationModal(
            this.i18n('Mark'),
            this.i18n('OSD lost'),
            this.i18n('marked lost'),
            this.osdService.markLost
          ),
        disable: () => this.isNotSelectedOrInState('up'),
        icon: 'fa-unlink'
      },
      {
        name: this.i18n('Purge'),
        permission: 'delete',
        click: () =>
          this.showCriticalConfirmationModal(
            this.i18n('Purge'),
            this.i18n('OSD'),
            this.i18n('purged'),
            this.osdService.purge
          ),
        disable: () => this.isNotSelectedOrInState('up'),
        icon: 'fa-eraser'
      },
      {
        name: this.i18n('Destroy'),
        permission: 'delete',
        click: () =>
          this.showCriticalConfirmationModal(
            this.i18n('destroy'),
            this.i18n('OSD'),
            this.i18n('destroyed'),
            this.osdService.destroy
          ),
        disable: () => this.isNotSelectedOrInState('up'),
        icon: 'fa-remove'
      }
    ];
  }

  ngOnInit() {
    this.columns = [
      { prop: 'host.name', name: this.i18n('Host') },
      { prop: 'id', name: this.i18n('ID'), cellTransformation: CellTemplate.bold },
      { prop: 'collectedStates', name: this.i18n('Status'), cellTemplate: this.statusColor },
      { prop: 'stats.numpg', name: this.i18n('PGs') },
      { prop: 'stats.stat_bytes', name: this.i18n('Size'), pipe: this.dimlessBinaryPipe },
      { name: this.i18n('Usage'), cellTemplate: this.osdUsageTpl },
      {
        prop: 'stats_history.out_bytes',
        name: this.i18n('Read bytes'),
        cellTransformation: CellTemplate.sparkline
      },
      {
        prop: 'stats_history.in_bytes',
        name: this.i18n('Writes bytes'),
        cellTransformation: CellTemplate.sparkline
      },
      {
        prop: 'stats.op_r',
        name: this.i18n('Read ops'),
        cellTransformation: CellTemplate.perSecond
      },
      {
        prop: 'stats.op_w',
        name: this.i18n('Write ops'),
        cellTransformation: CellTemplate.perSecond
      }
    ];
  }

  get hasOsdSelected() {
    if (this.selection.hasSelection) {
      const osdId = this.selection.first().id;
      const osd = this.osds.filter((o) => o.id === osdId).pop();
      return !!osd;
    }
    return false;
  }

  updateSelection(selection: CdTableSelection) {
    this.selection = selection;
  }

  /**
   * Returns true if no row is selected or if the selected row is in the given
   * state. Useful for deactivating the corresponding menu entry.
   */
  isNotSelectedOrInState(state: 'in' | 'up' | 'down' | 'out'): boolean {
    if (!this.hasOsdSelected) {
      return true;
    }

    const osdId = this.selection.first().id;
    const osd = this.osds.filter((o) => o.id === osdId).pop();

    if (!osd) {
      // `osd` is undefined if the selected OSD has been removed.
      return true;
    }

    switch (state) {
      case 'in':
        return osd.in === 1;
      case 'out':
        return osd.in !== 1;
      case 'down':
        return osd.up !== 1;
      case 'up':
        return osd.up === 1;
    }
  }

  getOsdList() {
    this.osdService.getList().subscribe((data: any[]) => {
      this.osds = data;
      data.map((osd) => {
        osd.collectedStates = OsdListComponent.collectStates(osd);
        osd.stats_history.out_bytes = osd.stats_history.op_out_bytes.map((i) => i[1]);
        osd.stats_history.in_bytes = osd.stats_history.op_in_bytes.map((i) => i[1]);
        osd.cdIsBinary = true;
        return osd;
      });
    });
  }

  scrubAction(deep) {
    if (!this.hasOsdSelected) {
      return;
    }

    const initialState = {
      selected: this.tableComponent.selection.selected,
      deep: deep
    };

    this.bsModalRef = this.modalService.show(OsdScrubModalComponent, { initialState });
  }

  configureClusterAction() {
    this.bsModalRef = this.modalService.show(OsdFlagsModalComponent, {});
  }

  showConfirmationModal(markAction: string, onSubmit: (id: number) => Observable<any>) {
    this.bsModalRef = this.modalService.show(ConfirmationModalComponent, {
      initialState: {
        titleText: this.i18n('Mark OSD {{markAction}}', { markAction: markAction }),
        buttonText: this.i18n('Mark {{markAction}}', { markAction: markAction }),
        bodyTpl: this.markOsdConfirmationTpl,
        bodyContext: {
          markActionDescription: markAction
        },
        onSubmit: () => {
          onSubmit
            .call(this.osdService, this.selection.first().id)
            .subscribe(() => this.bsModalRef.hide());
        }
      }
    });
  }

  reweight() {
    const selectedOsd = this.osds.filter((o) => o.id === this.selection.first().id).pop();
    this.modalService.show(OsdReweightModalComponent, {
      initialState: {
        currentWeight: selectedOsd.weight,
        osdId: selectedOsd.id
      }
    });
  }

  showCriticalConfirmationModal(
    actionDescription: string,
    itemDescription: string,
    templateItemDescription: string,
    action: (id: number) => Observable<any>
  ): void {
    this.osdService.safeToDestroy(this.selection.first().id).subscribe((result) => {
      const modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
        initialState: {
          actionDescription: actionDescription,
          itemDescription: itemDescription,
          bodyTemplate: this.criticalConfirmationTpl,
          bodyContext: {
            result: result,
            actionDescription: templateItemDescription
          },
          submitAction: () => {
            action
              .call(this.osdService, this.selection.first().id)
              .subscribe(() => modalRef.hide());
          }
        }
      });
    });
  }

  configureQosParamsAction() {
    this.bsModalRef = this.modalService.show(OsdRecvSpeedModalComponent, {});
  }
}
<tabset>
  <tab i18n-heading
       heading="OSDs List">
    <cd-table [data]="osds"
              (fetchData)="getOsdList()"
              [columns]="columns"
              selectionType="single"
              (updateSelection)="updateSelection($event)"
              [updateSelectionOnRefresh]="'never'">
      <div class="table-actions btn-toolbar">
        <cd-table-actions [permission]="permissions.osd"
                          [selection]="selection"
                          class="btn-group"
                          [tableActions]="tableActions">
        </cd-table-actions>

        <div class="btn-group"
             dropdown>
          <button type="button"
                  class="btn btn-sm btn-default btn-label tc_configureCluster"
                  (click)="configureClusterAction()">
            <i class="fa fa-fw fa-cog"
               aria-hidden="true">
            </i>
            <ng-container i18n>Set Cluster-wide Flags</ng-container>
          </button>
          <button type="button"
                  dropdownToggle
                  class="btn btn-sm btn-default dropdown-toggle dropdown-toggle-split">
            <span class="caret caret-black"></span>
          </button>
          <ul *dropdownMenu
              class="dropdown-menu"
              role="menu">
            <li role="menuitem">
              <a class="dropdown-item"
                 (click)="configureQosParamsAction()">
                <i class="fa fa-fw fa-cog"
                   aria-hidden="true">
                </i>
                <ng-container i18n>Set Cluster-wide Recovery Priority</ng-container>
              </a>
            </li>
          </ul>
        </div>
      </div>

      <cd-osd-details cdTableDetail
                      [selection]="selection">
      </cd-osd-details>
    </cd-table>

    <ng-template #statusColor
                 let-value="value">
      <span *ngFor="let state of value; last as last">
        <span class="label"
              [ngClass]="{'label-success': ['in', 'up'].includes(state), 'label-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
        <span *ngIf="!last">&nbsp;</span>
      </span>
    </ng-template>

    <ng-template #osdUsageTpl
                 let-row="row">
      <cd-usage-bar [totalBytes]="row.stats.stat_bytes"
                    [usedBytes]="row.stats.stat_bytes_used">
      </cd-usage-bar>
    </ng-template>
  </tab>
  <tab i18n-heading
       *ngIf="permissions.grafana.read"
       heading="Overall Performance">
    <cd-grafana [grafanaPath]="'osd-overview?'"
                uid="lo02I1Aiz"
                grafanaStyle="three">
    </cd-grafana>
  </tab>
</tabset>

<ng-template #markOsdConfirmationTpl
             let-markActionDescription="markActionDescription">
  <ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be marked
  <strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
</ng-template>

<ng-template #criticalConfirmationTpl
             let-safeToDestroyResult="result"
             let-actionDescription="actionDescription">
  <div *ngIf="!safeToDestroyResult['is_safe_to_destroy']"
       class="danger">
    <cd-warning-panel i18n>The OSD is not safe to destroy!</cd-warning-panel>
  </div>
  <ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be
  <strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
</ng-template>

./osd-list.component.scss

.caret.caret-black {
  color: #000000;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""