Site replication status (#1834)
Site replication status UI Site replication status ui-test Address review comment by Alex Add functional test for API Add integration tests for status API
This commit is contained in:
committed by
GitHub
parent
4541b4de03
commit
d1d3d91fc1
97
models/site_replication_status_response.go
Normal file
97
models/site_replication_status_response.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// SiteReplicationStatusResponse site replication status response
|
||||
//
|
||||
// swagger:model siteReplicationStatusResponse
|
||||
type SiteReplicationStatusResponse struct {
|
||||
|
||||
// bucket stats
|
||||
BucketStats interface{} `json:"bucketStats,omitempty"`
|
||||
|
||||
// enabled
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
|
||||
// group stats
|
||||
GroupStats interface{} `json:"groupStats,omitempty"`
|
||||
|
||||
// max buckets
|
||||
MaxBuckets int64 `json:"maxBuckets,omitempty"`
|
||||
|
||||
// max groups
|
||||
MaxGroups int64 `json:"maxGroups,omitempty"`
|
||||
|
||||
// max policies
|
||||
MaxPolicies int64 `json:"maxPolicies,omitempty"`
|
||||
|
||||
// max users
|
||||
MaxUsers int64 `json:"maxUsers,omitempty"`
|
||||
|
||||
// policy stats
|
||||
PolicyStats interface{} `json:"policyStats,omitempty"`
|
||||
|
||||
// sites
|
||||
Sites interface{} `json:"sites,omitempty"`
|
||||
|
||||
// stats summary
|
||||
StatsSummary interface{} `json:"statsSummary,omitempty"`
|
||||
|
||||
// user stats
|
||||
UserStats interface{} `json:"userStats,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this site replication status response
|
||||
func (m *SiteReplicationStatusResponse) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this site replication status response based on context it is used
|
||||
func (m *SiteReplicationStatusResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *SiteReplicationStatusResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *SiteReplicationStatusResponse) UnmarshalBinary(b []byte) error {
|
||||
var res SiteReplicationStatusResponse
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -162,6 +162,7 @@ export const IAM_PAGES = {
|
||||
TIERS_ADD: "/settings/tiers/add",
|
||||
TIERS_ADD_SERVICE: "/settings/tiers/add/:service",
|
||||
SITE_REPLICATION: "/settings/site-replication",
|
||||
SITE_REPLICATION_STATUS: "/settings/site-replication/status",
|
||||
|
||||
/* Operator */
|
||||
TENANTS: "/tenants",
|
||||
@@ -185,7 +186,7 @@ export const IAM_PAGES = {
|
||||
NAMESPACE_TENANT_POOLS_ADD:
|
||||
"/namespaces/:tenantNamespace/tenants/:tenantName/add-pool",
|
||||
NAMESPACE_TENANT_POOLS_EDIT:
|
||||
"/namespaces/:tenantNamespace/tenants/:tenantName/edit-pool",
|
||||
"/namespaces/:tenantNamespace/tenants/:tenantName/edit-pool",
|
||||
NAMESPACE_TENANT_VOLUMES:
|
||||
"/namespaces/:tenantNamespace/tenants/:tenantName/volumes",
|
||||
NAMESPACE_TENANT_LICENSE:
|
||||
@@ -384,7 +385,11 @@ export const IAM_PAGES_PERMISSIONS = {
|
||||
IAM_SCOPES.ADMIN_SERVER_INFO,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
};
|
||||
[IAM_PAGES.SITE_REPLICATION_STATUS]: [
|
||||
IAM_SCOPES.ADMIN_SERVER_INFO,
|
||||
IAM_SCOPES.ADMIN_CONFIG_UPDATE,
|
||||
],
|
||||
}
|
||||
|
||||
export const S3_ALL_RESOURCES = "arn:aws:s3:::*";
|
||||
export const CONSOLE_UI_RESOURCE = "console-ui";
|
||||
|
||||
@@ -28,6 +28,7 @@ type DeleteButtonProps = {
|
||||
tooltip?: string;
|
||||
classes?: any;
|
||||
icon?: React.ReactNode;
|
||||
showLabelAlways?:boolean;
|
||||
[x: string]: any;
|
||||
};
|
||||
|
||||
@@ -80,6 +81,7 @@ const RBIconButton = (props: RBIconProps) => {
|
||||
tooltip,
|
||||
icon = null,
|
||||
className = "",
|
||||
showLabelAlways=false,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@@ -98,7 +100,8 @@ const RBIconButton = (props: RBIconProps) => {
|
||||
"& span": {
|
||||
fontSize: 14,
|
||||
"@media (max-width: 900px)": {
|
||||
display: "none",
|
||||
display: showLabelAlways?"inline":"none",
|
||||
marginRight:showLabelAlways?"7px":""
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
||||
import { ClustersIcon } from "../../../../icons";
|
||||
import useApi from "../../Common/Hooks/useApi";
|
||||
import { StatsResponseType } from "./SiteReplicationStatus";
|
||||
import BucketEntityStatus from "./LookupStatus/BucketEntityStatus";
|
||||
import Loader from "../../Common/Loader/Loader";
|
||||
import PolicyEntityStatus from "./LookupStatus/PolicyEntityStatus";
|
||||
import GroupEntityStatus from "./LookupStatus/GroupEntityStatus";
|
||||
import UserEntityStatus from "./LookupStatus/UserEntityStatus";
|
||||
|
||||
const EntityReplicationLookup = () => {
|
||||
const [entityType, setEntityType] = useState<string>("bucket");
|
||||
const [entityValue, setEntityValue] = useState<string>("");
|
||||
|
||||
const [stats, setStats] = useState<StatsResponseType>({});
|
||||
const [statsLoaded, setStatsLoaded] = useState<boolean>(false);
|
||||
|
||||
const [isStatsLoading, invokeSiteStatsApi] = useApi(
|
||||
(res: any) => {
|
||||
setStats(res);
|
||||
setStatsLoaded(true);
|
||||
},
|
||||
(err: any) => {
|
||||
setStats({});
|
||||
setStatsLoaded(true);
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
bucketStats = {},
|
||||
sites = {},
|
||||
userStats = {},
|
||||
policyStats = {},
|
||||
groupStats = {},
|
||||
} = stats || {};
|
||||
|
||||
const getStats = (entityType: string = "", entityValue: string = "") => {
|
||||
setStatsLoaded(false);
|
||||
if (entityType && entityValue) {
|
||||
let url = `api/v1/admin/site-replication/status?buckets=false&entityType=${entityType}&entityValue=${entityValue}&groups=false&policies=false&users=false`;
|
||||
invokeSiteStatsApi("GET", url);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
alignItems: "center",
|
||||
gridTemplateColumns: {
|
||||
md: ".7fr .9fr 1.2fr .3fr",
|
||||
sm: "1.2fr .7fr .7fr .3fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "240px", flexGrow: "0" }}>
|
||||
View Replication Status for a:
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginLeft: {
|
||||
md: "-25px",
|
||||
xs: "0px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SelectWrapper
|
||||
id="replicationEntityLookup"
|
||||
name="replicationEntityLookup"
|
||||
onChange={(e) => {
|
||||
setEntityType(e.target.value);
|
||||
setStatsLoaded(false);
|
||||
}}
|
||||
label=""
|
||||
value={entityType}
|
||||
options={[
|
||||
{
|
||||
label: "Bucket",
|
||||
value: "bucket",
|
||||
},
|
||||
{
|
||||
label: "User",
|
||||
value: "user",
|
||||
},
|
||||
{
|
||||
label: "Group",
|
||||
value: "group",
|
||||
},
|
||||
{
|
||||
label: "Policy",
|
||||
value: "policy",
|
||||
},
|
||||
]}
|
||||
disabled={false}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
flex: 2,
|
||||
}}
|
||||
>
|
||||
<InputBoxWrapper
|
||||
id="replicationLookupEntityValue"
|
||||
name="replicationLookupEntityValue"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setEntityValue(e.target.value);
|
||||
setStatsLoaded(false);
|
||||
}}
|
||||
placeholder={`test-${entityType}`}
|
||||
label=""
|
||||
value={entityValue}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
maxWidth: "80px",
|
||||
}}
|
||||
>
|
||||
<RBIconButton
|
||||
type={"button"}
|
||||
onClick={() => {
|
||||
getStats(entityType, entityValue);
|
||||
}}
|
||||
text={`View `}
|
||||
tooltip={"View across sites"}
|
||||
icon={<ClustersIcon />}
|
||||
color={"primary"}
|
||||
showLabelAlways
|
||||
disabled={!entityValue || !entityType}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{isStatsLoading ? (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"center"}
|
||||
marginTop={"45px"}
|
||||
>
|
||||
<Loader style={{ width: 25, height: 25 }} />
|
||||
</Grid>
|
||||
) : null}
|
||||
|
||||
{statsLoaded ? (
|
||||
<Box>
|
||||
{!isStatsLoading && entityType === "bucket" && entityValue ? (
|
||||
<BucketEntityStatus
|
||||
bucketStats={bucketStats}
|
||||
sites={sites}
|
||||
lookupValue={entityValue}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{!isStatsLoading && entityType === "user" && entityValue ? (
|
||||
<UserEntityStatus
|
||||
userStats={userStats}
|
||||
sites={sites}
|
||||
lookupValue={entityValue}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{!isStatsLoading && entityType === "group" && entityValue ? (
|
||||
<GroupEntityStatus
|
||||
groupStats={groupStats}
|
||||
sites={sites}
|
||||
lookupValue={entityValue}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{!isStatsLoading && entityType === "policy" && entityValue ? (
|
||||
<PolicyEntityStatus
|
||||
policyStats={policyStats}
|
||||
sites={sites}
|
||||
lookupValue={entityValue}
|
||||
/>
|
||||
) : null}
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EntityReplicationLookup;
|
||||
@@ -0,0 +1,129 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { StatsResponseType } from "../SiteReplicationStatus";
|
||||
import LookupStatusTable from "./LookupStatusTable";
|
||||
import { EntityNotFound, isEntityNotFound, syncStatus } from "./Utils";
|
||||
|
||||
type BucketEntityStatusProps = Partial<StatsResponseType> & {
|
||||
lookupValue?: string;
|
||||
};
|
||||
const BucketEntityStatus = ({
|
||||
bucketStats = {},
|
||||
sites = {},
|
||||
lookupValue = "",
|
||||
}: BucketEntityStatusProps) => {
|
||||
const rowsForStatus = [
|
||||
"Tags",
|
||||
"Policy",
|
||||
"Quota",
|
||||
"Retention",
|
||||
"Encryption",
|
||||
"Replication",
|
||||
];
|
||||
|
||||
const bucketSites: Record<string, any> = bucketStats[lookupValue] || {};
|
||||
|
||||
if (!lookupValue) return null;
|
||||
|
||||
const siteKeys = Object.keys(sites);
|
||||
|
||||
const notFound = isEntityNotFound(sites, bucketSites, "HasBucket");
|
||||
const resultMatrix: any = [];
|
||||
if (notFound) {
|
||||
return <EntityNotFound entityType={"Bucket"} entityValue={lookupValue} />;
|
||||
} else {
|
||||
const row = [];
|
||||
for (let sCol = 0; sCol < siteKeys.length; sCol++) {
|
||||
if (sCol === 0) {
|
||||
row.push("");
|
||||
}
|
||||
/**
|
||||
* ----------------------------------
|
||||
* | <blank cell> | sit-0 | site-1 |
|
||||
* -----------------------------------
|
||||
*/
|
||||
row.push(sites[siteKeys[sCol]].name);
|
||||
}
|
||||
resultMatrix.push(row);
|
||||
for (let fi = 0; fi < rowsForStatus.length; fi++) {
|
||||
/**
|
||||
* -------------------------------------------------
|
||||
* | Feature Name | site-0-status | site-1-status |
|
||||
* --------------------------------------------------
|
||||
*/
|
||||
const sfRow = [];
|
||||
const feature = rowsForStatus[fi];
|
||||
let sbStatus: string | boolean = "";
|
||||
|
||||
for (let si = 0; si < siteKeys.length; si++) {
|
||||
const bucketSiteDeploymentId = sites[siteKeys[si]].deploymentID;
|
||||
|
||||
const rSite = bucketSites[bucketSiteDeploymentId];
|
||||
|
||||
if (si === 0) {
|
||||
sfRow.push(feature);
|
||||
}
|
||||
|
||||
switch (fi) {
|
||||
case 0:
|
||||
sbStatus = syncStatus(rSite.TagMismatch, rSite.HasTagsSet);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 1:
|
||||
sbStatus = syncStatus(rSite.PolicyMismatch, rSite.HasPolicySet);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 2:
|
||||
sbStatus = syncStatus(rSite.QuotaCfgMismatch, rSite.HasQuotaCfgSet);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 3:
|
||||
sbStatus = syncStatus(
|
||||
rSite.OLockConfigMismatch,
|
||||
rSite.HasOLockConfigSet
|
||||
);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 4:
|
||||
sbStatus = syncStatus(rSite.SSEConfigMismatch, rSite.HasSSECfgSet);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 5:
|
||||
sbStatus = syncStatus(
|
||||
rSite.ReplicationCfgMismatch,
|
||||
rSite.HasReplicationCfg
|
||||
);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultMatrix.push(sfRow);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<LookupStatusTable
|
||||
matrixData={resultMatrix}
|
||||
entityName={lookupValue}
|
||||
entityType={"Bucket"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BucketEntityStatus;
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const EntityNotFound = ({
|
||||
entityType,
|
||||
entityValue,
|
||||
}: {
|
||||
entityType: string;
|
||||
entityValue: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "45px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{entityType}:{" "}
|
||||
<Box sx={{ marginLeft: "5px", marginRight: "5px", fontWeight: 600 }}>
|
||||
{entityValue}
|
||||
</Box>{" "}
|
||||
not found.
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EntityNotFound;
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { StatsResponseType } from "../SiteReplicationStatus";
|
||||
import LookupStatusTable from "./LookupStatusTable";
|
||||
import { EntityNotFound, isEntityNotFound, syncStatus } from "./Utils";
|
||||
|
||||
type GroupEntityStatusProps = Partial<StatsResponseType> & {
|
||||
lookupValue?: string;
|
||||
};
|
||||
const UserEntityStatus = ({
|
||||
groupStats = {},
|
||||
sites = {},
|
||||
lookupValue = "",
|
||||
}: GroupEntityStatusProps) => {
|
||||
const rowsForStatus = ["Info", "Policy mapping"];
|
||||
|
||||
const groupSites: Record<string, any> = groupStats[lookupValue] || {};
|
||||
|
||||
if (!lookupValue) return null;
|
||||
|
||||
const siteKeys = Object.keys(sites);
|
||||
const notFound = isEntityNotFound(sites, groupSites, "HasGroup");
|
||||
const resultMatrix: any = [];
|
||||
if (notFound) {
|
||||
return <EntityNotFound entityType={"Group"} entityValue={lookupValue} />;
|
||||
} else {
|
||||
const row = [];
|
||||
for (let sCol = 0; sCol < siteKeys.length; sCol++) {
|
||||
if (sCol === 0) {
|
||||
row.push("");
|
||||
}
|
||||
/**
|
||||
* ----------------------------------
|
||||
* | <blank cell> | sit-0 | site-1 |
|
||||
* -----------------------------------
|
||||
*/
|
||||
row.push(sites[siteKeys[sCol]].name);
|
||||
}
|
||||
resultMatrix.push(row);
|
||||
for (let fi = 0; fi < rowsForStatus.length; fi++) {
|
||||
/**
|
||||
* -------------------------------------------------
|
||||
* | Feature Name | site-0-status | site-1-status |
|
||||
* --------------------------------------------------
|
||||
*/
|
||||
const sfRow = [];
|
||||
const feature = rowsForStatus[fi];
|
||||
let sbStatus: string | boolean = "";
|
||||
|
||||
for (let si = 0; si < siteKeys.length; si++) {
|
||||
const bucketSiteDeploymentId = sites[siteKeys[si]].deploymentID;
|
||||
|
||||
const rSite = groupSites[bucketSiteDeploymentId];
|
||||
|
||||
if (si === 0) {
|
||||
sfRow.push(feature);
|
||||
}
|
||||
|
||||
switch (fi) {
|
||||
case 0:
|
||||
sbStatus = syncStatus(rSite.GroupDescMismatch, rSite.HasGroup);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 1:
|
||||
sbStatus = syncStatus(rSite.PolicyMismatch, rSite.HasPolicyMapping);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultMatrix.push(sfRow);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<LookupStatusTable
|
||||
matrixData={resultMatrix}
|
||||
entityName={lookupValue}
|
||||
entityType={"Group"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserEntityStatus;
|
||||
@@ -0,0 +1,142 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { CircleIcon } from "../../../../../icons";
|
||||
|
||||
const LookupStatusTable = ({
|
||||
matrixData = [],
|
||||
entityName = "",
|
||||
entityType = "",
|
||||
}: {
|
||||
matrixData: any;
|
||||
entityName: string;
|
||||
entityType: string;
|
||||
}) => {
|
||||
//Assumes 1st row should be a header row.
|
||||
const [header = [], ...rows] = matrixData;
|
||||
|
||||
const tableHeader = header.map((hC: string, hcIdx: number) => {
|
||||
return (
|
||||
<td className="header-cell" key={`${0}${hcIdx}`}>
|
||||
{hC}
|
||||
</td>
|
||||
);
|
||||
});
|
||||
|
||||
const tableRowsToRender = rows.map((r: any, rIdx: number) => {
|
||||
return (
|
||||
<tr key={`r-${rIdx + 1}`}>
|
||||
{r.map((v: any, cIdx: number) => {
|
||||
let indicator = null;
|
||||
|
||||
if (cIdx === 0) {
|
||||
indicator = v;
|
||||
} else if (v === "") {
|
||||
indicator = "";
|
||||
}
|
||||
if (v === true) {
|
||||
indicator = (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
"& .min-icon": {
|
||||
fill: "#4CCB92",
|
||||
height: "15px",
|
||||
width: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircleIcon />
|
||||
</Box>
|
||||
);
|
||||
} else if (v === false) {
|
||||
indicator = (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
"& .min-icon": {
|
||||
fill: "#C83B51",
|
||||
height: "15px",
|
||||
width: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircleIcon />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
key={`${rIdx + 1}${cIdx}`}
|
||||
className={cIdx === 0 ? "feature-cell" : "status-cell"}
|
||||
>
|
||||
{indicator}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "15px",
|
||||
table: {
|
||||
width: "100%",
|
||||
borderCollapse: "collapse",
|
||||
|
||||
"& .feature-cell": {
|
||||
fontWeight: 600,
|
||||
fontSize: "14px",
|
||||
paddingLeft: "15px",
|
||||
},
|
||||
"& .status-cell": {
|
||||
textAlign: "center",
|
||||
},
|
||||
"& .header-cell": {
|
||||
textAlign: "center",
|
||||
},
|
||||
"& tr": {
|
||||
height: "38px",
|
||||
},
|
||||
"tr td ": {
|
||||
border: "1px solid #f1f1f1",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box sx={{ marginTop: "15px", marginBottom: "15px" }}>
|
||||
Replication status for {entityType}: <strong>{entityName}</strong>.
|
||||
</Box>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>{tableHeader}</tr>
|
||||
</thead>
|
||||
<tbody>{tableRowsToRender}</tbody>
|
||||
</table>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LookupStatusTable;
|
||||
@@ -0,0 +1,85 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { StatsResponseType } from "../SiteReplicationStatus";
|
||||
import LookupStatusTable from "./LookupStatusTable";
|
||||
import { EntityNotFound, isEntityNotFound, syncStatus } from "./Utils";
|
||||
|
||||
type PolicyEntityStatusProps = Partial<StatsResponseType> & {
|
||||
lookupValue?: string;
|
||||
};
|
||||
const PolicyEntityStatus = ({
|
||||
policyStats = {},
|
||||
sites = {},
|
||||
lookupValue = "",
|
||||
}: PolicyEntityStatusProps) => {
|
||||
const rowsForStatus = ["Policy"];
|
||||
|
||||
const policySites: Record<string, any> = policyStats[lookupValue] || {};
|
||||
|
||||
if (!lookupValue) return null;
|
||||
|
||||
const siteKeys = Object.keys(sites);
|
||||
const notFound = isEntityNotFound(sites, policySites, "HasPolicy");
|
||||
const resultMatrix: any = [];
|
||||
if (notFound) {
|
||||
return <EntityNotFound entityType={"Policy"} entityValue={lookupValue} />;
|
||||
} else {
|
||||
const row = [];
|
||||
for (let sCol = 0; sCol < siteKeys.length; sCol++) {
|
||||
if (sCol === 0) {
|
||||
row.push("");
|
||||
}
|
||||
row.push(sites[siteKeys[sCol]].name);
|
||||
}
|
||||
resultMatrix.push(row);
|
||||
for (let fi = 0; fi < rowsForStatus.length; fi++) {
|
||||
const sfRow = [];
|
||||
const feature = rowsForStatus[fi];
|
||||
let sbStatus: string | boolean = "";
|
||||
|
||||
for (let si = 0; si < siteKeys.length; si++) {
|
||||
const bucketSiteDeploymentId = sites[siteKeys[si]].deploymentID;
|
||||
|
||||
const rSite = policySites[bucketSiteDeploymentId];
|
||||
|
||||
if (si === 0) {
|
||||
sfRow.push(feature);
|
||||
}
|
||||
|
||||
switch (fi) {
|
||||
case 0:
|
||||
sbStatus = syncStatus(rSite.PolicyMismatch, rSite.HasPolicy);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultMatrix.push(sfRow);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<LookupStatusTable
|
||||
matrixData={resultMatrix}
|
||||
entityName={lookupValue}
|
||||
entityType={"Policy"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PolicyEntityStatus;
|
||||
@@ -0,0 +1,91 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { StatsResponseType } from "../SiteReplicationStatus";
|
||||
import LookupStatusTable from "./LookupStatusTable";
|
||||
import { EntityNotFound, isEntityNotFound, syncStatus } from "./Utils";
|
||||
|
||||
type PolicyEntityStatusProps = Partial<StatsResponseType> & {
|
||||
lookupValue?: string;
|
||||
};
|
||||
const UserEntityStatus = ({
|
||||
userStats = {},
|
||||
sites = {},
|
||||
lookupValue = "",
|
||||
}: PolicyEntityStatusProps) => {
|
||||
const rowsForStatus = ["Info", "Policy mapping"];
|
||||
|
||||
const userSites: Record<string, any> = userStats[lookupValue] || {};
|
||||
|
||||
if (!lookupValue) return null;
|
||||
|
||||
const siteKeys = Object.keys(sites);
|
||||
|
||||
const notFound = isEntityNotFound(sites, userSites, "HasUser");
|
||||
|
||||
const resultMatrix: any = [];
|
||||
if (notFound) {
|
||||
return <EntityNotFound entityType={"User"} entityValue={lookupValue} />;
|
||||
} else {
|
||||
const row = [];
|
||||
for (let sCol = 0; sCol < siteKeys.length; sCol++) {
|
||||
if (sCol === 0) {
|
||||
row.push("");
|
||||
}
|
||||
row.push(sites[siteKeys[sCol]].name);
|
||||
}
|
||||
resultMatrix.push(row);
|
||||
for (let fi = 0; fi < rowsForStatus.length; fi++) {
|
||||
const sfRow = [];
|
||||
const feature = rowsForStatus[fi];
|
||||
let sbStatus: string | boolean = "";
|
||||
|
||||
for (let si = 0; si < siteKeys.length; si++) {
|
||||
const bucketSiteDeploymentId = sites[siteKeys[si]].deploymentID;
|
||||
|
||||
const rSite = userSites[bucketSiteDeploymentId];
|
||||
|
||||
if (si === 0) {
|
||||
sfRow.push(feature);
|
||||
}
|
||||
|
||||
switch (fi) {
|
||||
case 0:
|
||||
sbStatus = syncStatus(rSite.UserInfoMismatch, rSite.HasUser);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
case 1:
|
||||
sbStatus = syncStatus(rSite.PolicyMismatch, rSite.HasPolicyMapping);
|
||||
sfRow.push(sbStatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultMatrix.push(sfRow);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<LookupStatusTable
|
||||
matrixData={resultMatrix}
|
||||
entityName={lookupValue}
|
||||
entityType={"User"}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserEntityStatus;
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import { StatsResponseType } from "../SiteReplicationStatus";
|
||||
|
||||
export function syncStatus(mismatch: boolean, set: boolean): string | boolean {
|
||||
if (!set) {
|
||||
return "";
|
||||
}
|
||||
return !mismatch;
|
||||
}
|
||||
|
||||
export function isEntityNotFound(
|
||||
sites: Partial<StatsResponseType>,
|
||||
lookupList: Partial<StatsResponseType>,
|
||||
lookupKey: string
|
||||
) {
|
||||
const siteKeys: string[] = Object.keys(sites);
|
||||
return siteKeys.find((sk: string) => {
|
||||
// there is no way to find the type of this ! as it is an entry in the structure itself.
|
||||
// @ts-ignore
|
||||
const result: Record<string, any> = lookupList[sk] || {};
|
||||
return !result[lookupKey];
|
||||
});
|
||||
}
|
||||
|
||||
export const EntityNotFound = ({
|
||||
entityType,
|
||||
entityValue,
|
||||
}: {
|
||||
entityType: string;
|
||||
entityValue: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "45px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{entityType}:{" "}
|
||||
<Box sx={{ marginLeft: "5px", marginRight: "5px", fontWeight: 600 }}>
|
||||
{entityValue}
|
||||
</Box>{" "}
|
||||
not found.
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -15,15 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState } from "react";
|
||||
import ListSubheader from "@mui/material/ListSubheader";
|
||||
import List from "@mui/material/List";
|
||||
import ListItemButton from "@mui/material/ListItemButton";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import { Box, Button, DialogContentText, Tooltip } from "@mui/material";
|
||||
import {
|
||||
MenuCollapsedIcon,
|
||||
MenuExpandedIcon,
|
||||
} from "../../../../icons/SidebarMenus";
|
||||
import { ReplicationSite } from "./SiteReplication";
|
||||
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
||||
import TrashIcon from "../../../../icons/TrashIcon";
|
||||
@@ -67,16 +61,10 @@ const ReplicationSites = ({
|
||||
onRefresh: () => void;
|
||||
classes: any;
|
||||
}) => {
|
||||
const [expanded, setExpanded] = React.useState<string>("");
|
||||
|
||||
const [deleteSiteKey, setIsDeleteSiteKey] = useState<string>("");
|
||||
const [editSite, setEditSite] = useState<any>(null);
|
||||
const [editEndPointName, setEditEndPointName] = useState<string>("");
|
||||
|
||||
const handleClick = (key: string) => {
|
||||
setExpanded(key);
|
||||
};
|
||||
|
||||
const [isEditing, invokeSiteEditApi] = useApi(
|
||||
(res: any) => {
|
||||
if (res.success) {
|
||||
@@ -103,7 +91,6 @@ const ReplicationSites = ({
|
||||
});
|
||||
};
|
||||
|
||||
const hasExpand = false; //siteInfo.isCurrent to b
|
||||
let isValidEndPointUrl = false;
|
||||
|
||||
try {
|
||||
@@ -139,20 +126,11 @@ const ReplicationSites = ({
|
||||
</Box>
|
||||
{sites.map((siteInfo, index) => {
|
||||
const key = `${siteInfo.name}`;
|
||||
const isExpanded = expanded === siteInfo.name;
|
||||
|
||||
const handleToggle = () => {
|
||||
if (!isExpanded) {
|
||||
handleClick(key);
|
||||
} else {
|
||||
handleClick("");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
<ListItemButton
|
||||
disableRipple
|
||||
className={isExpanded ? "expanded" : ""}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
@@ -274,89 +252,7 @@ const ReplicationSites = ({
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{hasExpand ? (
|
||||
<Box
|
||||
sx={{
|
||||
height: "25px",
|
||||
width: "25px",
|
||||
background: "#FBFAFA",
|
||||
borderRadius: "2px",
|
||||
border: "1px solid #eaeaea",
|
||||
"&:hover": {
|
||||
background: "#fafafa",
|
||||
},
|
||||
display: {
|
||||
md: "block",
|
||||
xs: "none",
|
||||
},
|
||||
"& .collapse-icon": {
|
||||
fill: "#494949",
|
||||
"& g rect": {
|
||||
fill: "#ffffff",
|
||||
},
|
||||
},
|
||||
"& .expand-icon": {
|
||||
fill: "#494949",
|
||||
"& rect": {
|
||||
fill: "#ffffff",
|
||||
},
|
||||
},
|
||||
}}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
{isExpanded ? (
|
||||
<MenuCollapsedIcon className="collapse-icon" />
|
||||
) : (
|
||||
<MenuExpandedIcon className="expand-icon" />
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
height: "25px",
|
||||
width: "25px",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ListItemButton>
|
||||
{isExpanded ? (
|
||||
<Box
|
||||
key={`${siteInfo.name}`}
|
||||
sx={{
|
||||
border: "1px solid #f1f1f1",
|
||||
borderLeft: "0",
|
||||
borderRight: "0",
|
||||
borderTop: "0",
|
||||
}}
|
||||
>
|
||||
<ListSubheader
|
||||
key={`${index}-drive-details`}
|
||||
component="div"
|
||||
sx={{ paddingLeft: "30px" }}
|
||||
>
|
||||
Replication status
|
||||
</ListSubheader>
|
||||
|
||||
<Collapse
|
||||
in={isExpanded}
|
||||
timeout="auto"
|
||||
unmountOnExit
|
||||
sx={{
|
||||
width: "100%",
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
padding: { md: "15px 30px", xs: "10px 10px" },
|
||||
"& .MuiCollapse-wrapperInner": {
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
gap: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
Status info
|
||||
</Collapse>
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
{deleteSiteKey === key ? (
|
||||
<ConfirmDialog
|
||||
|
||||
@@ -30,6 +30,8 @@ import { setErrorSnackMessage, setSnackBarMessage } from "../../../../actions";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import HelpBox from "../../../../common/HelpBox";
|
||||
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
||||
import history from "../../../../history";
|
||||
import { IAM_PAGES } from "../../../../common/SecureComponent/permissions";
|
||||
|
||||
export type ReplicationSite = {
|
||||
deploymentID: string;
|
||||
@@ -125,6 +127,17 @@ const SiteReplication = ({
|
||||
setIsDeleteAll(true);
|
||||
}}
|
||||
/>
|
||||
<RBIconButton
|
||||
tooltip={"Replication Status"}
|
||||
text={"Replication Status"}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
icon={<RecoverIcon />}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
history.push(IAM_PAGES.SITE_REPLICATION_STATUS);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
) : null}
|
||||
<RBIconButton
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import PageLayout from "../../Common/Layout/PageLayout";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import useApi from "../../Common/Hooks/useApi";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
import { IAM_PAGES } from "../../../../common/SecureComponent/permissions";
|
||||
import ScreenTitle from "../../Common/ScreenTitle/ScreenTitle";
|
||||
import StatusCountCard from "../../Dashboard/BasicDashboard/StatusCountCard";
|
||||
import {
|
||||
BucketsIcon,
|
||||
GroupsIcon,
|
||||
IAMPoliciesIcon,
|
||||
RefreshIcon,
|
||||
UsersIcon,
|
||||
} from "../../../../icons";
|
||||
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
|
||||
import EntityReplicationLookup from "./EntityReplicationLookup";
|
||||
import Loader from "../../Common/Loader/Loader";
|
||||
|
||||
export type StatsResponseType = {
|
||||
maxBuckets?: number;
|
||||
bucketStats?: Record<string, any>;
|
||||
maxGroups?: number;
|
||||
groupStats?: Record<string, any>;
|
||||
maxUsers?: number;
|
||||
userStats?: Record<string, any>;
|
||||
maxPolicies?: number;
|
||||
policyStats?: Record<string, any>;
|
||||
sites?: Record<string, any>;
|
||||
};
|
||||
|
||||
const SREntityStatus = ({
|
||||
maxValue = 0,
|
||||
entityStatObj = {},
|
||||
entityTextPlural = "",
|
||||
icon = null,
|
||||
}: {
|
||||
maxValue: number;
|
||||
entityStatObj: Record<string, any>;
|
||||
entityTextPlural: string;
|
||||
icon?: React.ReactNode;
|
||||
}) => {
|
||||
const statEntityLen = Object.keys(entityStatObj || {})?.length;
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
border: "1px solid #f1f1f1",
|
||||
padding: "25px",
|
||||
maxWidth: {
|
||||
sm: "100%",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StatusCountCard
|
||||
icon={icon}
|
||||
onlineCount={maxValue}
|
||||
offlineCount={statEntityLen}
|
||||
okStatusText={"Synced"}
|
||||
notOkStatusText={"Failed"}
|
||||
label={entityTextPlural}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const SiteReplicationStatus = () => {
|
||||
const [stats, setStats] = useState<StatsResponseType>({});
|
||||
|
||||
const [isStatsLoading, invokeSiteStatsApi] = useApi(
|
||||
(res: any) => {
|
||||
setStats(res);
|
||||
},
|
||||
(err: any) => {
|
||||
setStats({});
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
maxBuckets = 0,
|
||||
bucketStats = {},
|
||||
maxGroups = 0,
|
||||
groupStats = {},
|
||||
maxUsers = 0,
|
||||
userStats = {},
|
||||
maxPolicies = 0,
|
||||
policyStats = {},
|
||||
} = stats || {};
|
||||
|
||||
const getStats = () => {
|
||||
let url = `api/v1/admin/site-replication/status?buckets=true&groups=true&policies=true&users=true`;
|
||||
invokeSiteStatsApi("GET", url);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getStats();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader
|
||||
label={
|
||||
<BackLink
|
||||
to={IAM_PAGES.SITE_REPLICATION}
|
||||
label={"Site Replication"}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PageLayout>
|
||||
<ScreenTitle
|
||||
title={"Replication status from all Sites"}
|
||||
actions={
|
||||
<Fragment>
|
||||
<RBIconButton
|
||||
onClick={() => {
|
||||
getStats();
|
||||
}}
|
||||
tooltip={"Refresh"}
|
||||
text={"Refresh"}
|
||||
showLabelAlways
|
||||
icon={<RefreshIcon />}
|
||||
color="primary"
|
||||
variant={"contained"}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
|
||||
{!isStatsLoading ? (
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
marginTop: "25px",
|
||||
gridTemplateColumns: {
|
||||
md: "1fr 1fr 1fr 1fr",
|
||||
sm: "1fr 1fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
gap: "30px",
|
||||
}}
|
||||
>
|
||||
<SREntityStatus
|
||||
entityStatObj={bucketStats}
|
||||
entityTextPlural={"Buckets"}
|
||||
maxValue={maxBuckets}
|
||||
icon={<BucketsIcon />}
|
||||
/>
|
||||
<SREntityStatus
|
||||
entityStatObj={userStats}
|
||||
entityTextPlural={"Users"}
|
||||
maxValue={maxUsers}
|
||||
icon={<UsersIcon />}
|
||||
/>
|
||||
<SREntityStatus
|
||||
entityStatObj={groupStats}
|
||||
entityTextPlural={"Groups"}
|
||||
maxValue={maxGroups}
|
||||
icon={<GroupsIcon />}
|
||||
/>
|
||||
<SREntityStatus
|
||||
entityStatObj={policyStats}
|
||||
entityTextPlural={"Policies"}
|
||||
maxValue={maxPolicies}
|
||||
icon={<IAMPoliciesIcon />}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"center"}
|
||||
marginTop={"45px"}
|
||||
>
|
||||
<Loader style={{ width: 25, height: 25 }} />
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
border: "1px solid #eaeaea",
|
||||
minHeight: {
|
||||
sm: "450px",
|
||||
xs: "250px",
|
||||
},
|
||||
marginTop: "25px",
|
||||
padding: "25px",
|
||||
}}
|
||||
>
|
||||
<EntityReplicationLookup />
|
||||
</Box>
|
||||
</PageLayout>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default SiteReplicationStatus;
|
||||
@@ -121,6 +121,7 @@ const AddPool = React.lazy(
|
||||
const SiteReplication = React.lazy(
|
||||
() => import("./Configurations/SiteReplication/SiteReplication")
|
||||
);
|
||||
const SiteReplicationStatus = React.lazy(() => import("./Configurations/SiteReplication/SiteReplicationStatus"));
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
@@ -373,6 +374,10 @@ const Console = ({
|
||||
component: SiteReplication,
|
||||
path: IAM_PAGES.SITE_REPLICATION,
|
||||
},
|
||||
{
|
||||
component:SiteReplicationStatus,
|
||||
path:IAM_PAGES.SITE_REPLICATION_STATUS,
|
||||
},
|
||||
{
|
||||
component: Account,
|
||||
path: IAM_PAGES.ACCOUNT,
|
||||
|
||||
@@ -23,11 +23,15 @@ export const StatusCountCard = ({
|
||||
offlineCount = 0,
|
||||
icon = null,
|
||||
label = "",
|
||||
okStatusText = "Online",
|
||||
notOkStatusText = "Offline",
|
||||
}: {
|
||||
icon: any;
|
||||
onlineCount: number;
|
||||
offlineCount: number;
|
||||
label: string;
|
||||
okStatusText?: string;
|
||||
notOkStatusText?: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
@@ -115,7 +119,7 @@ export const StatusCountCard = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircleIcon /> <div className="stat-text">Online</div>
|
||||
<CircleIcon /> <div className="stat-text">{okStatusText}</div>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -130,7 +134,8 @@ export const StatusCountCard = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircleIcon /> <div className="stat-text">Offline</div>
|
||||
<CircleIcon />{" "}
|
||||
<div className="stat-text">{notOkStatusText}</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -29,7 +29,7 @@ export const addSitesBtn = Selector("button").withText("Add Sites");
|
||||
// Command to invoke the test locally: testcafe chrome tests/permissions/site-replication.ts
|
||||
/* End Local Testing config block */
|
||||
|
||||
fixture("Site Replication for user with Admin permissions")
|
||||
fixture("Site Replication Status for user with Admin permissions")
|
||||
.page(testDomainUrl)
|
||||
.beforeEach(async (t) => {
|
||||
await t.useRole(roles.settings);
|
||||
|
||||
@@ -203,3 +203,64 @@ func TestDeleteSiteReplicationInfo(t *testing.T) {
|
||||
fmt.Println("TestDeleteReplicationInfo: ", response.StatusCode)
|
||||
|
||||
}
|
||||
|
||||
// Status API
|
||||
|
||||
func makeStatusExecuteReq(method string, url string) (*http.Response, error) {
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
method,
|
||||
url,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func TestGetSiteReplicationStatus(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
reqUrls := [5]string{
|
||||
//default
|
||||
"http://localhost:9090/api/v1/admin/site-replication/status?users=true&groups=true&buckets=true&policies=true",
|
||||
//specific bucket lookup
|
||||
"http://localhost:9090/api/v1/admin/site-replication/status?users=false&groups=false&buckets=false&policies=false&entityValue=test-bucket&entityType=bucket",
|
||||
//specific-user lookup
|
||||
"http://localhost:9090/api/v1/admin/site-replication/status?users=false&groups=false&buckets=false&policies=false&entityValue=test-user&entityType=user",
|
||||
//specific-group lookup
|
||||
"http://localhost:9090/api/v1/admin/site-replication/status?users=false&groups=false&buckets=false&policies=false&entityValue=test-group&entityType=group",
|
||||
//specific-policy lookup
|
||||
"http://localhost:9090/api/v1/admin/site-replication/status?users=false&groups=false&buckets=false&policies=false&entityValue=test-policies&entityType=policiy",
|
||||
}
|
||||
|
||||
for i, url := range reqUrls {
|
||||
|
||||
response, err := makeStatusExecuteReq("GET", url)
|
||||
|
||||
tgt := &models.SiteReplicationStatusResponse{}
|
||||
json.NewDecoder(response.Body).Decode(tgt)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(200, response.StatusCode, "Status Code for", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
92
restapi/admin_replication_status.go
Normal file
92
restapi/admin_replication_status.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
"github.com/minio/console/restapi/operations/admin_api"
|
||||
"github.com/minio/madmin-go"
|
||||
)
|
||||
|
||||
func registerSiteReplicationStatusHandler(api *operations.ConsoleAPI) {
|
||||
|
||||
api.AdminAPIGetSiteReplicationStatusHandler = admin_api.GetSiteReplicationStatusHandlerFunc(func(params admin_api.GetSiteReplicationStatusParams, session *models.Principal) middleware.Responder {
|
||||
rInfo, err := getSRStatusResponse(session, params)
|
||||
if err != nil {
|
||||
return admin_api.NewGetSiteReplicationStatusDefault(500).WithPayload(prepareError(err))
|
||||
}
|
||||
return admin_api.NewGetSiteReplicationStatusOK().WithPayload(rInfo)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func getSRStatusResponse(session *models.Principal, params admin_api.GetSiteReplicationStatusParams) (info *models.SiteReplicationStatusResponse, err error) {
|
||||
|
||||
mAdmin, err := NewMinioAdminClient(session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adminClient := AdminClient{Client: mAdmin}
|
||||
ctx := context.Background()
|
||||
|
||||
res, err := getSRStats(ctx, adminClient, params)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getSRStats(ctx context.Context, client MinioAdmin, params admin_api.GetSiteReplicationStatusParams) (info *models.SiteReplicationStatusResponse, err error) {
|
||||
|
||||
srParams := madmin.SRStatusOptions{
|
||||
Buckets: *params.Buckets,
|
||||
Policies: *params.Policies,
|
||||
Users: *params.Users,
|
||||
Groups: *params.Groups,
|
||||
}
|
||||
if params.EntityType != nil && params.EntityValue != nil {
|
||||
srParams.Entity = madmin.GetSREntityType(*params.EntityType)
|
||||
srParams.EntityValue = *params.EntityValue
|
||||
}
|
||||
|
||||
srInfo, err := client.getSiteReplicationStatus(ctx, srParams)
|
||||
|
||||
retInfo := models.SiteReplicationStatusResponse{
|
||||
BucketStats: &srInfo.BucketStats,
|
||||
Enabled: srInfo.Enabled,
|
||||
GroupStats: srInfo.GroupStats,
|
||||
MaxBuckets: int64(srInfo.MaxBuckets),
|
||||
MaxGroups: int64(srInfo.MaxGroups),
|
||||
MaxPolicies: int64(srInfo.MaxPolicies),
|
||||
MaxUsers: int64(srInfo.MaxUsers),
|
||||
PolicyStats: &srInfo.PolicyStats,
|
||||
Sites: &srInfo.Sites,
|
||||
StatsSummary: srInfo.StatsSummary,
|
||||
UserStats: &srInfo.UserStats,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &retInfo, nil
|
||||
|
||||
}
|
||||
@@ -52,6 +52,12 @@ func (ac adminClientMock) deleteSiteReplicationInfo(ctx context.Context, removeR
|
||||
return deleteSiteReplicationInfoMock(ctx, removeReq)
|
||||
}
|
||||
|
||||
var getSiteReplicationStatus func(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
|
||||
|
||||
func (ac adminClientMock) getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error) {
|
||||
return getSiteReplicationStatus(ctx, params)
|
||||
}
|
||||
|
||||
func TestGetSiteReplicationInfo(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// mock minIO client
|
||||
@@ -243,3 +249,60 @@ func TestDeleteSiteReplicationInfo(t *testing.T) {
|
||||
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
|
||||
|
||||
}
|
||||
|
||||
func TestSiteReplicationStatus(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// mock minIO client
|
||||
adminClient := adminClientMock{}
|
||||
|
||||
function := "getSiteReplicationStatus()"
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
retValueMock := madmin.SRStatusInfo{
|
||||
Enabled: true,
|
||||
MaxBuckets: 0,
|
||||
MaxUsers: 0,
|
||||
MaxGroups: 0,
|
||||
MaxPolicies: 0,
|
||||
Sites: nil,
|
||||
StatsSummary: nil,
|
||||
BucketStats: nil,
|
||||
PolicyStats: nil,
|
||||
UserStats: nil,
|
||||
GroupStats: nil,
|
||||
}
|
||||
|
||||
expValueMock := &madmin.SRStatusInfo{
|
||||
Enabled: true,
|
||||
MaxBuckets: 0,
|
||||
MaxUsers: 0,
|
||||
MaxGroups: 0,
|
||||
MaxPolicies: 0,
|
||||
Sites: nil,
|
||||
StatsSummary: nil,
|
||||
BucketStats: nil,
|
||||
PolicyStats: nil,
|
||||
UserStats: nil,
|
||||
GroupStats: nil,
|
||||
}
|
||||
|
||||
getSiteReplicationStatus = func(ctx context.Context, params madmin.SRStatusOptions) (info *madmin.SRStatusInfo, err error) {
|
||||
return &retValueMock, nil
|
||||
}
|
||||
|
||||
reqValues := madmin.SRStatusOptions{
|
||||
Buckets: true,
|
||||
Policies: true,
|
||||
Users: true,
|
||||
Groups: true,
|
||||
}
|
||||
srInfo, err := adminClient.getSiteReplicationStatus(ctx, reqValues)
|
||||
|
||||
if err != nil {
|
||||
assert.Error(err)
|
||||
}
|
||||
|
||||
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: expected result is not same", function))
|
||||
|
||||
}
|
||||
|
||||
@@ -119,6 +119,9 @@ type MinioAdmin interface {
|
||||
addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite) (*madmin.ReplicateAddStatus, error)
|
||||
editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo) (*madmin.ReplicateEditStatus, error)
|
||||
deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
|
||||
|
||||
//Replication status
|
||||
getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
@@ -547,3 +550,12 @@ func (ac AdminClient) deleteSiteReplicationInfo(ctx context.Context, removeReq m
|
||||
ErrDetail: res.ErrDetail,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ac AdminClient) getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error) {
|
||||
|
||||
res, err := ac.Client.SRStatusInfo(ctx, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
|
||||
registerNodesHandler(api)
|
||||
|
||||
registerSiteReplicationHandler(api)
|
||||
registerSiteReplicationStatusHandler(api)
|
||||
|
||||
// Operator Console
|
||||
|
||||
|
||||
@@ -429,6 +429,71 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/site-replication/status": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Display overall site replication status",
|
||||
"operationId": "GetSiteReplicationStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Bucket stats",
|
||||
"name": "buckets",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Group stats",
|
||||
"name": "groups",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Policies stats",
|
||||
"name": "policies",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Policies stats",
|
||||
"name": "users",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Entity Type to lookup",
|
||||
"name": "entityType",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Entity Value to lookup",
|
||||
"name": "entityValue",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/siteReplicationStatusResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/tiers": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -6311,6 +6376,44 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"siteReplicationStatusResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucketStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"maxBuckets": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxGroups": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxPolicies": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxUsers": {
|
||||
"type": "integer"
|
||||
},
|
||||
"policyStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"sites": {
|
||||
"type": "object"
|
||||
},
|
||||
"statsSummary": {
|
||||
"type": "object"
|
||||
},
|
||||
"userStats": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"startProfilingItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7250,6 +7353,71 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/site-replication/status": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Display overall site replication status",
|
||||
"operationId": "GetSiteReplicationStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Bucket stats",
|
||||
"name": "buckets",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Group stats",
|
||||
"name": "groups",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Policies stats",
|
||||
"name": "policies",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Include Policies stats",
|
||||
"name": "users",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Entity Type to lookup",
|
||||
"name": "entityType",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Entity Value to lookup",
|
||||
"name": "entityValue",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/siteReplicationStatusResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/tiers": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -13258,6 +13426,44 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"siteReplicationStatusResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucketStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"maxBuckets": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxGroups": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxPolicies": {
|
||||
"type": "integer"
|
||||
},
|
||||
"maxUsers": {
|
||||
"type": "integer"
|
||||
},
|
||||
"policyStats": {
|
||||
"type": "object"
|
||||
},
|
||||
"sites": {
|
||||
"type": "object"
|
||||
},
|
||||
"statsSummary": {
|
||||
"type": "object"
|
||||
},
|
||||
"userStats": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"startProfilingItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
88
restapi/operations/admin_api/get_site_replication_status.go
Normal file
88
restapi/operations/admin_api/get_site_replication_status.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// GetSiteReplicationStatusHandlerFunc turns a function with the right signature into a get site replication status handler
|
||||
type GetSiteReplicationStatusHandlerFunc func(GetSiteReplicationStatusParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn GetSiteReplicationStatusHandlerFunc) Handle(params GetSiteReplicationStatusParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// GetSiteReplicationStatusHandler interface for that can handle valid get site replication status params
|
||||
type GetSiteReplicationStatusHandler interface {
|
||||
Handle(GetSiteReplicationStatusParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewGetSiteReplicationStatus creates a new http.Handler for the get site replication status operation
|
||||
func NewGetSiteReplicationStatus(ctx *middleware.Context, handler GetSiteReplicationStatusHandler) *GetSiteReplicationStatus {
|
||||
return &GetSiteReplicationStatus{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/* GetSiteReplicationStatus swagger:route GET /admin/site-replication/status AdminAPI getSiteReplicationStatus
|
||||
|
||||
Display overall site replication status
|
||||
|
||||
*/
|
||||
type GetSiteReplicationStatus struct {
|
||||
Context *middleware.Context
|
||||
Handler GetSiteReplicationStatusHandler
|
||||
}
|
||||
|
||||
func (o *GetSiteReplicationStatus) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
*r = *rCtx
|
||||
}
|
||||
var Params = NewGetSiteReplicationStatusParams()
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
if aCtx != nil {
|
||||
*r = *aCtx
|
||||
}
|
||||
var principal *models.Principal
|
||||
if uprinc != nil {
|
||||
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||
}
|
||||
|
||||
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NewGetSiteReplicationStatusParams creates a new GetSiteReplicationStatusParams object
|
||||
// with the default values initialized.
|
||||
func NewGetSiteReplicationStatusParams() GetSiteReplicationStatusParams {
|
||||
|
||||
var (
|
||||
// initialize parameters with default values
|
||||
|
||||
bucketsDefault = bool(true)
|
||||
|
||||
groupsDefault = bool(true)
|
||||
policiesDefault = bool(true)
|
||||
usersDefault = bool(true)
|
||||
)
|
||||
|
||||
return GetSiteReplicationStatusParams{
|
||||
Buckets: &bucketsDefault,
|
||||
|
||||
Groups: &groupsDefault,
|
||||
|
||||
Policies: &policiesDefault,
|
||||
|
||||
Users: &usersDefault,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSiteReplicationStatusParams contains all the bound params for the get site replication status operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters GetSiteReplicationStatus
|
||||
type GetSiteReplicationStatusParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*Include Bucket stats
|
||||
In: query
|
||||
Default: true
|
||||
*/
|
||||
Buckets *bool
|
||||
/*Entity Type to lookup
|
||||
In: query
|
||||
*/
|
||||
EntityType *string
|
||||
/*Entity Value to lookup
|
||||
In: query
|
||||
*/
|
||||
EntityValue *string
|
||||
/*Include Group stats
|
||||
In: query
|
||||
Default: true
|
||||
*/
|
||||
Groups *bool
|
||||
/*Include Policies stats
|
||||
In: query
|
||||
Default: true
|
||||
*/
|
||||
Policies *bool
|
||||
/*Include Policies stats
|
||||
In: query
|
||||
Default: true
|
||||
*/
|
||||
Users *bool
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewGetSiteReplicationStatusParams() beforehand.
|
||||
func (o *GetSiteReplicationStatusParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
qs := runtime.Values(r.URL.Query())
|
||||
|
||||
qBuckets, qhkBuckets, _ := qs.GetOK("buckets")
|
||||
if err := o.bindBuckets(qBuckets, qhkBuckets, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qEntityType, qhkEntityType, _ := qs.GetOK("entityType")
|
||||
if err := o.bindEntityType(qEntityType, qhkEntityType, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qEntityValue, qhkEntityValue, _ := qs.GetOK("entityValue")
|
||||
if err := o.bindEntityValue(qEntityValue, qhkEntityValue, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qGroups, qhkGroups, _ := qs.GetOK("groups")
|
||||
if err := o.bindGroups(qGroups, qhkGroups, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qPolicies, qhkPolicies, _ := qs.GetOK("policies")
|
||||
if err := o.bindPolicies(qPolicies, qhkPolicies, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
qUsers, qhkUsers, _ := qs.GetOK("users")
|
||||
if err := o.bindUsers(qUsers, qhkUsers, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindBuckets binds and validates parameter Buckets from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindBuckets(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewGetSiteReplicationStatusParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertBool(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("buckets", "query", "bool", raw)
|
||||
}
|
||||
o.Buckets = &value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindEntityType binds and validates parameter EntityType from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindEntityType(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
return nil
|
||||
}
|
||||
o.EntityType = &raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindEntityValue binds and validates parameter EntityValue from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindEntityValue(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
return nil
|
||||
}
|
||||
o.EntityValue = &raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindGroups binds and validates parameter Groups from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindGroups(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewGetSiteReplicationStatusParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertBool(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("groups", "query", "bool", raw)
|
||||
}
|
||||
o.Groups = &value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindPolicies binds and validates parameter Policies from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindPolicies(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewGetSiteReplicationStatusParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertBool(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("policies", "query", "bool", raw)
|
||||
}
|
||||
o.Policies = &value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindUsers binds and validates parameter Users from query.
|
||||
func (o *GetSiteReplicationStatusParams) bindUsers(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: false
|
||||
// AllowEmptyValue: false
|
||||
|
||||
if raw == "" { // empty values pass all other validations
|
||||
// Default values have been previously initialized by NewGetSiteReplicationStatusParams()
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := swag.ConvertBool(raw)
|
||||
if err != nil {
|
||||
return errors.InvalidType("users", "query", "bool", raw)
|
||||
}
|
||||
o.Users = &value
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// GetSiteReplicationStatusOKCode is the HTTP code returned for type GetSiteReplicationStatusOK
|
||||
const GetSiteReplicationStatusOKCode int = 200
|
||||
|
||||
/*GetSiteReplicationStatusOK A successful response.
|
||||
|
||||
swagger:response getSiteReplicationStatusOK
|
||||
*/
|
||||
type GetSiteReplicationStatusOK struct {
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.SiteReplicationStatusResponse `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetSiteReplicationStatusOK creates GetSiteReplicationStatusOK with default headers values
|
||||
func NewGetSiteReplicationStatusOK() *GetSiteReplicationStatusOK {
|
||||
|
||||
return &GetSiteReplicationStatusOK{}
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get site replication status o k response
|
||||
func (o *GetSiteReplicationStatusOK) WithPayload(payload *models.SiteReplicationStatusResponse) *GetSiteReplicationStatusOK {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get site replication status o k response
|
||||
func (o *GetSiteReplicationStatusOK) SetPayload(payload *models.SiteReplicationStatusResponse) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *GetSiteReplicationStatusOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(200)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*GetSiteReplicationStatusDefault Generic error response.
|
||||
|
||||
swagger:response getSiteReplicationStatusDefault
|
||||
*/
|
||||
type GetSiteReplicationStatusDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewGetSiteReplicationStatusDefault creates GetSiteReplicationStatusDefault with default headers values
|
||||
func NewGetSiteReplicationStatusDefault(code int) *GetSiteReplicationStatusDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &GetSiteReplicationStatusDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the get site replication status default response
|
||||
func (o *GetSiteReplicationStatusDefault) WithStatusCode(code int) *GetSiteReplicationStatusDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the get site replication status default response
|
||||
func (o *GetSiteReplicationStatusDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the get site replication status default response
|
||||
func (o *GetSiteReplicationStatusDefault) WithPayload(payload *models.Error) *GetSiteReplicationStatusDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the get site replication status default response
|
||||
func (o *GetSiteReplicationStatusDefault) SetPayload(payload *models.Error) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *GetSiteReplicationStatusDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
golangswaggerpaths "path"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// GetSiteReplicationStatusURL generates an URL for the get site replication status operation
|
||||
type GetSiteReplicationStatusURL struct {
|
||||
Buckets *bool
|
||||
EntityType *string
|
||||
EntityValue *string
|
||||
Groups *bool
|
||||
Policies *bool
|
||||
Users *bool
|
||||
|
||||
_basePath string
|
||||
// avoid unkeyed usage
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *GetSiteReplicationStatusURL) WithBasePath(bp string) *GetSiteReplicationStatusURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *GetSiteReplicationStatusURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *GetSiteReplicationStatusURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/admin/site-replication/status"
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
_basePath = "/api/v1"
|
||||
}
|
||||
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||
|
||||
qs := make(url.Values)
|
||||
|
||||
var bucketsQ string
|
||||
if o.Buckets != nil {
|
||||
bucketsQ = swag.FormatBool(*o.Buckets)
|
||||
}
|
||||
if bucketsQ != "" {
|
||||
qs.Set("buckets", bucketsQ)
|
||||
}
|
||||
|
||||
var entityTypeQ string
|
||||
if o.EntityType != nil {
|
||||
entityTypeQ = *o.EntityType
|
||||
}
|
||||
if entityTypeQ != "" {
|
||||
qs.Set("entityType", entityTypeQ)
|
||||
}
|
||||
|
||||
var entityValueQ string
|
||||
if o.EntityValue != nil {
|
||||
entityValueQ = *o.EntityValue
|
||||
}
|
||||
if entityValueQ != "" {
|
||||
qs.Set("entityValue", entityValueQ)
|
||||
}
|
||||
|
||||
var groupsQ string
|
||||
if o.Groups != nil {
|
||||
groupsQ = swag.FormatBool(*o.Groups)
|
||||
}
|
||||
if groupsQ != "" {
|
||||
qs.Set("groups", groupsQ)
|
||||
}
|
||||
|
||||
var policiesQ string
|
||||
if o.Policies != nil {
|
||||
policiesQ = swag.FormatBool(*o.Policies)
|
||||
}
|
||||
if policiesQ != "" {
|
||||
qs.Set("policies", policiesQ)
|
||||
}
|
||||
|
||||
var usersQ string
|
||||
if o.Users != nil {
|
||||
usersQ = swag.FormatBool(*o.Users)
|
||||
}
|
||||
if usersQ != "" {
|
||||
qs.Set("users", usersQ)
|
||||
}
|
||||
|
||||
_result.RawQuery = qs.Encode()
|
||||
|
||||
return &_result, nil
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *GetSiteReplicationStatusURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if u == nil {
|
||||
panic("url can't be nil")
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *GetSiteReplicationStatusURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *GetSiteReplicationStatusURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on GetSiteReplicationStatusURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on GetSiteReplicationStatusURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base.Scheme = scheme
|
||||
base.Host = host
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *GetSiteReplicationStatusURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
@@ -225,6 +225,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
||||
AdminAPIGetSiteReplicationInfoHandler: admin_api.GetSiteReplicationInfoHandlerFunc(func(params admin_api.GetSiteReplicationInfoParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.GetSiteReplicationInfo has not yet been implemented")
|
||||
}),
|
||||
AdminAPIGetSiteReplicationStatusHandler: admin_api.GetSiteReplicationStatusHandlerFunc(func(params admin_api.GetSiteReplicationStatusParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.GetSiteReplicationStatus has not yet been implemented")
|
||||
}),
|
||||
AdminAPIGetTierHandler: admin_api.GetTierHandlerFunc(func(params admin_api.GetTierParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.GetTier has not yet been implemented")
|
||||
}),
|
||||
@@ -591,6 +594,8 @@ type ConsoleAPI struct {
|
||||
UserAPIGetServiceAccountPolicyHandler user_api.GetServiceAccountPolicyHandler
|
||||
// AdminAPIGetSiteReplicationInfoHandler sets the operation handler for the get site replication info operation
|
||||
AdminAPIGetSiteReplicationInfoHandler admin_api.GetSiteReplicationInfoHandler
|
||||
// AdminAPIGetSiteReplicationStatusHandler sets the operation handler for the get site replication status operation
|
||||
AdminAPIGetSiteReplicationStatusHandler admin_api.GetSiteReplicationStatusHandler
|
||||
// AdminAPIGetTierHandler sets the operation handler for the get tier operation
|
||||
AdminAPIGetTierHandler admin_api.GetTierHandler
|
||||
// AdminAPIGetUserInfoHandler sets the operation handler for the get user info operation
|
||||
@@ -973,6 +978,9 @@ func (o *ConsoleAPI) Validate() error {
|
||||
if o.AdminAPIGetSiteReplicationInfoHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.GetSiteReplicationInfoHandler")
|
||||
}
|
||||
if o.AdminAPIGetSiteReplicationStatusHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.GetSiteReplicationStatusHandler")
|
||||
}
|
||||
if o.AdminAPIGetTierHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.GetTierHandler")
|
||||
}
|
||||
@@ -1492,6 +1500,10 @@ func (o *ConsoleAPI) initHandlerCache() {
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/admin/site-replication/status"] = admin_api.NewGetSiteReplicationStatus(o.context, o.AdminAPIGetSiteReplicationStatusHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["GET"]["/admin/tiers/{type}/{name}"] = admin_api.NewGetTier(o.context, o.AdminAPIGetTierHandler)
|
||||
if o.handlers["GET"] == nil {
|
||||
o.handlers["GET"] = make(map[string]http.Handler)
|
||||
|
||||
@@ -2504,6 +2504,52 @@ paths:
|
||||
tags:
|
||||
- AdminAPI
|
||||
|
||||
/admin/site-replication/status:
|
||||
get:
|
||||
summary: Display overall site replication status
|
||||
operationId: GetSiteReplicationStatus
|
||||
parameters:
|
||||
- name: buckets
|
||||
description: Include Bucket stats
|
||||
in: query
|
||||
type: boolean
|
||||
default: true
|
||||
- name: groups
|
||||
description: Include Group stats
|
||||
in: query
|
||||
type: boolean
|
||||
default: true
|
||||
- name: policies
|
||||
description: Include Policies stats
|
||||
in: query
|
||||
type: boolean
|
||||
default: true
|
||||
- name: users
|
||||
description: Include Policies stats
|
||||
in: query
|
||||
type: boolean
|
||||
default: true
|
||||
- name: entityType
|
||||
description: Entity Type to lookup
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
- name: entityValue
|
||||
description: Entity Value to lookup
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: A successful response.
|
||||
schema:
|
||||
$ref: "#/definitions/siteReplicationStatusResponse"
|
||||
default:
|
||||
description: Generic error response.
|
||||
schema:
|
||||
$ref: "#/definitions/error"
|
||||
tags:
|
||||
- AdminAPI
|
||||
|
||||
/admin/tiers:
|
||||
get:
|
||||
@@ -3923,6 +3969,32 @@ definitions:
|
||||
serviceAccountAccessKey:
|
||||
type: string
|
||||
|
||||
siteReplicationStatusResponse:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
maxBuckets:
|
||||
type: integer
|
||||
maxUsers:
|
||||
type: integer
|
||||
maxGroups:
|
||||
type: integer
|
||||
maxPolicies:
|
||||
type: integer
|
||||
sites:
|
||||
type: object
|
||||
statsSummary:
|
||||
type: object
|
||||
bucketStats:
|
||||
type: object
|
||||
policyStats:
|
||||
type: object
|
||||
userStats:
|
||||
type: object
|
||||
groupStats:
|
||||
type: object
|
||||
|
||||
updateUser:
|
||||
type: object
|
||||
required:
|
||||
|
||||
Reference in New Issue
Block a user