From dada47c07e08720738e07c9157653df31e3ede08 Mon Sep 17 00:00:00 2001 From: FangyuanCheng Date: Wed, 13 Mar 2019 16:04:17 +0800 Subject: [PATCH] Refactoring vulnerability ui support cron Signed-off-by: FangyuanCheng --- src/portal/lib/src/config/gc/gc.component.ts | 4 +- .../src/config/registry-config.component.html | 2 +- .../vulnerability/scanAll.api.repository.ts | 42 +++ .../config/vulnerability/scanAll.service.ts | 50 ++++ .../vulnerability-config.component.html | 25 +- .../vulnerability-config.component.ts | 273 +++++------------- .../cron-schedule.component.html | 14 +- .../cron-schedule.component.scss | 4 +- src/portal/lib/src/harbor-library.module.ts | 12 +- src/portal/lib/src/service.config.ts | 2 + .../src/app/config/config.component.html | 2 +- src/portal/src/app/shared/shared.module.ts | 3 +- .../Harbor-Pages/Configuration_Elements.robot | 2 +- .../Harbor-Pages/Vulnerability.robot | 8 +- 14 files changed, 196 insertions(+), 247 deletions(-) create mode 100644 src/portal/lib/src/config/vulnerability/scanAll.api.repository.ts create mode 100644 src/portal/lib/src/config/vulnerability/scanAll.service.ts diff --git a/src/portal/lib/src/config/gc/gc.component.ts b/src/portal/lib/src/config/gc/gc.component.ts index 9f0e18ef6..925fa1900 100644 --- a/src/portal/lib/src/config/gc/gc.component.ts +++ b/src/portal/lib/src/config/gc/gc.component.ts @@ -54,8 +54,8 @@ export class GcComponent implements OnInit { } public initSchedule(schedule: any) { - if (schedule && schedule.length > 0) { - this.schedule = schedule[0]; + if (schedule && schedule.schedule !== null) { + this.schedule = schedule; this.originCron = this.schedule.schedule; } else { this.originCron = { diff --git a/src/portal/lib/src/config/registry-config.component.html b/src/portal/lib/src/config/registry-config.component.html index bc1d3afec..0cd7784ce 100644 --- a/src/portal/lib/src/config/registry-config.component.html +++ b/src/portal/lib/src/config/registry-config.component.html @@ -10,7 +10,7 @@ - + diff --git a/src/portal/lib/src/config/vulnerability/scanAll.api.repository.ts b/src/portal/lib/src/config/vulnerability/scanAll.api.repository.ts new file mode 100644 index 000000000..1657a9319 --- /dev/null +++ b/src/portal/lib/src/config/vulnerability/scanAll.api.repository.ts @@ -0,0 +1,42 @@ + +import { Injectable, Inject } from '@angular/core'; +import { Http } from '@angular/http'; +import { throwError as observableThrowError, Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +import { SERVICE_CONFIG, IServiceConfig } from "../../service.config"; + +export abstract class ScanApiRepository { + abstract postSchedule(param): Observable; + + abstract putSchedule(param): Observable; + + abstract getSchedule(): Observable; + +} + +@Injectable() +export class ScanApiDefaultRepository extends ScanApiRepository { + constructor( + private http: Http, + @Inject(SERVICE_CONFIG) private config: IServiceConfig + ) { + super(); + } + + public postSchedule(param): Observable { + return this.http.post(`${this.config.ScanAllEndpoint}/schedule`, param) + .pipe(catchError(error => observableThrowError(error))); + } + + public putSchedule(param): Observable { + return this.http.put(`${this.config.ScanAllEndpoint}/schedule`, param) + .pipe(catchError(error => observableThrowError(error))); + } + + public getSchedule(): Observable { + return this.http.get(`${this.config.ScanAllEndpoint}/schedule`) + .pipe(catchError(error => observableThrowError(error))) + .pipe(map(response => response.json())); + } + +} diff --git a/src/portal/lib/src/config/vulnerability/scanAll.service.ts b/src/portal/lib/src/config/vulnerability/scanAll.service.ts new file mode 100644 index 000000000..f69f7a473 --- /dev/null +++ b/src/portal/lib/src/config/vulnerability/scanAll.service.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs'; +import { ScanApiRepository } from './scanAll.api.repository'; +import { ErrorHandler } from '../../error-handler/index'; + + +@Injectable() +export class ScanAllRepoService { + + constructor(private http: Http, + private scanApiRepository: ScanApiRepository, + private errorHandler: ErrorHandler) { + } + + public manualScan(): Observable { + let param = { + "schedule": { + "type": "Manual" + } + }; + return this.scanApiRepository.postSchedule(param); + } + + public getSchedule(): Observable { + return this.scanApiRepository.getSchedule(); + } + + public postSchedule(type, cron): Observable { + let param = { + "schedule": { + "type": type, + "cron": cron, + } + }; + + return this.scanApiRepository.postSchedule(param); + } + + public putSchedule(type, cron): Observable { + let param = { + "schedule": { + "type": type, + "cron": cron, + } + }; + + return this.scanApiRepository.putSchedule(param); + } +} diff --git a/src/portal/lib/src/config/vulnerability/vulnerability-config.component.html b/src/portal/lib/src/config/vulnerability/vulnerability-config.component.html index 2336c539a..f6279a82f 100644 --- a/src/portal/lib/src/config/vulnerability/vulnerability-config.component.html +++ b/src/portal/lib/src/config/vulnerability/vulnerability-config.component.html @@ -23,30 +23,7 @@ {{ updatedTimestamp | date:'MM/dd/y HH:mm:ss' }} AM -
- {{ 'CONFIG.SCANNING.SCAN_ALL' | translate }} - {{ (scanningType ? 'SCHEDULE.'+ scanningType.toUpperCase(): "") | translate }} - {{'SCHEDULE.AT' | translate}} - {{ dailyTime | translate }} AM - -
-
- -
- -
- {{'SCHEDULE.AT' | translate}} - - - - {{'CONFIG.TOOLTIP.SCANNING_POLICY' | translate}} - - - -
+

diff --git a/src/portal/lib/src/config/vulnerability/vulnerability-config.component.ts b/src/portal/lib/src/config/vulnerability/vulnerability-config.component.ts index afb785c29..8bb26ac98 100644 --- a/src/portal/lib/src/config/vulnerability/vulnerability-config.component.ts +++ b/src/portal/lib/src/config/vulnerability/vulnerability-config.component.ts @@ -13,12 +13,12 @@ import { ErrorHandler } from '../../error-handler/index'; import { isEmptyObject, clone} from '../../utils'; import { TranslateService } from '@ngx-translate/core'; import { ClairDetail } from '../../service/interface'; +import { ScanAllRepoService } from './scanAll.service'; +import { OriginCron } from '../../service/interface'; +import { CronScheduleComponent } from "../../cron-schedule/cron-schedule.component"; const ONE_HOUR_SECONDS: number = 3600; const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS; -const SCHEDULE_TYPE = { - NONE: "none", - DAILY: "daily" -}; +const SCHEDULE_TYPE_NONE = "None"; @Component({ selector: 'vulnerability-config', templateUrl: './vulnerability-config.component.html', @@ -26,39 +26,25 @@ const SCHEDULE_TYPE = { }) export class VulnerabilityConfigComponent implements OnInit { _localTime: Date = new Date(); - isEditMode: boolean = false; - SCHEDULE_TYPE = SCHEDULE_TYPE; - configCopy: Configuration; + originCron: OriginCron; + schedule: any; onSubmitting: boolean = false; config: Configuration; openState: boolean = false; - @Output() configChange: EventEmitter = new EventEmitter(); + getLabelCurrent: string; + + @ViewChild(CronScheduleComponent) + CronScheduleComponent: CronScheduleComponent; @Input() - get vulnerabilityConfig(): Configuration { - return this.config; - } - set vulnerabilityConfig(cfg: Configuration) { - this.config = cfg; - if (this.config.scan_all_policy && - this.config.scan_all_policy.value) { - if (this.config.scan_all_policy.value.type === "daily") { - if (!this.config.scan_all_policy.value.parameter) { - this.config.scan_all_policy.value.parameter = { - daily_time: 0 - }; - } - } - } - this.configChange.emit(this.config); - } @Input() showSubTitle: boolean = false; @Input() showScanningNamespaces: boolean = false; systemInfo: SystemInfo; constructor( - private scanningService: ScanningResultService, + // private scanningService: ScanningResultService, + private scanningService: ScanAllRepoService, private errorHandler: ErrorHandler, private translate: TranslateService, private systemInfoService: SystemInfoService, @@ -69,6 +55,12 @@ export class VulnerabilityConfigComponent implements OnInit { return !this.onSubmitting; } + getScanText() { + this.translate.get('CONFIG.SCANNING.SCAN_ALL').subscribe((res: string) => { + this.getLabelCurrent = res; + }); + } + get updatedTimestamp(): Date { if (this.systemInfo && this.systemInfo.clair_vulnerability_status && @@ -90,146 +82,29 @@ export class VulnerabilityConfigComponent implements OnInit { return []; } - // UTC time - get dailyTime(): string { - if (!(this.config && - this.config.scan_all_policy && - this.config.scan_all_policy.value && - this.config.scan_all_policy.value.type === "daily")) { - return "00:00"; - } + getSchedule() { + this.scanningService.getSchedule().subscribe(schedule => { + this.initSchedule(schedule); + }); + } - let timeOffset: number = 0; // seconds - if (this.config.scan_all_policy.value.parameter) { - let daily_time = this.config.scan_all_policy.value.parameter.daily_time; - if (daily_time && typeof daily_time === "number") { - timeOffset = +daily_time; - } - } - // Convert to current time - let timezoneOffset: number = this._localTime.getTimezoneOffset(); - // Local time - timeOffset = timeOffset - timezoneOffset * 60; - if (timeOffset < 0) { - timeOffset = timeOffset + ONE_DAY_SECONDS; - } - - if (timeOffset >= ONE_DAY_SECONDS) { - timeOffset -= ONE_DAY_SECONDS; - } - - // To time string - let hours: number = Math.floor(timeOffset / ONE_HOUR_SECONDS); - let minutes: number = Math.floor((timeOffset - hours * ONE_HOUR_SECONDS) / 60); - - let timeStr: string = "" + hours; - if (hours < 10) { - timeStr = "0" + timeStr; - } - if (minutes < 10) { - timeStr += ":0"; + public initSchedule(schedule: any) { + if (schedule && schedule.schedule !== null) { + this.schedule = schedule; + this.originCron = this.schedule.schedule; } else { - timeStr += ":"; + this.originCron = { + type: SCHEDULE_TYPE_NONE, + cron: '' + }; } - timeStr += minutes; - - return timeStr; - } - set dailyTime(v: string) { - if (!v || v === "") { - return; - } - - if (!(this.config && - this.config.scan_all_policy && - this.config.scan_all_policy.value && - this.config.scan_all_policy.value.type === "daily")) { - return; - } - - // Double confirm inner parameter existing. - if (!this.config.scan_all_policy.value.parameter) { - this.config.scan_all_policy.value.parameter = { - daily_time: 0 - }; - } - - let values: string[] = v.split(":"); - if (!values || values.length !== 2) { - return; - } - - let hours: number = +values[0]; - let minutes: number = +values[1]; - // Convert to UTC time - let timezoneOffset: number = this._localTime.getTimezoneOffset(); - let utcTimes: number = hours * ONE_HOUR_SECONDS + minutes * 60; - utcTimes += timezoneOffset * 60; - if (utcTimes < 0) { - utcTimes += ONE_DAY_SECONDS; - } - - if (utcTimes >= ONE_DAY_SECONDS) { - utcTimes -= ONE_DAY_SECONDS; - } - - this.config.scan_all_policy.value.parameter.daily_time = utcTimes; - } - - // Scanning type - get scanningType(): string { - if (this.config && - this.config.scan_all_policy && - this.config.scan_all_policy.value) { - return this.config.scan_all_policy.value.type; - } else { - // default - return "none"; - } - } - - - set scanningType(v: string) { - if (this.config && - this.config.scan_all_policy && - this.config.scan_all_policy.value) { - let type: string = (v && v.trim() !== "") ? v : "none"; - this.config.scan_all_policy.value.type = type; - if (type !== "daily") { - // No parameter - if (this.config.scan_all_policy.value.parameter) { - delete (this.config.scan_all_policy.value.parameter); - } - } else { - // Has parameter - if (!this.config.scan_all_policy.value.parameter) { - this.config.scan_all_policy.value.parameter = { - daily_time: 0 - }; - } - } - } - } - + } @ViewChild("systemConfigFrom") systemSettingsForm: NgForm; - get editable(): boolean { - return this.vulnerabilityConfig && - this.vulnerabilityConfig.scan_all_policy && - this.vulnerabilityConfig.scan_all_policy.editable; - } - get isValid(): boolean { return this.systemSettingsForm && this.systemSettingsForm.valid; } - get showTimePicker(): boolean { - return this.vulnerabilityConfig && - this.vulnerabilityConfig.scan_all_policy && - this.vulnerabilityConfig.scan_all_policy.value && - this.vulnerabilityConfig.scan_all_policy.value.type === "daily"; - } - get isClairDBFullyReady(): boolean { return this.systemInfo && this.systemInfo.clair_vulnerability_status && @@ -238,23 +113,10 @@ export class VulnerabilityConfigComponent implements OnInit { ngOnInit(): void { this.getSystemInfo(); - this.getConfigurations(); + this.getScanText(); + this.getSchedule(); } - getConfigurations(): void { - this.configService.getConfigurations() - .subscribe((config: Configuration) => { - this.configCopy = clone(config); - this.config = config; - }, error => { - this.errorHandler.error(error); - }); - } - - editSchedule() { - this.isEditMode = true; - } - convertToLocalTime(utcTime: number): Date { let dt: Date = new Date(); dt.setTime(utcTime * 1000); @@ -272,7 +134,7 @@ export class VulnerabilityConfigComponent implements OnInit { } this.onSubmitting = true; - this.scanningService.startScanningAll() + this.scanningService.manualScan() .subscribe(() => { this.translate.get("CONFIG.SCANNING.TRIGGER_SCAN_ALL_SUCCESS").subscribe((res: string) => { this.errorHandler.info(res); @@ -306,38 +168,43 @@ export class VulnerabilityConfigComponent implements OnInit { })); } - save(): void { - let getchanges = this.config.scan_all_policy.value; - let changes = {"scan_all_policy": getchanges}; + reset(cron): void { + this.schedule = { + schedule: { + type: this.CronScheduleComponent.scheduleType, + cron: cron + } + }; + } - if (isEmptyObject(changes)) { - return; - } - - this.configService.saveConfigurations(changes) - .subscribe(() => { - this.translate.get("CONFIG.SAVE_SUCCESS").subscribe((res: string) => { - this.errorHandler.info(res); + scanAll(cron: string): void { + let schedule = this.schedule; + if (schedule && schedule.schedule && schedule.schedule.type !== SCHEDULE_TYPE_NONE) { + this.scanningService.putSchedule(this.CronScheduleComponent.scheduleType, cron) + .subscribe(response => { + this.translate + .get("CONFIG.SAVE_SUCCESS") + .subscribe((res) => { + this.errorHandler.info(res); }); - this.getConfigurations(); - this.isEditMode = false; - }, error => { - this.errorHandler.error(error); - this.reset(); - }); - } - - cancel(): void { - this.reset(); - this.isEditMode = false; - } - - reset(): void { - // Reset to the values of copy - let getchanges = this.config.scan_all_policy.value; - let changes = {"scan_all_policy": getchanges}; - for (let prop of Object.keys(changes)) { - this.config[prop] = clone(this.configCopy[prop]); + this.reset(cron); + }, + error => { + this.errorHandler.error(error); + } + ); + } else { + this.scanningService.postSchedule(this.CronScheduleComponent.scheduleType, cron) + .subscribe(response => { + this.translate.get("CONFIG.SAVE_SUCCESS").subscribe((res) => { + this.errorHandler.info(res); + }); + this.reset(cron); + }, + error => { + this.errorHandler.error(error); + } + ); } } } diff --git a/src/portal/lib/src/cron-schedule/cron-schedule.component.html b/src/portal/lib/src/cron-schedule/cron-schedule.component.html index 2312de378..6a2a4e359 100644 --- a/src/portal/lib/src/cron-schedule/cron-schedule.component.html +++ b/src/portal/lib/src/cron-schedule/cron-schedule.component.html @@ -15,14 +15,14 @@ {{ "SCHEDULE.CRON" | translate }} : {{ oriCron }} -
{{ labelEdit | translate }}
- @@ -31,9 +31,9 @@
{{ "SCHEDULE.CRON" | translate }} : -
-
-
\ No newline at end of file diff --git a/src/portal/lib/src/cron-schedule/cron-schedule.component.scss b/src/portal/lib/src/cron-schedule/cron-schedule.component.scss index 944262fec..469a6e609 100644 --- a/src/portal/lib/src/cron-schedule/cron-schedule.component.scss +++ b/src/portal/lib/src/cron-schedule/cron-schedule.component.scss @@ -34,8 +34,8 @@ display: inline-block; width: 100px; } - - .cron-input { + + .cron-label { width: 195px; } } diff --git a/src/portal/lib/src/harbor-library.module.ts b/src/portal/lib/src/harbor-library.module.ts index 2d1bda19b..63f13f30b 100644 --- a/src/portal/lib/src/harbor-library.module.ts +++ b/src/portal/lib/src/harbor-library.module.ts @@ -58,8 +58,10 @@ import { UserPermissionDefaultService } from './service/index'; import { GcRepoService } from './config/gc/gc.service'; +import { ScanAllRepoService } from './config/vulnerability/scanAll.service'; import {GcViewModelFactory} from './config/gc/gc.viewmodel.factory'; import {GcApiRepository, GcApiDefaultRepository} from './config/gc/gc.api.repository'; +import {ScanApiRepository, ScanApiDefaultRepository} from './config/vulnerability/scanAll.api.repository'; import { ErrorHandler, DefaultErrorHandler @@ -100,7 +102,8 @@ export const DefaultServiceConfig: IServiceConfig = { labelEndpoint: "/api/labels", helmChartEndpoint: "/api/chartrepo", downloadChartEndpoint: "/chartrepo", - gcEndpoint: "/api/system/gc" + gcEndpoint: "/api/system/gc", + ScanAllEndpoint: "/api/system/scanAll" }; /** @@ -160,6 +163,9 @@ export interface HarborModuleConfig { // Service implementation for gc gcApiRepository?: Provider; + // Service implementation for scanAll + ScanApiRepository?: Provider; + } /** @@ -261,6 +267,7 @@ export class HarborLibraryModule { config.labelService || { provide: LabelService, useClass: LabelDefaultService }, config.userPermissionService || { provide: UserPermissionService, useClass: UserPermissionDefaultService }, config.gcApiRepository || {provide: GcApiRepository, useClass: GcApiDefaultRepository}, + config.ScanApiRepository || {provide: ScanApiRepository, useClass: ScanApiDefaultRepository}, // Do initializing TranslateServiceInitializer, { @@ -272,6 +279,7 @@ export class HarborLibraryModule { ChannelService, OperationService, GcRepoService, + ScanAllRepoService, GcViewModelFactory ] }; @@ -297,9 +305,11 @@ export class HarborLibraryModule { config.labelService || { provide: LabelService, useClass: LabelDefaultService }, config.userPermissionService || { provide: UserPermissionService, useClass: UserPermissionDefaultService }, config.gcApiRepository || {provide: GcApiRepository, useClass: GcApiDefaultRepository}, + config.ScanApiRepository || {provide: ScanApiRepository, useClass: ScanApiDefaultRepository}, ChannelService, OperationService, GcRepoService, + ScanAllRepoService, GcViewModelFactory ] }; diff --git a/src/portal/lib/src/service.config.ts b/src/portal/lib/src/service.config.ts index 185d80d00..885c62eb1 100644 --- a/src/portal/lib/src/service.config.ts +++ b/src/portal/lib/src/service.config.ts @@ -239,4 +239,6 @@ export interface IServiceConfig { downloadChartEndpoint?: string; gcEndpoint?: string; + + ScanAllEndpoint?: string; } diff --git a/src/portal/src/app/config/config.component.html b/src/portal/src/app/config/config.component.html index 4e0b6a34b..dd24bb686 100644 --- a/src/portal/src/app/config/config.component.html +++ b/src/portal/src/app/config/config.component.html @@ -36,7 +36,7 @@ - +
diff --git a/src/portal/src/app/shared/shared.module.ts b/src/portal/src/app/shared/shared.module.ts index 08e7310ab..306422df0 100644 --- a/src/portal/src/app/shared/shared.module.ts +++ b/src/portal/src/app/shared/shared.module.ts @@ -75,7 +75,8 @@ const uiLibConfig: IServiceConfig = { labelEndpoint: "/api/labels", helmChartEndpoint: "/api/chartrepo", downloadChartEndpoint: "/chartrepo", - gcEndpoint: "/api/system/gc" + gcEndpoint: "/api/system/gc", + ScanAllEndpoint: "/api/system/scanAll" }; @NgModule({ diff --git a/tests/resources/Harbor-Pages/Configuration_Elements.robot b/tests/resources/Harbor-Pages/Configuration_Elements.robot index bfe072ec0..1639b865b 100644 --- a/tests/resources/Harbor-Pages/Configuration_Elements.robot +++ b/tests/resources/Harbor-Pages/Configuration_Elements.robot @@ -23,7 +23,7 @@ ${config_save_button_xpath} //config//div/button[contains(.,'SAVE')] ${config_email_save_button_xpath} //*[@id='config_email_save'] ${config_auth_save_button_xpath} //*[@id='config_auth_save'] ${config_system_save_button_xpath} //*[@id='config_system_save'] -${vulnerbility_save_button_xpath} //*[@id='config_vulnerbility_save'] +${vulnerbility_save_button_xpath} //*[@id='config-save'] ${configuration_xpath} //clr-vertical-nav-group-children/a[contains(.,'Configuration')] ${system_config_xpath} //*[@id='config-system'] ${garbage_collection_xpath} //*[@id='config-gc'] diff --git a/tests/resources/Harbor-Pages/Vulnerability.robot b/tests/resources/Harbor-Pages/Vulnerability.robot index 0e377229b..6c0c174bb 100644 --- a/tests/resources/Harbor-Pages/Vulnerability.robot +++ b/tests/resources/Harbor-Pages/Vulnerability.robot @@ -7,10 +7,10 @@ Resource ../../resources/Util.robot *** Keywords *** Disable Scan Schedule - Click Element //vulnerability-config//button[@id='editSchedule'] - Click Element //vulnerability-config//select[@id='scanAllPolicy'] - Click Element //vulnerability-config//select[@id='scanAllPolicy']//option[contains(.,'None')] - Click Element //button[@id='config_vulnerbility_save'] + Click Element //vulnerability-config//cron-selection//button[contains(.,'EDIT')] + Click Element //vulnerability-config//cron-selection//select[@id='selectPolicy'] + Click Element //vulnerability-config//cron-selection//select[@id='selectPolicy']//option[contains(.,'None')] + Click Element //cron-selection//button[contains(.,'SAVE')] Go To Vulnerability Config Click Element //config//button[contains(.,'Vulnerability')]