File

src/app/ceph/pool/erasure-code-profile-form/erasure-code-profile-form.component.ts

Implements

OnInit

Metadata

selector cd-erasure-code-profile-form
styleUrls ./erasure-code-profile-form.component.scss
templateUrl ./erasure-code-profile-form.component.html

Index

Properties
Methods
Outputs

Constructor

constructor(formBuilder: CdFormBuilder, bsModalRef: BsModalRef, taskWrapper: TaskWrapperService, ecpService: ErasureCodeProfileService, i18n: I18n, actionLabels: ActionLabelsI18n)
Parameters :
Name Type Optional
formBuilder CdFormBuilder No
bsModalRef BsModalRef No
taskWrapper TaskWrapperService No
ecpService ErasureCodeProfileService No
i18n I18n No
actionLabels ActionLabelsI18n No

Outputs

submitAction
Type : EventEmitter

Methods

createForm
createForm()
Returns : void
Private createJson
createJson()
Returns : any
Private extendJson
extendJson(name: string, ecp: ErasureCodeProfile)
Parameters :
Name Type Optional
name string No
ecp ErasureCodeProfile No
Returns : void
ngOnInit
ngOnInit()
Returns : void
onPluginChange
onPluginChange(plugin)
Parameters :
Name Optional
plugin No
Returns : void
onSubmit
onSubmit()
Returns : void
Private setDefaults
setDefaults(defaults: object)
Parameters :
Name Type Optional
defaults object No
Returns : void
Private setIsaDefaults
setIsaDefaults()
Returns : void
Private setJerasureDefaults
setJerasureDefaults()
Returns : void
Private setKMValidators
setKMValidators(required: boolean)
Parameters :
Name Type Optional
required boolean No
Returns : void
Private setLrcDefaults
setLrcDefaults()
Returns : void
Private setNumberValidators
setNumberValidators(name: string, required: boolean)
Parameters :
Name Type Optional
name string No
required boolean No
Returns : void
Private setShecDefaults
setShecDefaults()
Returns : void

Properties

action
Type : string
Public actionLabels
Type : ActionLabelsI18n
Public bsModalRef
Type : BsModalRef
devices
Type : string[]
Default value : []
failureDomains
Type : string[]
form
Type : CdFormGroup
names
Type : string[]
plugin
Default value : this.PLUGIN.JERASURE
PLUGIN
Type : object
Default value : { LRC: 'lrc', // Locally Repairable Erasure Code SHEC: 'shec', // Shingled Erasure Code JERASURE: 'jerasure', // default ISA: 'isa' // Intel Storage Acceleration }
plugins
Type : string[]
requiredControls
Type : string[]
Default value : []
resource
Type : string
techniques
Type : string[]
tooltips
Default value : this.ecpService.formTooltips
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Validators } from '@angular/forms';

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

import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
import { CdFormBuilder } from '../../../shared/forms/cd-form-builder';
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import { CdValidators } from '../../../shared/forms/cd-validators';
import { ErasureCodeProfile } from '../../../shared/models/erasure-code-profile';
import { FinishedTask } from '../../../shared/models/finished-task';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';

@Component({
  selector: 'cd-erasure-code-profile-form',
  templateUrl: './erasure-code-profile-form.component.html',
  styleUrls: ['./erasure-code-profile-form.component.scss']
})
export class ErasureCodeProfileFormComponent implements OnInit {
  @Output()
  submitAction = new EventEmitter();

  form: CdFormGroup;
  failureDomains: string[];
  plugins: string[];
  names: string[];
  techniques: string[];
  requiredControls: string[] = [];
  devices: string[] = [];
  tooltips = this.ecpService.formTooltips;

  PLUGIN = {
    LRC: 'lrc', // Locally Repairable Erasure Code
    SHEC: 'shec', // Shingled Erasure Code
    JERASURE: 'jerasure', // default
    ISA: 'isa' // Intel Storage Acceleration
  };
  plugin = this.PLUGIN.JERASURE;
  action: string;
  resource: string;

