mirror of
https://github.com/goharbor/harbor
synced 2025-05-17 20:02:51 +00:00
Support clair db timestamps (#2767)
* refine the test case of scheduler * Fix bug * Support root cert downloaded * Fix code conflicts * support clair db timestamps
This commit is contained in:
parent
ca6bd3b585
commit
0ce74dd377
@ -0,0 +1,9 @@
|
|||||||
|
export const REGISTRY_CONFIG_STYLES: string = `
|
||||||
|
.info-tips-icon {
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-tips-icon:hover {
|
||||||
|
color: #007CBB;
|
||||||
|
}
|
||||||
|
`;
|
@ -2,7 +2,7 @@ export const REGISTRY_CONFIG_HTML: string = `
|
|||||||
<div>
|
<div>
|
||||||
<replication-config #replicationConfig [(replicationConfig)]="config" [showSubTitle]="true"></replication-config>
|
<replication-config #replicationConfig [(replicationConfig)]="config" [showSubTitle]="true"></replication-config>
|
||||||
<system-settings #systemSettings [(systemSettings)]="config" [showSubTitle]="true" [hasAdminRole]="hasAdminRole" [hasCAFile]="hasCAFile"></system-settings>
|
<system-settings #systemSettings [(systemSettings)]="config" [showSubTitle]="true" [hasAdminRole]="hasAdminRole" [hasCAFile]="hasCAFile"></system-settings>
|
||||||
<vulnerability-config *ngIf="withClair" #vulnerabilityConfig [(vulnerabilityConfig)]="config" [showSubTitle]="true"></vulnerability-config>
|
<vulnerability-config *ngIf="withClair" #vulnerabilityConfig [(vulnerabilityConfig)]="config" [showSubTitle]="true" [clairDBStatus]="clairDB"></vulnerability-config>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="shouldDisable">{{'BUTTON.SAVE' | translate}}</button>
|
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="shouldDisable">{{'BUTTON.SAVE' | translate}}</button>
|
||||||
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="shouldDisable">{{'BUTTON.CANCEL' | translate}}</button>
|
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="shouldDisable">{{'BUTTON.CANCEL' | translate}}</button>
|
||||||
|
@ -2,7 +2,7 @@ import { Component, OnInit, EventEmitter, Output, ViewChild, Input } from '@angu
|
|||||||
|
|
||||||
import { Configuration, ComplexValueItem } from './config';
|
import { Configuration, ComplexValueItem } from './config';
|
||||||
import { REGISTRY_CONFIG_HTML } from './registry-config.component.html';
|
import { REGISTRY_CONFIG_HTML } from './registry-config.component.html';
|
||||||
import { ConfigurationService, SystemInfoService, SystemInfo } from '../service/index';
|
import { ConfigurationService, SystemInfoService, SystemInfo, ClairDBStatus } from '../service/index';
|
||||||
import { toPromise } from '../utils';
|
import { toPromise } from '../utils';
|
||||||
import { ErrorHandler } from '../error-handler';
|
import { ErrorHandler } from '../error-handler';
|
||||||
import {
|
import {
|
||||||
@ -54,6 +54,11 @@ export class RegistryConfigComponent implements OnInit {
|
|||||||
return this.systemInfo && this.systemInfo.with_clair;
|
return this.systemInfo && this.systemInfo.with_clair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get clairDB(): ClairDBStatus {
|
||||||
|
return this.systemInfo && this.systemInfo.clair_vulnerability_status ?
|
||||||
|
this.systemInfo.clair_vulnerability_status : null;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
//Get system info
|
//Get system info
|
||||||
toPromise<SystemInfo>(this.systemInfoService.getSystemInfo())
|
toPromise<SystemInfo>(this.systemInfoService.getSystemInfo())
|
||||||
|
@ -3,10 +3,12 @@ import { NgForm } from '@angular/forms';
|
|||||||
|
|
||||||
import { REPLICATION_CONFIG_HTML } from './replication-config.component.html';
|
import { REPLICATION_CONFIG_HTML } from './replication-config.component.html';
|
||||||
import { Configuration } from '../config';
|
import { Configuration } from '../config';
|
||||||
|
import { REGISTRY_CONFIG_STYLES } from '../registry-config.component.css';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'replication-config',
|
selector: 'replication-config',
|
||||||
template: REPLICATION_CONFIG_HTML
|
template: REPLICATION_CONFIG_HTML,
|
||||||
|
styles: [REGISTRY_CONFIG_STYLES]
|
||||||
})
|
})
|
||||||
export class ReplicationConfigComponent {
|
export class ReplicationConfigComponent {
|
||||||
config: Configuration;
|
config: Configuration;
|
||||||
|
@ -3,10 +3,12 @@ import { NgForm } from '@angular/forms';
|
|||||||
|
|
||||||
import { SYSTEM_SETTINGS_HTML } from './system-settings.component.html';
|
import { SYSTEM_SETTINGS_HTML } from './system-settings.component.html';
|
||||||
import { Configuration } from '../config';
|
import { Configuration } from '../config';
|
||||||
|
import { REGISTRY_CONFIG_STYLES } from '../registry-config.component.css';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'system-settings',
|
selector: 'system-settings',
|
||||||
template: SYSTEM_SETTINGS_HTML
|
template: SYSTEM_SETTINGS_HTML,
|
||||||
|
styles: [REGISTRY_CONFIG_STYLES]
|
||||||
})
|
})
|
||||||
export class SystemSettingsComponent {
|
export class SystemSettingsComponent {
|
||||||
config: Configuration;
|
config: Configuration;
|
||||||
|
@ -2,6 +2,21 @@ export const VULNERABILITY_CONFIG_HTML: string = `
|
|||||||
<form #systemConfigFrom="ngForm" class="compact">
|
<form #systemConfigFrom="ngForm" class="compact">
|
||||||
<section class="form-block" style="margin-top:0px;margin-bottom:0px;">
|
<section class="form-block" style="margin-top:0px;margin-bottom:0px;">
|
||||||
<label class="section-title" *ngIf="showSubTitle">{{ 'CONFIG.SCANNING.TITLE' | translate }}</label>
|
<label class="section-title" *ngIf="showSubTitle">{{ 'CONFIG.SCANNING.TITLE' | translate }}</label>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{ 'CONFIG.SCANNING.DB_REFRESH_TIME' | translate }}</label>
|
||||||
|
<clr-dropdown [clrMenuPosition]="'bottom-right'" style="margin-top:-8px;" class="clr-dropdown-override">
|
||||||
|
<button class="btn btn-link btn-font" clrDropdownToggle>
|
||||||
|
{{ updatedTimestamp }}
|
||||||
|
<clr-icon shape="caret down"></clr-icon>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" style="min-width:300px;">
|
||||||
|
<div *ngFor="let nt of namespaceTimestamps" class="namespace">
|
||||||
|
<span class="label label-info">{{nt.namespace}}</span>
|
||||||
|
<span>{{convertToLocalTime(nt.last_update*1000)}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</clr-dropdown>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="scanAllPolicy">{{ 'CONFIG.SCANNING.SCAN_ALL' | translate }}</label>
|
<label for="scanAllPolicy">{{ 'CONFIG.SCANNING.SCAN_ALL' | translate }}</label>
|
||||||
<div class="select">
|
<div class="select">
|
||||||
@ -33,4 +48,16 @@ export const VULNERABILITY_CONFIG_STYLES: string = `
|
|||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
font-weight: 600 !important;
|
font-weight: 600 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-font {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
margin-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-dropdown-override {
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
`;
|
`;
|
@ -7,6 +7,9 @@ import { ScanningResultService } from '../../service/scanning.service';
|
|||||||
import { ErrorHandler } from '../../error-handler';
|
import { ErrorHandler } from '../../error-handler';
|
||||||
import { toPromise } from '../../utils';
|
import { toPromise } from '../../utils';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { ClairDBStatus, ClairDetail } from '../../service/interface';
|
||||||
|
|
||||||
|
import { REGISTRY_CONFIG_STYLES } from '../registry-config.component.css';
|
||||||
|
|
||||||
const ONE_HOUR_SECONDS: number = 3600;
|
const ONE_HOUR_SECONDS: number = 3600;
|
||||||
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
|
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
|
||||||
@ -14,12 +17,13 @@ const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'vulnerability-config',
|
selector: 'vulnerability-config',
|
||||||
template: VULNERABILITY_CONFIG_HTML,
|
template: VULNERABILITY_CONFIG_HTML,
|
||||||
styles: [VULNERABILITY_CONFIG_STYLES]
|
styles: [VULNERABILITY_CONFIG_STYLES, REGISTRY_CONFIG_STYLES]
|
||||||
})
|
})
|
||||||
export class VulnerabilityConfigComponent {
|
export class VulnerabilityConfigComponent {
|
||||||
_localTime: Date = new Date();
|
_localTime: Date = new Date();
|
||||||
|
|
||||||
config: Configuration;
|
config: Configuration;
|
||||||
|
openState: boolean = false;
|
||||||
@Output() configChange: EventEmitter<Configuration> = new EventEmitter<Configuration>();
|
@Output() configChange: EventEmitter<Configuration> = new EventEmitter<Configuration>();
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@ -41,7 +45,26 @@ export class VulnerabilityConfigComponent {
|
|||||||
this.configChange.emit(this.config);
|
this.configChange.emit(this.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() showSubTitle: boolean = false
|
@Input() showSubTitle: boolean = false;
|
||||||
|
@Input() clairDBStatus: ClairDBStatus;
|
||||||
|
|
||||||
|
get updatedTimestamp(): string {
|
||||||
|
if (this.clairDBStatus && this.clairDBStatus.overall_last_update > 0) {
|
||||||
|
return this.convertToLocalTime(this.clairDBStatus.overall_last_update*1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
get namespaceTimestamps(): ClairDetail[] {
|
||||||
|
if (this.clairDBStatus &&
|
||||||
|
this.clairDBStatus.details &&
|
||||||
|
this.clairDBStatus.details.length > 0) {
|
||||||
|
return this.clairDBStatus.details;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
//UTC time
|
//UTC time
|
||||||
get dailyTime(): string {
|
get dailyTime(): string {
|
||||||
@ -188,6 +211,14 @@ export class VulnerabilityConfigComponent {
|
|||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
private translate: TranslateService) { }
|
private translate: TranslateService) { }
|
||||||
|
|
||||||
|
convertToLocalTime(utcTime: number): string {
|
||||||
|
let offset: number = this._localTime.getTimezoneOffset() * 60;
|
||||||
|
let timeWithLocal: number = utcTime - offset;
|
||||||
|
let dt = new Date();
|
||||||
|
dt.setTime(timeWithLocal);
|
||||||
|
return dt.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
scanNow(): void {
|
scanNow(): void {
|
||||||
toPromise<any>(this.scanningService.startScanningAll())
|
toPromise<any>(this.scanningService.startScanningAll())
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -155,6 +155,23 @@ export interface SystemInfo {
|
|||||||
self_registration?: boolean;
|
self_registration?: boolean;
|
||||||
has_ca_root?: boolean;
|
has_ca_root?: boolean;
|
||||||
harbor_version?: string;
|
harbor_version?: string;
|
||||||
|
clair_vulnerability_status?: ClairDBStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clair database status info.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ClairDetail
|
||||||
|
*/
|
||||||
|
export interface ClairDetail {
|
||||||
|
namespace: string;
|
||||||
|
last_update: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClairDBStatus {
|
||||||
|
overall_last_update: number;
|
||||||
|
details: ClairDetail[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum VulnerabilitySeverity {
|
export enum VulnerabilitySeverity {
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
"clarity-icons": "^0.9.8",
|
"clarity-icons": "^0.9.8",
|
||||||
"clarity-ui": "^0.9.8",
|
"clarity-ui": "^0.9.8",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
"harbor-ui": "^0.2.55",
|
"harbor-ui": "~0.2.63",
|
||||||
"intl": "^1.2.5",
|
"intl": "^1.2.5",
|
||||||
"mutationobserver-shim": "^0.3.2",
|
"mutationobserver-shim": "^0.3.2",
|
||||||
"ngx-cookie": "^1.0.0",
|
"ngx-cookie": "^1.0.0",
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
import { ClairDBStatus } from 'harbor-ui';
|
||||||
|
|
||||||
export class AppConfig {
|
export class AppConfig {
|
||||||
constructor() {
|
constructor() {
|
||||||
//Set default value
|
//Set default value
|
||||||
@ -23,7 +25,11 @@ export class AppConfig {
|
|||||||
this.project_creation_restriction = "everyone";
|
this.project_creation_restriction = "everyone";
|
||||||
this.self_registration = true;
|
this.self_registration = true;
|
||||||
this.has_ca_root = false;
|
this.has_ca_root = false;
|
||||||
this.harbor_version = "0.5.0";//default
|
this.harbor_version = "1.2.0";//default
|
||||||
|
this.clair_vulnerability_status = {
|
||||||
|
overall_last_update: 0,
|
||||||
|
details: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
with_notary: boolean;
|
with_notary: boolean;
|
||||||
@ -36,4 +42,5 @@ export class AppConfig {
|
|||||||
self_registration: boolean;
|
self_registration: boolean;
|
||||||
has_ca_root: boolean;
|
has_ca_root: boolean;
|
||||||
harbor_version: string;
|
harbor_version: string;
|
||||||
|
clair_vulnerability_status?: ClairDBStatus;
|
||||||
}
|
}
|
@ -32,7 +32,7 @@
|
|||||||
<system-settings [(systemSettings)]="allConfig" [hasAdminRole]="hasAdminRole" [hasCAFile]="hasCAFile"></system-settings>
|
<system-settings [(systemSettings)]="allConfig" [hasAdminRole]="hasAdminRole" [hasCAFile]="hasCAFile"></system-settings>
|
||||||
</section>
|
</section>
|
||||||
<section id="vulnerability" *ngIf="withClair" role="tabpanel" aria-labelledby="config-vulnerability" [hidden]='!isCurrentTabContent("vulnerability")'>
|
<section id="vulnerability" *ngIf="withClair" role="tabpanel" aria-labelledby="config-vulnerability" [hidden]='!isCurrentTabContent("vulnerability")'>
|
||||||
<vulnerability-config [(vulnerabilityConfig)]="allConfig"></vulnerability-config>
|
<vulnerability-config [(vulnerabilityConfig)]="allConfig" [clairDBStatus]="clairDB"></vulnerability-config>
|
||||||
</section>
|
</section>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
|
||||||
|
@ -32,7 +32,8 @@ import {
|
|||||||
ComplexValueItem,
|
ComplexValueItem,
|
||||||
ReplicationConfigComponent,
|
ReplicationConfigComponent,
|
||||||
SystemSettingsComponent,
|
SystemSettingsComponent,
|
||||||
VulnerabilityConfigComponent
|
VulnerabilityConfigComponent,
|
||||||
|
ClairDBStatus
|
||||||
} from 'harbor-ui';
|
} from 'harbor-ui';
|
||||||
|
|
||||||
const fakePass = "aWpLOSYkIzJTTU4wMDkx";
|
const fakePass = "aWpLOSYkIzJTTU4wMDkx";
|
||||||
@ -84,6 +85,10 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
|
|||||||
return this.appConfigService.getConfig().with_clair;
|
return this.appConfigService.getConfig().with_clair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get clairDB(): ClairDBStatus {
|
||||||
|
return this.appConfigService.getConfig().clair_vulnerability_status;
|
||||||
|
}
|
||||||
|
|
||||||
isCurrentTabLink(tabId: string): boolean {
|
isCurrentTabLink(tabId: string): boolean {
|
||||||
return this.currentTabId === tabId;
|
return this.currentTabId === tabId;
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,9 @@
|
|||||||
"SCAN_NOW": "SCAN NOW",
|
"SCAN_NOW": "SCAN NOW",
|
||||||
"NONE_POLICY": "None",
|
"NONE_POLICY": "None",
|
||||||
"DAILY_POLICY": "Daily At",
|
"DAILY_POLICY": "Daily At",
|
||||||
"REFRESH_POLICY": "Upon Refresh"
|
"REFRESH_POLICY": "Upon Refresh",
|
||||||
|
"DB_REFRESH_TIME": "Database updated on",
|
||||||
|
"DB_NOT_READY": "Vulnerability database might not be fully ready!"
|
||||||
},
|
},
|
||||||
"TEST_MAIL_SUCCESS": "Connection to mail server is verified.",
|
"TEST_MAIL_SUCCESS": "Connection to mail server is verified.",
|
||||||
"TEST_LDAP_SUCCESS": "Connection to LDAP server is verified.",
|
"TEST_LDAP_SUCCESS": "Connection to LDAP server is verified.",
|
||||||
|
@ -414,7 +414,9 @@
|
|||||||
"SCAN_NOW": "SCAN NOW",
|
"SCAN_NOW": "SCAN NOW",
|
||||||
"NONE_POLICY": "None",
|
"NONE_POLICY": "None",
|
||||||
"DAILY_POLICY": "Daily At",
|
"DAILY_POLICY": "Daily At",
|
||||||
"REFRESH_POLICY": "Upon Refresh"
|
"REFRESH_POLICY": "Upon Refresh",
|
||||||
|
"DB_REFRESH_TIME": "Database updated on",
|
||||||
|
"DB_NOT_READY": "Vulnerability database might not be fully ready!"
|
||||||
},
|
},
|
||||||
"TEST_MAIL_SUCCESS": "La conexión al servidor de correo ha sido verificada.",
|
"TEST_MAIL_SUCCESS": "La conexión al servidor de correo ha sido verificada.",
|
||||||
"TEST_LDAP_SUCCESS": "La conexión al servidor LDAP ha sido verificada.",
|
"TEST_LDAP_SUCCESS": "La conexión al servidor LDAP ha sido verificada.",
|
||||||
|
@ -413,7 +413,9 @@
|
|||||||
"SCAN_NOW": "开始扫描",
|
"SCAN_NOW": "开始扫描",
|
||||||
"NONE_POLICY": "无",
|
"NONE_POLICY": "无",
|
||||||
"DAILY_POLICY": "每日定时",
|
"DAILY_POLICY": "每日定时",
|
||||||
"REFRESH_POLICY": "缺陷库刷新后"
|
"REFRESH_POLICY": "缺陷库刷新后",
|
||||||
|
"DB_REFRESH_TIME": "数据库更新于",
|
||||||
|
"DB_NOT_READY": "缺陷数据库可能没有完全准备好!"
|
||||||
},
|
},
|
||||||
"TEST_MAIL_SUCCESS": "邮件服务器的连通正常。",
|
"TEST_MAIL_SUCCESS": "邮件服务器的连通正常。",
|
||||||
"TEST_LDAP_SUCCESS": "LDAP服务器的连通正常。",
|
"TEST_LDAP_SUCCESS": "LDAP服务器的连通正常。",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user