Set Bucket Quota on Creation (#308)

Introces the capability to set bucket quota on bucket creation and adds the API to set the bucket on it's own
This commit is contained in:
Daniel Valdivia
2020-10-01 18:59:20 -07:00
committed by GitHub
parent fcf5d5c9f7
commit 28eb8784a9
30 changed files with 2497 additions and 454 deletions

View File

@@ -38,6 +38,9 @@ type MakeBucketRequest struct {
// Required: true
Name *string `json:"name"`
// quota
Quota *SetBucketQuota `json:"quota,omitempty"`
// versioning
Versioning bool `json:"versioning,omitempty"`
}
@@ -50,6 +53,10 @@ func (m *MakeBucketRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateQuota(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -65,6 +72,24 @@ func (m *MakeBucketRequest) validateName(formats strfmt.Registry) error {
return nil
}
func (m *MakeBucketRequest) validateQuota(formats strfmt.Registry) error {
if swag.IsZero(m.Quota) { // not required
return nil
}
if m.Quota != nil {
if err := m.Quota.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("quota")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *MakeBucketRequest) MarshalBinary() ([]byte, error) {
if m == nil {

137
models/set_bucket_quota.go Normal file
View File

@@ -0,0 +1,137 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SetBucketQuota set bucket quota
//
// swagger:model setBucketQuota
type SetBucketQuota struct {
// amount
Amount int64 `json:"amount,omitempty"`
// enabled
// Required: true
Enabled *bool `json:"enabled"`
// quota type
// Enum: [fifo hard]
QuotaType string `json:"quota_type,omitempty"`
}
// Validate validates this set bucket quota
func (m *SetBucketQuota) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEnabled(formats); err != nil {
res = append(res, err)
}
if err := m.validateQuotaType(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *SetBucketQuota) validateEnabled(formats strfmt.Registry) error {
if err := validate.Required("enabled", "body", m.Enabled); err != nil {
return err
}
return nil
}
var setBucketQuotaTypeQuotaTypePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["fifo","hard"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
setBucketQuotaTypeQuotaTypePropEnum = append(setBucketQuotaTypeQuotaTypePropEnum, v)
}
}
const (
// SetBucketQuotaQuotaTypeFifo captures enum value "fifo"
SetBucketQuotaQuotaTypeFifo string = "fifo"
// SetBucketQuotaQuotaTypeHard captures enum value "hard"
SetBucketQuotaQuotaTypeHard string = "hard"
)
// prop value enum
func (m *SetBucketQuota) validateQuotaTypeEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, setBucketQuotaTypeQuotaTypePropEnum, true); err != nil {
return err
}
return nil
}
func (m *SetBucketQuota) validateQuotaType(formats strfmt.Registry) error {
if swag.IsZero(m.QuotaType) { // not required
return nil
}
// value enum
if err := m.validateQuotaTypeEnum("quota_type", "body", m.QuotaType); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SetBucketQuota) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SetBucketQuota) UnmarshalBinary(b []byte) error {
var res SetBucketQuota
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

3
package-lock.json generated
View File

@@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const rewireReactHotLoader = require('react-app-rewire-hot-loader');
/* config-overrides.js */
module.exports = function override(config, env) {
if (env === 'development') {
config.resolve.alias['react-dom'] = '@hot-loader/react-dom';
}
config = rewireReactHotLoader(config, env);
return config;
};

View File

@@ -5,6 +5,7 @@
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
"@babel/plugin-transform-react-jsx-development": "^7.9.0",
"@hot-loader/react-dom": "^16.9.0",
"@material-ui/core": "^4.9.12",
"@material-ui/icons": "^4.9.1",
"@types/history": "^4.7.3",
@@ -29,9 +30,13 @@
"moment": "^2.24.0",
"npm": "^6.14.4",
"react": "^16.13.1",
"react-app-rewire-hot-loader": "^2.0.1",
"react-app-rewired": "^2.1.6",
"react-async-hook": "^3.6.1",
"react-chartjs-2": "^2.9.0",
"react-codemirror2": "^7.1.0",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.13.0",
"react-moment": "^0.9.7",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
@@ -42,10 +47,11 @@
"superagent": "^5.1.0",
"typeface-roboto": "^0.0.75",
"typescript": "3.6.4",
"use-debounce": "^5.0.1",
"websocket": "^1.0.31"
},
"scripts": {
"start": "PORT=5000 react-scripts start",
"start": "PORT=5000 react-app-rewired start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

View File

@@ -25,6 +25,7 @@ import { connect } from "react-redux";
import { AppState } from "./store";
import { userLoggedIn } from "./actions";
import LoginCallback from "./screens/LoginPage/LoginCallback";
import { hot } from "react-hot-loader/root";
const isLoggedIn = () => {
return (
@@ -75,4 +76,4 @@ class Routes extends React.Component<RoutesProps> {
}
}
export default connector(Routes);
export default hot(connector(Routes));

View File

@@ -14,21 +14,30 @@
// 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 React, { useEffect, useState } from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import {
Button,
Checkbox,
FormControlLabel,
LinearProgress,
} from "@material-ui/core";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import api from "../../../../common/api";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import CheckboxWrapper from "../../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
import { factorForDropdown, getBytes } from "../../../../common/utils";
import { AppState } from "../../../../store";
import { connect } from "react-redux";
import {
addBucketName,
addBucketQuota,
addBucketQuotaSize,
addBucketQuotaType,
addBucketQuotaUnit,
addBucketVersioned,
} from "../actions";
import { useDebounce } from "use-debounce";
import { MakeBucketRequest } from "../types";
const styles = (theme: Theme) =>
createStyles({
@@ -38,6 +47,15 @@ const styles = (theme: Theme) =>
buttonContainer: {
textAlign: "right",
},
multiContainer: {
display: "flex",
alignItems: "center" as const,
justifyContent: "flex-start" as const,
},
sizeFactorContainer: {
marginLeft: 8,
alignSelf: "flex-start" as const,
},
...modalBasic,
});
@@ -45,66 +63,89 @@ interface IAddBucketProps {
classes: any;
open: boolean;
closeModalAndRefresh: () => void;
}
interface IAddBucketState {
addLoading: boolean;
versioned: boolean;
addError: string;
addBucketName: typeof addBucketName;
addBucketVersioned: typeof addBucketVersioned;
addBucketQuota: typeof addBucketQuota;
addBucketQuotaType: typeof addBucketQuotaType;
addBucketQuotaSize: typeof addBucketQuotaSize;
addBucketQuotaUnit: typeof addBucketQuotaUnit;
bucketName: string;
versioned: boolean;
enableQuota: boolean;
quotaType: string;
quotaSize: string;
quotaUnit: string;
}
class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
state: IAddBucketState = {
addLoading: false,
versioned: false,
addError: "",
bucketName: "",
};
const AddBucket = ({
classes,
open,
closeModalAndRefresh,
addBucketName,
addBucketVersioned,
addBucketQuota,
addBucketQuotaType,
addBucketQuotaSize,
addBucketQuotaUnit,
bucketName,
versioned,
enableQuota,
quotaType,
quotaSize,
quotaUnit,
}: IAddBucketProps) => {
const [bName, setBName] = useState<string>(bucketName);
const [addLoading, setAddLoading] = useState<boolean>(false);
const [addError, setAddError] = useState<string>("");
addRecord(event: React.FormEvent) {
const addRecord = (event: React.FormEvent) => {
event.preventDefault();
const { bucketName, addLoading, versioned } = this.state;
if (addLoading) {
return;
}
this.setState({ addLoading: true }, () => {
api
.invoke("POST", "/api/v1/buckets", {
setAddLoading(true);
let request: MakeBucketRequest = {
name: bucketName,
versioning: versioned,
})
.then((res) => {
this.setState(
{
addLoading: false,
addError: "",
},
() => {
this.props.closeModalAndRefresh();
}
);
})
.catch((err) => {
this.setState({
addLoading: false,
addError: err,
});
});
});
};
if (enableQuota) {
const amount = getBytes(quotaSize, quotaUnit, false);
request.quota = {
enabled: true,
quota_type: quotaType,
amount: parseInt(amount),
};
}
render() {
const { classes, open } = this.props;
const { addLoading, addError, bucketName, versioned } = this.state;
api
.invoke("POST", "/api/v1/buckets", request)
.then((res) => {
setAddLoading(false);
setAddError("");
closeModalAndRefresh();
})
.catch((err) => {
setAddLoading(false);
setAddError(err);
});
};
const [value] = useDebounce(bName, 1000);
useEffect(() => {
console.log("called");
addBucketName(value);
}, [value]);
return (
<ModalWrapper
title="Create Bucket"
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
});
setAddError("");
closeModalAndRefresh();
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
@@ -113,7 +154,7 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
addRecord(e);
}}
>
<Grid container>
@@ -133,11 +174,11 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
<InputBoxWrapper
id="bucket-name"
name="bucket-name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ bucketName: e.target.value });
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setBName(event.target.value);
}}
label="Bucket Name"
value={bucketName}
value={bName}
/>
</Grid>
<Grid item xs={12}>
@@ -147,11 +188,74 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
name="versioned"
checked={versioned}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ versioned: event.target.checked });
addBucketVersioned(event.target.checked);
}}
label={"Turn On Versioning"}
/>
</Grid>
<Grid item xs={12}>
<CheckboxWrapper
value="bucket_quota"
id="bucket_quota"
name="bucket_quota"
checked={enableQuota}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
addBucketQuota(event.target.checked);
}}
label={"Enable Bucket Quota"}
/>
</Grid>
{enableQuota && (
<React.Fragment>
<Grid item xs={12}>
<SelectWrapper
value={quotaType}
label="Quota Type"
id="quota_type"
name="quota_type"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
addBucketQuotaType(e.target.value as string);
}}
options={[
{ value: "hard", label: "Hard" },
{ value: "fifo", label: "FIFO" },
]}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<div>
<InputBoxWrapper
type="number"
id="quota_size"
name="quota_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
addBucketQuotaSize(e.target.value);
}}
label="Size"
value={quotaSize}
required
min="1"
/>
</div>
<div className={classes.sizeFactorContainer}>
<SelectWrapper
label=""
id="quota_unit"
name="quota_unit"
value={quotaUnit}
onChange={(
e: React.ChangeEvent<{ value: unknown }>
) => {
addBucketQuotaUnit(e.target.value as string);
}}
options={factorForDropdown()}
/>
</div>
</div>
</Grid>
</React.Fragment>
)}
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
@@ -172,7 +276,25 @@ class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
</form>
</ModalWrapper>
);
}
}
};
export default withStyles(styles)(AddBucket);
const mapState = (state: AppState) => ({
addBucketModalOpen: state.buckets.open,
bucketName: state.buckets.addBucketName,
versioned: state.buckets.addBucketVersioning,
enableQuota: state.buckets.addBucketQuotaEnabled,
quotaType: state.buckets.addBucketQuotaType,
quotaSize: state.buckets.addBucketQuotaSize,
quotaUnit: state.buckets.addBucketQuotaUnit,
});
const connector = connect(mapState, {
addBucketName: addBucketName,
addBucketVersioned: addBucketVersioned,
addBucketQuota: addBucketQuota,
addBucketQuotaType: addBucketQuotaType,
addBucketQuotaSize: addBucketQuotaSize,
addBucketQuotaUnit: addBucketQuotaUnit,
});
export default connector(withStyles(styles)(AddBucket));