  constructor(
    private formBuilder: CdFormBuilder,
    public bsModalRef: BsModalRef,
    private taskWrapper: TaskWrapperService,
    private ecpService: ErasureCodeProfileService,
    private i18n: I18n,
    public actionLabels: ActionLabelsI18n
  ) {
    this.action = this.actionLabels.CREATE;
    this.resource = this.i18n('EC Profile');
    this.createForm();
    this.setJerasureDefaults();
  }

  createForm() {
    this.form = this.formBuilder.group({
      name: [
        null,
        [
          Validators.required,
          Validators.pattern('[A-Za-z0-9_-]+'),
          CdValidators.custom(
            'uniqueName',
            (value) => this.names && this.names.indexOf(value) !== -1
          )
        ]
      ],
      plugin: [this.PLUGIN.JERASURE, [Validators.required]],
      k: [1], // Will be replaced by plugin defaults
      m: [1], // Will be replaced by plugin defaults
      crushFailureDomain: ['host'],
      crushRoot: ['default'], // default for all - is a list possible???
      crushDeviceClass: [''], // set none to empty at submit - get list from configs?
      directory: [''],
      // Only for 'jerasure' and 'isa' use
      technique: ['reed_sol_van'],
      // Only for 'jerasure' use
      packetSize: [2048, [Validators.min(1)]],
      // Only for 'lrc' use
      l: [1, [Validators.required, Validators.min(1)]],
      crushLocality: [''], // set to none at the end (same list as for failure domains)
      // Only for 'shec' use
      c: [1, [Validators.required, Validators.min(1)]]
    });
    this.form.get('plugin').valueChanges.subscribe((plugin) => this.onPluginChange(plugin));
  }

  onPluginChange(plugin) {
    this.plugin = plugin;
    if (plugin === this.PLUGIN.JERASURE) {
      this.setJerasureDefaults();
    } else if (plugin === this.PLUGIN.LRC) {
      this.setLrcDefaults();
    } else if (plugin === this.PLUGIN.ISA) {
      this.setIsaDefaults();
    } else if (plugin === this.PLUGIN.SHEC) {
      this.setShecDefaults();
    }
  }

  private setNumberValidators(name: string, required: boolean) {
    const validators = [Validators.min(1)];
    if (required) {
      validators.push(Validators.required);
    }
    this.form.get(name).setValidators(validators);
  }

  private setKMValidators(required: boolean) {
    ['k', 'm'].forEach((name) => this.setNumberValidators(name, required));
  }

  private setJerasureDefaults() {
    this.requiredControls = ['k', 'm'];
    this.setDefaults({
      k: 4,
      m: 2
    });
    this.setKMValidators(true);
    this.techniques = [
      'reed_sol_van',
      'reed_sol_r6_op',
      'cauchy_orig',
      'cauchy_good',
      'liberation',
      'blaum_roth',
      'liber8tion'
    ];
  }

  private setLrcDefaults() {
    this.requiredControls = ['k', 'm', 'l'];
    this.setKMValidators(true);
    this.setNumberValidators('l', true);
    this.setDefaults({
      k: 4,
      m: 2,
      l: 3
    });
  }

  private setIsaDefaults() {
    this.requiredControls = [];
    this.setKMValidators(false);
    this.setDefaults({
      k: 7,
      m: 3
    });
    this.techniques = ['reed_sol_van', 'cauchy'];
  }

  private setShecDefaults() {
    this.requiredControls = [];
    this.setKMValidators(false);
    this.setDefaults({
      k: 4,
      m: 3,
      c: 2
    });
  }

  private setDefaults(defaults: object) {
    Object.keys(defaults).forEach((controlName) => {
      if (this.form.get(controlName).pristine) {
        this.form.silentSet(controlName, defaults[controlName]);
      }
    });
  }

