]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; |
2 | import { FormControl, Validators } from '@angular/forms'; | |
3 | import { ActivatedRoute, Router } from '@angular/router'; | |
4 | ||
5 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
6 | import * as _ from 'lodash'; | |
7 | import { forkJoin, Observable, of } from 'rxjs'; | |
8 | import { map, mergeMap } from 'rxjs/operators'; | |
9 | ||
10 | import { NfsService } from '../../../shared/api/nfs.service'; | |
11 | import { RgwUserService } from '../../../shared/api/rgw-user.service'; | |
12 | import { SelectMessages } from '../../../shared/components/select/select-messages.model'; | |
13 | import { SelectOption } from '../../../shared/components/select/select-option.model'; | |
eafe8130 | 14 | import { ActionLabelsI18n } from '../../../shared/constants/app.constants'; |
11fdf7f2 TL |
15 | import { CdFormBuilder } from '../../../shared/forms/cd-form-builder'; |
16 | import { CdFormGroup } from '../../../shared/forms/cd-form-group'; | |
17 | import { CdValidators } from '../../../shared/forms/cd-validators'; | |
18 | import { FinishedTask } from '../../../shared/models/finished-task'; | |
19 | import { Permission } from '../../../shared/models/permissions'; | |
eafe8130 | 20 | import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; |
11fdf7f2 | 21 | import { AuthStorageService } from '../../../shared/services/auth-storage.service'; |
eafe8130 | 22 | import { SummaryService } from '../../../shared/services/summary.service'; |
11fdf7f2 TL |
23 | import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; |
24 | import { NfsFormClientComponent } from '../nfs-form-client/nfs-form-client.component'; | |
25 | ||
26 | @Component({ | |
27 | selector: 'cd-nfs-form', | |
28 | templateUrl: './nfs-form.component.html', | |
29 | styleUrls: ['./nfs-form.component.scss'] | |
30 | }) | |
31 | export class NfsFormComponent implements OnInit { | |
32 | @ViewChild('nfsClients') | |
33 | nfsClients: NfsFormClientComponent; | |
34 | ||
35 | permission: Permission; | |
36 | nfsForm: CdFormGroup; | |
37 | isEdit = false; | |
38 | ||
39 | cluster_id = null; | |
40 | export_id = null; | |
41 | ||
42 | isNewDirectory = false; | |
43 | isNewBucket = false; | |
44 | isDefaultCluster = false; | |
45 | ||
46 | allClusters: string[] = null; | |
47 | allDaemons = {}; | |
48 | ||
49 | allFsals: any[] = []; | |
50 | allRgwUsers: any[] = []; | |
51 | allCephxClients: any[] = null; | |
52 | allFsNames: any[] = null; | |
53 | ||
eafe8130 | 54 | defaultAccessType = { RGW: 'RO' }; |
11fdf7f2 TL |
55 | nfsAccessType: any[] = this.nfsService.nfsAccessType; |
56 | nfsSquash: any[] = this.nfsService.nfsSquash; | |
57 | ||
eafe8130 TL |
58 | action: string; |
59 | resource: string; | |
60 | docsUrl: string; | |
61 | ||
11fdf7f2 TL |
62 | daemonsSelections: SelectOption[] = []; |
63 | daemonsMessages = new SelectMessages( | |
64 | { noOptions: this.i18n('There are no daemons available.') }, | |
65 | this.i18n | |
66 | ); | |
67 | ||
68 | pathDataSource: Observable<any> = Observable.create((observer: any) => { | |
69 | observer.next(this.nfsForm.getValue('path')); | |
70 | }).pipe( | |
71 | mergeMap((token: string) => this.getPathTypeahead(token)), | |
72 | map((val: any) => val.paths) | |
73 | ); | |
74 | ||
75 | bucketDataSource: Observable<any> = Observable.create((observer: any) => { | |
76 | observer.next(this.nfsForm.getValue('path')); | |
77 | }).pipe(mergeMap((token: string) => this.getBucketTypeahead(token))); | |
78 | ||
79 | constructor( | |
80 | private authStorageService: AuthStorageService, | |
81 | private nfsService: NfsService, | |
82 | private route: ActivatedRoute, | |
83 | private router: Router, | |
84 | private rgwUserService: RgwUserService, | |
85 | private formBuilder: CdFormBuilder, | |
eafe8130 TL |
86 | private summaryservice: SummaryService, |
87 | private cephReleaseNamePipe: CephReleaseNamePipe, | |
11fdf7f2 TL |
88 | private taskWrapper: TaskWrapperService, |
89 | private cdRef: ChangeDetectorRef, | |
eafe8130 TL |
90 | private i18n: I18n, |
91 | public actionLabels: ActionLabelsI18n | |
11fdf7f2 TL |
92 | ) { |
93 | this.permission = this.authStorageService.getPermissions().pool; | |
eafe8130 | 94 | this.resource = this.i18n('NFS export'); |
11fdf7f2 TL |
95 | this.createForm(); |
96 | } | |
97 | ||
98 | ngOnInit() { | |
99 | const promises: any[] = [ | |
100 | this.nfsService.daemon(), | |
101 | this.nfsService.fsals(), | |
102 | this.nfsService.clients(), | |
103 | this.nfsService.filesystems() | |
104 | ]; | |
105 | ||
106 | if (this.router.url.startsWith('/nfs/edit')) { | |
107 | this.isEdit = true; | |
108 | } | |
109 | ||
110 | if (this.isEdit) { | |
eafe8130 | 111 | this.action = this.actionLabels.EDIT; |
11fdf7f2 TL |
112 | this.route.params.subscribe((params: { cluster_id: string; export_id: string }) => { |
113 | this.cluster_id = decodeURIComponent(params.cluster_id); | |
114 | this.export_id = decodeURIComponent(params.export_id); | |
115 | promises.push(this.nfsService.get(this.cluster_id, this.export_id)); | |
116 | ||
117 | this.getData(promises); | |
118 | }); | |
119 | } else { | |
eafe8130 | 120 | this.action = this.actionLabels.CREATE; |
11fdf7f2 TL |
121 | this.getData(promises); |
122 | } | |
eafe8130 TL |
123 | |
124 | const summary = this.summaryservice.getCurrentSummary(); | |
125 | const releaseName = this.cephReleaseNamePipe.transform(summary.version); | |
126 | this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/radosgw/nfs/`; | |
11fdf7f2 TL |
127 | } |
128 | ||
129 | getData(promises) { | |
130 | forkJoin(promises).subscribe((data: any[]) => { | |
131 | this.resolveDaemons(data[0]); | |
132 | this.resolvefsals(data[1]); | |
133 | this.resolveClients(data[2]); | |
134 | this.resolveFilesystems(data[3]); | |
135 | if (data[4]) { | |
136 | this.resolveModel(data[4]); | |
137 | } | |
138 | }); | |
139 | } | |
140 | ||
141 | createForm() { | |
142 | this.nfsForm = new CdFormGroup({ | |
143 | cluster_id: new FormControl('', { | |
144 | validators: [Validators.required] | |
145 | }), | |
146 | daemons: new FormControl([]), | |
147 | fsal: new CdFormGroup({ | |
148 | name: new FormControl('', { | |
149 | validators: [Validators.required] | |
150 | }), | |
151 | user_id: new FormControl('', { | |
152 | validators: [ | |
153 | CdValidators.requiredIf({ | |
154 | name: 'CEPH' | |
155 | }) | |
156 | ] | |
157 | }), | |
158 | fs_name: new FormControl('', { | |
159 | validators: [ | |
160 | CdValidators.requiredIf({ | |
161 | name: 'CEPH' | |
162 | }) | |
163 | ] | |
164 | }), | |
165 | rgw_user_id: new FormControl('', { | |
166 | validators: [ | |
167 | CdValidators.requiredIf({ | |
168 | name: 'RGW' | |
169 | }) | |
170 | ] | |
171 | }) | |
172 | }), | |
173 | path: new FormControl(''), | |
174 | protocolNfsv3: new FormControl(true, { | |
175 | validators: [ | |
176 | CdValidators.requiredIf({ protocolNfsv4: false }, (value) => { | |
177 | return !value; | |
178 | }) | |
179 | ] | |
180 | }), | |
181 | protocolNfsv4: new FormControl(true, { | |
182 | validators: [ | |
183 | CdValidators.requiredIf({ protocolNfsv3: false }, (value) => { | |
184 | return !value; | |
185 | }) | |
186 | ] | |
187 | }), | |
188 | tag: new FormControl(''), | |
189 | pseudo: new FormControl('', { | |
190 | validators: [ | |
191 | CdValidators.requiredIf({ protocolNfsv4: true }), | |
192 | Validators.pattern('^/[^><|&()]*$') | |
193 | ] | |
194 | }), | |
195 | access_type: new FormControl('RW', { | |
196 | validators: [Validators.required] | |
197 | }), | |
198 | squash: new FormControl('', { | |
199 | validators: [Validators.required] | |
200 | }), | |
201 | transportUDP: new FormControl(true, { | |
202 | validators: [ | |
203 | CdValidators.requiredIf({ transportTCP: false }, (value) => { | |
204 | return !value; | |
205 | }) | |
206 | ] | |
207 | }), | |
208 | transportTCP: new FormControl(true, { | |
209 | validators: [ | |
210 | CdValidators.requiredIf({ transportUDP: false }, (value) => { | |
211 | return !value; | |
212 | }) | |
213 | ] | |
214 | }), | |
215 | clients: this.formBuilder.array([]), | |
216 | security_label: new FormControl(false), | |
217 | sec_label_xattr: new FormControl( | |
218 | 'security.selinux', | |
219 | CdValidators.requiredIf({ security_label: true, 'fsal.name': 'CEPH' }) | |
220 | ) | |
221 | }); | |
11fdf7f2 TL |
222 | } |
223 | ||
224 | resolveModel(res) { | |
225 | if (res.fsal.name === 'CEPH') { | |
226 | res.sec_label_xattr = res.fsal.sec_label_xattr; | |
227 | } | |
228 | ||
229 | this.daemonsSelections = _.map( | |
230 | this.allDaemons[res.cluster_id], | |
231 | (daemon) => new SelectOption(res.daemons.indexOf(daemon) !== -1, daemon, '') | |
232 | ); | |
233 | this.daemonsSelections = [...this.daemonsSelections]; | |
234 | ||
235 | res.protocolNfsv3 = res.protocols.indexOf(3) !== -1; | |
236 | res.protocolNfsv4 = res.protocols.indexOf(4) !== -1; | |
237 | delete res.protocols; | |
238 | ||
239 | res.transportTCP = res.transports.indexOf('TCP') !== -1; | |
240 | res.transportUDP = res.transports.indexOf('UDP') !== -1; | |
241 | delete res.transports; | |
242 | ||
243 | res.clients.forEach((client) => { | |
244 | let addressStr = ''; | |
245 | client.addresses.forEach((address) => { | |
246 | addressStr += address + ', '; | |
247 | }); | |
248 | if (addressStr.length >= 2) { | |
249 | addressStr = addressStr.substring(0, addressStr.length - 2); | |
250 | } | |
251 | client.addresses = addressStr; | |
252 | }); | |
253 | ||
254 | this.nfsForm.patchValue(res); | |
255 | this.setPathValidation(); | |
256 | this.nfsClients.resolveModel(res.clients); | |
257 | } | |
258 | ||
259 | resolveDaemons(daemons) { | |
260 | daemons = _.sortBy(daemons, ['daemon_id']); | |
261 | ||
262 | this.allClusters = _(daemons) | |
263 | .map((daemon) => daemon.cluster_id) | |
264 | .sortedUniq() | |
265 | .value(); | |
266 | ||
267 | _.forEach(this.allClusters, (cluster) => { | |
268 | this.allDaemons[cluster] = []; | |
269 | }); | |
270 | ||
271 | _.forEach(daemons, (daemon) => { | |
272 | this.allDaemons[daemon.cluster_id].push(daemon.daemon_id); | |
273 | }); | |
274 | ||
275 | const hasOneCluster = _.isArray(this.allClusters) && this.allClusters.length === 1; | |
276 | this.isDefaultCluster = hasOneCluster && this.allClusters[0] === '_default_'; | |
277 | if (hasOneCluster) { | |
278 | this.nfsForm.patchValue({ | |
279 | cluster_id: this.allClusters[0] | |
280 | }); | |
281 | this.onClusterChange(); | |
282 | } | |
283 | } | |
284 | ||
285 | resolvefsals(res: string[]) { | |
286 | res.forEach((fsal) => { | |
287 | const fsalItem = this.nfsService.nfsFsal.find((currentFsalItem) => { | |
288 | return fsal === currentFsalItem.value; | |
289 | }); | |
290 | ||
291 | if (_.isObjectLike(fsalItem)) { | |
292 | this.allFsals.push(fsalItem); | |
293 | if (fsalItem.value === 'RGW') { | |
294 | this.rgwUserService.list().subscribe((result: any) => { | |
295 | result.forEach((user) => { | |
296 | if (user.suspended === 0 && user.keys.length > 0) { | |
297 | this.allRgwUsers.push(user.user_id); | |
298 | } | |
299 | }); | |
300 | }); | |
301 | } | |
302 | } | |
303 | }); | |
304 | ||
305 | if (this.allFsals.length === 1 && _.isUndefined(this.nfsForm.getValue('fsal'))) { | |
306 | this.nfsForm.patchValue({ | |
307 | fsal: this.allFsals[0] | |
308 | }); | |
309 | } | |
310 | } | |
311 | ||
312 | resolveClients(clients) { | |
313 | this.allCephxClients = clients; | |
314 | } | |
315 | ||
316 | resolveFilesystems(filesystems) { | |
317 | this.allFsNames = filesystems; | |
318 | if (filesystems.length === 1) { | |
319 | this.nfsForm.patchValue({ | |
320 | fsal: { | |
321 | fs_name: filesystems[0].name | |
322 | } | |
323 | }); | |
324 | } | |
325 | } | |
326 | ||
327 | fsalChangeHandler() { | |
328 | this.nfsForm.patchValue({ | |
329 | tag: this._generateTag(), | |
eafe8130 TL |
330 | pseudo: this._generatePseudo(), |
331 | access_type: this._updateAccessType() | |
11fdf7f2 TL |
332 | }); |
333 | ||
334 | this.setPathValidation(); | |
335 | ||
336 | this.cdRef.detectChanges(); | |
337 | } | |
338 | ||
eafe8130 TL |
339 | accessTypeChangeHandler() { |
340 | const name = this.nfsForm.getValue('name'); | |
341 | const accessType = this.nfsForm.getValue('access_type'); | |
342 | this.defaultAccessType[name] = accessType; | |
343 | } | |
344 | ||
11fdf7f2 TL |
345 | setPathValidation() { |
346 | if (this.nfsForm.getValue('name') === 'RGW') { | |
347 | this.nfsForm | |
348 | .get('path') | |
349 | .setValidators([Validators.required, Validators.pattern('^(/|[^/><|&()#?]+)$')]); | |
350 | } else { | |
351 | this.nfsForm | |
352 | .get('path') | |
353 | .setValidators([Validators.required, Validators.pattern('^/[^><|&()?]*$')]); | |
354 | } | |
355 | } | |
356 | ||
357 | rgwUserIdChangeHandler() { | |
358 | this.nfsForm.patchValue({ | |
359 | pseudo: this._generatePseudo() | |
360 | }); | |
361 | } | |
362 | ||
363 | getAccessTypeHelp(accessType) { | |
364 | const accessTypeItem = this.nfsAccessType.find((currentAccessTypeItem) => { | |
365 | if (accessType === currentAccessTypeItem.value) { | |
366 | return currentAccessTypeItem; | |
367 | } | |
368 | }); | |
369 | return _.isObjectLike(accessTypeItem) ? accessTypeItem.help : ''; | |
370 | } | |
371 | ||
372 | getId() { | |
373 | if ( | |
374 | _.isString(this.nfsForm.getValue('cluster_id')) && | |
375 | _.isString(this.nfsForm.getValue('path')) | |
376 | ) { | |
377 | return this.nfsForm.getValue('cluster_id') + ':' + this.nfsForm.getValue('path'); | |
378 | } | |
379 | return ''; | |
380 | } | |
381 | ||
382 | getPathTypeahead(path) { | |
383 | if (!_.isString(path) || path === '/') { | |
384 | return of([]); | |
385 | } | |
386 | ||
387 | return this.nfsService.lsDir(path); | |
388 | } | |
389 | ||
390 | pathChangeHandler() { | |
391 | this.nfsForm.patchValue({ | |
392 | pseudo: this._generatePseudo() | |
393 | }); | |
394 | ||
395 | const path = this.nfsForm.getValue('path'); | |
396 | this.getPathTypeahead(path).subscribe((res: any) => { | |
397 | this.isNewDirectory = path !== '/' && res.paths.indexOf(path) === -1; | |
398 | }); | |
399 | } | |
400 | ||
401 | bucketChangeHandler() { | |
402 | this.nfsForm.patchValue({ | |
403 | tag: this._generateTag(), | |
404 | pseudo: this._generatePseudo() | |
405 | }); | |
406 | ||
407 | const bucket = this.nfsForm.getValue('path'); | |
408 | this.getBucketTypeahead(bucket).subscribe((res: any) => { | |
409 | this.isNewBucket = bucket !== '' && res.indexOf(bucket) === -1; | |
410 | }); | |
411 | } | |
412 | ||
413 | getBucketTypeahead(path: string): Observable<any> { | |
414 | const rgwUserId = this.nfsForm.getValue('rgw_user_id'); | |
415 | ||
416 | if (_.isString(rgwUserId) && _.isString(path) && path !== '/' && path !== '') { | |
417 | return this.nfsService.buckets(rgwUserId); | |
418 | } else { | |
419 | return of([]); | |
420 | } | |
421 | } | |
422 | ||
423 | _generateTag() { | |
424 | let newTag = this.nfsForm.getValue('tag'); | |
425 | if (!this.nfsForm.get('tag').dirty) { | |
426 | newTag = undefined; | |
427 | if (this.nfsForm.getValue('fsal') === 'RGW') { | |
428 | newTag = this.nfsForm.getValue('path'); | |
429 | } | |
430 | } | |
431 | return newTag; | |
432 | } | |
433 | ||
434 | _generatePseudo() { | |
435 | let newPseudo = this.nfsForm.getValue('pseudo'); | |
436 | if (this.nfsForm.get('pseudo') && !this.nfsForm.get('pseudo').dirty) { | |
437 | newPseudo = undefined; | |
438 | if (this.nfsForm.getValue('fsal') === 'CEPH') { | |
439 | newPseudo = '/cephfs'; | |
440 | if (_.isString(this.nfsForm.getValue('path'))) { | |
441 | newPseudo += this.nfsForm.getValue('path'); | |
442 | } | |
443 | } else if (this.nfsForm.getValue('fsal') === 'RGW') { | |
444 | if (_.isString(this.nfsForm.getValue('rgw_user_id'))) { | |
445 | newPseudo = '/' + this.nfsForm.getValue('rgw_user_id'); | |
446 | if (_.isString(this.nfsForm.getValue('path'))) { | |
447 | newPseudo += '/' + this.nfsForm.getValue('path'); | |
448 | } | |
449 | } | |
450 | } | |
451 | } | |
452 | return newPseudo; | |
453 | } | |
454 | ||
eafe8130 TL |
455 | _updateAccessType() { |
456 | const name = this.nfsForm.getValue('name'); | |
457 | let accessType = this.defaultAccessType[name]; | |
458 | ||
459 | if (!accessType) { | |
460 | accessType = 'RW'; | |
461 | } | |
462 | ||
463 | return accessType; | |
464 | } | |
465 | ||
11fdf7f2 TL |
466 | onClusterChange() { |
467 | const cluster_id = this.nfsForm.getValue('cluster_id'); | |
468 | this.daemonsSelections = _.map( | |
469 | this.allDaemons[cluster_id], | |
470 | (daemon) => new SelectOption(false, daemon, '') | |
471 | ); | |
472 | this.daemonsSelections = [...this.daemonsSelections]; | |
473 | this.nfsForm.patchValue({ daemons: [] }); | |
474 | } | |
475 | ||
476 | removeDaemon(index, daemon) { | |
477 | this.daemonsSelections.forEach((value) => { | |
478 | if (value.name === daemon) { | |
479 | value.selected = false; | |
480 | } | |
481 | }); | |
482 | ||
483 | const daemons = this.nfsForm.get('daemons'); | |
484 | daemons.value.splice(index, 1); | |
485 | daemons.setValue(daemons.value); | |
486 | ||
487 | return false; | |
488 | } | |
489 | ||
490 | onDaemonSelection() { | |
491 | this.nfsForm.get('daemons').setValue(this.nfsForm.getValue('daemons')); | |
492 | } | |
493 | ||
494 | submitAction() { | |
495 | let action: Observable<any>; | |
496 | const requestModel = this._buildRequest(); | |
497 | ||
498 | if (this.isEdit) { | |
499 | action = this.taskWrapper.wrapTaskAroundCall({ | |
500 | task: new FinishedTask('nfs/edit', { | |
501 | cluster_id: this.cluster_id, | |
502 | export_id: this.export_id | |
503 | }), | |
504 | call: this.nfsService.update(this.cluster_id, this.export_id, requestModel) | |
505 | }); | |
506 | } else { | |
507 | // Create | |
508 | action = this.taskWrapper.wrapTaskAroundCall({ | |
509 | task: new FinishedTask('nfs/create', { | |
510 | path: requestModel.path, | |
511 | fsal: requestModel.fsal, | |
512 | cluster_id: requestModel.cluster_id | |
513 | }), | |
514 | call: this.nfsService.create(requestModel) | |
515 | }); | |
516 | } | |
517 | ||
518 | action.subscribe( | |
519 | undefined, | |
520 | () => this.nfsForm.setErrors({ cdSubmitButton: true }), | |
521 | () => this.router.navigate(['/nfs']) | |
522 | ); | |
523 | } | |
524 | ||
525 | _buildRequest() { | |
526 | const requestModel: any = _.cloneDeep(this.nfsForm.value); | |
527 | ||
528 | if (_.isUndefined(requestModel.tag) || requestModel.tag === '') { | |
529 | requestModel.tag = null; | |
530 | } | |
531 | ||
532 | if (this.isEdit) { | |
533 | requestModel.export_id = this.export_id; | |
534 | } | |
535 | ||
536 | if (requestModel.fsal.name === 'CEPH') { | |
537 | delete requestModel.fsal.rgw_user_id; | |
538 | } else { | |
539 | delete requestModel.fsal.fs_name; | |
540 | delete requestModel.fsal.user_id; | |
541 | } | |
542 | ||
543 | requestModel.protocols = []; | |
544 | if (requestModel.protocolNfsv3) { | |
545 | requestModel.protocols.push(3); | |
546 | } else { | |
547 | requestModel.tag = null; | |
548 | } | |
549 | delete requestModel.protocolNfsv3; | |
550 | if (requestModel.protocolNfsv4) { | |
551 | requestModel.protocols.push(4); | |
552 | } else { | |
553 | requestModel.pseudo = null; | |
554 | } | |
555 | delete requestModel.protocolNfsv4; | |
556 | ||
557 | requestModel.transports = []; | |
558 | if (requestModel.transportTCP) { | |
559 | requestModel.transports.push('TCP'); | |
560 | } | |
561 | delete requestModel.transportTCP; | |
562 | if (requestModel.transportUDP) { | |
563 | requestModel.transports.push('UDP'); | |
564 | } | |
565 | delete requestModel.transportUDP; | |
566 | ||
567 | requestModel.clients.forEach((client) => { | |
568 | if (_.isString(client.addresses)) { | |
569 | client.addresses = _(client.addresses) | |
570 | .split(/[ ,]+/) | |
571 | .uniq() | |
572 | .filter((address) => address !== '') | |
573 | .value(); | |
574 | } else { | |
575 | client.addresses = []; | |
576 | } | |
81eedcae TL |
577 | |
578 | if (!client.squash) { | |
579 | client.squash = requestModel.squash; | |
580 | } | |
581 | ||
582 | if (!client.access_type) { | |
583 | client.access_type = requestModel.access_type; | |
584 | } | |
11fdf7f2 TL |
585 | }); |
586 | ||
587 | if (requestModel.security_label === false || requestModel.fsal.name === 'RGW') { | |
588 | requestModel.fsal.sec_label_xattr = null; | |
589 | } else { | |
590 | requestModel.fsal.sec_label_xattr = requestModel.sec_label_xattr; | |
591 | } | |
592 | delete requestModel.sec_label_xattr; | |
593 | ||
594 | return requestModel; | |
595 | } | |
596 | } |