feat: extend the p2p preheat policy

Add the field extra_attrs to the p2p preheat policy for the provider to
define their specified parameters when preheating.

Signed-off-by: chlins <chlins.zhang@gmail.com>
This commit is contained in:
chlins 2024-10-30 16:02:30 +08:00
parent 91082af39f
commit 8c21bc8e22
23 changed files with 2235 additions and 2069 deletions

View File

@ -1193,7 +1193,7 @@ paths:
'404':
$ref: '#/responses/404'
'422':
$ref: '#/responses/422'
$ref: '#/responses/422'
'500':
$ref: '#/responses/500'
/projects/{project_name}/repositories/{repository_name}/artifacts/{reference}/scan/stop:
@ -1226,7 +1226,7 @@ paths:
'404':
$ref: '#/responses/404'
'422':
$ref: '#/responses/422'
$ref: '#/responses/422'
'500':
$ref: '#/responses/500'
/projects/{project_name}/repositories/{repository_name}/artifacts/{reference}/scan/{report_id}/log:
@ -6553,7 +6553,7 @@ responses:
description: The ID of the corresponding request for the response
type: string
schema:
$ref: '#/definitions/Errors'
$ref: '#/definitions/Errors'
'500':
description: Internal server error
headers:
@ -7098,6 +7098,9 @@ definitions:
scope:
type: string
description: The scope of preheat policy
extra_attrs:
type: string
description: The extra attributes of preheat policy
creation_time:
type: string
format: date-time
@ -7937,7 +7940,7 @@ definitions:
properties:
resource:
type: string
description: The resource of the access. Possible resources are listed here for system and project level https://github.com/goharbor/harbor/blob/main/src/common/rbac/const.go
description: The resource of the access. Possible resources are listed here for system and project level https://github.com/goharbor/harbor/blob/main/src/common/rbac/const.go
action:
type: string
description: The action of the access. Possible actions are *, pull, push, create, read, update, delete, list, operate, scanner-pull and stop.
@ -10112,4 +10115,4 @@ definitions:
scan_type:
type: string
description: 'The scan type for the scan request. Two options are currently supported, vulnerability and sbom'
enum: [ vulnerability, sbom ]
enum: [ vulnerability, sbom ]

View File

@ -0,0 +1 @@
ALTER TABLE p2p_preheat_policy ADD COLUMN IF NOT EXISTS extra_attrs json;

View File