  ngOnInit() {
    this.ecpService
      .getInfo()
      .subscribe(
        ({
          failure_domains,
          plugins,
          names,
          directory,
          devices
        }: {
          failure_domains: string[];
          plugins: string[];
          names: string[];
          directory: string;
          devices: string[];
        }) => {
          this.failureDomains = failure_domains;
          this.plugins = plugins;
          this.names = names;
          this.devices = devices;
          this.form.silentSet('directory', directory);
        }
      );
  }

  private createJson() {
    const pluginControls = {
      technique: [this.PLUGIN.ISA, this.PLUGIN.JERASURE],
      packetSize: [this.PLUGIN.JERASURE],
      l: [this.PLUGIN.LRC],
      crushLocality: [this.PLUGIN.LRC],
      c: [this.PLUGIN.SHEC]
    };
    const ecp = new ErasureCodeProfile();
    const plugin = this.form.getValue('plugin');
    Object.keys(this.form.controls)
      .filter((name) => {
        const pluginControl = pluginControls[name];
        const control = this.form.get(name);
        const usable = (pluginControl && pluginControl.includes(plugin)) || !pluginControl;
        return (
          usable &&
          (control.dirty || this.requiredControls.includes(name)) &&
          this.form.getValue(name)
        );
      })
      .forEach((name) => {
        this.extendJson(name, ecp);
      });
    return ecp;
  }

  private extendJson(name: string, ecp: ErasureCodeProfile) {
    const differentApiAttributes = {
      crushFailureDomain: 'crush-failure-domain',
      crushRoot: 'crush-root',
      crushDeviceClass: 'crush-device-class',
      packetSize: 'packetsize',
      crushLocality: 'crush-locality'
    };
    ecp[differentApiAttributes[name] || name] = this.form.getValue(name);
  }

  onSubmit() {
    if (this.form.invalid) {
      this.form.setErrors({ cdSubmitButton: true });
      return;
    }
    const profile = this.createJson();
    this.taskWrapper
      .wrapTaskAroundCall({
        task: new FinishedTask('ecp/create', { name: profile.name }),
        call: this.ecpService.create(profile)
      })
      .subscribe(
        undefined,
        () => {
          this.form.setErrors({ cdSubmitButton: true });
        },
        () => {
          this.bsModalRef.hide();
          this.submitAction.emit(profile);
        }
      );
  }
}
<div class="modal-header">
  <h4 i18n="form title|Example: Create Pool@@formTitle"
      class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
  <button type="button"
          class="close pull-right"
          aria-label="Close"
          (click)="bsModalRef.hide()">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

