diff --git a/models/multi_bucket_replication.go b/models/multi_bucket_replication.go
index db5b90d776..36d3972624 100644
--- a/models/multi_bucket_replication.go
+++ b/models/multi_bucket_replication.go
@@ -56,6 +56,9 @@ type MultiBucketReplication struct {
// prefix
Prefix string `json:"prefix,omitempty"`
+ // priority
+ Priority int32 `json:"priority,omitempty"`
+
// region
Region string `json:"region,omitempty"`
diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/AddReplicationModal.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/AddReplicationModal.tsx
index 257bdec1d0..83391b8981 100644
--- a/portal-ui/src/screens/Console/Buckets/BucketDetails/AddReplicationModal.tsx
+++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/AddReplicationModal.tsx
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
@@ -28,7 +28,7 @@ import {
modalStyleUtils,
spacingUtils,
} from "../../Common/FormComponents/common/styleLibrary";
-import { BulkReplicationResponse } from "../types";
+import { BucketReplicationRule, BulkReplicationResponse } from "../types";
import { setModalErrorSnackMessage } from "../../../../actions";
import { ErrorResponseHandler } from "../../../../common/types";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
@@ -46,6 +46,7 @@ interface IReplicationModal {
classes: any;
bucketName: string;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
+ setReplicationRules: BucketReplicationRule[];
}
const styles = (theme: Theme) =>
@@ -81,8 +82,10 @@ const AddReplicationModal = ({
classes,
bucketName,
setModalErrorSnackMessage,
+ setReplicationRules,
}: IReplicationModal) => {
const [addLoading, setAddLoading] = useState(false);
+ const [priority, setPriority] = useState("1");
const [accessKey, setAccessKey] = useState("");
const [secretKey, setSecretKey] = useState("");
const [targetURL, setTargetURL] = useState("");
@@ -99,6 +102,23 @@ const AddReplicationModal = ({
const [bandwidthUnit, setBandwidthUnit] = useState("Gi");
const [healthCheck, setHealthCheck] = useState("60");
+ useEffect(() => {
+ if (setReplicationRules.length === 0) {
+ setPriority("1");
+ return;
+ }
+
+ const greatestValue = setReplicationRules.reduce((prevAcc, currValue) => {
+ if (currValue.priority > prevAcc) {
+ return currValue.priority;
+ }
+ return prevAcc;
+ }, 0);
+
+ const nextPriority = greatestValue + 1;
+ setPriority(nextPriority.toString());
+ }, [setReplicationRules]);
+
const addRecord = () => {
const replicate = [
{
@@ -127,6 +147,7 @@ const AddReplicationModal = ({
tags: tags,
replicateDeleteMarkers: repDeleteMarker,
replicateDeletes: repDelete,
+ priority: parseInt(priority),
};
api
@@ -184,6 +205,20 @@ const AddReplicationModal = ({
>
+
+ ) => {
+ if (e.target.validity.valid) {
+ setPriority(e.target.value);
+ }
+ }}
+ label="Priority"
+ value={priority}
+ pattern={"[0-9]*"}
+ />
+
replicationRules.length > 1,
+ disableButtonFunction: () => replicationRules.length === 1,
},
];
@@ -170,6 +170,7 @@ const BucketReplicationPanel = ({
closeModalAndRefresh={closeAddReplication}
open={openSetReplication}
bucketName={bucketName}
+ setReplicationRules={replicationRules}
/>
)}
diff --git a/restapi/admin_remote_buckets.go b/restapi/admin_remote_buckets.go
index 300cde76f7..0d57fef960 100644
--- a/restapi/admin_remote_buckets.go
+++ b/restapi/admin_remote_buckets.go
@@ -269,7 +269,7 @@ func addRemoteBucket(ctx context.Context, client MinioAdmin, params models.Creat
return bucketARN, err
}
-func addBucketReplicationItem(ctx context.Context, session *models.Principal, minClient minioClient, bucketName, prefix, destinationARN string, repDelMark, repDels, repMeta bool, tags string) error {
+func addBucketReplicationItem(ctx context.Context, session *models.Principal, minClient minioClient, bucketName, prefix, destinationARN string, repDelMark, repDels, repMeta bool, tags string, priority int32) error {
// we will tolerate this call failing
cfg, err := minClient.getBucketReplication(ctx, bucketName)
if err != nil {
@@ -278,12 +278,17 @@ func addBucketReplicationItem(ctx context.Context, session *models.Principal, mi
// add rule
maxPrio := 0
- for _, r := range cfg.Rules {
- if r.Priority > maxPrio {
- maxPrio = r.Priority
+
+ if priority <= 0 { // We pick next priority by default
+ for _, r := range cfg.Rules {
+ if r.Priority > maxPrio {
+ maxPrio = r.Priority
+ }
}
+ maxPrio++
+ } else { // User picked priority, we try to set this manually
+ maxPrio = int(priority)
}
- maxPrio++
s3Client, err := newS3BucketClient(session, bucketName, prefix)
if err != nil {
@@ -366,7 +371,8 @@ func setMultiBucketReplication(ctx context.Context, session *models.Principal, c
params.Body.ReplicateDeleteMarkers,
params.Body.ReplicateDeletes,
params.Body.ReplicateMetadata,
- params.Body.Tags)
+ params.Body.Tags,
+ params.Body.Priority)
}
var errorReturn = ""
diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go
index 9875e5a158..7cb4fe770a 100644
--- a/restapi/embedded_spec.go
+++ b/restapi/embedded_spec.go
@@ -4578,6 +4578,11 @@ func init() {
"prefix": {
"type": "string"
},
+ "priority": {
+ "type": "integer",
+ "format": "int32",
+ "default": 0
+ },
"region": {
"type": "string"
},
@@ -10409,6 +10414,11 @@ func init() {
"prefix": {
"type": "string"
},
+ "priority": {
+ "type": "integer",
+ "format": "int32",
+ "default": 0
+ },
"region": {
"type": "string"
},
diff --git a/swagger-console.yml b/swagger-console.yml
index 9c19ab97a3..72c1c92087 100644
--- a/swagger-console.yml
+++ b/swagger-console.yml
@@ -2967,6 +2967,10 @@ definitions:
type: boolean
replicateMetadata:
type: boolean
+ priority:
+ type: integer
+ format: int32
+ default: 0
bucketsRelation:
type: array
minLength: 1