@ -402,7 +402,7 @@ func (de *defaultEnforcer) launchExecutions(ctx context.Context, candidates []*s
// Start tasks
count := 0
for _, c := range candidates {
if _, err = de.startTask(ctx, eid, c, insData, pl.Scope); err != nil {
if _, err = de.startTask(ctx, eid, c, insData, pl.Scope, pl.ExtraAttrs); err != nil {
// Just log the error and skip
log.Errorf("start task error for preheating image: %s/%s:%s@%s", c.Namespace, c.Repository, c.Tags[0], c.Digest)
continue
@ -421,7 +421,7 @@ func (de *defaultEnforcer) launchExecutions(ctx context.Context, candidates []*s
}
// startTask starts the preheat task(job) for the given candidate
func (de *defaultEnforcer) startTask(ctx context.Context, executionID int64, candidate *selector.Candidate, instance, scope string) (int64, error) {
func (de *defaultEnforcer) startTask(ctx context.Context, executionID int64, candidate *selector.Candidate, instance, scope string, extraAttrs map[string]interface{}) (int64, error) {
u, err := de.fullURLGetter(candidate)
if err != nil {
return -1, err
@ -438,10 +438,11 @@ func (de *defaultEnforcer) startTask(ctx context.Context, executionID int64, can
Headers: map[string]interface{}{
accessCredHeaderKey: cred,
},
ImageName: fmt.Sprintf("%s/%s", candidate.Namespace, candidate.Repository),
Tag: candidate.Tags[0],
Digest: candidate.Digest,
Scope: scope,
ImageName: fmt.Sprintf("%s/%s", candidate.Namespace, candidate.Repository),
Tag: candidate.Tags[0],
Digest: candidate.Digest,
Scope: scope,
ExtraAttrs: extraAttrs,
}
piData, err := pi.ToJSON()

View File

@ -81,9 +81,12 @@ type Schema struct {
TriggerStr string `orm:"column(trigger)" json:"-"`
Enabled bool `orm:"column(enabled)" json:"enabled"`
// Scope decides the preheat scope.
Scope string `orm:"column(scope)" json:"scope"`
CreatedAt time.Time `orm:"column(creation_time)" json:"creation_time"`
UpdatedTime time.Time `orm:"column(update_time)" json:"update_time"`
Scope string `orm:"column(scope)" json:"scope"`
// ExtraAttrs is used to store extra attributes provided by vendor.
ExtraAttrsStr string `orm:"column(extra_attrs)" json:"-"`
ExtraAttrs map[string]interface{} `orm:"-" json:"extra_attrs"`
CreatedAt time.Time `orm:"column(creation_time)" json:"creation_time"`
UpdatedTime time.Time `orm:"column(update_time)" json:"update_time"`
}
// TableName specifies the policy schema table name.
@ -162,6 +165,14 @@ func (s *Schema) Encode() error {
s.TriggerStr = string(triggerStr)
}
if s.ExtraAttrs != nil {
extraAttrsStr, err := json.Marshal(s.ExtraAttrs)
if err != nil {
return err
}
s.ExtraAttrsStr = string(extraAttrsStr)
}
return nil
}
@ -181,6 +192,13 @@ func (s *Schema) Decode() error {
}
s.Trigger = trigger
// parse extra attributes
extraAttrs, err := decodeExtraAttrs(s.ExtraAttrsStr)
if err != nil {
return err
}
s.ExtraAttrs = extraAttrs
return nil
}
@ -230,3 +248,17 @@ func decodeTrigger(triggerStr string) (*Trigger, error) {
return trigger, nil
}
// decodeExtraAttrs parse extraAttrsStr to extraAttrs.
func decodeExtraAttrs(extraAttrsStr string) (map[string]interface{}, error) {
if len(extraAttrsStr) == 0 {
return nil, nil
}
extraAttrs := make(map[string]interface{})
if err := json.Unmarshal([]byte(extraAttrsStr), &extraAttrs); err != nil {
return nil, err
}
return extraAttrs, nil
}

View File

@ -76,23 +76,25 @@ func (p *PolicyTestSuite) TestValidatePreheatPolicy() {
// TestDecode tests decode.
func (p *PolicyTestSuite) TestDecode() {
s := &Schema{
ID: 100,
Name: "test-for-decode",
Description: "",
ProjectID: 1,
ProviderID: 1,
Filters: nil,
FiltersStr: "[{\"type\":\"repository\",\"value\":\"**\"},{\"type\":\"tag\",\"value\":\"**\"},{\"type\":\"label\",\"value\":\"test\"}]",
Trigger: nil,
TriggerStr: "{\"type\":\"event_based\",\"trigger_setting\":{\"cron\":\"\"}}",
Enabled: false,
Scope: "all_peers",
ID: 100,
Name: "test-for-decode",
Description: "",
ProjectID: 1,
ProviderID: 1,
Filters: nil,
FiltersStr: "[{\"type\":\"repository\",\"value\":\"**\"},{\"type\":\"tag\",\"value\":\"**\"},{\"type\":\"label\",\"value\":\"test\"}]",
Trigger: nil,
TriggerStr: "{\"type\":\"event_based\",\"trigger_setting\":{\"cron\":\"\"}}",
Enabled: false,
Scope: "all_peers",
ExtraAttrsStr: "{\"key\":\"value\"}",
}
p.NoError(s.Decode())
p.Len(s.Filters, 3)
p.NotNil(s.Trigger)
p.Equal(ScopeTypeAllPeers, s.Scope)
p.Equal(map[string]interface{}{"key": "value"}, s.ExtraAttrs)
// invalid filter or trigger
s.FiltersStr = ""
@ -133,9 +135,13 @@ func (p *PolicyTestSuite) TestEncode() {
TriggerStr: "",
Enabled: false,
Scope: "single_peer",
ExtraAttrs: map[string]interface{}{
"key": "value",
},
}
p.NoError(s.Encode())
p.Equal(`[{"type":"repository","value":"**"},{"type":"tag","value":"**"},{"type":"label","value":"test"}]`, s.FiltersStr)
p.Equal(`{"type":"event_based","trigger_setting":{}}`, s.TriggerStr)
p.Equal(ScopeTypeSinglePeer, s.Scope)
p.Equal(`{"key":"value"}`, s.ExtraAttrsStr)
}

View File

@ -54,13 +54,13 @@ const (
type dragonflyCreateJobRequest struct {
// Type is the job type, support preheat.
Type string `json:"type" binding:"required"`
Type string `json:"type"`
// Args is the preheating args.
Args dragonflyCreateJobRequestArgs `json:"args" binding:"omitempty"`
Args dragonflyCreateJobRequestArgs `json:"args"`
// SchedulerClusterIDs is the scheduler cluster ids for preheating.
SchedulerClusterIDs []uint `json:"scheduler_cluster_ids" binding:"omitempty"`
SchedulerClusterIDs []uint `json:"scheduler_cluster_ids"`
}
type dragonflyCreateJobRequestArgs struct {
@ -150,6 +150,12 @@ type dragonflyJobResponse struct {
} `json:"result"`
}
// dragonflyExtraAttrs is the extra attributes model definition for dragonfly provider.
type dragonflyExtraAttrs struct {
// ClusterIDs is the cluster ids for dragonfly provider.
ClusterIDs []uint `json:"cluster_ids"`
}
// DragonflyDriver implements the provider driver interface for Alibaba dragonfly.
// More details, please refer to https://github.com/alibaba/Dragonfly
type DragonflyDriver struct {
@ -201,6 +207,18 @@ func (dd *DragonflyDriver) Preheat(preheatingImage *PreheatImage) (*PreheatingSt
return nil, errors.New("no image specified")
}
var extraAttrs dragonflyExtraAttrs
if preheatingImage.ExtraAttrs != nil && len(preheatingImage.ExtraAttrs) > 0 {
extraAttrsStr, err := json.Marshal(preheatingImage.ExtraAttrs)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal extra attributes")
}
if err := json.Unmarshal(extraAttrsStr, &extraAttrs); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal extra attributes")
}
}
// Construct the preheat job request by the given parameters of the preheating image .
req := &dragonflyCreateJobRequest{
Type: "preheat",
@ -213,6 +231,11 @@ func (dd *DragonflyDriver) Preheat(preheatingImage *PreheatImage) (*PreheatingSt
},
}
// Set the cluster ids if it is specified.
if len(extraAttrs.ClusterIDs) > 0 {
req.SchedulerClusterIDs = extraAttrs.ClusterIDs
}
url := fmt.Sprintf("%s%s", strings.TrimSuffix(dd.instance.Endpoint, "/"), dragonflyJobPath)
data, err := client.GetHTTPClient(dd.instance.Insecure).Post(url, dd.getCred(), req, nil)
if err != nil {

View File

@ -86,6 +86,9 @@ func (suite *DragonflyTestSuite) TestPreheat() {
URL: "https://harbor.com",
Digest: "sha256:f3c97e3bd1e27393eb853a5c90b1132f2cda84336d5ba5d100c720dc98524c82",
Scope: "single_peer",
ExtraAttrs: map[string]interface{}{
"cluster_ids": []uint{1, 2, 3},
},
})
require.NoError(suite.T(), err, "preheat image")
suite.Equal(provider.PreheatingStatusPending, st.Status, "preheat status")

View File

@ -48,6 +48,9 @@ type PreheatImage struct {
// Scope indicates the preheat scope.
Scope string `json:"scope,omitempty"`
// ExtraAttrs contains extra attributes for the preheating image.
ExtraAttrs map[string]interface{} `json:"extra_attrs,omitempty"`
}
// FromJSON build preheating image from the given data.

View File

@ -481,6 +481,23 @@
</select>
</clr-select-container>
</div>
<!-- extra_attrs -->
<div class="clr-form-control">
<label class="clr-control-label width-6rem">{{
'P2P_PROVIDER.EXTRA_ATTRIBUTES' | translate
}}</label>
<div class="clr-control-container">
<textarea
autocomplete="off"
class="clr-textarea width-380"
type="text"
id="extraAttrs"
#ngExtraAttrs="ngModel"
[disabled]="loading"
[(ngModel)]="extraAttrs"
name="extraAttrs"></textarea>
</div>
</div>
</section>
</form>
<div class="mt-1 bottom-btn" *ngIf="!isEdit">

View File

@ -12,6 +12,7 @@ import { NgForm } from '@angular/forms';
import { OriginCron, ProjectService } from '../../../../shared/services';
import { CronScheduleComponent } from '../../../../shared/components/cron-schedule';
import { PreheatService } from '../../../../../../ng-swagger-gen/services/preheat.service';
import { ExtraAttrs } from '../../../../../../ng-swagger-gen/models/extra-attrs';
import {
debounceTime,
distinctUntilChanged,
@ -76,6 +77,7 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
labels: string;
triggerType: string = TRIGGER.MANUAL;
scope: string = SCOPE.SINGLE_PEER;
extraAttrs: string;
cron: string;
@ViewChild('policyForm', { static: true }) currentForm: NgForm;
loading: boolean = false;
@ -90,6 +92,8 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
originLabelsForEdit: string;
originTriggerTypeForEdit: string;
originCronForEdit: string;
originScopeForEdit: string;
originExtraAttrsForEdit: string;
@Input()
providers: ProviderUnderProject[] = [];
preventVul: boolean = false;
@ -309,6 +313,7 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
this.loading = true;
this.buttonStatus = ClrLoadingState.LOADING;
policy.scope = this.scope ? this.scope : SCOPE.SINGLE_PEER;
policy.extra_attrs = this.extraAttrs;
deleteEmptyKey(policy);
if (isAdd) {
policy.project_id = this.projectId;
@ -410,7 +415,11 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
return true;
}
// eslint-disable-next-line eqeqeq
if (this.policy.scope != this.scope) {
if (this.originScopeForEdit != this.scope) {
return true;
}
// eslint-disable-next-line eqeqeq
if (this.originExtraAttrsForEdit != this.extraAttrs) {
return true;
}
// eslint-disable-next-line eqeqeq

View File

@ -166,6 +166,10 @@
<clr-dg-column>{{ 'P2P_PROVIDER.PROVIDER' | translate }}</clr-dg-column>
<clr-dg-column>{{ 'P2P_PROVIDER.FILTERS' | translate }}</clr-dg-column>
<clr-dg-column>{{ 'P2P_PROVIDER.TRIGGER' | translate }}</clr-dg-column>
<clr-dg-column>{{ 'P2P_PROVIDER.SCOPE' | translate }}</clr-dg-column>
<clr-dg-column>{{
'P2P_PROVIDER.EXTRA_ATTRIBUTES' | translate
}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="'creation_time'">{{
'P2P_PROVIDER.CREATED' | translate
}}</clr-dg-column>
@ -284,6 +288,29 @@
</clr-signpost-content>
</clr-signpost>
</clr-dg-cell>
<clr-dg-cell>{{ getScopeI18n(p.scope) | translate }}</clr-dg-cell>
<clr-dg-cell class="flex">
<clr-signpost>
<a class="btn btn-link link-normal" clrSignpostTrigger>
<span>
{{ toString(toJson(p?.extra_attrs)) }}
</span>
</a>
<clr-signpost-content
class="pre"
[clrPosition]="'top-middle'"
*clrIfOpen>
<hbr-copy-input
[iconMode]="true"
[defaultValue]="
toString(p?.extra_attrs)
"></hbr-copy-input>
<pre
[innerHTML]="toJson(p?.extra_attrs) | json"
class="abc"></pre>
</clr-signpost-content>
</clr-signpost>
</clr-dg-cell>
<clr-dg-cell>{{
p.creation_time | harborDatetime : 'short'
}}</clr-dg-cell>

View File

@ -19,11 +19,11 @@
height: 100%;
}
.margin-left-5px{
.margin-left-5px {
margin-left: 5px;
}
.margin-left-10px{
.margin-left-10px {
margin-left: 10px;
}
@ -58,3 +58,24 @@
.no-wrapper {
white-space: nowrap;
}
.flex {
display: flex;
}
.pre {
min-width: 25rem;
max-width: 40rem;
}
pre {
border: none;
}
.link-normal {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 10rem;
text-transform: unset;
}

View File

@ -38,6 +38,7 @@ import {
TIME_OUT,
TRIGGER,
TRIGGER_I18N_MAP,
SCOPE_I18N_MAP,
} from '../p2p-provider.service';
import { PreheatPolicy } from '../../../../../../ng-swagger-gen/models/preheat-policy';
import { PreheatService } from '../../../../../../ng-swagger-gen/services/preheat.service';
@ -490,7 +491,8 @@ export class PolicyComponent implements OnInit, OnDestroy {
severity: this.addP2pPolicyComponent.severity,
label: this.addP2pPolicyComponent.labels,
triggerType: this.addP2pPolicyComponent.triggerType,
scope: this.addP2pPolicyComponent.scope,
scope: this.addP2pPolicyComponent.policy.scope,
extraAttrs: this.addP2pPolicyComponent.policy.extra_attrs,
});
this.addP2pPolicyComponent.originPolicyForEdit = clone(
this.selectedRow
@ -509,6 +511,10 @@ export class PolicyComponent implements OnInit, OnDestroy {
this.addP2pPolicyComponent.triggerType;
this.addP2pPolicyComponent.originCronForEdit =
this.addP2pPolicyComponent.cron;
this.addP2pPolicyComponent.originScopeForEdit =
this.addP2pPolicyComponent.scope;
this.addP2pPolicyComponent.originExtraAttrsForEdit =
this.addP2pPolicyComponent.extraAttrs;
}
}
@ -666,6 +672,13 @@ export class PolicyComponent implements OnInit, OnDestroy {
return trigger;
}
getScopeI18n(scope: string): string {
if (scope) {
return SCOPE_I18N_MAP[scope];
}
return '';
}
isScheduled(trigger: string): boolean {
return JSON.parse(trigger).type === TRIGGER.SCHEDULED;
}
@ -794,4 +807,17 @@ export class PolicyComponent implements OnInit, OnDestroy {
}
}
}
toString(v: any) {
if (v) {
return JSON.stringify(v);
}
return '';
}
toJson(v: any) {
if (v) {
return JSON.parse(v);
}
return null;
}
}

View File

@ -16,7 +16,7 @@
"HEADER_LINK": "Einloggen",
"OR": "ODER",
"VIA_LOCAL_DB": "LOGIN MIT LOKALER DB",
"CORE_SERVICE_NOT_AVAILABLE": "Core Service ist nicht verfügbar"
"CORE_SERVICE_NOT_AVAILABLE": "Core Service ist nicht verfügbar"
},
"SIGN_UP": {
"TITLE": "Registrieren"
@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "Projekt erfolgreich geändert.",
"FAILED_TO_DELETE_PROJECT": "Das Projekt enthält Repositories, Replikations-Regeln oder Helm-Charts und kann daher nicht gelöscht werden.",
"INLINE_HELP_PUBLIC": "Wenn ein Projekt öffentlich ist, hat jeder lesenden Zugriff auf die Repositories innerhalb des Projekts. Der Nutzer muss nicht \"docker login\" vor dem Pull eines Images durchführen.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "von",
@ -385,7 +385,7 @@
"INVALID_VALUE": "Der Wert der Ablaufzeit ist ungültig",
"NEVER_EXPIRED": "Läuft nie ab",
"NAME_PREFIX": "Prefix für den Namen der Robot-Zugänge",
"NAME_PREFIX_REQUIRED": "Es ist ein Prefix für den Robot-Zugang erforderlich",
"NAME_PREFIX_REQUIRED": "Es ist ein Prefix für den Robot-Zugang erforderlich",
"UPDATE": "Update",
"AUDIT_LOG": "Audit Log",
"PREHEAT_INSTANCE": "Preheat Instance",
@ -936,7 +936,6 @@
"LDAP_GROUP_MEMBERSHIP_INFO": "Dass Attribut, das die Mitglieder einer LDAP-Gruppe identifiziert. Standardwert ist memberof, in manchen LDAP Servern kann es \"ismemberof\" sein. Das Feld darf nicht leer sein, sofern eine LDAP Gruppen Funktion eingesetzt wird.",
"GROUP_SCOPE": "LDAP Gruppen Search Scope",
"GROUP_SCOPE_INFO": "Der Scope mit dem nach Gruppen gesucht wird. Standard ist Subtree."
},
"UAA": {
"ENDPOINT": "UAA Endpunkt",
@ -966,8 +965,8 @@
"OIDC_USERNAME": "Nutzername",
"GROUP_CLAIM_NAME": "Group Claim Name",
"GROUP_CLAIM_NAME_INFO": "The name of a custom group claim that you have configured in your OIDC provider",
"OIDC_ADMIN_GROUP": "OIDC Administratorengruppe",
"OIDC_ADMIN_GROUP_INFO": "Spezifiziere den Namen einer OIDC Administratorengruppe. Alle Mitglieder dieser Gruppe haben in Harbor administrative Berechtigungen. Falls dies nicht gewünscht ist, kann das Feld leer gelassen werden.",
"OIDC_ADMIN_GROUP": "OIDC Administratorengruppe",
"OIDC_ADMIN_GROUP_INFO": "Spezifiziere den Namen einer OIDC Administratorengruppe. Alle Mitglieder dieser Gruppe haben in Harbor administrative Berechtigungen. Falls dies nicht gewünscht ist, kann das Feld leer gelassen werden.",
"OIDC_GROUP_FILTER": "OIDC Group Filter",
"OIDC_GROUP_FILTER_INFO": "Filter OIDC groups who match the provided regular expression.Keep it blank to match all the groups."
},
@ -1310,7 +1309,6 @@
"ON": "am",
"AT": "um",
"NOSCHEDULE": "Ein Fehler ist aufgetreten beim setzen des Intervalls"
},
"GC": {
"CURRENT_SCHEDULE": "Speicherbereinigungs-Intervall",
@ -1444,8 +1442,8 @@
"DAYS_LARGE": "Parameter \"TAGE\" ist zu hoch",
"EXECUTION_TYPE": "Ausführungstyp",
"ACTION": "AKTION",
"YES": "Ja",
"NO": "Nein"
"YES": "Ja",
"NO": "Nein"
},
"IMMUTABLE_TAG": {
"IMMUTABLE_RULES": "Immutability Regeln",
@ -1636,6 +1634,7 @@
"SCOPE": "Umfang",
"SCOPE_SINGLE_PEER": "Einzelner Peer",
"SCOPE_ALL_PEERS": "Alle Peers",
"EXTRA_ATTRIBUTES": "Extra Attributes",
"NO_POLICY": "Keine Regelwerke",
"ENABLED_POLICY_SUMMARY": "Soll das Regelwerk {{name}} aktiviert werden?",
"DISABLED_POLICY_SUMMARY": "Soll das Regelwerk {{name}} deaktiviert werden?",

View File

@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "Toggled project successfully.",
"FAILED_TO_DELETE_PROJECT": "Project contains repositories or replication rules or helm-charts cannot be deleted.",
"INLINE_HELP_PUBLIC": "When a project is set to public, anyone has read permission to the repositories under this project, and the user does not need to run \"docker login\" before pulling images under this project.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "of",
@ -486,7 +486,6 @@
"CLOUD_EVENT": "CloudEvents",
"PAYLOAD_DATA": "Payload Data",
"SLACK_RATE_LIMIT": "Please be aware of Slack Rate Limits"
},
"GROUP": {
"GROUP": "Group",
@ -936,10 +935,9 @@
"LDAP_GROUP_MEMBERSHIP": "LDAP Group Membership",
"LDAP_GROUP_MEMBERSHIP_INFO": "The attribute indicates the membership of LDAP group, default value is memberof, in some LDAP server it could be \"ismemberof\". This field cannot be empty if you need to enable the LDAP group related feature.",
"GROUP_SCOPE": "LDAP Group Search Scope",
"GROUP_SCOPE_INFO": "The scope to search for groups, select Subtree by default.",
"GROUP_ATTACH_PARALLEL": "LDAP Group Attached In Parallel",
"GROUP_ATTACH_PARALLEL_INFO": "Enable this option to attach group in parallel to avoid timeout when there are too many groups. If disabled, the LDAP group information will be attached sequentially."
"GROUP_SCOPE_INFO": "The scope to search for groups, select Subtree by default.",
"GROUP_ATTACH_PARALLEL": "LDAP Group Attached In Parallel",
"GROUP_ATTACH_PARALLEL_INFO": "Enable this option to attach group in parallel to avoid timeout when there are too many groups. If disabled, the LDAP group information will be attached sequentially."
},
"UAA": {
"ENDPOINT": "UAA Endpoint",
@ -1313,7 +1311,6 @@
"ON": "on",
"AT": "at",
"NOSCHEDULE": "An error occurred in Get schedule"
},
"GC": {
"CURRENT_SCHEDULE": "Schedule to GC",
@ -1639,6 +1636,7 @@
"SCOPE": "Scope",
"SCOPE_SINGLE_PEER": "Single Peer",
"SCOPE_ALL_PEERS": "All Peers",
"EXTRA_ATTRIBUTES": "Extra Attributes",
"NO_POLICY": "No policy",
"ENABLED_POLICY_SUMMARY": "Do you want to enable policy {{name}}?",
"DISABLED_POLICY_SUMMARY": "Do you want to deactivate policy {{name}}?",

View File

@ -247,7 +247,7 @@
"TOGGLED_SUCCESS": "Proyecto alternado satisfactoriamente.",
"FAILED_TO_DELETE_PROJECT": "Project contains repositories or replication rules or helm-charts cannot be deleted.",
"INLINE_HELP_PUBLIC": "Cuando un proyecto se marca como público, todo el mundo tiene permisos de lectura sobre los repositorio de dicho proyecto, y no hace falta hacer \"docker login\" antes de subir imágenes a ellos.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "of",
@ -913,7 +913,6 @@
"WEEKLY_CRON": "Run once a week, midnight between Sat/Sun. Equivalente a 0 0 0 * * 0.",
"DAILY_CRON": "Run once a day, midnight. Equivalente a 0 0 0 * * *.",
"SKIP_SCANNER_PULL_TIME_TOOLTIP": "Vulnerability scanner(e.g. Trivy) will not update the image \"last pull time\" when the image is scanned."
},
"LDAP": {
"URL": "LDAP URL",
@ -1196,7 +1195,6 @@
"ADD_TAG": "ADD TAG",
"REMOVE_TAG": "REMOVE TAG",
"NAME_ALREADY_EXISTS": "Tag already exists under the repository"
},
"LABEL": {
"LABEL": "Label",
@ -1307,7 +1305,6 @@
"ON": "on",
"AT": "at",
"NOSCHEDULE": "An error occurred in Get schedule"
},
"GC": {
"CURRENT_SCHEDULE": "Schedule to GC",
@ -1633,6 +1630,7 @@
"SCOPE": "Scope",
"SCOPE_SINGLE_PEER": "Single Peer",
"SCOPE_ALL_PEERS": "All Peers",
"EXTRA_ATTRIBUTES": "Extra Attributes",
"NO_POLICY": "No policy",
"ENABLED_POLICY_SUMMARY": "Do you want to enable policy {{name}}?",
"DISABLED_POLICY_SUMMARY": "Do you want to disable policy {{name}}?",

View File

@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "Projet basculé avec succès.",
"FAILED_TO_DELETE_PROJECT": "Le projet contient des dépôts, des règles de réplication ou des charts Helm et ne peut pas être supprimé.",
"INLINE_HELP_PUBLIC": "Lorsqu'un projet est mis en public, n'importe qui a l'autorisation de lire les dépôts sous ce projet, et l'utilisateur n'a pas besoin d'exécuter \"docker login\" avant de prendre des images de ce projet.",
"PROXY_CACHE_BANDWIDTH":"Définissez la bande passante maximale du réseau pour les pulls d'image en amont pour le proxy-cache. Pour une bande passante illimitée, entrez -1. ",
"PROXY_CACHE_BANDWIDTH": "Définissez la bande passante maximale du réseau pour les pulls d'image en amont pour le proxy-cache. Pour une bande passante illimitée, entrez -1. ",
"BANDWIDTH": "Bande passante",
"SPEED_LIMIT_TIP": "Entrez -1 ou un nombre entier supérieur à 0. ",
"OF": "sur",
@ -340,7 +340,7 @@
"SWITCHED_SUCCESS": "Rôle du membre changé avec succès.",
"OF": "sur",
"SWITCH_TITLE": "Confirmez le changement de membres projet",
"SWITCH_SUMMARY": "Voulez-vous changer les membres projet {{param}}?",
"SWITCH_SUMMARY": "Voulez-vous changer les membres projet {{param}}?",
"SET_ROLE": "Définir Role",
"REMOVE": "Retirer",
"GROUP_NAME_REQUIRED": "Le nom du groupe est requis",
@ -562,7 +562,7 @@
"OVERRIDE": "Surcharger",
"ENABLED_RULE": "Activer la règle",
"OVERRIDE_INFO": "Surcharger",
"OPERATION": "Opération",
"OPERATION": "Opération",
"CURRENT": "courant",
"FILTER_PLACEHOLDER": "Filtrer les tâches",
"STOP_TITLE": "Confirmer l'arrêt des exécutions",
@ -587,7 +587,7 @@
"DELETION_TITLE": "Confirmer la suppression de la règle",
"DELETION_SUMMARY": "Voulez-vous supprimer la règle {{param}} ?",
"REPLICATION_TITLE": "Confirmer la règle de réplication",
"REPLICATION_SUMMARY": "Voulez-vous répliquer la règle {{param}}?",
"REPLICATION_SUMMARY": "Voulez-vous répliquer la règle {{param}}?",
"DELETION_TITLE_FAILURE": "la règle {{param}} n'a pas été supprimée",
"DELETION_SUMMARY_FAILURE": "{{param}} ont le statut en attente/en fonctionnement/en train de réessayer",
"REPLICATE_SUMMARY_FAILURE": "ont le statut pending/running",
@ -602,7 +602,7 @@
"TESTING_CONNECTION": "En train de tester la connexion...",
"TEST_CONNECTION_SUCCESS": "Connexion testée avec succès.",
"TEST_CONNECTION_FAILURE": "Échec du ping de l'endpoint.",
"ID": "ID",
"ID": "ID",
"NAME": "Nom",
"NAME_IS_REQUIRED": "Le nom est obligatoire.",
"DESCRIPTION": "Description",
@ -624,7 +624,7 @@
"ACTIVATION": "Activation",
"REPLICATION_EXECUTION": "Travaux de réplication",
"REPLICATION_EXECUTIONS": "Travaux de réplication",
"STOPJOB": "Stop",
"STOPJOB": "Stop",
"ALL": "Tous",
"PENDING": "En attente",
"RUNNING": "En fonctionnement",
@ -639,7 +639,7 @@
"OPERATION": "Opération",
"CREATION_TIME": "Heure de départ",
"UPDATE_TIME": "Heure de mise à jour",
"END_TIME": "Fin",
"END_TIME": "Fin",
"LOGS": "Logs",
"OF": "sur",
"ITEMS": "entrées",
@ -735,7 +735,7 @@
"TEST_CONNECTION": "Test de connexion",
"TITLE_EDIT": "Éditer l'endpoint",
"TITLE_ADD": "Nouveau endpoint de registre",
"EDIT": "Éditer",
"EDIT": "Éditer",
"DELETE": "Supprimer l'endpoint",
"TESTING_CONNECTION": "En train de tester la connexion...",
"TEST_CONNECTION_SUCCESS": "Connexion testée avec succès.",
@ -805,7 +805,7 @@
"COPY": "Copier",
"NOTARY_IS_UNDETERMINED": "Ne peut pas déterminer la signature de ce tag.",
"PLACEHOLDER": "Nous n'avons trouvé aucun dépôt !",
"INFO": "Info",
"INFO": "Info",
"NO_INFO": "Pas de description pour ce dépôt. Vous pouvez l'ajouter à ce dépôt.",
"IMAGE": "Images",
"LABELS": "Labels",
@ -1636,6 +1636,7 @@
"SCOPE": "Champ d'application",
"SCOPE_SINGLE_PEER": "Pair unique",
"SCOPE_ALL_PEERS": "Tous les pairs",
"EXTRA_ATTRIBUTES": "Attributs supplémentaires",
"NO_POLICY": "Aucune stratégie",
"ENABLED_POLICY_SUMMARY": "Voulez-vous activer la stratégie {{name}} ?",
"DISABLED_POLICY_SUMMARY": "Voulez-vous désactiver la stratégie {{name}} ?",

View File

@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "프로젝트가 성공적으로 전환됐습니다.",
"FAILED_TO_DELETE_PROJECT": "프로젝트에 리포지토리 또는 복제 규칙이 포함되어 있거나 헬름 차트를 삭제할 수 없습니다.",
"INLINE_HELP_PUBLIC": "프로젝트가 공개로 설정되면 누구나 이 프로젝트의 저장소에 대한 읽기 권한을 갖게 되며 사용자는 이 프로젝트에서 이미지를 가져오기 전에 \"docker login\"을 실행할 필요가 없습니다.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "of",
@ -483,7 +483,6 @@
"CLOUD_EVENT": "클라우드이벤트",
"PAYLOAD_DATA": "페이로드 데이터",
"SLACK_RATE_LIMIT": "Slack 속도 제한에 유의하세요."
},
"GROUP": {
"GROUP": "그룹",
@ -934,7 +933,6 @@
"LDAP_GROUP_MEMBERSHIP_INFO": "속성은 LDAP 그룹의 멤버십을 나타내며 기본값은 memberof이며 일부 LDAP 서버에서는 \"ismemberof\"일 수 있습니다. LDAP 그룹 관련 기능을 활성화해야 하는 경우 이 필드를 비워둘 수 없습니다.",
"GROUP_SCOPE": "LDAP 그룹 검색 범위",
"GROUP_SCOPE_INFO": "그룹을 검색할 범위는 기본적으로 Subtree를 선택합니다."
},
"UAA": {
"ENDPOINT": "UAA 엔드포인트",
@ -1308,7 +1306,6 @@
"ON": "on",
"AT": "at",
"NOSCHEDULE": "예약내역을 가져오던 중 에러가 발생했습니다"
},
"GC": {
"CURRENT_SCHEDULE": "가비지 컬렉션 예약",
@ -1630,6 +1627,7 @@
"SCOPE": "범위",
"SCOPE_SINGLE_PEER": "싱글 피어",
"SCOPE_ALL_PEERS": "모든 피어",
"EXTRA_ATTRIBUTES": "추가 속성",
"NO_POLICY": "정책 없음",
"ENABLED_POLICY_SUMMARY": "정책{{name}}을 활성화하시겠습니까?",
"DISABLED_POLICY_SUMMARY": "정책{{name}}을 비활성화하시겠습니까?",

View File

@ -245,7 +245,7 @@
"TOGGLED_SUCCESS": "Projeto alterado com sucesso.",
"FAILED_TO_DELETE_PROJECT": "Projeto não pode ser removido porque ainda possui recursos em repositórios, regras de replicação ou helm charts.",
"INLINE_HELP_PUBLIC": "Quando o projeto é público, o acesso de leitura aos repositórios é liberado, incluindo usuários anônimos não autenticados. O usuário não precisa executar \"docker login\" para baixar imagens desse projeto.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "de",
@ -933,7 +933,6 @@
"LDAP_GROUP_MEMBERSHIP_INFO": "Atributo que informa a lista de grupos do usuário. Se não informado, o nome \"memberof\" será usado. Alguns servidores LDAP utilizam o atributo \"ismemberof\". This field cannot be empty if you need to enable the LDAP group related feature.",
"GROUP_SCOPE": "LDAP Group Search Scope",
"GROUP_SCOPE_INFO": "O escopo que deve ser utilizado na busca por grupos, utiliza Subtree por padrão."
},
"UAA": {
"ENDPOINT": "Endereço UAA",
@ -1303,7 +1302,6 @@
"ON": "em",
"AT": "às",
"NOSCHEDULE": "Ocorreu um erro na rotina Get"
},
"GC": {
"CURRENT_SCHEDULE": "Agenda",
@ -1633,6 +1631,7 @@
"SCOPE": "Escopo",
"SCOPE_SINGLE_PEER": "Par único",
"SCOPE_ALL_PEERS": "Todos os pares",
"EXTRA_ATTRIBUTES": "Atributos extras",
"NO_POLICY": "Nenhuma política",
"ENABLED_POLICY_SUMMARY": "Gostaria de habilitar a política {{name}}?",
"DISABLED_POLICY_SUMMARY": "Gostaria de desabilitar a política {{name}}?",

View File

@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "Proje başarıyla değiştirildi.",
"FAILED_TO_DELETE_PROJECT": "Proje havuzları veya çoğaltma kurallarını içeriyor veya helm tabloları silinemiyor.",
"INLINE_HELP_PUBLIC": "Bir proje herkese açık olarak ayarlandığında, herkes bu proje altındaki depoları okuma iznine sahiptir ve kullanıcının bu proje altındaki imajları çekmeden önce \"docker login\" çalıştırması gerekmez.",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"OF": "of",
@ -936,7 +936,6 @@
"LDAP_GROUP_MEMBERSHIP_INFO": "Öznitelik, LDAP grubunun üyeliğini gösterir, varsayılan değer memberof, bazı LDAP sunucularında \"ismemberof\" olabilir. This field cannot be empty if you need to enable the LDAP group related feature.",
"GROUP_SCOPE": "LDAP Group Search Scope",
"GROUP_SCOPE_INFO": "Grupları aramak için kapsamı, Varsayılan olarak Alt Ağaç'ı seçin."
},
"UAA": {
"ENDPOINT": "UAA Uç Noktası",
@ -1310,7 +1309,6 @@
"ON": "on",
"AT": "at",
"NOSCHEDULE": "Takvimlendirme de bir hata oluştu"
},
"GC": {
"CURRENT_SCHEDULE": "Schedule to GC",
@ -1636,6 +1634,7 @@
"SCOPE": "Scope",
"SCOPE_SINGLE_PEER": "Single Peer",
"SCOPE_ALL_PEERS": "All Peers",
"EXTRA_ATTRIBUTES": "Extra Attributes",
"NO_POLICY": "No policy",
"ENABLED_POLICY_SUMMARY": "Do you want to enable policy {{name}}?",
"DISABLED_POLICY_SUMMARY": "Do you want to disable policy {{name}}?",

View File

@ -246,7 +246,7 @@
"TOGGLED_SUCCESS": "切换状态成功。",
"FAILED_TO_DELETE_PROJECT": "项目包含镜像仓库或复制规则或Helm Charts无法删除。",
"INLINE_HELP_PUBLIC": "当项目设为公开后任何人都有此项目下镜像的读权限。命令行用户不需要“docker login”就可以拉取此项目下的镜像。",
"PROXY_CACHE_BANDWIDTH":"Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"PROXY_CACHE_BANDWIDTH": "Set the maximum network bandwidth to pull image from upstream for proxy-cache. For unlimited bandwidth, please enter -1. ",
"BANDWIDTH": "Bandwidth",
"SPEED_LIMIT_TIP": "Please enter -1 or an integer greater than 0. ",
"COUNT_QUOTA": "存储数量",
@ -934,10 +934,9 @@
"LDAP_GROUP_MEMBERSHIP": "LDAP 组成员",
"LDAP_GROUP_MEMBERSHIP_INFO": "LDAP组成员的membership属性默认为 memberof, 在某些LDAP服务器会变为 ismemberof。如果要开启LDAP组功能则此项必填",
"GROUP_SCOPE": "LDAP组搜索范围",
"GROUP_SCOPE_INFO": "搜索组的范围,默认值为\"子树\"",
"GROUP_ATTACH_PARALLEL": "LDAP组并行同步",
"GROUP_ATTACH_PARALLEL_INFO": "打开这个选项时LDAP组的信息是并行同步到Harbor, 这样可以防止用户组太多时造成的登录超时如果关闭这个选项LDAP组信息是顺序同步到Harbor"
"GROUP_SCOPE_INFO": "搜索组的范围,默认值为\"子树\"",
"GROUP_ATTACH_PARALLEL": "LDAP组并行同步",
"GROUP_ATTACH_PARALLEL_INFO": "打开这个选项时LDAP组的信息是并行同步到Harbor, 这样可以防止用户组太多时造成的登录超时如果关闭这个选项LDAP组信息是顺序同步到Harbor"
},
"UAA": {
"ENDPOINT": "UAA Endpoint",
@ -1309,7 +1308,6 @@
"ON": " ",
"AT": " ",
"NOSCHEDULE": "获取schedule时出现错误"
},
"GC": {
"CURRENT_SCHEDULE": "当前定时任务",
@ -1635,6 +1633,7 @@
"SCOPE": "范围",
"SCOPE_SINGLE_PEER": "单节点",
"SCOPE_ALL_PEERS": "全节点",
"EXTRA_ATTRIBUTES": "额外属性",
"NO_POLICY": "暂无记录",
"ENABLED_POLICY_SUMMARY": "是否启用策略 {{name}}?",
"DISABLED_POLICY_SUMMARY": "是否禁用策略 {{name}}?",

File diff suppressed because it is too large Load Diff

View File

@ -484,6 +484,7 @@ func convertPolicyToPayload(policy *policy.Schema) (*models.PreheatPolicy, error
ProviderID: policy.ProviderID,
Trigger: policy.TriggerStr,
Scope: policy.Scope,
ExtraAttrs: policy.ExtraAttrsStr,
UpdateTime: strfmt.DateTime(policy.UpdatedTime),
}, nil
}
@ -504,17 +505,18 @@ func convertParamPolicyToModelPolicy(model *models.PreheatPolicy) (*policy.Schem
}
return &policy.Schema{
ID: model.ID,
Name: model.Name,
Description: model.Description,
ProjectID: model.ProjectID,
ProviderID: model.ProviderID,
FiltersStr: model.Filters,
TriggerStr: model.Trigger,
Enabled: model.Enabled,
Scope: model.Scope,
CreatedAt: time.Time(model.CreationTime),
UpdatedTime: time.Time(model.UpdateTime),
ID: model.ID,
Name: model.Name,
Description: model.Description,
ProjectID: model.ProjectID,
ProviderID: model.ProviderID,
FiltersStr: model.Filters,
TriggerStr: model.Trigger,
Enabled: model.Enabled,
Scope: model.Scope,
ExtraAttrsStr: model.ExtraAttrs,
CreatedAt: time.Time(model.CreationTime),
UpdatedTime: time.Time(model.UpdateTime),
}, nil
}