<form class="form-horizontal"
      #frm="ngForm"
      [formGroup]="form"
      novalidate>
  <div class="modal-body">
    <div class="form-group"
         [ngClass]="{'has-error': form.showError('name', frm)}">
      <label for="name"
             class="control-label col-sm-3">
        <ng-container i18n>Name</ng-container>
        <span class="required"></span>
      </label>
      <div class="col-sm-9">
        <input type="text"
               id="name"
               name="name"
               class="form-control"
               placeholder="Name..."
               formControlName="name"
               autofocus>
        <span class="help-block"
              *ngIf="form.showError('name', frm, 'required')"
              i18n>This field is required!</span>
        <span class="help-block"
              *ngIf="form.showError('name', frm, 'pattern')"
              i18n>The name can only consist of alphanumeric characters, dashes and underscores.</span>
        <span class="help-block"
              *ngIf="form.showError('name', frm, 'uniqueName')"
              i18n>The chosen erasure code profile name is already in use.</span>
      </div>
    </div>

    <div class="form-group">
      <label for="plugin"
             class="control-label col-sm-3">
        <ng-container i18n>Plugin</ng-container>
        <span class="required"></span>
        <cd-helper [html]="tooltips.plugins[plugin].description">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <select class="form-control"
                id="plugin"
                name="plugin"
                formControlName="plugin">
          <option *ngIf="!plugins"
                  ngValue=""
                  i18n>Loading...</option>
          <option *ngFor="let plugin of plugins"
                  [ngValue]="plugin">
            {{ plugin }}
          </option>
        </select>
        <span class="help-block"
              *ngIf="form.showError('name', frm, 'required')"
              i18n>This field is required!</span>
      </div>
    </div>

    <div class="form-group"
         [ngClass]="{'has-error': form.showError('k', frm)}">
      <label for="k"
             class="control-label col-sm-3">
        <ng-container i18n>Data chunks (k)</ng-container>
        <span class="required"
              *ngIf="requiredControls.includes('k')"></span>
        <cd-helper [html]="tooltips.k">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="number"
               id="k"
               name="k"
               class="form-control"
               ng-model="$ctrl.erasureCodeProfile.k"
               placeholder="Data chunks..."
               formControlName="k">
        <span class="help-block"
              *ngIf="form.showError('k', frm, 'required')"
              i18n>This field is required!</span>
        <span class="help-block"
              *ngIf="form.showError('k', frm, 'min')"
              i18n>Must be equal to or greater than 2.</span>
      </div>
    </div>

    <div class="form-group"
         [ngClass]="{'has-error': form.showError('m', frm)}">
      <label for="m"
             class="control-label col-sm-3">
        <ng-container i18n>Coding chunks (m)</ng-container>
        <span class="required"
              *ngIf="requiredControls.includes('m')"></span>
        <cd-helper [html]="tooltips.m">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="number"
               id="m"
               name="m"
               class="form-control"
               placeholder="Coding chunks..."
               formControlName="m">
        <span class="help-block"
              *ngIf="form.showError('m', frm, 'required')"
              i18n>This field is required!</span>
        <span class="help-block"
              *ngIf="form.showError('m', frm, 'min')"
              i18n>Must be equal to or greater than 1.</span>
      </div>
    </div>

    <div class="form-group"
         *ngIf="plugin === 'shec'"
         [ngClass]="{'has-error': form.showError('c', frm)}">
      <label for="c"
             class="control-label col-sm-3">
        <ng-container i18n>Durability estimator (c)</ng-container>
        <cd-helper [html]="tooltips.plugins.shec.c">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="number"
               id="c"
               name="c"
               class="form-control"
               placeholder="Coding chunks..."
               formControlName="c">
        <span class="help-block"
              *ngIf="form.showError('c', frm, 'min')"
              i18n>Must be equal to or greater than 1.</span>
      </div>
    </div>

    <div class="form-group"
         *ngIf="plugin === PLUGIN.LRC"
         [ngClass]="{'has-error': form.showError('l', frm)}">
      <label for="l"
             class="control-label col-sm-3">
        <ng-container i18n>Locality (l)</ng-container>
        <span class="required"></span>
        <cd-helper [html]="tooltips.plugins.lrc.l">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="number"
               id="l"
               name="l"
               class="form-control"
               placeholder="Coding chunks..."
               formControlName="l">
        <span class="help-block"
              *ngIf="form.showError('l', frm, 'required')"
              i18n>This field is required!</span>
        <span class="help-block"
              *ngIf="form.showError('l', frm, 'min')"
              i18n>Must be equal to or greater than 1.</span>
      </div>
    </div>

    <div class="form-group">
      <label for="crushFailureDomain"
             class="control-label col-sm-3">
        <ng-container i18n>Crush failure domain</ng-container>
        <cd-helper [html]="tooltips.crushFailureDomain">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <select class="form-control"
                id="crushFailureDomain"
                name="crushFailureDomain"
                formControlName="crushFailureDomain">
          <option *ngIf="!failureDomains"
                  ngValue=""
                  i18n>Loading...</option>
          <option *ngFor="let domain of failureDomains"
                  [ngValue]="domain">
            {{ domain }}
          </option>
        </select>
      </div>
    </div>

    <div class="form-group"
         *ngIf="plugin === PLUGIN.LRC">
      <label for="crushLocality"
             class="control-label col-sm-3">
        <ng-container i18n>Crush Locality</ng-container>
        <cd-helper [html]="tooltips.plugins.lrc.crushLocality">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <select class="form-control"
                id="crushLocality"
                name="crushLocality"
                formControlName="crushLocality">
          <option *ngIf="!failureDomains"
                  ngValue=""
                  i18n>Loading...</option>
          <option *ngIf="failureDomains && failureDomains.length > 0"
                  ngValue=""
                  i18n>None</option>
          <option *ngFor="let domain of failureDomains"
                  [ngValue]="domain">
            {{ domain }}
          </option>
        </select>
      </div>
    </div>

    <div class="form-group"
         *ngIf="[PLUGIN.JERASURE, PLUGIN.ISA].includes(plugin)">
      <label for="technique"
             class="control-label col-sm-3">
        <ng-container i18n>Technique</ng-container>
        <cd-helper [html]="tooltips.plugins[plugin].technique">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <select class="form-control"
                id="technique"
                name="technique"
                formControlName="technique">
          <option *ngFor="let technique of techniques"
                  [ngValue]="technique">
            {{ technique }}
          </option>
        </select>
      </div>
    </div>

    <div class="form-group"
         *ngIf="plugin === PLUGIN.JERASURE"
         [ngClass]="{'has-error': form.showError('packetSize', frm)}">
      <label for="packetSize"
             class="control-label col-sm-3">
        <ng-container i18n>Packetsize</ng-container>
        <cd-helper [html]="tooltips.plugins.jerasure.packetSize">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="number"
               id="packetSize"
               name="packetSize"
               class="form-control"
               placeholder="Packetsize..."
               formControlName="packetSize">
        <span class="help-block"
              *ngIf="form.showError('packetSize', frm, 'min')"
              i18n>Must be equal to or greater than 1.</span>
      </div>
    </div>

    <div class="form-group"
         [ngClass]="{'has-error': form.showError('crushRoot', frm)}">
      <label for="crushRoot"
             class="control-label col-sm-3">
        <ng-container i18n>Crush root</ng-container>
        <cd-helper [html]="tooltips.crushRoot">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="text"
               id="crushRoot"
               name="crushRoot"
               class="form-control"
               placeholder="root..."
               formControlName="crushRoot">
      </div>
    </div>

    <div class="form-group">
      <label for="crushDeviceClass"
             class="control-label col-sm-3">
        <ng-container i18n>Crush device class</ng-container>
        <cd-helper [html]="tooltips.crushDeviceClass">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <select class="form-control"
                id="crushDeviceClass"
                name="crushDeviceClass"
                formControlName="crushDeviceClass">
          <option ngValue=""
                  i18n>any</option>
          <option *ngFor="let deviceClass of devices"
                  [ngValue]="deviceClass">
            {{ deviceClass }}
          </option>
        </select>
      </div>
    </div>

    <div class="form-group">
      <label for="directory"
             class="control-label col-sm-3">
        <ng-container i18n>Directory</ng-container>
        <cd-helper [html]="tooltips.directory">
        </cd-helper>
      </label>
      <div class="col-sm-9">
        <input type="text"
               id="directory"
               name="directory"
               class="form-control"
               placeholder="Path..."
               formControlName="directory">
      </div>
    </div>
  </div>

  <div class="modal-footer">
    <cd-submit-button
      (submitAction)="onSubmit()"
      i18n="form action button|Example: Create Pool@@formActionButton"
      [form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
    <cd-back-button [back]="bsModalRef.hide"></cd-back-button>
  </div>
</form>

./erasure-code-profile-form.component.scss

Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""