View File

@@ -14,7 +14,7 @@
// 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 React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import { Button } from "@material-ui/core";
@@ -31,6 +31,10 @@ import DeleteBucket from "./DeleteBucket";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
import { niceBytes } from "../../../../common/utils";
import { AppState } from "../../../../store";
import { connect } from "react-redux";
import { logMessageReceived, logResetMessages } from "../../Logs/actions";
import { addBucketOpen, addBucketReset } from "../actions";
const styles = (theme: Theme) =>
createStyles({
@@ -78,53 +82,43 @@ const styles = (theme: Theme) =>
interface IListBucketsProps {
classes: any;
addBucketOpen: typeof addBucketOpen;
addBucketModalOpen: boolean;
addBucketReset: typeof addBucketReset;
}
interface IListBucketsState {
records: Bucket[];
totalRecords: number;
loading: boolean;
error: string;
deleteError: string;
addScreenOpen: boolean;
page: number;
rowsPerPage: number;
deleteOpen: boolean;
selectedBucket: string;
filterBuckets: string;
}
const ListBuckets = ({
classes,
addBucketOpen,
addBucketModalOpen,
addBucketReset,
}: IListBucketsProps) => {
const [records, setRecords] = useState<Bucket[]>([]);
const [totalRecords, setTotalRecords] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string>("");
const [deleteError, setDeleteError] = useState<string>("");
const [page, setPage] = useState<number>(0);
const [rowsPerPage, setRowsPerPage] = useState<number>(10);
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [selectedBucket, setSelectedBucket] = useState<string>("");
const [filterBuckets, setFilterBuckets] = useState<string>("");
class ListBuckets extends React.Component<
IListBucketsProps,
IListBucketsState
> {
state: IListBucketsState = {
records: [],
totalRecords: 0,
loading: false,
error: "",
deleteError: "",
addScreenOpen: false,
page: 0,
rowsPerPage: 10,
deleteOpen: false,
selectedBucket: "",
filterBuckets: "",
};
fetchRecords() {
this.setState({ loading: true }, () => {
const { page, rowsPerPage } = this.state;
useEffect(() => {
if (loading) {
const fetchRecords = () => {
setLoading(true);
const offset = page * rowsPerPage;
api
.invoke("GET", `/api/v1/buckets?offset=${offset}&limit=${rowsPerPage}`)
.invoke(
"GET",
`/api/v1/buckets?offset=${offset}&limit=${rowsPerPage}`
)
.then((res: BucketList) => {
this.setState({
loading: false,
records: res.buckets || [],
totalRecords: !res.buckets ? 0 : res.total,
error: "",
});
setLoading(false);
setRecords(res.buckets || []);
setTotalRecords(!res.buckets ? 0 : res.total);
setError("");
// if we get 0 results, and page > 0 , go down 1 page
if (
(res.buckets === undefined ||
@@ -133,73 +127,63 @@ class ListBuckets extends React.Component<
page > 0
) {
const newPage = page - 1;
this.setState({ page: newPage }, () => {
this.fetchRecords();
});
setPage(newPage);
setLoading(true);
}
})
.catch((err: any) => {
this.setState({ loading: false, error: err });
});
setLoading(false);
setError(err);
});
};
fetchRecords();
}
}, [loading, page, rowsPerPage]);
closeAddModalAndRefresh() {
this.setState({ addScreenOpen: false }, () => {
this.fetchRecords();
});
}
const closeAddModalAndRefresh = () => {
addBucketOpen(false);
addBucketReset();
setLoading(true);
};
closeDeleteModalAndRefresh(refresh: boolean) {
this.setState({ deleteOpen: false }, () => {
const closeDeleteModalAndRefresh = (refresh: boolean) => {
setDeleteOpen(false);
if (refresh) {
this.fetchRecords();
}
});
setLoading(true);
}
};
componentDidMount(): void {
this.fetchRecords();
}
useEffect(() => {
setLoading(true);
}, []);
bucketFilter(): void {}
useEffect(() => {
setLoading(true);
}, [page, rowsPerPage]);
render() {
const { classes } = this.props;
const {
records,
totalRecords,
addScreenOpen,
loading,
page,
rowsPerPage,
deleteOpen,
selectedBucket,
filterBuckets,
} = this.state;
const offset = page * rowsPerPage;
const confirmDeleteBucket = (bucket: string) => {
setDeleteOpen(true);
setSelectedBucket(bucket);
};
const handleChangePage = (event: unknown, newPage: number) => {
this.setState({ page: newPage });
setPage(newPage);
};
const handleChangeRowsPerPage = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const rPP = parseInt(event.target.value, 10);
this.setState({ page: 0, rowsPerPage: rPP });
setPage(0);
setRowsPerPage(rPP);
};
const confirmDeleteBucket = (bucket: string) => {
this.setState({ deleteOpen: true, selectedBucket: bucket });
};
const tableActions = [
{ type: "view", to: `/buckets`, sendOnlyId: true },
{ type: "delete", onClick: confirmDeleteBucket, sendOnlyId: true },
];
const offset = page * rowsPerPage;
const displayParsedDate = (date: string) => {
return <Moment>{date}</Moment>;
};
@@ -220,11 +204,11 @@ class ListBuckets extends React.Component<
return (
<React.Fragment>
{addScreenOpen && (
{addBucketModalOpen && (
<AddBucket
open={addScreenOpen}
open={addBucketModalOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
closeAddModalAndRefresh();
}}
/>
)}
@@ -233,7 +217,7 @@ class ListBuckets extends React.Component<
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
closeDeleteModalAndRefresh(refresh);
}}
/>
)}
@@ -251,9 +235,7 @@ class ListBuckets extends React.Component<
id="search-resource"
label=""
onChange={(val) => {
this.setState({
filterBuckets: val.target.value,
});
setFilterBuckets(val.target.value);
}}
InputProps={{
disableUnderline: true,
@@ -269,9 +251,7 @@ class ListBuckets extends React.Component<
color="primary"
startIcon={<CreateIcon />}
onClick={() => {
this.setState({
addScreenOpen: true,
});
addBucketOpen(true);
}}
>
Create Bucket
@@ -319,7 +299,15 @@ class ListBuckets extends React.Component<
</Grid>
</React.Fragment>
);
}
}
};
export default withStyles(styles)(ListBuckets);
const mapState = (state: AppState) => ({
addBucketModalOpen: state.buckets.open,
});
const connector = connect(mapState, {
addBucketOpen: addBucketOpen,
addBucketReset: addBucketReset,
});
export default connector(withStyles(styles)(ListBuckets));

View File

@@ -0,0 +1,126 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 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/>.
export const ADD_BUCKET_OPEN = "ADD_BUCKET_OPEN";
export const ADD_BUCKET_NAME = "ADD_BUCKET_NAME";
export const ADD_BUCKET_VERSIONED = "ADD_BUCKET_VERSIONED";
export const ADD_BUCKET_QUOTA = "ADD_BUCKET_QUOTA";
export const ADD_BUCKET_QUOTA_TYPE = "ADD_BUCKET_QUOTA_TYPE";
export const ADD_BUCKET_QUOTA_SIZE = "ADD_BUCKET_QUOTA_SIZE";
export const ADD_BUCKET_QUOTA_UNIT = "ADD_BUCKET_QUOTA_UNIT";
export const ADD_BUCKET_RESET = "ADD_BUCKET_RESET";
interface AddBucketOpenAction {
type: typeof ADD_BUCKET_OPEN;
open: boolean;
}
interface AddBucketNameAction {
type: typeof ADD_BUCKET_NAME;
name: string;
}
interface AddBucketVersionedAction {
type: typeof ADD_BUCKET_VERSIONED;
versioned: boolean;
}
interface AddBucketQuotaAction {
type: typeof ADD_BUCKET_QUOTA;
quota: boolean;
}
interface AddBucketQuotaTypeAction {
type: typeof ADD_BUCKET_QUOTA_TYPE;
quotaType: string;
}
interface AddBucketQuotaSizeAction {
type: typeof ADD_BUCKET_QUOTA_SIZE;
quotaSize: string;
}
interface AddBucketQuotaUnitAction {
type: typeof ADD_BUCKET_QUOTA_UNIT;
quotaUnit: string;
}
interface AddBucketResetAction {
type: typeof ADD_BUCKET_RESET;
}
export type BucketActionTypes =
| AddBucketOpenAction
| AddBucketNameAction
| AddBucketVersionedAction
| AddBucketQuotaAction
| AddBucketQuotaTypeAction
| AddBucketQuotaSizeAction
| AddBucketQuotaUnitAction
| AddBucketResetAction;
export function addBucketOpen(open: boolean) {
return {
type: ADD_BUCKET_OPEN,
open: open,
};
}
export function addBucketName(name: string) {
return {
type: ADD_BUCKET_NAME,
name: name,
};
}
export function addBucketVersioned(versioned: boolean) {
return {
type: ADD_BUCKET_VERSIONED,
versioned: versioned,
};
}
export function addBucketQuota(quota: boolean) {
return {
type: ADD_BUCKET_QUOTA,
quota: quota,
};
}
export function addBucketQuotaType(quotaType: string) {
return {
type: ADD_BUCKET_QUOTA_TYPE,
quotaType: quotaType,
};
}
export function addBucketQuotaSize(quotaSize: string) {
return {
type: ADD_BUCKET_QUOTA_SIZE,
quotaSize: quotaSize,
};
}
export function addBucketQuotaUnit(quotaUnit: string) {
return {
type: ADD_BUCKET_QUOTA_UNIT,
quotaUnit: quotaUnit,
};
}
export function addBucketReset() {
return {
type: ADD_BUCKET_RESET,
};
}

View File

@@ -0,0 +1,102 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 {
ADD_BUCKET_NAME,
ADD_BUCKET_OPEN,
ADD_BUCKET_QUOTA,
ADD_BUCKET_QUOTA_SIZE,
ADD_BUCKET_QUOTA_TYPE,
ADD_BUCKET_QUOTA_UNIT,
ADD_BUCKET_RESET,
ADD_BUCKET_VERSIONED,
BucketActionTypes,
} from "./actions";
export interface BucketsState {
open: boolean;
addBucketName: string;
addBucketVersioning: boolean;
addBucketQuotaEnabled: boolean;
addBucketQuotaType: string;
addBucketQuotaSize: string;
addBucketQuotaUnit: string;
}
const initialState: BucketsState = {
open: false,
addBucketName: "",
addBucketVersioning: false,
addBucketQuotaEnabled: false,
addBucketQuotaType: "hard",
addBucketQuotaSize: "1",
addBucketQuotaUnit: "TiB",
};
export function bucketsReducer(
state = initialState,
action: BucketActionTypes
): BucketsState {
switch (action.type) {
case ADD_BUCKET_OPEN:
return {
...state,
open: action.open,
};
case ADD_BUCKET_NAME:
return {
...state,
addBucketName: action.name,
};
case ADD_BUCKET_VERSIONED:
return {
...state,
addBucketVersioning: action.versioned,
};
case ADD_BUCKET_QUOTA:
return {
...state,
addBucketQuotaEnabled: action.quota,
};
case ADD_BUCKET_QUOTA_TYPE:
return {
...state,
addBucketQuotaType: action.quotaType,
};
case ADD_BUCKET_QUOTA_SIZE:
return {
...state,
addBucketQuotaSize: action.quotaSize,
};
case ADD_BUCKET_QUOTA_UNIT:
return {
...state,
addBucketQuotaUnit: action.quotaUnit,
};
case ADD_BUCKET_RESET:
return {
...state,
addBucketName: "",
addBucketVersioning: false,
addBucketQuotaEnabled: false,
addBucketQuotaType: "hard",
addBucketQuotaSize: "1",
addBucketQuotaUnit: "TiB",
};
default:
return state;
}
}

View File

@@ -67,3 +67,15 @@ export interface BucketReplicationRule {
export interface BucketReplication {
rules: BucketReplicationRule[];
}
export interface QuotaRequest {
enabled: boolean;
quota_type: string;
amount: number;
}
export interface MakeBucketRequest {
name: string;
versioning: boolean;
quota?: QuotaRequest;
}

View File

@@ -21,6 +21,7 @@ import { traceReducer } from "./screens/Console/Trace/reducers";
import { logReducer } from "./screens/Console/Logs/reducers";
import { watchReducer } from "./screens/Console/Watch/reducers";
import { consoleReducer } from "./screens/Console/reducer";
import { bucketsReducer } from "./screens/Console/Buckets/reducers";
const globalReducer = combineReducers({
system: systemReducer,
@@ -28,6 +29,7 @@ const globalReducer = combineReducers({
logs: logReducer,
watch: watchReducer,
console: consoleReducer,
buckets: bucketsReducer,
});
declare global {

View File

@@ -1205,6 +1205,16 @@
dependencies:
"@hapi/hoek" "^8.3.0"
"@hot-loader/react-dom@^16.9.0":
version "16.9.0"
resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.9.0.tgz#7782cec9d78172f3e4c86a317ba7a73bd0271acd"
integrity sha512-MsOdCBB7c5YNyB4iDDct+tS7AihvYyfwZVV+z/QnbTjPgxH98kqIDXO92nU7tLXp0OtYFErHZfcWjtszP/572w==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.15.0"
"@iarna/cli@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@iarna/cli/-/cli-1.2.0.tgz#0f7af5e851afe895104583c4ca07377a8094d641"
@@ -4371,6 +4381,11 @@ dom-serializer@0:
domelementtype "^2.0.1"
entities "^2.0.0"
dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@@ -5119,7 +5134,7 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@~2.0.6:
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
@@ -5631,6 +5646,14 @@ global-prefix@^3.0.0:
kind-of "^6.0.2"
which "^1.3.1"
global@^4.3.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -8060,6 +8083,13 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"
mini-create-react-context@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040"
@@ -10099,7 +10129,7 @@ promzard@^0.3.0:
dependencies:
read "1"
prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -10316,6 +10346,23 @@ react-app-polyfill@^1.0.6:
regenerator-runtime "^0.13.3"
whatwg-fetch "^3.0.0"
react-app-rewire-hot-loader@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-app-rewire-hot-loader/-/react-app-rewire-hot-loader-2.0.1.tgz#9b47d299dac4d861dafdf18b49c3698d0ff04a52"
integrity sha512-XTUPOv5q0zJeEtXECfilDPfqCiktSVbIyupiqigIHOO8EMZec2YfNpwZzqDWMu3yfaEHRs54qRCcCgRR/1w3EQ==
react-app-rewired@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/react-app-rewired/-/react-app-rewired-2.1.6.tgz#33ee3076a7f34d6a7c94e649cac67e7c8c580de8"
integrity sha512-06flj0kK5tf/RN4naRv/sn6j3sQd7rsURoRLKLpffXDzJeNiAaTNic+0I8Basojy5WDwREkTqrMLewSAjcb13w==
dependencies:
semver "^5.6.0"
react-async-hook@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/react-async-hook/-/react-async-hook-3.6.1.tgz#aed3e492d87319392865c83ed7cef3609e2a7fef"
integrity sha512-YWBB2feVQF79t5u2raMPHlZ8975Jds+guCvkWVC4kRLDlSCouLsYpQm4DGSqPeHvoHYVVcDfqNayLZAXQmnxnw==
react-chartjs-2@^2.9.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-2.10.0.tgz#857e7f4788cae27e872624ba7826d53cf82f1ee6"
@@ -10374,6 +10421,20 @@ react-error-overlay@^6.0.7:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
react-hot-loader@^4.13.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.0.tgz#c27e9408581c2a678f5316e69c061b226dc6a202"
integrity sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==
dependencies:
fast-levenshtein "^2.0.6"
global "^4.3.0"
hoist-non-react-statics "^3.3.0"
loader-utils "^1.1.0"
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
shallowequal "^1.1.0"
source-map "^0.7.3"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -11162,6 +11223,14 @@ saxes@^3.1.9:
dependencies:
xmlchars "^2.1.1"
scheduler@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.15.0.tgz#6bfcf80ff850b280fed4aeecc6513bc0b4f17f8e"
integrity sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@^0.19.1:
version "0.19.1"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
@@ -11343,6 +11412,11 @@ shallow-clone@^3.0.0:
dependencies:
kind-of "^6.0.2"
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -11561,6 +11635,11 @@ source-map@^0.5.0, source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
source-map@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
spdx-correct@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
@@ -12478,6 +12557,11 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
use-debounce@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-5.0.1.tgz#b11861bc63970bfc6fd8393a0a3cc3d7cb5944ce"
integrity sha512-YHzlVa7qKFRlrMpVRiStGWGE0lumwJiQPvsTMlatsIrck39ycyJkdf0npUYG5MJEVxaJQWwvpmePRYZb534upg==
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"

View File

@@ -279,6 +279,11 @@ func (ac adminClient) addRemoteBucket(ctx context.Context, bucket string, target
return ac.client.SetRemoteTarget(ctx, bucket, target)
}
// addRemoteBucket sets up a remote target for this bucket
func (ac adminClient) setBucketQuota(ctx context.Context, bucket string, quota *madmin.BucketQuota) error {
return ac.client.SetBucketQuota(ctx, bucket, quota)
}
func newMAdminClient(sessionClaims *models.Principal) (*madmin.AdminClient, error) {
adminClient, err := newAdminFromClaims(sessionClaims)
if err != nil {

View File

@@ -120,6 +120,8 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
registerParityHandlers(api)
// Register Object's Handlers
registerObjectsHandlers(api)
// Register Bucket Quota's Handlers
registerBucketQuotaHandlers(api)
api.PreServerShutdown = func() {}

View File

@@ -611,6 +611,74 @@ func init() {
}
}
},
"/buckets/{name}/quota": {
"get": {
"tags": [
"UserAPI"
],
"summary": "Get Bucket Quota",
"operationId": "GetBucketQuota",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/listObjectsResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"put": {
"tags": [
"UserAPI"
],
"summary": "Bucket Quota",
"operationId": "SetBucketQuota",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/setBucketQuota"
}
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/bucket"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/buckets/{name}/set-policy": {
"put": {
"tags": [
@@ -3233,6 +3301,9 @@ func init() {
"name": {
"type": "string"
},
"quota": {
"$ref": "#/definitions/setBucketQuota"
},
"versioning": {
"type": "boolean"
}
@@ -3712,6 +3783,27 @@ func init() {
}
}
},
"setBucketQuota": {
"type": "object",
"required": [
"enabled"
],
"properties": {
"amount": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"quota_type": {
"type": "string",
"enum": [
"fifo",
"hard"
]
}
}
},
"setBucketVersioning": {
"type": "object",
"properties": {
@@ -4893,6 +4985,74 @@ func init() {
}
}
},
"/buckets/{name}/quota": {
"get": {
"tags": [
"UserAPI"
],
"summary": "Get Bucket Quota",
"operationId": "GetBucketQuota",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/listObjectsResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"put": {
"tags": [
"UserAPI"
],
"summary": "Bucket Quota",
"operationId": "SetBucketQuota",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/setBucketQuota"
}
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/bucket"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/buckets/{name}/set-policy": {
"put": {
"tags": [
@@ -8038,6 +8198,9 @@ func init() {
"name": {
"type": "string"
},
"quota": {
"$ref": "#/definitions/setBucketQuota"
},
"versioning": {
"type": "boolean"
}
@@ -8451,6 +8614,27 @@ func init() {
}
}
},
"setBucketQuota": {
"type": "object",
"required": [
"enabled"
],
"properties": {
"amount": {
"type": "integer"
},
"enabled": {
"type": "boolean"
},
"quota_type": {
"type": "string",
"enum": [
"fifo",
"hard"
]
}
}
},
"setBucketVersioning": {
"type": "object",
"properties": {

View File

@@ -126,6 +126,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
AdminAPIDeleteTenantHandler: admin_api.DeleteTenantHandlerFunc(func(params admin_api.DeleteTenantParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation admin_api.DeleteTenant has not yet been implemented")
}),
UserAPIGetBucketQuotaHandler: user_api.GetBucketQuotaHandlerFunc(func(params user_api.GetBucketQuotaParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.GetBucketQuota has not yet been implemented")
}),
UserAPIGetBucketReplicationHandler: user_api.GetBucketReplicationHandlerFunc(func(params user_api.GetBucketReplicationParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.GetBucketReplication has not yet been implemented")
}),
@@ -231,6 +234,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
UserAPISessionCheckHandler: user_api.SessionCheckHandlerFunc(func(params user_api.SessionCheckParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.SessionCheck has not yet been implemented")
}),
UserAPISetBucketQuotaHandler: user_api.SetBucketQuotaHandlerFunc(func(params user_api.SetBucketQuotaParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.SetBucketQuota has not yet been implemented")
}),
UserAPISetBucketVersioningHandler: user_api.SetBucketVersioningHandlerFunc(func(params user_api.SetBucketVersioningParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.SetBucketVersioning has not yet been implemented")
}),
@@ -358,6 +364,8 @@ type ConsoleAPI struct {
UserAPIDeleteServiceAccountHandler user_api.DeleteServiceAccountHandler
// AdminAPIDeleteTenantHandler sets the operation handler for the delete tenant operation
AdminAPIDeleteTenantHandler admin_api.DeleteTenantHandler
// UserAPIGetBucketQuotaHandler sets the operation handler for the get bucket quota operation
UserAPIGetBucketQuotaHandler user_api.GetBucketQuotaHandler
// UserAPIGetBucketReplicationHandler sets the operation handler for the get bucket replication operation
UserAPIGetBucketReplicationHandler user_api.GetBucketReplicationHandler
// UserAPIGetBucketVersioningHandler sets the operation handler for the get bucket versioning operation
@@ -428,6 +436,8 @@ type ConsoleAPI struct {
AdminAPIRestartServiceHandler admin_api.RestartServiceHandler
// UserAPISessionCheckHandler sets the operation handler for the session check operation
UserAPISessionCheckHandler user_api.SessionCheckHandler
// UserAPISetBucketQuotaHandler sets the operation handler for the set bucket quota operation
UserAPISetBucketQuotaHandler user_api.SetBucketQuotaHandler
// UserAPISetBucketVersioningHandler sets the operation handler for the set bucket versioning operation
UserAPISetBucketVersioningHandler user_api.SetBucketVersioningHandler
// AdminAPISetConfigHandler sets the operation handler for the set config operation
@@ -588,6 +598,9 @@ func (o *ConsoleAPI) Validate() error {
if o.AdminAPIDeleteTenantHandler == nil {
unregistered = append(unregistered, "admin_api.DeleteTenantHandler")
}
if o.UserAPIGetBucketQuotaHandler == nil {
unregistered = append(unregistered, "user_api.GetBucketQuotaHandler")
}
if o.UserAPIGetBucketReplicationHandler == nil {
unregistered = append(unregistered, "user_api.GetBucketReplicationHandler")
}
@@ -693,6 +706,9 @@ func (o *ConsoleAPI) Validate() error {
if o.UserAPISessionCheckHandler == nil {
unregistered = append(unregistered, "user_api.SessionCheckHandler")
}
if o.UserAPISetBucketQuotaHandler == nil {
unregistered = append(unregistered, "user_api.SetBucketQuotaHandler")
}
if o.UserAPISetBucketVersioningHandler == nil {
unregistered = append(unregistered, "user_api.SetBucketVersioningHandler")
}
@@ -916,6 +932,10 @@ func (o *ConsoleAPI) initHandlerCache() {
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/buckets/{name}/quota"] = user_api.NewGetBucketQuota(o.context, o.UserAPIGetBucketQuotaHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/buckets/{bucket_name}/replication"] = user_api.NewGetBucketReplication(o.context, o.UserAPIGetBucketReplicationHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
@@ -1056,6 +1076,10 @@ func (o *ConsoleAPI) initHandlerCache() {
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)
}
o.handlers["PUT"]["/buckets/{name}/quota"] = user_api.NewSetBucketQuota(o.context, o.UserAPISetBucketQuotaHandler)
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)
}
o.handlers["PUT"]["/buckets/{bucket_name}/versioning"] = user_api.NewSetBucketVersioning(o.context, o.UserAPISetBucketVersioningHandler)
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)

View File

@@ -0,0 +1,90 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
)
// GetBucketQuotaHandlerFunc turns a function with the right signature into a get bucket quota handler
type GetBucketQuotaHandlerFunc func(GetBucketQuotaParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn GetBucketQuotaHandlerFunc) Handle(params GetBucketQuotaParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// GetBucketQuotaHandler interface for that can handle valid get bucket quota params
type GetBucketQuotaHandler interface {
Handle(GetBucketQuotaParams, *models.Principal) middleware.Responder
}
// NewGetBucketQuota creates a new http.Handler for the get bucket quota operation
func NewGetBucketQuota(ctx *middleware.Context, handler GetBucketQuotaHandler) *GetBucketQuota {
return &GetBucketQuota{Context: ctx, Handler: handler}
}
/*GetBucketQuota swagger:route GET /buckets/{name}/quota UserAPI getBucketQuota
Get Bucket Quota
*/
type GetBucketQuota struct {
Context *middleware.Context
Handler GetBucketQuotaHandler
}
func (o *GetBucketQuota) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
var Params = NewGetBucketQuotaParams()
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)
}

View File

@@ -0,0 +1,89 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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/middleware"
"github.com/go-openapi/strfmt"
)
// NewGetBucketQuotaParams creates a new GetBucketQuotaParams object
// no default values defined in spec.
func NewGetBucketQuotaParams() GetBucketQuotaParams {
return GetBucketQuotaParams{}
}
// GetBucketQuotaParams contains all the bound params for the get bucket quota operation
// typically these are obtained from a http.Request
//
// swagger:parameters GetBucketQuota
type GetBucketQuotaParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: path
*/
Name string
}
// 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 NewGetBucketQuotaParams() beforehand.
func (o *GetBucketQuotaParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rName, rhkName, _ := route.Params.GetOK("name")
if err := o.bindName(rName, rhkName, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindName binds and validates parameter Name from path.
func (o *GetBucketQuotaParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Name = raw
return nil
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
)
// GetBucketQuotaOKCode is the HTTP code returned for type GetBucketQuotaOK
const GetBucketQuotaOKCode int = 200
/*GetBucketQuotaOK A successful response.
swagger:response getBucketQuotaOK
*/
type GetBucketQuotaOK struct {
/*
In: Body
*/
Payload *models.ListObjectsResponse `json:"body,omitempty"`
}
// NewGetBucketQuotaOK creates GetBucketQuotaOK with default headers values
func NewGetBucketQuotaOK() *GetBucketQuotaOK {
return &GetBucketQuotaOK{}
}
// WithPayload adds the payload to the get bucket quota o k response
func (o *GetBucketQuotaOK) WithPayload(payload *models.ListObjectsResponse) *GetBucketQuotaOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get bucket quota o k response
func (o *GetBucketQuotaOK) SetPayload(payload *models.ListObjectsResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetBucketQuotaOK) 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
}
}
}
/*GetBucketQuotaDefault Generic error response.
swagger:response getBucketQuotaDefault
*/
type GetBucketQuotaDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewGetBucketQuotaDefault creates GetBucketQuotaDefault with default headers values
func NewGetBucketQuotaDefault(code int) *GetBucketQuotaDefault {
if code <= 0 {
code = 500
}
return &GetBucketQuotaDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the get bucket quota default response
func (o *GetBucketQuotaDefault) WithStatusCode(code int) *GetBucketQuotaDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the get bucket quota default response
func (o *GetBucketQuotaDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the get bucket quota default response
func (o *GetBucketQuotaDefault) WithPayload(payload *models.Error) *GetBucketQuotaDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get bucket quota default response
func (o *GetBucketQuotaDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetBucketQuotaDefault) 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
}
}
}

View File

@@ -0,0 +1,116 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
"strings"
)
// GetBucketQuotaURL generates an URL for the get bucket quota operation
type GetBucketQuotaURL struct {
Name string
_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 *GetBucketQuotaURL) WithBasePath(bp string) *GetBucketQuotaURL {
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 *GetBucketQuotaURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *GetBucketQuotaURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/buckets/{name}/quota"
name := o.Name
if name != "" {
_path = strings.Replace(_path, "{name}", name, -1)
} else {
return nil, errors.New("name is required on GetBucketQuotaURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *GetBucketQuotaURL) 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 *GetBucketQuotaURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *GetBucketQuotaURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on GetBucketQuotaURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on GetBucketQuotaURL")
}
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 *GetBucketQuotaURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -0,0 +1,90 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
)
// SetBucketQuotaHandlerFunc turns a function with the right signature into a set bucket quota handler
type SetBucketQuotaHandlerFunc func(SetBucketQuotaParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn SetBucketQuotaHandlerFunc) Handle(params SetBucketQuotaParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// SetBucketQuotaHandler interface for that can handle valid set bucket quota params
type SetBucketQuotaHandler interface {
Handle(SetBucketQuotaParams, *models.Principal) middleware.Responder
}
// NewSetBucketQuota creates a new http.Handler for the set bucket quota operation
func NewSetBucketQuota(ctx *middleware.Context, handler SetBucketQuotaHandler) *SetBucketQuota {
return &SetBucketQuota{Context: ctx, Handler: handler}
}
/*SetBucketQuota swagger:route PUT /buckets/{name}/quota UserAPI setBucketQuota
Bucket Quota
*/
type SetBucketQuota struct {
Context *middleware.Context
Handler SetBucketQuotaHandler
}
func (o *SetBucketQuota) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
var Params = NewSetBucketQuotaParams()
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)
}

View File

@@ -0,0 +1,120 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"io"
"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/minio/console/models"
)
// NewSetBucketQuotaParams creates a new SetBucketQuotaParams object
// no default values defined in spec.
func NewSetBucketQuotaParams() SetBucketQuotaParams {
return SetBucketQuotaParams{}
}
// SetBucketQuotaParams contains all the bound params for the set bucket quota operation
// typically these are obtained from a http.Request
//
// swagger:parameters SetBucketQuota
type SetBucketQuotaParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: body
*/
Body *models.SetBucketQuota
/*
Required: true
In: path
*/
Name string
}
// 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 NewSetBucketQuotaParams() beforehand.
func (o *SetBucketQuotaParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if runtime.HasBody(r) {
defer r.Body.Close()
var body models.SetBucketQuota
if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF {
res = append(res, errors.Required("body", "body", ""))
} else {
res = append(res, errors.NewParseError("body", "body", "", err))
}
} else {
// validate body object
if err := body.Validate(route.Formats); err != nil {
res = append(res, err)
}
if len(res) == 0 {
o.Body = &body
}
}
} else {
res = append(res, errors.Required("body", "body", ""))
}
rName, rhkName, _ := route.Params.GetOK("name")
if err := o.bindName(rName, rhkName, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindName binds and validates parameter Name from path.
func (o *SetBucketQuotaParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Name = raw
return nil
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
)
// SetBucketQuotaOKCode is the HTTP code returned for type SetBucketQuotaOK
const SetBucketQuotaOKCode int = 200
/*SetBucketQuotaOK A successful response.
swagger:response setBucketQuotaOK
*/
type SetBucketQuotaOK struct {
/*
In: Body
*/
Payload *models.Bucket `json:"body,omitempty"`
}
// NewSetBucketQuotaOK creates SetBucketQuotaOK with default headers values
func NewSetBucketQuotaOK() *SetBucketQuotaOK {
return &SetBucketQuotaOK{}
}
// WithPayload adds the payload to the set bucket quota o k response
func (o *SetBucketQuotaOK) WithPayload(payload *models.Bucket) *SetBucketQuotaOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the set bucket quota o k response
func (o *SetBucketQuotaOK) SetPayload(payload *models.Bucket) {
o.Payload = payload
}
// WriteResponse to the client
func (o *SetBucketQuotaOK) 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
}
}
}
/*SetBucketQuotaDefault Generic error response.
swagger:response setBucketQuotaDefault
*/
type SetBucketQuotaDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewSetBucketQuotaDefault creates SetBucketQuotaDefault with default headers values
func NewSetBucketQuotaDefault(code int) *SetBucketQuotaDefault {
if code <= 0 {
code = 500
}
return &SetBucketQuotaDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the set bucket quota default response
func (o *SetBucketQuotaDefault) WithStatusCode(code int) *SetBucketQuotaDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the set bucket quota default response
func (o *SetBucketQuotaDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the set bucket quota default response
func (o *SetBucketQuotaDefault) WithPayload(payload *models.Error) *SetBucketQuotaDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the set bucket quota default response
func (o *SetBucketQuotaDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *SetBucketQuotaDefault) 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
}
}
}

View File

@@ -0,0 +1,116 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 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 user_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"
"strings"
)
// SetBucketQuotaURL generates an URL for the set bucket quota operation
type SetBucketQuotaURL struct {
Name string
_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 *SetBucketQuotaURL) WithBasePath(bp string) *SetBucketQuotaURL {
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 *SetBucketQuotaURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *SetBucketQuotaURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/buckets/{name}/quota"
name := o.Name
if name != "" {
_path = strings.Replace(_path, "{name}", name, -1)
} else {
return nil, errors.New("name is required on SetBucketQuotaURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *SetBucketQuotaURL) 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 *SetBucketQuotaURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *SetBucketQuotaURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on SetBucketQuotaURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on SetBucketQuotaURL")
}
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 *SetBucketQuotaURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -0,0 +1,87 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 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"
"errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/user_api"
"github.com/minio/minio/pkg/madmin"
"github.com/minio/console/models"
)
func registerBucketQuotaHandlers(api *operations.ConsoleAPI) {
// set bucket quota
api.UserAPISetBucketQuotaHandler = user_api.SetBucketQuotaHandlerFunc(func(params user_api.SetBucketQuotaParams, session *models.Principal) middleware.Responder {
err := setBucketQuotaResponse(session, params)
if err != nil {
return user_api.NewSetBucketQuotaDefault(int(err.Code)).WithPayload(err)
}
return user_api.NewSetBucketQuotaOK()
})
}
func setBucketQuotaResponse(session *models.Principal, params user_api.SetBucketQuotaParams) *models.Error {
mAdmin, err := newMAdminClient(session)
if err != nil {
return prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
if err := setBucketQuota(params.HTTPRequest.Context(), &adminClient, &params.Name, params.Body); err != nil {
return &models.Error{
Code: 500,
Message: swag.String(err.Error()),
}
}
return nil
}
func setBucketQuota(ctx context.Context, ac *adminClient, bucket *string, bucketQuota *models.SetBucketQuota) error {
if bucketQuota == nil {
return errors.New("nil bucket quota was provided")
}
if *bucketQuota.Enabled {
var quotaType madmin.QuotaType
switch bucketQuota.QuotaType {
case models.SetBucketQuotaQuotaTypeFifo:
quotaType = madmin.FIFOQuota
case models.SetBucketQuotaQuotaTypeHard:
quotaType = madmin.HardQuota
}
if err := ac.setBucketQuota(ctx, *bucket, &madmin.BucketQuota{
Quota: uint64(bucketQuota.Amount),
Type: quotaType,
}); err != nil {
return err
}
} else {
if err := ac.client.SetBucketQuota(ctx, *bucket, &madmin.BucketQuota{}); err != nil {
return err
}
}
return nil
}

View File

@@ -296,6 +296,20 @@ func getMakeBucketResponse(session *models.Principal, br *models.MakeBucketReque
log.Println("error versioning bucket:", err)
}
}
// if it has support for
if br.Quota != nil && br.Quota.Enabled != nil && *br.Quota.Enabled {
mAdmin, err := newMAdminClient(session)
if err != nil {
return prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
// we will tolerate this call failing
if err := setBucketQuota(ctx, &adminClient, br.Name, br.Quota); err != nil {
log.Println("error versioning bucket:", err)
}
}
return nil
}

View File

@@ -307,6 +307,51 @@ paths:
tags:
- UserAPI
/buckets/{name}/quota:
get:
summary: Get Bucket Quota
operationId: GetBucketQuota
parameters:
- name: name
in: path
required: true
type: string
responses:
200:
description: A successful response.
schema:
$ref: "#/definitions/listObjectsResponse"
default:
description: Generic error response.
schema:
$ref: "#/definitions/error"
tags:
- UserAPI
put:
summary: Bucket Quota
operationId: SetBucketQuota
parameters:
- name: name
in: path
required: true
type: string
- name: body
in: body
required: true
schema:
$ref: "#/definitions/setBucketQuota"
responses:
200:
description: A successful response.
schema:
$ref: "#/definitions/bucket"
default:
description: Generic error response.
schema:
$ref: "#/definitions/error"
tags:
- UserAPI
/buckets/{bucket_name}/events:
get:
summary: List Bucket Events
@@ -1626,6 +1671,8 @@ definitions:
type: string
versioning:
type: boolean
quota:
$ref: "#/definitions/setBucketQuota"
error:
type: object
required:
@@ -1937,6 +1984,20 @@ definitions:
properties:
access:
$ref: "#/definitions/bucketAccess"
setBucketQuota:
type: object
required:
- enabled
properties:
enabled:
type: boolean
quota_type:
type: string
enum:
- fifo
- hard
amount:
type: integer
loginDetails:
type: object
properties:

144
yarn.lock
View File

@@ -2,3 +2,147 @@
# yarn lockfile v1
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
global@^4.3.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"
hoist-non-react-statics@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
dependencies:
minimist "^1.2.0"
loader-utils@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
json5 "^1.0.1"
loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"
minimist@^1.2.0:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
prop-types@^15.6.1:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
react-app-rewire-hot-loader@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-app-rewire-hot-loader/-/react-app-rewire-hot-loader-2.0.1.tgz#9b47d299dac4d861dafdf18b49c3698d0ff04a52"
integrity sha512-XTUPOv5q0zJeEtXECfilDPfqCiktSVbIyupiqigIHOO8EMZec2YfNpwZzqDWMu3yfaEHRs54qRCcCgRR/1w3EQ==
react-app-rewired@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/react-app-rewired/-/react-app-rewired-2.1.6.tgz#33ee3076a7f34d6a7c94e649cac67e7c8c580de8"
integrity sha512-06flj0kK5tf/RN4naRv/sn6j3sQd7rsURoRLKLpffXDzJeNiAaTNic+0I8Basojy5WDwREkTqrMLewSAjcb13w==
dependencies:
semver "^5.6.0"
react-hot-loader@^4.13.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.0.tgz#c27e9408581c2a678f5316e69c061b226dc6a202"
integrity sha512-JrLlvUPqh6wIkrK2hZDfOyq/Uh/WeVEr8nc7hkn2/3Ul0sx1Kr5y4kOGNacNRoj7RhwLNcQ3Udf1KJXrqc0ZtA==
dependencies:
fast-levenshtein "^2.0.6"
global "^4.3.0"
hoist-non-react-statics "^3.3.0"
loader-utils "^1.1.0"
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
shallowequal "^1.1.0"
source-map "^0.7.3"
react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
semver@^5.6.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
source-map@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==