Compare commits
7 Commits
v0.42.0
...
upgrade-op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fa3279a93 | ||
|
|
b631ab38d0 | ||
|
|
16c25c0880 | ||
|
|
5dbdf35295 | ||
|
|
5ecb311f79 | ||
|
|
e432183bd6 | ||
|
|
008075133a |
@@ -1,7 +1,6 @@
|
||||
node_modules/
|
||||
dist/
|
||||
target/
|
||||
console
|
||||
!console/
|
||||
mcs
|
||||
!mcs/
|
||||
portal-ui/node_modules/
|
||||
.git/
|
||||
|
||||
48
.github/ISSUE_TEMPLATE/bug_report.md
vendored
48
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,48 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: community, triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## NOTE
|
||||
If this case is urgent, please subscribe to [Subnet](https://min.io/pricing) so that our 24/7 support team may help you faster.
|
||||
|
||||
<!--- Provide a general summary of the issue in the title above -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
## Steps to Reproduce (for bugs)
|
||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Regression
|
||||
<!-- Is this issue a regression? (Yes / No) -->
|
||||
<!-- If Yes, optionally please include the MinIO version or commit id or PR# that caused this regression, if you have these details. -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* MinIO version used (`minio --version`):
|
||||
* Server setup and configuration:
|
||||
* Operating System and version (`uname -a`):
|
||||
52
.github/workflows/codeql.yml
vendored
Normal file
52
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: "Code scanning - action"
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 19 * * 0'
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
# CodeQL runs on ubuntu-latest and windows-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
166
.github/workflows/cross-compile.yaml
vendored
166
.github/workflows/cross-compile.yaml
vendored
@@ -1,166 +0,0 @@
|
||||
# @format
|
||||
|
||||
name: Cross Compile
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- go.sum
|
||||
|
||||
# This ensures that previous jobs for the PR are canceled when the PR is
|
||||
# updated.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
cross-compile-1:
|
||||
name: Cross compile
|
||||
needs:
|
||||
- lint-job
|
||||
- ui-assets
|
||||
- reuse-golang-dependencies
|
||||
- semgrep-static-code-analysis
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
id: go
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make crosscompile arg1="'linux/ppc64le linux/mips64'"
|
||||
|
||||
cross-compile-2:
|
||||
name: Cross compile 2
|
||||
needs:
|
||||
- lint-job
|
||||
- ui-assets
|
||||
- reuse-golang-dependencies
|
||||
- semgrep-static-code-analysis
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
id: go
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make crosscompile arg1="'linux/arm64 linux/s390x'"
|
||||
|
||||
cross-compile-3:
|
||||
name: Cross compile 3
|
||||
needs:
|
||||
- lint-job
|
||||
- ui-assets
|
||||
- reuse-golang-dependencies
|
||||
- semgrep-static-code-analysis
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
id: go
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make crosscompile arg1="'darwin/amd64 freebsd/amd64'"
|
||||
|
||||
cross-compile-4:
|
||||
name: Cross compile 4
|
||||
needs:
|
||||
- lint-job
|
||||
- ui-assets
|
||||
- reuse-golang-dependencies
|
||||
- semgrep-static-code-analysis
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
id: go
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make crosscompile arg1="'windows/amd64 linux/arm'"
|
||||
|
||||
cross-compile-5:
|
||||
name: Cross compile 5
|
||||
needs:
|
||||
- lint-job
|
||||
- ui-assets
|
||||
- reuse-golang-dependencies
|
||||
- semgrep-static-code-analysis
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.x ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
id: go
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make crosscompile arg1="'linux/386 netbsd/amd64'"
|
||||
36
.github/workflows/go.yml
vendored
Normal file
36
.github/workflows/go.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Go
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Test on Go ${{ matrix.go-version }} and ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.13.x, 1.14.x]
|
||||
os: [ubuntu-latest]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build on ${{ matrix.os }}
|
||||
env:
|
||||
GO111MODULE: on
|
||||
GOOS: linux
|
||||
run: |
|
||||
make verifiers
|
||||
make test
|
||||
make mcs
|
||||
18
.github/workflows/issues.yaml
vendored
18
.github/workflows/issues.yaml
vendored
@@ -1,18 +0,0 @@
|
||||
# @format
|
||||
|
||||
name: Issue Workflow
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v0.5.0
|
||||
with:
|
||||
project-url: https://github.com/orgs/miniohq/projects/2
|
||||
github-token: ${{ secrets.BOT_PAT }}
|
||||
1322
.github/workflows/jobs.yaml
vendored
1322
.github/workflows/jobs.yaml
vendored
File diff suppressed because it is too large
Load Diff
53
.github/workflows/vulncheck.yaml
vendored
53
.github/workflows/vulncheck.yaml
vendored
@@ -1,53 +0,0 @@
|
||||
# @format
|
||||
|
||||
name: Vulnerability Check
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
vulncheck:
|
||||
name: Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21.5
|
||||
check-latest: true
|
||||
- name: Get official govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
shell: bash
|
||||
- name: Run govulncheck
|
||||
run: govulncheck ./...
|
||||
shell: bash
|
||||
|
||||
react-code-known-vulnerabilities:
|
||||
name: "React Code Has No Known Vulnerable Deps"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.21.5 ]
|
||||
os: [ ubuntu-latest ]
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NVMRC }}
|
||||
cache: "yarn"
|
||||
cache-dependency-path: portal-ui/yarn.lock
|
||||
- name: Checks for known security issues with the installed packages
|
||||
working-directory: ./portal-ui
|
||||
continue-on-error: false
|
||||
run: |
|
||||
yarn audit --groups dependencies
|
||||
22
.gitignore
vendored
22
.gitignore
vendored
@@ -1,13 +1,3 @@
|
||||
# Playwright Data
|
||||
portal-ui/storage/
|
||||
portal-ui/playwright/.auth/admin.json
|
||||
|
||||
# Report from Playwright
|
||||
portal-ui/playwright-report/
|
||||
|
||||
# Coverage from Playwright
|
||||
portal-ui/.nyc_output/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
@@ -29,16 +19,11 @@ vendor/
|
||||
|
||||
# Ignore executables
|
||||
target/
|
||||
!pkg/logger/target/
|
||||
console
|
||||
!console/
|
||||
mcs
|
||||
!mcs/
|
||||
|
||||
dist/
|
||||
|
||||
# Ignore node_modules
|
||||
|
||||
portal-ui/node_modules/
|
||||
|
||||
# Ignore tls cert and key
|
||||
private.key
|
||||
public.crt
|
||||
@@ -46,5 +31,4 @@ public.crt
|
||||
# Ignore VsCode files
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
*~
|
||||
.eslintcache
|
||||
*~
|
||||
@@ -5,45 +5,24 @@ linters-settings:
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
goheader:
|
||||
values:
|
||||
regexp:
|
||||
copyright-holder: Copyright \(c\) (20\d\d\-20\d\d)|2021|({{year}})
|
||||
template-path: .license.tmpl
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- typecheck
|
||||
- goimports
|
||||
- misspell
|
||||
- govet
|
||||
- revive
|
||||
- golint
|
||||
- ineffassign
|
||||
- gosimple
|
||||
- gomodguard
|
||||
- gofmt
|
||||
- deadcode
|
||||
- unparam
|
||||
- unused
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- gocritic
|
||||
- gofumpt
|
||||
- durationcheck
|
||||
- structcheck
|
||||
|
||||
service:
|
||||
golangci-lint-version: 1.43.0 # use the fixed version to not introduce new linters unexpectedly
|
||||
golangci-lint-version: 1.21.0 # use the fixed version to not introduce new linters unexpectedly
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- should have a package comment
|
||||
# TODO(y4m4): Remove once all exported ident. have comments!
|
||||
- comment on exported function
|
||||
- comment on exported type
|
||||
- should have comment
|
||||
- use leading k in Go names
|
||||
- comment on exported const
|
||||
run:
|
||||
skip-dirs:
|
||||
- pkg/clientgen
|
||||
- pkg/apis/networking.gke.io
|
||||
- restapi/operations
|
||||
|
||||
75
.goreleaser.yml
Normal file
75
.goreleaser.yml
Normal file
@@ -0,0 +1,75 @@
|
||||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
project_name: mcs
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# you may remove this if you don't use vgo
|
||||
- go mod tidy
|
||||
builds:
|
||||
-
|
||||
goos:
|
||||
- freebsd
|
||||
- windows
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
main: ./cmd/mcs/
|
||||
flags:
|
||||
- -trimpath
|
||||
- --tags=kqueue
|
||||
ldflags:
|
||||
- -s -w -X github.com/minio/mcs/pkg.ReleaseTag={{.Tag}} -X github.com/minio/mcs/pkg.CommitID={{.FullCommit}} -X github.com/minio/mcs/pkg.Version={{.Version}} -X github.com/minio/mcs/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/mcs/pkg.ReleaseTime={{.Date}}
|
||||
archives:
|
||||
-
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
freebsd: FreeBSD
|
||||
amd64: x86_64
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- README.md
|
||||
- LICENSE
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: 'snapshot-{{ time "2006-01-02" }}'
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
nfpms:
|
||||
-
|
||||
vendor: MinIO Inc.
|
||||
homepage: https://github.com/minio/mcs
|
||||
maintainer: MinIO <minio@minio.io>
|
||||
description: MinIO Console Server
|
||||
license: GNU Affero General Public License v3.0
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
freebsd: FreeBSD
|
||||
amd64: x86_64
|
||||
dockers:
|
||||
-
|
||||
# GOOS of the built binary that should be used.
|
||||
goos: linux
|
||||
# GOARCH of the built binary that should be used.
|
||||
goarch: amd64
|
||||
dockerfile: Dockerfile.release
|
||||
image_templates:
|
||||
- "minio/mcs:{{ .Tag }}"
|
||||
- "minio/mcs:latest"
|
||||
@@ -1,15 +0,0 @@
|
||||
This file is part of MinIO Console Server
|
||||
{{copyright-holder}} 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/>.
|
||||
@@ -1,35 +0,0 @@
|
||||
# Ignore git items
|
||||
.gitignore
|
||||
.git/
|
||||
:include .gitignore
|
||||
|
||||
# Common large paths
|
||||
node_modules/
|
||||
portal-ui/node_modules/
|
||||
build/
|
||||
dist/
|
||||
.idea/
|
||||
vendor/
|
||||
.env/
|
||||
.venv/
|
||||
.tox/
|
||||
*.min.js
|
||||
|
||||
# Common test paths
|
||||
test/
|
||||
tests/
|
||||
*_test.go
|
||||
|
||||
# Semgrep rules folder
|
||||
.semgrep
|
||||
|
||||
# Semgrep-action log folder
|
||||
.semgrep_logs/
|
||||
|
||||
# Ignore VsCode files
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
*~
|
||||
.eslintcache
|
||||
|
||||
consoleApi.ts
|
||||
186
CHANGELOG.md
186
CHANGELOG.md
@@ -1,186 +0,0 @@
|
||||
<!-- @format -->
|
||||
|
||||
# Changelog
|
||||
|
||||
## Release v0.42.0
|
||||
|
||||
Features:
|
||||
|
||||
- Introducing Dark Mode
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed vulnerabilities
|
||||
- Changes on Upload and Delete object urls
|
||||
- Fixed blocking subpath creation if not enough permissions
|
||||
- Removed share object option at prefix level
|
||||
- Updated allowed actions for a deleted object
|
||||
|
||||
## Release v0.41.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated pages to use mds components
|
||||
- support for resolving IPv4/IPv6
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Remove cache for ClientIP
|
||||
- Fixed override environment variables display in settings page
|
||||
- Fixed daylight savings time support in share modal
|
||||
|
||||
## Release v0.40.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated OpenID page
|
||||
- Added New bucket event types support
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed crash in access keys page
|
||||
- Fixed AuditLog filters issue
|
||||
- Fixed multiple issues with Object Browser
|
||||
|
||||
## Release v0.39.0
|
||||
|
||||
Features:
|
||||
|
||||
- Migrated metrics page to mds
|
||||
- Migrated Register page to mds
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed LDAP configuration page issues
|
||||
- Load available certificates in logout
|
||||
- Updated dependencies & go version
|
||||
- Fixed delete objects functionality
|
||||
|
||||
## Release v0.38.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added extra information to Service Accounts page
|
||||
- Updated Tiers, Site Replication, Speedtest, Heal & Watch pages components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed IDP expiry time errors
|
||||
- Updated project Dependencies
|
||||
|
||||
## Release v0.37.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Trace and Logs page components
|
||||
- Updated Prometheus metrics
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Disabled input fields for Subscription features if MinIO is not registered
|
||||
|
||||
## Release v0.36.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Settings page components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Show LDAP Enabled value LDAP configuration
|
||||
- Download multiple objects in same path as they were selected
|
||||
|
||||
## Release v0.35.1
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Change timestamp format for zip creation
|
||||
|
||||
## Release v0.35.0
|
||||
|
||||
Features:
|
||||
|
||||
- Add Exclude Folders and Exclude Prefixes during bucket creation
|
||||
- Download multiple selected objects as zip and ignore deleted objects
|
||||
- Updated Call Home, Inspet, Profile and Health components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Remove extra white spaces for configuration strings
|
||||
- Allow Create New Path in bucket view when having right permissions
|
||||
|
||||
## Release v0.34.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Buckets components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed SUBNET Health report upload
|
||||
- Updated Download Handler
|
||||
- Fixes issue with rewind
|
||||
- Avoid 1 hour expiration for IDP credentials
|
||||
|
||||
---
|
||||
|
||||
## Release v0.33.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated OpenID, LDAP components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed security issues
|
||||
- Fixed navigation issues in Object Browser
|
||||
- Fixed Dashboard metrics
|
||||
|
||||
---
|
||||
|
||||
## Release v0.32.0
|
||||
|
||||
Features:
|
||||
|
||||
- Updated Users and Groups components
|
||||
- Added placeholder image for Help Menu
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed memory leak in WebSocket API for Object Browser
|
||||
|
||||
---
|
||||
|
||||
## Release v0.31.0
|
||||
|
||||
**Breaking Changes:**
|
||||
|
||||
- **Removed support for Standalone Deployments**
|
||||
|
||||
Features:
|
||||
|
||||
- Updated way files are displayed in uploading component
|
||||
- Updated Audit Logs and Policies components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Fixed Download folders issue in Object Browser
|
||||
- Added missing Notification Events (ILM & REPLICA) in Events Notification Page
|
||||
- Fixed Security Vulnerability for `semver` dependency
|
||||
|
||||
---
|
||||
|
||||
## Release v0.30.0
|
||||
|
||||
Features:
|
||||
|
||||
- Added MinIO Console Help Menu
|
||||
- Updated UI Menu components
|
||||
|
||||
Bug Fix:
|
||||
|
||||
- Disable the Upload button on Object Browser if the user is not allowed
|
||||
- Fixed security vulnerability for `lestrrat-go/jwx` and `fast-xml-parser`
|
||||
- Fixed bug on sub-paths for Object Browser
|
||||
- Reduce the number of calls to `/session` API endpoint to improve performance
|
||||
- Rolled back the previous change for the Share File feature to no longer ask for Service Account access keys
|
||||
@@ -20,7 +20,7 @@ make swagger-gen
|
||||
|
||||
This will update all the necessary code.
|
||||
|
||||
`./restapi/configure_console.go` is a file that contains the handlers to be used by the application, here is the only place where we need to update our code to support the new apis. This file is not affected when running the swagger generator and it is safe to edit.
|
||||
`./restapi/configure_mcs.go` is a file that contains the handlers to be used by the application, here is the only place where we need to update our code to support the new apis. This file is not affected when running the swagger generator and it is safe to edit.
|
||||
|
||||
## Unit Tests
|
||||
`./restapi/handlers_test.go` needs to be updated with the proper tests for the new api.
|
||||
@@ -47,7 +47,7 @@ $ git push origin my-new-feature
|
||||
Pull requests can be created via GitHub. Refer to [this document](https://help.github.com/articles/creating-a-pull-request/) for detailed steps on how to create a pull request. After a Pull Request gets peer reviewed and approved, it will be merged.
|
||||
|
||||
## FAQs
|
||||
### How does ``console`` manages dependencies?
|
||||
### How does ``mcs`` manages dependencies?
|
||||
``MinIO`` uses `go mod` to manage its dependencies.
|
||||
- Run `go get foo/bar` in the source folder to add the dependency to `go.mod` file.
|
||||
|
||||
@@ -55,5 +55,5 @@ To remove a dependency
|
||||
- Edit your code and remove the import reference.
|
||||
- Run `go mod tidy` in the source folder to remove dependency from `go.mod` file.
|
||||
|
||||
### What are the coding guidelines for console?
|
||||
``console`` is fully conformant with Golang style. Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).
|
||||
### What are the coding guidelines for mcs?
|
||||
``mcs`` is fully conformant with Golang style. Refer: [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project. If you observe offending code, please feel free to send a pull request or ping us on [Slack](https://slack.min.io).
|
||||
|
||||
155
DEVELOPMENT.md
155
DEVELOPMENT.md
@@ -1,97 +1,4 @@
|
||||
# Developing MinIO Console
|
||||
|
||||
The MinIO Console requires the [MinIO Server](https://github.com/minio/minio). For development purposes, you also need to run both the MinIO Console web app and the MinIO Console server.
|
||||
|
||||
## Running MinIO Console server
|
||||
|
||||
Build the server in the main folder by running:
|
||||
```
|
||||
make
|
||||
```
|
||||
> Note: If it's the first time running the server, you might need to run `go mod tidy` to ensure you have all modules required.
|
||||
To start the server run:
|
||||
```
|
||||
CONSOLE_ACCESS_KEY=<your-access-key>
|
||||
CONSOLE_SECRET_KEY=<your-secret-key>
|
||||
CONSOLE_MINIO_SERVER=<minio-server-endpoint>
|
||||
CONSOLE_DEV_MODE=on
|
||||
./console server
|
||||
```
|
||||
|
||||
## Running MinIO Console web app
|
||||
Refer to `/portal-ui` [instructions](/portal-ui/README.md) to run the web app locally.
|
||||
|
||||
|
||||
# Building with MinIO
|
||||
|
||||
To test console in its shipping format, you need to build it from the MinIO repository, the following step will guide
|
||||
you to do that.
|
||||
|
||||
### 0. Building with UI Changes
|
||||
|
||||
If you are performing changes in the UI components of console and want to test inside the MinIO binary, you need to
|
||||
build assets first.
|
||||
|
||||
In the console folder run
|
||||
|
||||
```shell
|
||||
make assets
|
||||
```
|
||||
|
||||
This will regenerate all the static assets that will be served by MinIO.
|
||||
|
||||
### 1. Clone the `MinIO` repository
|
||||
|
||||
In the parent folder of where you cloned this `console` repository, clone the MinIO Repository
|
||||
|
||||
```shell
|
||||
git clone https://github.com/minio/minio.git
|
||||
```
|
||||
|
||||
### 2. Update `go.mod` to use your local version
|
||||
|
||||
In the MinIO repository open `go.mod` and after the first `require()` directive add a `replace()` directive
|
||||
|
||||
```
|
||||
...
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/minio/console => "../console"
|
||||
)
|
||||
|
||||
require (
|
||||
...
|
||||
```
|
||||
|
||||
### 3. Build `MinIO`
|
||||
|
||||
Still in the MinIO folder, run
|
||||
|
||||
```shell
|
||||
make build
|
||||
```
|
||||
|
||||
# Testing on Kubernetes
|
||||
|
||||
If you want to test console on kubernetes, you can perform all the steps from `Building with MinIO`, but change `Step 3`
|
||||
to the following:
|
||||
|
||||
```shell
|
||||
TAG=miniodev/console:dev make docker
|
||||
```
|
||||
|
||||
This will build a docker container image that can be used to test with your local kubernetes environment.
|
||||
|
||||
For example, if you are using kind:
|
||||
|
||||
```shell
|
||||
kind load docker-image miniodev/console:dev
|
||||
```
|
||||
|
||||
and then deploy any `Tenant` that uses this image
|
||||
|
||||
# LDAP authentication with Console
|
||||
# LDAP authentication with MCS
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -104,12 +11,44 @@ $ docker run --rm -p 389:389 -p 636:636 --name my-openldap-container --detach os
|
||||
Run the `billy.ldif` file using `ldapadd` command to create a new user and assign it to a group.
|
||||
|
||||
```
|
||||
$ docker cp console/docs/ldap/billy.ldif my-openldap-container:/container/service/slapd/assets/test/billy.ldif
|
||||
$ docker exec my-openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/billy.ldif -H ldap://localhost
|
||||
$ cat > billy.ldif << EOF
|
||||
# LDIF fragment to create group branch under root
|
||||
dn: uid=billy,dc=example,dc=org
|
||||
uid: billy
|
||||
cn: billy
|
||||
sn: 3
|
||||
objectClass: top
|
||||
objectClass: posixAccount
|
||||
objectClass: inetOrgPerson
|
||||
loginShell: /bin/bash
|
||||
homeDirectory: /home/billy
|
||||
uidNumber: 14583102
|
||||
gidNumber: 14564100
|
||||
userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A
|
||||
mail: billy@example.org
|
||||
gecos: Billy User
|
||||
# Create base group
|
||||
dn: ou=groups,dc=example,dc=org
|
||||
objectclass:organizationalunit
|
||||
ou: groups
|
||||
description: generic groups branch
|
||||
# create mcsAdmin group (this already exists on minio and have a policy of s3::*)
|
||||
dn: cn=mcsAdmin,ou=groups,dc=example,dc=org
|
||||
objectClass: top
|
||||
objectClass: posixGroup
|
||||
gidNumber: 678
|
||||
# Assing group to new user
|
||||
dn: cn=mcsAdmin,ou=groups,dc=example,dc=org
|
||||
changetype: modify
|
||||
add: memberuid
|
||||
memberuid: billy
|
||||
EOF
|
||||
|
||||
$ docker cp billy.ldif my-openldap-container:/container/service/slapd/assets/test/billy.ldif
|
||||
$ docker exec my-openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /container/service/slapd/assets/test/billy.ldif -H ldap://localhost -ZZ
|
||||
```
|
||||
|
||||
Query the ldap server to check the user billy was created correctly and got assigned to the consoleAdmin group, you
|
||||
should get a list
|
||||
Query the ldap server to check the user billy was created correctly and got assigned to the mcsAdmin group, you should get a list
|
||||
containing ldap users and groups.
|
||||
|
||||
```
|
||||
@@ -124,7 +63,7 @@ $ docker exec my-openldap-container ldapsearch -x -H ldap://localhost -b uid=bil
|
||||
|
||||
### Change the password for user billy
|
||||
|
||||
Set the new password for `billy` to `minio123` and enter `admin` as the default `LDAP Password`
|
||||
Set the new password for `billy` to `minio123` and enter `admin` as the default `LDAP Password`
|
||||
|
||||
```
|
||||
$ docker exec -it my-openldap-container /bin/bash
|
||||
@@ -134,10 +73,9 @@ Re-enter new password:
|
||||
Enter LDAP Password:
|
||||
```
|
||||
|
||||
### Add the consoleAdmin policy to user billy on MinIO
|
||||
|
||||
### Add the mcsAdmin policy to user billy on MinIO
|
||||
```
|
||||
$ cat > consoleAdmin.json << EOF
|
||||
$ cat > mcsAdmin.json << EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
@@ -161,8 +99,8 @@ $ cat > consoleAdmin.json << EOF
|
||||
]
|
||||
}
|
||||
EOF
|
||||
$ mc admin policy create myminio consoleAdmin consoleAdmin.json
|
||||
$ mc admin policy attach myminio consoleAdmin --user="uid=billy,dc=example,dc=org"
|
||||
$ mc admin policy add myminio mcsAdmin mcsAdmin.json
|
||||
$ mc admin policy set myminio mcsAdmin user=billy
|
||||
```
|
||||
|
||||
## Run MinIO
|
||||
@@ -178,9 +116,12 @@ export MINIO_IDENTITY_LDAP_SERVER_INSECURE=on
|
||||
./minio server ~/Data
|
||||
```
|
||||
|
||||
## Run Console
|
||||
## Run MCS
|
||||
|
||||
```
|
||||
export CONSOLE_LDAP_ENABLED=on
|
||||
./console server
|
||||
export MCS_ACCESS_KEY=minio
|
||||
export MCS_SECRET_KEY=minio123
|
||||
...
|
||||
export MCS_LDAP_ENABLED=on
|
||||
./mcs server
|
||||
```
|
||||
|
||||
39
Dockerfile
39
Dockerfile
@@ -1,43 +1,26 @@
|
||||
ARG NODE_VERSION
|
||||
FROM node:$NODE_VERSION as uilayer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./portal-ui/package.json ./
|
||||
COPY ./portal-ui/yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
COPY ./portal-ui .
|
||||
|
||||
RUN make build-static
|
||||
|
||||
USER node
|
||||
|
||||
FROM golang:1.19 as golayer
|
||||
FROM golang:1.13
|
||||
|
||||
RUN apt-get update -y && apt-get install -y ca-certificates
|
||||
|
||||
ADD go.mod /go/src/github.com/minio/console/go.mod
|
||||
ADD go.sum /go/src/github.com/minio/console/go.sum
|
||||
WORKDIR /go/src/github.com/minio/console/
|
||||
ADD go.mod /go/src/github.com/minio/mcs/go.mod
|
||||
ADD go.sum /go/src/github.com/minio/mcs/go.sum
|
||||
WORKDIR /go/src/github.com/minio/mcs/
|
||||
|
||||
# Get dependencies - will also be cached if we won't change mod/sum
|
||||
RUN go mod download
|
||||
|
||||
ADD . /go/src/github.com/minio/console/
|
||||
WORKDIR /go/src/github.com/minio/console/
|
||||
ADD . /go/src/github.com/minio/mcs/
|
||||
WORKDIR /go/src/github.com/minio/mcs/
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
COPY --from=uilayer /app/build /go/src/github.com/minio/console/portal-ui/build
|
||||
RUN go build --tags=kqueue,operator -ldflags "-w -s" -a -o console ./cmd/console
|
||||
RUN go build -ldflags "-w -s" -a -o mcs ./cmd/mcs
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
|
||||
FROM scratch
|
||||
MAINTAINER MinIO Development "dev@min.io"
|
||||
EXPOSE 9090
|
||||
|
||||
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=0 /go/src/github.com/minio/mcs/mcs .
|
||||
|
||||
COPY --from=golayer /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=golayer /go/src/github.com/minio/console/console .
|
||||
|
||||
ENTRYPOINT ["/console"]
|
||||
CMD ["/mcs"]
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
ARG NODE_VERSION
|
||||
FROM node:$NODE_VERSION as uilayer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./portal-ui/package.json ./
|
||||
COPY ./portal-ui/yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
COPY ./portal-ui .
|
||||
|
||||
RUN yarn install && make build-static
|
||||
|
||||
USER node
|
||||
@@ -1,27 +1,6 @@
|
||||
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.2 as build
|
||||
|
||||
RUN microdnf update --nodocs && microdnf install ca-certificates --nodocs
|
||||
|
||||
FROM registry.access.redhat.com/ubi9/ubi-micro:9.2
|
||||
|
||||
ARG TAG
|
||||
|
||||
LABEL name="MinIO" \
|
||||
vendor="MinIO Inc <dev@min.io>" \
|
||||
maintainer="MinIO Inc <dev@min.io>" \
|
||||
version="${TAG}" \
|
||||
release="${TAG}" \
|
||||
summary="A graphical user interface for MinIO" \
|
||||
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."
|
||||
|
||||
# On RHEL the certificate bundle is located at:
|
||||
# - /etc/pki/tls/certs/ca-bundle.crt (RHEL 6)
|
||||
# - /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem (RHEL 7)
|
||||
COPY --from=build /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/pki/ca-trust/extracted/pem/
|
||||
COPY LICENSE /LICENSE
|
||||
COPY CREDITS /CREDITS
|
||||
COPY console /console
|
||||
|
||||
FROM scratch
|
||||
MAINTAINER MinIO Development "dev@min.io"
|
||||
EXPOSE 9090
|
||||
COPY mcs /mcs
|
||||
|
||||
ENTRYPOINT ["/console"]
|
||||
ENTRYPOINT ["/mcs"]
|
||||
|
||||
272
Makefile
272
Makefile
@@ -3,280 +3,62 @@ GOPATH := $(shell go env GOPATH)
|
||||
# Sets the build version based on the output of the following command, if we are building for a tag, that's the build else it uses the current git branch as the build
|
||||
BUILD_VERSION:=$(shell git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
BUILD_TIME:=$(shell date 2>/dev/null)
|
||||
TAG ?= "minio/console:$(BUILD_VERSION)-dev"
|
||||
MINIO_VERSION ?= "quay.io/minio/minio:latest"
|
||||
TARGET_BUCKET ?= "target"
|
||||
NODE_VERSION := $(shell cat .nvmrc)
|
||||
TAG ?= "minio/m3:$(VERSION)-dev"
|
||||
|
||||
default: console
|
||||
default: mcs
|
||||
|
||||
.PHONY: console
|
||||
console:
|
||||
@echo "Building Console binary to './console'"
|
||||
@(GO111MODULE=on CGO_ENABLED=0 go build -trimpath --tags=kqueue --ldflags "-s -w" -o console ./cmd/console)
|
||||
.PHONY: mcs
|
||||
mcs:
|
||||
@echo "Building mcs binary to './mcs'"
|
||||
@(GO111MODULE=on CGO_ENABLED=0 go build -trimpath --tags=kqueue --ldflags "-s -w" -o mcs ./cmd/mcs)
|
||||
|
||||
k8sdev:
|
||||
@docker build -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
|
||||
@kind load docker-image $(TAG)
|
||||
@echo "Done, now restart your mcs deployment"
|
||||
|
||||
getdeps:
|
||||
@mkdir -p ${GOPATH}/bin
|
||||
@echo "Installing golangci-lint" && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin
|
||||
@which golangci-lint 1>/dev/null || (echo "Installing golangci-lint" && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.27.0)
|
||||
|
||||
verifiers: getdeps fmt lint
|
||||
|
||||
fmt:
|
||||
@echo "Running $@ check"
|
||||
@(env bash $(PWD)/verify-gofmt.sh)
|
||||
|
||||
crosscompile:
|
||||
@(env bash $(PWD)/cross-compile.sh $(arg1))
|
||||
@GO111MODULE=on gofmt -d cmd/
|
||||
@GO111MODULE=on gofmt -d pkg/
|
||||
|
||||
lint:
|
||||
@echo "Running $@ check"
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
|
||||
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
|
||||
|
||||
install: console
|
||||
@echo "Installing console binary to '$(GOPATH)/bin/console'"
|
||||
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/console $(GOPATH)/bin/console
|
||||
@echo "Installation successful. To learn more, try \"console --help\"."
|
||||
install: mcs
|
||||
@echo "Installing mcs binary to '$(GOPATH)/bin/mcs'"
|
||||
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/mcs $(GOPATH)/bin/mcs
|
||||
@echo "Installation successful. To learn more, try \"mcs --help\"."
|
||||
|
||||
swagger-gen: clean-swagger swagger-console apply-gofmt
|
||||
@echo "Done Generating swagger server code from yaml"
|
||||
|
||||
apply-gofmt:
|
||||
@echo "Applying gofmt to all generated an existing files"
|
||||
@GO111MODULE=on gofmt -w .
|
||||
|
||||
clean-swagger:
|
||||
@echo "cleaning"
|
||||
swagger-gen:
|
||||
@echo "Generating swagger server code from yaml"
|
||||
@rm -rf models
|
||||
@rm -rf restapi/operations
|
||||
|
||||
swagger-console:
|
||||
@echo "Generating swagger server code from yaml"
|
||||
@swagger generate server -A console --main-package=management --server-package=restapi --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
|
||||
@echo "Generating typescript api"
|
||||
@npx swagger-typescript-api -p ./swagger.yml -o ./portal-ui/src/api -n consoleApi.ts
|
||||
@git restore restapi/server.go
|
||||
|
||||
@swagger generate server -A mcs --main-package=mcs --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE
|
||||
|
||||
assets:
|
||||
@(if [ -f "${NVM_DIR}/nvm.sh" ]; then \. "${NVM_DIR}/nvm.sh" && nvm install && nvm use && npm install -g yarn ; fi &&\
|
||||
cd portal-ui; yarn install --prefer-offline; make build-static; yarn prettier --write . --loglevel warn; cd ..)
|
||||
|
||||
test-integration:
|
||||
@(docker stop pgsqlcontainer || true)
|
||||
@(docker stop minio || true)
|
||||
@(docker stop minio2 || true)
|
||||
@(docker network rm mynet123 || true)
|
||||
@echo "create docker network to communicate containers MinIO & PostgreSQL"
|
||||
@(docker network create --subnet=173.18.0.0/29 mynet123)
|
||||
@echo "docker run with MinIO Version below:"
|
||||
@echo $(MINIO_VERSION)
|
||||
@echo "MinIO 1"
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 --net=mynet123 -d --name minio --rm -p 9000:9000 -p 9091:9091 -e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= $(MINIO_VERSION) server /data{1...4} --console-address ':9091' && sleep 5)
|
||||
@echo "MinIO 2"
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 --net=mynet123 -d --name minio2 --rm -p 9001:9001 -p 9092:9092 -e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= $(MINIO_VERSION) server /data{1...4} --address ':9001' --console-address ':9092' && sleep 5)
|
||||
@echo "Postgres"
|
||||
@(docker run --net=mynet123 --ip=173.18.0.4 --name pgsqlcontainer --rm -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres && sleep 5)
|
||||
@echo "execute test and get coverage for test-integration:"
|
||||
@(cd integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/system.out)
|
||||
@(docker stop pgsqlcontainer)
|
||||
@(docker stop minio)
|
||||
@(docker stop minio2)
|
||||
@(docker network rm mynet123)
|
||||
|
||||
test-replication:
|
||||
@(docker stop minio || true)
|
||||
@(docker stop minio1 || true)
|
||||
@(docker stop minio2 || true)
|
||||
@(docker network rm mynet123 || true)
|
||||
@(docker network create mynet123)
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--net=mynet123 -d \
|
||||
--name minio \
|
||||
--rm \
|
||||
-p 9000:9000 \
|
||||
-p 6000:6000 \
|
||||
-e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= \
|
||||
-e MINIO_ROOT_USER="minioadmin" \
|
||||
-e MINIO_ROOT_PASSWORD="minioadmin" \
|
||||
$(MINIO_VERSION) server /data{1...4} \
|
||||
--address :9000 \
|
||||
--console-address :6000)
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--net=mynet123 -d \
|
||||
--name minio1 \
|
||||
--rm \
|
||||
-p 9001:9001 \
|
||||
-p 6001:6001 \
|
||||
-e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= \
|
||||
-e MINIO_ROOT_USER="minioadmin" \
|
||||
-e MINIO_ROOT_PASSWORD="minioadmin" \
|
||||
$(MINIO_VERSION) server /data{1...4} \
|
||||
--address :9001 \
|
||||
--console-address :6001)
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--net=mynet123 -d \
|
||||
--name minio2 \
|
||||
--rm \
|
||||
-p 9002:9002 \
|
||||
-p 6002:6002 \
|
||||
-e MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw= \
|
||||
-e MINIO_ROOT_USER="minioadmin" \
|
||||
-e MINIO_ROOT_PASSWORD="minioadmin" \
|
||||
$(MINIO_VERSION) server /data{1...4} \
|
||||
--address :9002 \
|
||||
--console-address :6002)
|
||||
@(cd replication && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./replication.test -test.v -test.run "^Test*" -test.coverprofile=coverage/replication.out)
|
||||
@(docker stop minio || true)
|
||||
@(docker stop minio1 || true)
|
||||
@(docker stop minio2 || true)
|
||||
@(docker network rm mynet123 || true)
|
||||
|
||||
test-sso-integration:
|
||||
@echo "create the network in bridge mode to communicate all containers"
|
||||
@(docker network create my-net)
|
||||
@echo "run openldap container using MinIO Image: quay.io/minio/openldap:latest"
|
||||
@(docker run \
|
||||
-e LDAP_ORGANIZATION="MinIO Inc" \
|
||||
-e LDAP_DOMAIN="min.io" \
|
||||
-e LDAP_ADMIN_PASSWORD="admin" \
|
||||
--network my-net \
|
||||
-p 389:389 \
|
||||
-p 636:636 \
|
||||
--name openldap \
|
||||
--detach quay.io/minio/openldap:latest)
|
||||
@echo "Run Dex container using MinIO Image: quay.io/minio/dex:latest"
|
||||
@(docker run \
|
||||
-e DEX_ISSUER=http://dex:5556/dex \
|
||||
-e DEX_CLIENT_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
|
||||
-e DEX_LDAP_SERVER=openldap:389 \
|
||||
--network my-net \
|
||||
-p 5556:5556 \
|
||||
--name dex \
|
||||
--detach quay.io/minio/dex:latest)
|
||||
@echo "running minio server"
|
||||
@(docker run \
|
||||
-v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
--network my-net \
|
||||
-d \
|
||||
--name minio \
|
||||
--rm \
|
||||
-p 9000:9000 \
|
||||
-p 9001:9001 \
|
||||
-e MINIO_IDENTITY_OPENID_CLIENT_ID="minio-client-app" \
|
||||
-e MINIO_IDENTITY_OPENID_CLIENT_SECRET="minio-client-app-secret" \
|
||||
-e MINIO_IDENTITY_OPENID_CLAIM_NAME=name \
|
||||
-e MINIO_IDENTITY_OPENID_CONFIG_URL=http://dex:5556/dex/.well-known/openid-configuration \
|
||||
-e MINIO_IDENTITY_OPENID_REDIRECT_URI=http://127.0.0.1:9090/oauth_callback \
|
||||
-e MINIO_ROOT_USER=minio \
|
||||
-e MINIO_ROOT_PASSWORD=minio123 $(MINIO_VERSION) server /data{1...4} --address :9000 --console-address :9001)
|
||||
@echo "run mc commands to set the policy"
|
||||
@(docker run --name minio-client --network my-net -dit --entrypoint=/bin/sh minio/mc)
|
||||
@(docker exec minio-client mc alias set myminio/ http://minio:9000 minio minio123)
|
||||
@echo "adding policy to Dillon Harper to be able to login:"
|
||||
@(cd sso-integration && docker cp allaccess.json minio-client:/ && docker exec minio-client mc admin policy create myminio "Dillon Harper" allaccess.json)
|
||||
@echo "starting bash script"
|
||||
@(env bash $(PWD)/sso-integration/set-sso.sh)
|
||||
@echo "add python module"
|
||||
@(pip3 install bs4)
|
||||
@echo "Executing the test:"
|
||||
@(cd sso-integration && go test -coverpkg=../restapi -c -tags testrunmain . && mkdir -p coverage && ./sso-integration.test -test.v -test.run "^Test*" -test.coverprofile=coverage/sso-system.out)
|
||||
|
||||
test-permissions-1:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-1/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-2:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-2/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-3:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-3/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-4:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-4/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-5:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-5/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-6:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-6/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-permissions-7:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/permissions.sh "portal-ui/tests/permissions-7/")
|
||||
@(docker stop minio)
|
||||
|
||||
test-apply-permissions:
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/initialize-env.sh)
|
||||
|
||||
test-start-docker-minio:
|
||||
@(docker run -v /data1 -v /data2 -v /data3 -v /data4 -d --name minio --rm -p 9000:9000 quay.io/minio/minio:latest server /data{1...4})
|
||||
|
||||
initialize-permissions: test-start-docker-minio test-apply-permissions
|
||||
@echo "Done initializing permissions test"
|
||||
|
||||
cleanup-permissions:
|
||||
@(env bash $(PWD)/portal-ui/tests/scripts/cleanup-env.sh)
|
||||
@(docker stop minio)
|
||||
|
||||
initialize-docker-network:
|
||||
@(docker network create test-network)
|
||||
|
||||
test-start-docker-minio-w-redirect-url: initialize-docker-network
|
||||
@(docker run \
|
||||
-e MINIO_BROWSER_REDIRECT_URL='http://localhost:8000/console/subpath/' \
|
||||
-e MINIO_SERVER_URL='http://localhost:9000' \
|
||||
-v /data1 -v /data2 -v /data3 -v /data4 \
|
||||
-d --network host --name minio --rm\
|
||||
quay.io/minio/minio:latest server /data{1...4})
|
||||
|
||||
test-start-docker-nginx-w-subpath:
|
||||
@(docker run \
|
||||
--network host \
|
||||
-d --rm \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
-v ./portal-ui/tests/subpath-nginx/nginx.conf:/etc/nginx/nginx.conf \
|
||||
--name test-nginx nginx)
|
||||
|
||||
test-initialize-minio-nginx: test-start-docker-minio-w-redirect-url test-start-docker-nginx-w-subpath
|
||||
|
||||
cleanup-minio-nginx:
|
||||
@(docker stop minio test-nginx & docker network rm test-network)
|
||||
@(cd portal-ui; yarn install; make build-static; cd ..)
|
||||
|
||||
test:
|
||||
@echo "execute test and get coverage"
|
||||
@(cd restapi && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage.out)
|
||||
|
||||
|
||||
test-pkg:
|
||||
@echo "execute test and get coverage"
|
||||
@(cd pkg && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage-pkg.out)
|
||||
@(GO111MODULE=on go test -race -v github.com/minio/mcs/restapi/...)
|
||||
@(GO111MODULE=on go test -race -v github.com/minio/mcs/pkg/...)
|
||||
|
||||
coverage:
|
||||
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/console/restapi/... && go tool cover -html=coverage.out && open coverage.html)
|
||||
@(GO111MODULE=on go test -v -coverprofile=coverage.out github.com/minio/mcs/restapi/... && go tool cover -html=coverage.out && open coverage.html)
|
||||
|
||||
clean:
|
||||
@echo "Cleaning up all the generated files"
|
||||
@find . -name '*.test' | xargs rm -fv
|
||||
@find . -name '*~' | xargs rm -fv
|
||||
@rm -vf console
|
||||
@rm -vf mcs
|
||||
|
||||
docker:
|
||||
@docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' --build-arg NODE_VERSION='$(NODE_VERSION)' .
|
||||
|
||||
release: swagger-gen
|
||||
@echo "Generating Release: $(RELEASE)"
|
||||
@make assets
|
||||
@git add -u .
|
||||
@git add portal-ui/build/
|
||||
@docker build -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
|
||||
|
||||
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
||||
This file is part of MinIO Console Server
|
||||
Copyright (c) 2023 MinIO, Inc.
|
||||
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
|
||||
|
||||
230
README.md
230
README.md
@@ -1,64 +1,28 @@
|
||||
# MinIO Console
|
||||
|
||||
 
|
||||
|
||||
A graphical user interface for [MinIO](https://github.com/minio/minio)
|
||||
|
||||
| Object Browser | Dashboard | Creating a bucket |
|
||||
|------------------------------------|-------------------------------|-------------------------------|
|
||||
|  |  |  |
|
||||
|
||||
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
||||
**Table of Contents**
|
||||
|
||||
- [MinIO Console](#minio-console)
|
||||
- [Install](#install)
|
||||
- [Build from source](#build-from-source)
|
||||
- [Setup](#setup)
|
||||
- [1. Create a user `console` using `mc`](#1-create-a-user-console-using-mc)
|
||||
- [2. Create a policy for `console` with admin access to all resources (for testing)](#2-create-a-policy-for-console-with-admin-access-to-all-resources-for-testing)
|
||||
- [3. Set the policy for the new `console` user](#3-set-the-policy-for-the-new-console-user)
|
||||
- [Start Console service:](#start-console-service)
|
||||
- [Start Console service with TLS:](#start-console-service-with-tls)
|
||||
- [Connect Console to a Minio using TLS and a self-signed certificate](#connect-console-to-a-minio-using-tls-and-a-self-signed-certificate)
|
||||
- [Contribute to console Project](#contribute-to-console-project)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
## Install
|
||||
|
||||
MinIO Console is a library that provides a management and browser UI overlay for the MinIO Server.
|
||||
The standalone binary installation path has been removed.
|
||||
|
||||
In case a Console standalone binary is needed, it can be generated by building this package from source as follows:
|
||||
|
||||
### Build from source
|
||||
|
||||
> You will need a working Go environment. Therefore, please follow [How to install Go](https://golang.org/doc/install).
|
||||
> Minimum version required is go1.19
|
||||
|
||||
```
|
||||
go install github.com/minio/console/cmd/console@latest
|
||||
```
|
||||
| Dashboard | Adding A User |
|
||||
| ------------- | ------------- |
|
||||
|  |  |
|
||||
|
||||
## Setup
|
||||
|
||||
All `console` needs is a MinIO user with admin privileges and URL pointing to your MinIO deployment.
|
||||
|
||||
All `mcs` needs is a MinIO user with admin privileges and URL pointing to your MinIO deployment.
|
||||
> Note: We don't recommend using MinIO's Operator Credentials
|
||||
|
||||
### 1. Create a user `console` using `mc`
|
||||
|
||||
```bash
|
||||
mc admin user add myminio/
|
||||
Enter Access Key: console
|
||||
Enter Secret Key: xxxxxxxx
|
||||
1. Create a user for `mcs` using `mc`.
|
||||
```
|
||||
$ set +o history
|
||||
$ mc admin user add myminio mcs YOURMCSSECRET
|
||||
$ set -o history
|
||||
```
|
||||
|
||||
### 2. Create a policy for `console` with admin access to all resources (for testing)
|
||||
2. Create a policy for `mcs` with access to everything (for testing and debugging)
|
||||
|
||||
```sh
|
||||
cat > admin.json << EOF
|
||||
```
|
||||
$ cat > mcsAdmin.json << EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
@@ -81,130 +45,86 @@ cat > admin.json << EOF
|
||||
]
|
||||
}
|
||||
EOF
|
||||
$ mc admin policy add myminio mcsAdmin mcsAdmin.json
|
||||
```
|
||||
|
||||
```sh
|
||||
mc admin policy create myminio/ consoleAdmin admin.json
|
||||
3. Set the policy for the new `mcs` user
|
||||
|
||||
```
|
||||
$ mc admin policy set myminio mcsAdmin user=mcs
|
||||
```
|
||||
|
||||
### 3. Set the policy for the new `console` user
|
||||
|
||||
```sh
|
||||
mc admin policy attach myminio consoleAdmin --user=console
|
||||
### Note
|
||||
Additionally, you can create policies to limit the privileges for `mcs` users, for example, if you want the user to only have access to dashboard, buckets, notifications and watch page, the policy should look like this:
|
||||
```
|
||||
|
||||
> NOTE: Additionally, you can create policies to limit the privileges for other `console` users, for example, if you
|
||||
> want the user to only have access to dashboard, buckets, notifications and watch page, the policy should look like
|
||||
> this:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"admin:ServerInfo"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:ListenBucketNotification",
|
||||
"s3:PutBucketNotification",
|
||||
"s3:GetBucketNotification",
|
||||
"s3:ListMultipartUploadParts",
|
||||
"s3:ListBucketMultipartUploads",
|
||||
"s3:ListBucket",
|
||||
"s3:HeadBucket",
|
||||
"s3:GetObject",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:AbortMultipartUpload",
|
||||
"s3:CreateBucket",
|
||||
"s3:PutObject",
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteBucket",
|
||||
"s3:PutBucketPolicy",
|
||||
"s3:DeleteBucketPolicy",
|
||||
"s3:GetBucketPolicy"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Action": [
|
||||
"admin:ServerInfo"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
},
|
||||
{
|
||||
"Action": [
|
||||
"s3:ListenBucketNotification",
|
||||
"s3:PutBucketNotification",
|
||||
"s3:GetBucketNotification",
|
||||
"s3:ListMultipartUploadParts",
|
||||
"s3:ListBucketMultipartUploads",
|
||||
"s3:ListBucket",
|
||||
"s3:HeadBucket",
|
||||
"s3:GetObject",
|
||||
"s3:GetBucketLocation",
|
||||
"s3:AbortMultipartUpload",
|
||||
"s3:CreateBucket",
|
||||
"s3:PutObject",
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteBucket",
|
||||
"s3:PutBucketPolicy",
|
||||
"s3:DeleteBucketPolicy",
|
||||
"s3:GetBucketPolicy"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
],
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Start Console service:
|
||||
|
||||
Before running console service, following environment settings must be supplied
|
||||
|
||||
```sh
|
||||
# Salt to encrypt JWT payload
|
||||
export CONSOLE_PBKDF_PASSPHRASE=SECRET
|
||||
|
||||
# Required to encrypt JWT payload
|
||||
export CONSOLE_PBKDF_SALT=SECRET
|
||||
|
||||
# MinIO Endpoint
|
||||
export CONSOLE_MINIO_SERVER=http://localhost:9000
|
||||
```
|
||||
|
||||
Now start the console service.
|
||||
## Run MCS server
|
||||
To run the server:
|
||||
|
||||
```
|
||||
./console server
|
||||
2021-01-19 02:36:08.893735 I | 2021/01/19 02:36:08 server.go:129: Serving console at http://localhost:9090
|
||||
export MCS_HMAC_JWT_SECRET=YOURJWTSIGNINGSECRET
|
||||
|
||||
#required to encrypt jwet payload
|
||||
export MCS_PBKDF_PASSPHRASE=SECRET
|
||||
|
||||
#required to encrypt jwet payload
|
||||
export MCS_PBKDF_SALT=SECRET
|
||||
|
||||
export MCS_ACCESS_KEY=mcs
|
||||
export MCS_SECRET_KEY=YOURMCSSECRET
|
||||
export MCS_MINIO_SERVER=http://localhost:9000
|
||||
./mcs server
|
||||
```
|
||||
|
||||
By default `console` runs on port `9090` this can be changed with `--port` of your choice.
|
||||
|
||||
## Start Console service with TLS:
|
||||
|
||||
Copy your `public.crt` and `private.key` to `~/.console/certs`, then:
|
||||
|
||||
```sh
|
||||
./console server
|
||||
2021-01-19 02:36:08.893735 I | 2021/01/19 02:36:08 server.go:129: Serving console at http://[::]:9090
|
||||
2021-01-19 02:36:08.893735 I | 2021/01/19 02:36:08 server.go:129: Serving console at https://[::]:9443
|
||||
```
|
||||
|
||||
For advanced users, `console` has support for multiple certificates to service clients through multiple domains.
|
||||
|
||||
Following tree structure is expected for supporting multiple domains:
|
||||
|
||||
```sh
|
||||
certs/
|
||||
│
|
||||
├─ public.crt
|
||||
├─ private.key
|
||||
│
|
||||
├─ example.com/
|
||||
│ │
|
||||
│ ├─ public.crt
|
||||
│ └─ private.key
|
||||
└─ foobar.org/
|
||||
│
|
||||
├─ public.crt
|
||||
└─ private.key
|
||||
...
|
||||
## Connect MCS to a Minio using TLS and a self-signed certificate
|
||||
|
||||
```
|
||||
|
||||
## Connect Console to a Minio using TLS and a self-signed certificate
|
||||
|
||||
Copy the MinIO `ca.crt` under `~/.console/certs/CAs`, then:
|
||||
|
||||
```sh
|
||||
export CONSOLE_MINIO_SERVER=https://localhost:9000
|
||||
./console server
|
||||
...
|
||||
export MCS_MINIO_SERVER_TLS_ROOT_CAS=<certificate_file_name>
|
||||
export MCS_MINIO_SERVER=https://localhost:9000
|
||||
./mcs server
|
||||
```
|
||||
|
||||
You can verify that the apis work by doing the request on `localhost:9090/api/v1/...`
|
||||
|
||||
# Contribute to console Project
|
||||
|
||||
Please follow console [Contributor's Guide](https://github.com/minio/console/blob/master/CONTRIBUTING.md)
|
||||
# Contribute to mcs Project
|
||||
Please follow mcs [Contributor's Guide](https://github.com/minio/mcs/blob/master/CONTRIBUTING.md)
|
||||
|
||||
17
SECURITY.md
17
SECURITY.md
@@ -2,12 +2,12 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We always provide security updates for the [latest release](https://github.com/minio/console/releases/latest).
|
||||
We always provide security updates for the [latest release](https://github.com/minio/mcs/releases/latest).
|
||||
Whenever there is a security update you just need to upgrade to the latest version.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
All security bugs in [minio/console](https://github,com/minio/console) (or other minio/* repositories)
|
||||
All security bugs in [minio/mcs](https://github,com/minio/mcs) (or other minio/* repositories)
|
||||
should be reported by email to security@min.io. Your email will be acknowledged within 48 hours,
|
||||
and you'll receive a more detailed response to your email within 72 hours indicating the next steps
|
||||
in handling your report.
|
||||
@@ -18,14 +18,13 @@ you need access credentials for a successful exploit).
|
||||
|
||||
If you have not received a reply to your email within 48 hours or you have not heard from the security team
|
||||
for the past five days please contact the security team directly:
|
||||
|
||||
- Primary security coordinator: daniel@min.io
|
||||
- Secondary coordinator: security@min.io
|
||||
- If you receive no response: dev@min.io
|
||||
- Primary security coordinator: lenin@min.io
|
||||
- Secondary coordinator: daniel@min.io, cesar@min.io
|
||||
- If you receive no response: dev@min.io
|
||||
|
||||
### Disclosure Process
|
||||
|
||||
MinIO Console uses the following disclosure process:
|
||||
MinIO uses the following disclosure process:
|
||||
|
||||
1. Once the security report is received one member of the security team tries to verify and reproduce
|
||||
the issue and determines the impact it has.
|
||||
@@ -34,8 +33,8 @@ MinIO Console uses the following disclosure process:
|
||||
3. Code is audited to find any potential similar problems.
|
||||
4. Fixes are prepared for the latest release.
|
||||
5. On the date that the fixes are applied a security advisory will be published on https://blog.min.io.
|
||||
Please inform us in your report email whether MinIO Console should mention your contribution w.r.t. fixing
|
||||
the security issue. By default MinIO Console will **not** publish this information to protect your privacy.
|
||||
Please inform us in your report email whether MinIO should mention your contribution w.r.t. fixing
|
||||
the security issue. By default MinIO will **not** publish this information to protect your privacy.
|
||||
|
||||
This process can take some time, especially when coordination is required with maintainers of other projects.
|
||||
Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
## Vulnerability Management Policy
|
||||
|
||||
This document formally describes the process of addressing and managing a
|
||||
reported vulnerability that has been found in the MinIO Console server code base,
|
||||
any directly connected ecosystem component or a direct / indirect dependency
|
||||
of the code base.
|
||||
|
||||
### Scope
|
||||
|
||||
The vulnerability management policy described in this document covers the
|
||||
process of investigating, assessing and resolving a vulnerability report
|
||||
opened by a MinIO Console employee or an external third party.
|
||||
|
||||
Therefore, it lists pre-conditions and actions that should be performed to
|
||||
resolve and fix a reported vulnerability.
|
||||
|
||||
### Vulnerability Management Process
|
||||
|
||||
The vulnerability management process requires that the vulnerability report
|
||||
contains the following information:
|
||||
|
||||
- The project / component that contains the reported vulnerability.
|
||||
- A description of the vulnerability. In particular, the type of the
|
||||
reported vulnerability and how it might be exploited. Alternatively,
|
||||
a well-established vulnerability identifier, e.g. CVE number, can be
|
||||
used instead.
|
||||
|
||||
Based on the description mentioned above, a MinIO Console engineer or security team
|
||||
member investigates:
|
||||
|
||||
- Whether the reported vulnerability exists.
|
||||
- The conditions that are required such that the vulnerability can be exploited.
|
||||
- The steps required to fix the vulnerability.
|
||||
|
||||
In general, if the vulnerability exists in one of the MinIO Console code bases
|
||||
itself - not in a code dependency - then MinIO Console will, if possible, fix
|
||||
the vulnerability or implement reasonable countermeasures such that the
|
||||
vulnerability cannot be exploited anymore.
|
||||
959
bindata_assetfs.go
Normal file
959
bindata_assetfs.go
Normal file
File diff suppressed because one or more lines are too long
65
cluster/cluster.go
Normal file
65
cluster/cluster.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2019 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 cluster
|
||||
|
||||
import (
|
||||
operator "github.com/minio/operator/pkg/client/clientset/versioned"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
// getTLSClientConfig will return the right TLS configuration for the K8S client based on the configured TLS certificate
|
||||
func getTLSClientConfig() rest.TLSClientConfig {
|
||||
var defaultRootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
||||
var customRootCAFile = getK8sAPIServerTLSRootCA()
|
||||
tlsClientConfig := rest.TLSClientConfig{}
|
||||
// if console is running inside k8s by default he will have access to the CA Cert from the k8s local authority
|
||||
if _, err := certutil.NewPool(defaultRootCAFile); err == nil {
|
||||
tlsClientConfig.CAFile = defaultRootCAFile
|
||||
}
|
||||
// if the user explicitly define a custom CA certificate, instead, we will use that
|
||||
if customRootCAFile != "" {
|
||||
if _, err := certutil.NewPool(customRootCAFile); err == nil {
|
||||
tlsClientConfig.CAFile = customRootCAFile
|
||||
}
|
||||
}
|
||||
return tlsClientConfig
|
||||
}
|
||||
|
||||
// This operation will run only once at console startup
|
||||
var tlsClientConfig = getTLSClientConfig()
|
||||
|
||||
func GetK8sConfig(token string) *rest.Config {
|
||||
config := &rest.Config{
|
||||
Host: GetK8sAPIServer(),
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
APIPath: "/",
|
||||
BearerToken: token,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// OperatorClient returns an operator client using GetK8sConfig for its config
|
||||
func OperatorClient(token string) (*operator.Clientset, error) {
|
||||
return operator.NewForConfig(GetK8sConfig(token))
|
||||
}
|
||||
|
||||
// K8sClient returns kubernetes client using GetK8sConfig for its config
|
||||
func K8sClient(token string) (*kubernetes.Clientset, error) {
|
||||
return kubernetes.NewForConfig(GetK8sConfig(token))
|
||||
}
|
||||
168
cluster/config.go
Normal file
168
cluster/config.go
Normal file
@@ -0,0 +1,168 @@
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2019 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 cluster
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
var (
|
||||
errCantDetermineMinIOImage = errors.New("can't determine MinIO Image")
|
||||
errCantDetermineMCImage = errors.New("can't determine MC Image")
|
||||
)
|
||||
|
||||
func GetK8sAPIServer() string {
|
||||
// if console is running inside a k8s pod KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT will contain the k8s api server apiServerAddress
|
||||
// if console is not running inside k8s by default will look for the k8s api server on localhost:8001 (kubectl proxy)
|
||||
// NOTE: using kubectl proxy is for local development only, since every request send to localhost:8001 will bypass service account authentication
|
||||
// more info here: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-accessing-the-rest-api
|
||||
// you can override this using MCS_K8S_API_SERVER, ie use the k8s cluster from `kubectl config view`
|
||||
host, port := env.Get("KUBERNETES_SERVICE_HOST", ""), env.Get("KUBERNETES_SERVICE_PORT", "")
|
||||
apiServerAddress := "http://localhost:8001"
|
||||
if host != "" && port != "" {
|
||||
apiServerAddress = "https://" + net.JoinHostPort(host, port)
|
||||
}
|
||||
return env.Get(McsK8sAPIServer, apiServerAddress)
|
||||
}
|
||||
|
||||
// If MCS_K8S_API_SERVER_TLS_ROOT_CA is true mcs will load the certificate into the
|
||||
// http.client rootCAs pool, this is useful for testing an k8s ApiServer or when working with self-signed certificates
|
||||
func getK8sAPIServerTLSRootCA() string {
|
||||
return strings.TrimSpace(env.Get(McsK8SAPIServerTLSRootCA, ""))
|
||||
}
|
||||
|
||||
// GetNsFromFile assumes console is running inside a k8s pod and extract the current namespace from the
|
||||
// /var/run/secrets/kubernetes.io/serviceaccount/namespace file
|
||||
func GetNsFromFile() string {
|
||||
dat, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
|
||||
if err != nil {
|
||||
return "default"
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
// This operation will run only once at console startup
|
||||
var namespace = GetNsFromFile()
|
||||
|
||||
// Returns the namespace in which the controller is installed
|
||||
func GetNs() string {
|
||||
return env.Get(McsNamespace, namespace)
|
||||
}
|
||||
|
||||
// getLatestMinIOImage returns the latest docker image for MinIO if found on the internet
|
||||
func getLatestMinIOImage(client HTTPClientI) (*string, error) {
|
||||
resp, err := client.Get("https://dl.min.io/server/minio/release/linux-amd64/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var re = regexp.MustCompile(`(?m)\.\/minio\.(RELEASE.*?Z)"`)
|
||||
// look for a single match
|
||||
matches := re.FindAllStringSubmatch(string(body), 1)
|
||||
for i := range matches {
|
||||
release := matches[i][1]
|
||||
dockerImage := fmt.Sprintf("minio/minio:%s", release)
|
||||
return &dockerImage, nil
|
||||
}
|
||||
return nil, errCantDetermineMinIOImage
|
||||
}
|
||||
|
||||
var latestMinIOImage, errLatestMinIOImage = getLatestMinIOImage(
|
||||
&HTTPClient{
|
||||
Client: &http.Client{
|
||||
Timeout: 4 * time.Second,
|
||||
},
|
||||
})
|
||||
|
||||
// GetMinioImage returns the image URL to be used when deploying a MinIO instance, if there is
|
||||
// a preferred image to be used (configured via ENVIRONMENT VARIABLES) GetMinioImage will return that
|
||||
// if not, GetMinioImage will try to obtain the image URL for the latest version of MinIO and return that
|
||||
func GetMinioImage() (*string, error) {
|
||||
image := strings.TrimSpace(env.Get(McsMinioImage, ""))
|
||||
// if there is a preferred image configured by the user we'll always return that
|
||||
if image != "" {
|
||||
return &image, nil
|
||||
}
|
||||
if errLatestMinIOImage != nil {
|
||||
return nil, errLatestMinIOImage
|
||||
}
|
||||
return latestMinIOImage, nil
|
||||
}
|
||||
|
||||
// GetLatestMinioImage returns the latest image URL on minio repository
|
||||
func GetLatestMinioImage(client HTTPClientI) (*string, error) {
|
||||
latestMinIOImage, err := getLatestMinIOImage(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return latestMinIOImage, nil
|
||||
}
|
||||
|
||||
// getLatestMCImage returns the latest docker image for MC if found on the internet
|
||||
func getLatestMCImage() (*string, error) {
|
||||
// Create an http client with a 4 second timeout
|
||||
client := http.Client{
|
||||
Timeout: 4 * time.Second,
|
||||
}
|
||||
resp, err := client.Get("https://dl.min.io/client/mc/release/linux-amd64/")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var re = regexp.MustCompile(`(?m)\.\/mc\.(RELEASE.*?Z)"`)
|
||||
// look for a single match
|
||||
matches := re.FindAllStringSubmatch(string(body), 1)
|
||||
for i := range matches {
|
||||
release := matches[i][1]
|
||||
dockerImage := fmt.Sprintf("minio/mc:%s", release)
|
||||
return &dockerImage, nil
|
||||
}
|
||||
return nil, errCantDetermineMCImage
|
||||
}
|
||||
|
||||
var latestMCImage, errLatestMCImage = getLatestMCImage()
|
||||
|
||||
func GetMCImage() (*string, error) {
|
||||
image := strings.TrimSpace(env.Get(McsMCImage, ""))
|
||||
// if there is a preferred image configured by the user we'll always return that
|
||||
if image != "" {
|
||||
return &image, nil
|
||||
}
|
||||
if errLatestMCImage != nil {
|
||||
return nil, errLatestMCImage
|
||||
}
|
||||
return latestMCImage, nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2019 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
|
||||
@@ -14,14 +14,12 @@
|
||||
// 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 types
|
||||
package cluster
|
||||
|
||||
// TargetType indicates type of the target e.g. console, http, kafka
|
||||
type TargetType uint8
|
||||
|
||||
// Constants for target types
|
||||
const (
|
||||
_ TargetType = iota
|
||||
TargetConsole
|
||||
TargetHTTP
|
||||
McsK8sAPIServer = "MCS_K8S_API_SERVER"
|
||||
McsK8SAPIServerTLSRootCA = "MCS_K8S_API_SERVER_TLS_ROOT_CA"
|
||||
McsMinioImage = "MCS_MINIO_IMAGE"
|
||||
McsMCImage = "MCS_MC_IMAGE"
|
||||
McsNamespace = "MCS_NAMESPACE"
|
||||
)
|
||||
40
cluster/http_client.go
Normal file
40
cluster/http_client.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// 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 cluster
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPClientI interface with all functions to be implemented
|
||||
// by mock when testing, it should include all HttpClient respective api calls
|
||||
// that are used within this project.
|
||||
type HTTPClientI interface {
|
||||
Get(url string) (resp *http.Response, err error)
|
||||
}
|
||||
|
||||
// HTTPClient Interface implementation
|
||||
//
|
||||
// Define the structure of a http client and define the functions that are actually used
|
||||
type HTTPClient struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// Get implements http.Client.Get()
|
||||
func (c *HTTPClient) Get(url string) (resp *http.Response, err error) {
|
||||
return c.Client.Get(url)
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/pkg/logger"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/console/restapi"
|
||||
)
|
||||
|
||||
var appCmds = []cli.Command{
|
||||
serverCmd,
|
||||
updateCmd,
|
||||
}
|
||||
|
||||
// StartServer starts the console service
|
||||
func StartServer(ctx *cli.Context) error {
|
||||
if err := loadAllCerts(ctx); err != nil {
|
||||
// Log this as a warning and continue running console without TLS certificates
|
||||
restapi.LogError("Unable to load certs: %v", err)
|
||||
}
|
||||
|
||||
xctx := context.Background()
|
||||
|
||||
transport := restapi.PrepareSTSClientTransport(false, restapi.LocalAddress)
|
||||
if err := logger.InitializeLogger(xctx, transport.Transport); err != nil {
|
||||
fmt.Println("error InitializeLogger", err)
|
||||
logger.CriticalIf(xctx, err)
|
||||
}
|
||||
// custom error configuration
|
||||
restapi.LogInfo = logger.Info
|
||||
restapi.LogError = logger.Error
|
||||
restapi.LogIf = logger.LogIf
|
||||
|
||||
var rctx restapi.Context
|
||||
if err := rctx.Load(ctx); err != nil {
|
||||
restapi.LogError("argument validation failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
server, err := buildServer()
|
||||
if err != nil {
|
||||
restapi.LogError("Unable to initialize console server: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
server.Host = rctx.Host
|
||||
server.Port = rctx.HTTPPort
|
||||
// set conservative timesout for uploads
|
||||
server.ReadTimeout = 1 * time.Hour
|
||||
// no timeouts for response for downloads
|
||||
server.WriteTimeout = 0
|
||||
restapi.Port = strconv.Itoa(server.Port)
|
||||
restapi.Hostname = server.Host
|
||||
|
||||
if len(restapi.GlobalPublicCerts) > 0 {
|
||||
// If TLS certificates are provided enforce the HTTPS schema, meaning console will redirect
|
||||
// plain HTTP connections to HTTPS server
|
||||
server.EnabledListeners = []string{"http", "https"}
|
||||
server.TLSPort = rctx.HTTPSPort
|
||||
// Need to store tls-port, tls-host un config variables so secure.middleware can read from there
|
||||
restapi.TLSPort = strconv.Itoa(server.TLSPort)
|
||||
restapi.Hostname = rctx.Host
|
||||
restapi.TLSRedirect = rctx.TLSRedirect
|
||||
}
|
||||
|
||||
defer server.Shutdown()
|
||||
|
||||
return server.Serve()
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/console/pkg/certs"
|
||||
"github.com/minio/console/restapi"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
)
|
||||
|
||||
// starts the server
|
||||
var serverCmd = cli.Command{
|
||||
Name: "server",
|
||||
Aliases: []string{"srv"},
|
||||
Usage: "Start MinIO Console server",
|
||||
Action: StartServer,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: restapi.GetHostname(),
|
||||
Usage: "bind to a specific HOST, HOST can be an IP or hostname",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Value: restapi.GetPort(),
|
||||
Usage: "bind to specific HTTP port",
|
||||
},
|
||||
// This is kept here for backward compatibility,
|
||||
// hostname's do not have HTTP or HTTPs
|
||||
// hostnames are opaque so using --host
|
||||
// works for both HTTP and HTTPS setup.
|
||||
cli.StringFlag{
|
||||
Name: "tls-host",
|
||||
Value: restapi.GetHostname(),
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "certs-dir",
|
||||
Value: certs.GlobalCertsCADir.Get(),
|
||||
Usage: "path to certs directory",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "tls-port",
|
||||
Value: restapi.GetTLSPort(),
|
||||
Usage: "bind to specific HTTPS port",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-redirect",
|
||||
Value: restapi.GetTLSRedirect(),
|
||||
Usage: "toggle HTTP->HTTPS redirect",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-certificate",
|
||||
Value: "",
|
||||
Usage: "path to TLS public certificate",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-key",
|
||||
Value: "",
|
||||
Usage: "path to TLS private key",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-ca",
|
||||
Value: "",
|
||||
Usage: "path to TLS Certificate Authority",
|
||||
Hidden: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func buildServer() (*restapi.Server, error) {
|
||||
swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
api := operations.NewConsoleAPI(swaggerSpec)
|
||||
api.Logger = restapi.LogInfo
|
||||
server := restapi.NewServer(api)
|
||||
|
||||
parser := flags.NewParser(server, flags.Default)
|
||||
parser.ShortDescription = "MinIO Console Server"
|
||||
parser.LongDescription = swaggerSpec.Spec().Info.Description
|
||||
|
||||
server.ConfigureFlags()
|
||||
|
||||
// register all APIs
|
||||
server.ConfigureAPI()
|
||||
|
||||
for _, optsGroup := range api.CommandLineOptionsGroups {
|
||||
_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := parser.Parse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func loadAllCerts(ctx *cli.Context) error {
|
||||
var err error
|
||||
// Set all certs and CAs directories path
|
||||
certs.GlobalCertsDir, _, err = certs.NewConfigDirFromCtx(ctx, "certs-dir", certs.DefaultCertsDir.Get)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certs.GlobalCertsCADir = &certs.ConfigDir{Path: filepath.Join(certs.GlobalCertsDir.Get(), certs.CertsCADir)}
|
||||
// check if certs and CAs directories exists or can be created
|
||||
if err = certs.MkdirAllIgnorePerm(certs.GlobalCertsCADir.Get()); err != nil {
|
||||
return fmt.Errorf("unable to create certs CA directory at %s: failed with %w", certs.GlobalCertsCADir.Get(), err)
|
||||
}
|
||||
|
||||
// load the certificates and the CAs
|
||||
restapi.GlobalRootCAs, restapi.GlobalPublicCerts, restapi.GlobalTLSCertsManager, err = certs.GetAllCertificatesAndCAs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load certificates at %s: failed with %w", certs.GlobalCertsDir.Get(), err)
|
||||
}
|
||||
|
||||
{
|
||||
// TLS flags from swagger server, used to support VMware vsphere operator version.
|
||||
swaggerServerCertificate := ctx.String("tls-certificate")
|
||||
swaggerServerCertificateKey := ctx.String("tls-key")
|
||||
swaggerServerCACertificate := ctx.String("tls-ca")
|
||||
// load tls cert and key from swagger server tls-certificate and tls-key flags
|
||||
if swaggerServerCertificate != "" && swaggerServerCertificateKey != "" {
|
||||
if err = restapi.GlobalTLSCertsManager.AddCertificate(swaggerServerCertificate, swaggerServerCertificateKey); err != nil {
|
||||
return err
|
||||
}
|
||||
x509Certs, err := certs.ParsePublicCertFile(swaggerServerCertificate)
|
||||
if err == nil {
|
||||
restapi.GlobalPublicCerts = append(restapi.GlobalPublicCerts, x509Certs...)
|
||||
}
|
||||
}
|
||||
|
||||
// load ca cert from swagger server tls-ca flag
|
||||
if swaggerServerCACertificate != "" {
|
||||
caCert, caCertErr := os.ReadFile(swaggerServerCACertificate)
|
||||
if caCertErr == nil {
|
||||
restapi.GlobalRootCAs.AppendCertsFromPEM(caCert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if restapi.GlobalTLSCertsManager != nil {
|
||||
restapi.GlobalTLSCertsManager.ReloadOnSignal(syscall.SIGHUP)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/console/pkg"
|
||||
"github.com/minio/selfupdate"
|
||||
)
|
||||
|
||||
func getUpdateTransport(timeout time.Duration) http.RoundTripper {
|
||||
var updateTransport http.RoundTripper = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: timeout,
|
||||
KeepAlive: timeout,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
IdleConnTimeout: timeout,
|
||||
TLSHandshakeTimeout: timeout,
|
||||
ExpectContinueTimeout: timeout,
|
||||
DisableCompression: true,
|
||||
}
|
||||
return updateTransport
|
||||
}
|
||||
|
||||
func getUpdateReaderFromURL(u string, transport http.RoundTripper) (io.ReadCloser, int64, error) {
|
||||
clnt := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
|
||||
resp, err := clnt.Do(req)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
return resp.Body, resp.ContentLength, nil
|
||||
}
|
||||
|
||||
const defaultPubKey = "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav"
|
||||
|
||||
func getLatestRelease(tr http.RoundTripper) (string, error) {
|
||||
releaseURL := "https://api.github.com/repos/minio/console/releases/latest"
|
||||
|
||||
body, _, err := getUpdateReaderFromURL(releaseURL, tr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to access github release URL %w", err)
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
lm := make(map[string]interface{})
|
||||
if err = json.NewDecoder(body).Decode(&lm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
rel, ok := lm["tag_name"].(string)
|
||||
if !ok {
|
||||
return "", errors.New("unable to find latest release tag")
|
||||
}
|
||||
return rel, nil
|
||||
}
|
||||
|
||||
// update console in-place
|
||||
var updateCmd = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "update console to latest release",
|
||||
Action: updateInplace,
|
||||
}
|
||||
|
||||
func updateInplace(_ *cli.Context) error {
|
||||
transport := getUpdateTransport(30 * time.Second)
|
||||
rel, err := getLatestRelease(transport)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
latest, err := semver.Make(strings.TrimPrefix(rel, "v"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
current, err := semver.Make(pkg.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if current.GTE(latest) {
|
||||
fmt.Printf("You are already running the latest version v%v.\n", pkg.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
consoleBin := fmt.Sprintf("https://github.com/minio/console/releases/download/%s/console-%s-%s", rel, runtime.GOOS, runtime.GOARCH)
|
||||
reader, length, err := getUpdateReaderFromURL(consoleBin, transport)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch binary from %s: %w", consoleBin, err)
|
||||
}
|
||||
|
||||
minisignPubkey := os.Getenv("CONSOLE_MINISIGN_PUBKEY")
|
||||
if minisignPubkey == "" {
|
||||
minisignPubkey = defaultPubKey
|
||||
}
|
||||
|
||||
v := selfupdate.NewVerifier()
|
||||
if err = v.LoadFromURL(consoleBin+".minisig", minisignPubkey, transport); err != nil {
|
||||
return fmt.Errorf("unable to fetch binary signature for %s: %w", consoleBin, err)
|
||||
}
|
||||
opts := selfupdate.Options{
|
||||
Verifier: v,
|
||||
}
|
||||
|
||||
tmpl := `{{ red "Downloading:" }} {{bar . (red "[") (green "=") (red "]")}} {{speed . | rndcolor }}`
|
||||
bar := pb.ProgressBarTemplate(tmpl).Start64(length)
|
||||
barReader := bar.NewProxyReader(reader)
|
||||
if err = selfupdate.Apply(barReader, opts); err != nil {
|
||||
bar.Finish()
|
||||
if rerr := selfupdate.RollbackError(err); rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
bar.Finish()
|
||||
fmt.Printf("Updated 'console' to latest release %s\n", rel)
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,38 +23,44 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/minio/mcs/pkg"
|
||||
|
||||
"github.com/minio/minio/pkg/console"
|
||||
"github.com/minio/minio/pkg/trie"
|
||||
"github.com/minio/minio/pkg/words"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/console/pkg"
|
||||
"github.com/minio/pkg/v2/console"
|
||||
"github.com/minio/pkg/v2/trie"
|
||||
"github.com/minio/pkg/v2/words"
|
||||
)
|
||||
|
||||
// Help template for Console.
|
||||
var consoleHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
// Help template for mcs.
|
||||
var mcsHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
DESCRIPTION:
|
||||
{{.Description}}
|
||||
{{.Description}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}}{{end}} [ARGS...]
|
||||
{{.HelpName}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}}{{end}} [ARGS...]
|
||||
|
||||
COMMANDS:
|
||||
{{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .VisibleFlags}}
|
||||
{{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .VisibleFlags}}
|
||||
FLAGS:
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
{{range .VisibleFlags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
VERSION:
|
||||
{{.Version}}
|
||||
{{.Version}}
|
||||
`
|
||||
|
||||
var appCmds = []cli.Command{
|
||||
serverCmd,
|
||||
}
|
||||
|
||||
func newApp(name string) *cli.App {
|
||||
// Collection of console commands currently supported are.
|
||||
// Collection of mcs commands currently supported are.
|
||||
var commands []cli.Command
|
||||
|
||||
// Collection of console commands currently supported in a trie tree.
|
||||
// Collection of mcs commands currently supported in a trie tree.
|
||||
commandsTree := trie.NewTrie()
|
||||
|
||||
// registerCommand registers a cli command.
|
||||
@@ -70,19 +76,21 @@ func newApp(name string) *cli.App {
|
||||
|
||||
findClosestCommands := func(command string) []string {
|
||||
var closestCommands []string
|
||||
closestCommands = append(closestCommands, commandsTree.PrefixMatch(command)...)
|
||||
for _, value := range commandsTree.PrefixMatch(command) {
|
||||
closestCommands = append(closestCommands, value.(string))
|
||||
}
|
||||
|
||||
sort.Strings(closestCommands)
|
||||
// Suggest other close commands - allow missed, wrongly added and
|
||||
// even transposed characters
|
||||
for _, value := range commandsTree.Walk(commandsTree.Root()) {
|
||||
if sort.SearchStrings(closestCommands, value) < len(closestCommands) {
|
||||
if sort.SearchStrings(closestCommands, value.(string)) < len(closestCommands) {
|
||||
continue
|
||||
}
|
||||
// 2 is arbitrary and represents the max
|
||||
// allowed number of typed errors
|
||||
if words.DamerauLevenshteinDistance(command, value) < 2 {
|
||||
closestCommands = append(closestCommands, value)
|
||||
if words.DamerauLevenshteinDistance(command, value.(string)) < 2 {
|
||||
closestCommands = append(closestCommands, value.(string))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,13 +108,13 @@ func newApp(name string) *cli.App {
|
||||
app.Author = "MinIO, Inc."
|
||||
app.Usage = "MinIO Console Server"
|
||||
app.Description = `MinIO Console Server`
|
||||
app.Copyright = "(c) 2021 MinIO, Inc."
|
||||
app.Copyright = "(c) 2020 MinIO, Inc."
|
||||
app.Compiled, _ = time.Parse(time.RFC3339, pkg.ReleaseTime)
|
||||
app.Commands = commands
|
||||
app.HideHelpCommand = true // Hide `help, h` command, we already have `minio --help`.
|
||||
app.CustomAppHelpTemplate = consoleHelpTemplate
|
||||
app.CustomAppHelpTemplate = mcsHelpTemplate
|
||||
app.CommandNotFound = func(ctx *cli.Context, command string) {
|
||||
console.Printf("‘%s’ is not a console sub-command. See ‘console --help’.\n", command)
|
||||
console.Printf("‘%s’ is not a mcs sub-command. See ‘mcs --help’.\n", command)
|
||||
closestCommands := findClosestCommands(command)
|
||||
if len(closestCommands) > 0 {
|
||||
console.Println()
|
||||
132
cmd/mcs/server.go
Normal file
132
cmd/mcs/server.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mcs/restapi"
|
||||
"github.com/minio/mcs/restapi/operations"
|
||||
)
|
||||
|
||||
// starts the server
|
||||
var serverCmd = cli.Command{
|
||||
Name: "server",
|
||||
Aliases: []string{"srv"},
|
||||
Usage: "starts mcs server",
|
||||
Action: startServer,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host",
|
||||
Value: restapi.GetHostname(),
|
||||
Usage: "HTTP server hostname",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Value: restapi.GetPort(),
|
||||
Usage: "HTTP Server port",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-host",
|
||||
Value: restapi.GetSSLHostname(),
|
||||
Usage: "HTTPS server hostname",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "tls-port",
|
||||
Value: restapi.GetSSLPort(),
|
||||
Usage: "HTTPS server port",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-certificate",
|
||||
Value: "",
|
||||
Usage: "filename of public cert",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-key",
|
||||
Value: "",
|
||||
Usage: "filename of private key",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// starts the controller
|
||||
func startServer(ctx *cli.Context) error {
|
||||
swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
api := operations.NewMcsAPI(swaggerSpec)
|
||||
server := restapi.NewServer(api)
|
||||
defer server.Shutdown()
|
||||
|
||||
parser := flags.NewParser(server, flags.Default)
|
||||
parser.ShortDescription = "MinIO Console Server"
|
||||
parser.LongDescription = swaggerSpec.Spec().Info.Description
|
||||
server.ConfigureFlags()
|
||||
for _, optsGroup := range api.CommandLineOptionsGroups {
|
||||
_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := parser.Parse(); err != nil {
|
||||
code := 1
|
||||
if fe, ok := err.(*flags.Error); ok {
|
||||
if fe.Type == flags.ErrHelp {
|
||||
code = 0
|
||||
}
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
server.Host = ctx.String("host")
|
||||
server.Port = ctx.Int("port")
|
||||
|
||||
restapi.Hostname = ctx.String("host")
|
||||
restapi.Port = fmt.Sprintf("%v", ctx.Int("port"))
|
||||
|
||||
tlsCertificatePath := ctx.String("tls-certificate")
|
||||
tlsCertificateKeyPath := ctx.String("tls-key")
|
||||
|
||||
if tlsCertificatePath != "" && tlsCertificateKeyPath != "" {
|
||||
server.TLSCertificate = flags.Filename(tlsCertificatePath)
|
||||
server.TLSCertificateKey = flags.Filename(tlsCertificateKeyPath)
|
||||
// If TLS certificates are provided enforce the HTTPS schema, meaning mcs will redirect
|
||||
// plain HTTP connections to HTTPS server
|
||||
server.EnabledListeners = []string{"http", "https"}
|
||||
server.TLSPort = ctx.Int("tls-port")
|
||||
server.TLSHost = ctx.String("tls-host")
|
||||
// Need to store tls-port, tls-host un config variables so secure.middleware can read from there
|
||||
restapi.TLSPort = fmt.Sprintf("%v", ctx.Int("tls-port"))
|
||||
restapi.TLSHostname = ctx.String("tls-host")
|
||||
restapi.TLSRedirect = "on"
|
||||
}
|
||||
|
||||
server.ConfigureAPI()
|
||||
|
||||
if err := server.Serve(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
# Enable tracing if set.
|
||||
[ -n "$BASH_XTRACEFD" ] && set -x
|
||||
|
||||
## All binaries are static make sure to disable CGO.
|
||||
export CGO_ENABLED=0
|
||||
|
||||
## List of architectures and OS to test cross compilation.
|
||||
SUPPORTED_OSARCH_DEFAULTS="linux/ppc64le linux/mips64 linux/arm64 linux/s390x darwin/amd64 freebsd/amd64 windows/amd64 linux/arm linux/386 netbsd/amd64"
|
||||
SUPPORTED_OSARCH=${1:-$SUPPORTED_OSARCH_DEFAULTS}
|
||||
|
||||
_build() {
|
||||
local osarch=$1
|
||||
IFS=/ read -r -a arr <<<"$osarch"
|
||||
os="${arr[0]}"
|
||||
arch="${arr[1]}"
|
||||
package=$(go list -f '{{.ImportPath}}' ./cmd/console)
|
||||
printf -- "--> %15s:%s\n" "${osarch}" "${package}"
|
||||
|
||||
# go build -trimpath to build the binary.
|
||||
GOOS=$os GOARCH=$arch GO111MODULE=on go build -trimpath --tags=kqueue --ldflags "-s -w" -o /dev/null ./cmd/console
|
||||
}
|
||||
|
||||
main() {
|
||||
echo "Testing builds for OS/Arch: ${SUPPORTED_OSARCH}"
|
||||
for each_osarch in ${SUPPORTED_OSARCH}; do
|
||||
_build "${each_osarch}"
|
||||
done
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,35 +0,0 @@
|
||||
# LDIF fragment to create group branch under root
|
||||
dn: uid=billy,dc=example,dc=org
|
||||
uid: billy
|
||||
cn: billy
|
||||
sn: 3
|
||||
objectClass: top
|
||||
objectClass: posixAccount
|
||||
objectClass: inetOrgPerson
|
||||
loginShell: /bin/bash
|
||||
homeDirectory: /home/billy
|
||||
uidNumber: 14583102
|
||||
gidNumber: 14564100
|
||||
userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A
|
||||
mail: billy@example.org
|
||||
gecos: Billy User
|
||||
|
||||
# Create base group
|
||||
dn: ou=groups,dc=example,dc=org
|
||||
objectclass:organizationalunit
|
||||
ou: groups
|
||||
description: generic groups branch
|
||||
|
||||
# create consoleAdmin group (this already exists on minio and have a policy of s3::*)
|
||||
dn: cn=consoleAdmin,ou=groups,dc=example,dc=org
|
||||
objectClass: top
|
||||
objectClass: posixGroup
|
||||
gidNumber: 678
|
||||
|
||||
# Assing group to new user
|
||||
dn: cn=consoleAdmin,ou=groups,dc=example,dc=org
|
||||
changetype: modify
|
||||
add: memberuid
|
||||
memberuid: billy
|
||||
|
||||
|
||||
39
docs/mcs_operator_mode.md
Normal file
39
docs/mcs_operator_mode.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Running MCS in Operator mode
|
||||
|
||||
`MCS` will authenticate against `Kubernetes`using bearer tokens via HTTP `Authorization` header. The user will provide this token once
|
||||
in the login form, MCS will validate it against Kubernetes (list apis) and if valid will generate and return a new MCS sessions
|
||||
with encrypted claims (the user Service account token will be inside the JWT in the data field)
|
||||
|
||||
# Kubernetes
|
||||
|
||||
The provided `JWT token` corresponds to the `Kubernetes service account` that `MCS` will use to run tasks on behalf of the
|
||||
user, ie: list, create, edit, delete tenants, storage class, etc.
|
||||
|
||||
|
||||
# Development
|
||||
|
||||
If console is running inside a k8s pod `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` will contain the k8s api server apiServerAddress
|
||||
if console is not running inside k8s by default will look for the k8s api server on `localhost:8001` (kubectl proxy)
|
||||
|
||||
If you are running mcs in your local environment and wish to make request to `Kubernetes` you can set `MCS_K8S_API_SERVER`, if
|
||||
the environment variable is not present by default `MCS` will use `"http://localhost:8001"`, additionally you will need to set the
|
||||
`MCS_OPERATOR_MODE=on` variable to make MCS display the Operator UI.
|
||||
|
||||
NOTE: using `kubectl` proxy is for local development only, since every request send to localhost:8001 will bypass service account authentication
|
||||
more info here: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-accessing-the-rest-api
|
||||
you can override this using `MCS_K8S_API_SERVER`, ie use the k8s cluster from `kubectl config view`
|
||||
|
||||
## Extract the Service account token and use it with MCS
|
||||
|
||||
For local development you can use the jwt associated to the `mcs-sa` service account, you can get the token running
|
||||
the following command in your terminal:
|
||||
|
||||
```
|
||||
kubectl get secret $(kubectl get serviceaccount mcs-sa -o jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64 --decode
|
||||
```
|
||||
|
||||
Then run the mcs server
|
||||
|
||||
```
|
||||
MCS_OPERATOR_MODE=on ./mcs server
|
||||
```
|
||||
185
go.mod
185
go.mod
@@ -1,159 +1,34 @@
|
||||
module github.com/minio/console
|
||||
module github.com/minio/mcs
|
||||
|
||||
go 1.21
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.4
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/go-openapi/errors v0.20.4
|
||||
github.com/go-openapi/loads v0.21.2
|
||||
github.com/go-openapi/runtime v0.26.0
|
||||
github.com/go-openapi/spec v0.20.9
|
||||
github.com/go-openapi/strfmt v0.21.7
|
||||
github.com/go-openapi/swag v0.22.4
|
||||
github.com/go-openapi/validate v0.22.1
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/jessevdk/go-flags v1.5.0
|
||||
github.com/klauspost/compress v1.16.7
|
||||
github.com/minio/cli v1.24.2
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/kes v0.22.3
|
||||
github.com/minio/madmin-go/v3 v3.0.29
|
||||
github.com/minio/mc v0.0.0-20231030184332-9f2fb2b6a9f8
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20230920204636-e783c9ba11b3
|
||||
github.com/minio/selfupdate v0.6.0
|
||||
github.com/minio/websocket v1.6.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/rs/xid v1.5.0
|
||||
github.com/secure-io/sio-go v0.3.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tidwall/gjson v1.16.0
|
||||
github.com/unrolled/secure v1.13.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/oauth2 v0.12.0
|
||||
// Added to include security fix for
|
||||
// https://github.com/golang/go/issues/56152
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mattn/go-ieproxy v0.0.11
|
||||
github.com/minio/pkg/v2 v2.0.2
|
||||
)
|
||||
|
||||
require (
|
||||
aead.dev/mem v0.2.0 // indirect
|
||||
aead.dev/minisign v0.2.0 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/charmbracelet/bubbles v0.16.1 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.24.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.8.0 // indirect
|
||||
github.com/cheggaaa/pb v1.0.29 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/gdamore/tcell/v2 v2.6.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.7 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/jwx v1.2.26 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/colorjson v1.0.6 // indirect
|
||||
github.com/minio/filepath v1.0.0 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/navidys/tvxwidgets v0.3.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/philhofer/fwd v1.1.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/xattr v0.4.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/posener/complete v1.2.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/prometheus/prom2json v1.3.3 // indirect
|
||||
github.com/rivo/tview v0.0.0-20230909130259-ba6a2a345459 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.3 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.8 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tinylib/msgp v1.1.8 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.6.2 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.25.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
|
||||
google.golang.org/grpc v1.58.3 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/h2non/filetype.v1 v1.0.5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0
|
||||
github.com/go-openapi/errors v0.19.6
|
||||
github.com/go-openapi/loads v0.19.5
|
||||
github.com/go-openapi/runtime v0.19.19
|
||||
github.com/go-openapi/spec v0.19.8
|
||||
github.com/go-openapi/strfmt v0.19.5
|
||||
github.com/go-openapi/swag v0.19.9
|
||||
github.com/go-openapi/validate v0.19.10
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/minio/cli v1.22.0
|
||||
github.com/minio/mc v0.0.0-20200725183142-90d22b271f60
|
||||
github.com/minio/minio v0.0.0-20200725154241-abbf6ce6ccf8
|
||||
github.com/minio/minio-go/v7 v7.0.2-0.20200722162308-e0105ca08252
|
||||
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/unrolled/secure v1.0.7
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
k8s.io/api v0.18.0
|
||||
k8s.io/apimachinery v0.18.0
|
||||
k8s.io/client-go v0.18.0
|
||||
)
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
@@ -6,9 +20,12 @@ set -o pipefail
|
||||
|
||||
SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
|
||||
|
||||
GO111MODULE=off go get -d k8s.io/code-generator/...
|
||||
go get -d k8s.io/code-generator/...
|
||||
|
||||
REPOSITORY=github.com/minio/console
|
||||
# Checkout code-generator to compatible version
|
||||
#(cd $GOPATH/src/k8s.io/code-generator && git checkout origin/release-1.14 -B release-1.14)
|
||||
|
||||
REPOSITORY=github.com/minio/mcs
|
||||
$GOPATH/src/k8s.io/code-generator/generate-groups.sh all \
|
||||
$REPOSITORY/pkg/clientgen $REPOSITORY/pkg/apis networking.gke.io:v1beta2 \
|
||||
--go-header-file $SCRIPT_ROOT/hack/header.go.txt
|
||||
|
||||
BIN
images/pic1.png
BIN
images/pic1.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 635 KiB |
BIN
images/pic2.png
BIN
images/pic2.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 688 KiB |
BIN
images/pic3.png
BIN
images/pic3.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 MiB |
@@ -1,216 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_AddAccessRuleAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruleadd", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
bucket string
|
||||
prefix string
|
||||
access string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Create Access Rule - Valid",
|
||||
args: args{
|
||||
bucket: "testaccessruleadd",
|
||||
prefix: "/test/",
|
||||
access: "readonly",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Add Access Rule - Invalid",
|
||||
args: args{
|
||||
bucket: "testaccessruleadd",
|
||||
prefix: "/test/",
|
||||
access: "readonl",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Add Access Rule - Invalid Bucket",
|
||||
args: args{
|
||||
bucket: "fakebucket",
|
||||
prefix: "/test/",
|
||||
access: "readonl",
|
||||
},
|
||||
expectedStatus: 404,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["prefix"] = tt.args.prefix
|
||||
requestDataPolicy["access"] = tt.args.access
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", fmt.Sprintf("http://localhost:9090/api/v1/bucket/%s/access-rules", tt.args.bucket), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetAccessRulesAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruleget", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
bucket string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get Access Rule - Valid",
|
||||
args: args{
|
||||
bucket: "testaccessruleget",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1/bucket/%s/access-rules", tt.args.bucket), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteAccessRuleAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddBucket("testaccessruledelete", false, nil, nil, nil)
|
||||
|
||||
type args struct {
|
||||
prefix string
|
||||
access string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Delete Access Rule - Valid",
|
||||
args: args{
|
||||
prefix: "/test/",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["prefix"] = tt.args.prefix
|
||||
requestDataPolicy["access"] = tt.args.access
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"DELETE", "http://localhost:9090/api/v1/bucket/testaccessruledelete/access-rules", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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/>.
|
||||
|
||||
// These tests are for AdminAPI Tag based on swagger-console.yml
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func RestartService() (*http.Response, error) {
|
||||
/*
|
||||
Helper function to restart service
|
||||
HTTP Verb: POST
|
||||
URL: /api/v1/service/restart
|
||||
*/
|
||||
request, err := http.NewRequest(
|
||||
"POST",
|
||||
"http://localhost:9090/api/v1/service/restart",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2000 * time.Second, // increased timeout since restart takes time, more than other APIs.
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func GetNodes() (*http.Response, error) {
|
||||
/*
|
||||
Helper function to get nodes
|
||||
HTTP Verb: GET
|
||||
URL: /api/v1/nodes
|
||||
*/
|
||||
request, err := http.NewRequest(
|
||||
"GET",
|
||||
"http://localhost:9090/api/v1/nodes",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2000 * time.Second, // increased timeout since restart takes time, more than other APIs.
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func NotifyPostgres() (*http.Response, error) {
|
||||
/*
|
||||
Helper function to add Postgres Notification
|
||||
HTTP Verb: PUT
|
||||
URL: api/v1/configs/notify_postgres
|
||||
Body:
|
||||
{
|
||||
"key_values":[
|
||||
{
|
||||
"key":"connection_string",
|
||||
"value":"user=postgres password=password host=localhost dbname=postgres port=5432 sslmode=disable"
|
||||
},
|
||||
{
|
||||
"key":"table",
|
||||
"value":"accountsssss"
|
||||
},
|
||||
{
|
||||
"key":"format",
|
||||
"value":"namespace"
|
||||
},
|
||||
{
|
||||
"key":"queue_limit",
|
||||
"value":"10000"
|
||||
},
|
||||
{
|
||||
"key":"comment",
|
||||
"value":"comment"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
Body := models.SetConfigRequest{
|
||||
KeyValues: []*models.ConfigurationKV{
|
||||
{
|
||||
Key: "connection_string",
|
||||
Value: "user=postgres password=password host=173.18.0.4 dbname=postgres port=5432 sslmode=disable",
|
||||
},
|
||||
{
|
||||
Key: "table",
|
||||
Value: "accountsssss",
|
||||
},
|
||||
{
|
||||
Key: "format",
|
||||
Value: "namespace",
|
||||
},
|
||||
{
|
||||
Key: "queue_limit",
|
||||
Value: "10000",
|
||||
},
|
||||
{
|
||||
Key: "comment",
|
||||
Value: "comment",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(Body)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT",
|
||||
"http://localhost:9090/api/v1/configs/notify_postgres",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestNotifyPostgres(t *testing.T) {
|
||||
// Variables
|
||||
asserter := assert.New(t)
|
||||
|
||||
// Test
|
||||
response, err := NotifyPostgres()
|
||||
finalResponse := inspectHTTPResponse(response)
|
||||
asserter.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
asserter.Fail(finalResponse)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
asserter.Equal(200, response.StatusCode, finalResponse)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRestartService(t *testing.T) {
|
||||
asserter := assert.New(t)
|
||||
restartResponse, restartError := RestartService()
|
||||
asserter.Nil(restartError)
|
||||
if restartError != nil {
|
||||
log.Println(restartError)
|
||||
return
|
||||
}
|
||||
addObjRsp := inspectHTTPResponse(restartResponse)
|
||||
if restartResponse != nil {
|
||||
asserter.Equal(
|
||||
204,
|
||||
restartResponse.StatusCode,
|
||||
addObjRsp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func ListPoliciesWithBucket(bucketName string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to List Policies With Given Bucket
|
||||
HTTP Verb: GET
|
||||
URL: /bucket-policy/{bucket}
|
||||
*/
|
||||
request, err := http.NewRequest(
|
||||
"GET", "http://localhost:9090/api/v1/bucket-policy/"+bucketName, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestListPoliciesWithBucket(t *testing.T) {
|
||||
// Test Variables
|
||||
bucketName := "testlistpolicieswithbucket"
|
||||
asserter := assert.New(t)
|
||||
|
||||
// Test
|
||||
response, err := ListPoliciesWithBucket(bucketName)
|
||||
asserter.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
parsedResponse := inspectHTTPResponse(response)
|
||||
if response != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
response.StatusCode,
|
||||
parsedResponse,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func ListUsersWithAccessToBucket(bucketName string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to List Users With Access to a Given Bucket
|
||||
HTTP Verb: GET
|
||||
URL: /bucket-users/{bucket}
|
||||
*/
|
||||
request, err := http.NewRequest(
|
||||
"GET", "http://localhost:9090/api/v1/bucket-users/"+bucketName, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestListUsersWithAccessToBucket(t *testing.T) {
|
||||
// Test Variables
|
||||
bucketName := "testlistuserswithaccesstobucket1"
|
||||
asserter := assert.New(t)
|
||||
|
||||
// Test
|
||||
response, err := ListUsersWithAccessToBucket(bucketName)
|
||||
asserter.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
parsedResponse := inspectHTTPResponse(response)
|
||||
if response != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
response.StatusCode,
|
||||
parsedResponse,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNodes(t *testing.T) {
|
||||
asserter := assert.New(t)
|
||||
getNodesResponse, getNodesError := GetNodes()
|
||||
asserter.Nil(getNodesError)
|
||||
if getNodesError != nil {
|
||||
log.Println(getNodesError)
|
||||
return
|
||||
}
|
||||
addObjRsp := inspectHTTPResponse(getNodesResponse)
|
||||
if getNodesResponse != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
getNodesResponse.StatusCode,
|
||||
addObjRsp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func ArnList() (*http.Response, error) {
|
||||
/*
|
||||
Helper function to get arn list
|
||||
HTTP Verb: GET
|
||||
URL: /api/v1/admin/arns
|
||||
*/
|
||||
request, err := http.NewRequest(
|
||||
"GET", "http://localhost:9090/api/v1/admin/arns", nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestArnList(t *testing.T) {
|
||||
asserter := assert.New(t)
|
||||
resp, err := ArnList()
|
||||
asserter.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
objRsp := inspectHTTPResponse(resp)
|
||||
if resp != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
resp.StatusCode,
|
||||
objRsp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func ExportConfig() (*http.Response, error) {
|
||||
request, err := http.NewRequest(
|
||||
"GET", "http://localhost:9090/api/v1/configs/export", nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func ImportConfig() (*http.Response, error) {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
formFile, _ := writer.CreateFormFile("file", "sample-import-config.txt")
|
||||
fileDir, _ := os.Getwd()
|
||||
fileName := "sample-import-config.txt"
|
||||
filePath := path.Join(fileDir, fileName)
|
||||
file, _ := os.Open(filePath)
|
||||
io.Copy(formFile, file)
|
||||
writer.Close()
|
||||
request, err := http.NewRequest(
|
||||
"POST", "http://localhost:9090/api/v1/configs/import",
|
||||
bytes.NewReader(body.Bytes()),
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
rsp, _ := client.Do(request)
|
||||
if rsp.StatusCode != http.StatusOK {
|
||||
log.Printf("Request failed with response code: %d", rsp.StatusCode)
|
||||
}
|
||||
return rsp, err
|
||||
}
|
||||
|
||||
func TestExportConfig(t *testing.T) {
|
||||
asserter := assert.New(t)
|
||||
resp, err := ExportConfig()
|
||||
asserter.Nil(err)
|
||||
objRsp := inspectHTTPResponse(resp)
|
||||
if resp != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
resp.StatusCode,
|
||||
objRsp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportConfig(t *testing.T) {
|
||||
asserter := assert.New(t)
|
||||
resp, err := ImportConfig()
|
||||
asserter.Nil(err)
|
||||
objRsp := inspectHTTPResponse(resp)
|
||||
if resp != nil {
|
||||
asserter.Equal(
|
||||
200,
|
||||
resp.StatusCode,
|
||||
objRsp,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/minio/console/restapi"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
)
|
||||
|
||||
var token string
|
||||
|
||||
func encodeBase64(fileName string) string {
|
||||
/*
|
||||
Helper function to encode in base64 the file name so we can get the path
|
||||
*/
|
||||
path := b64.StdEncoding.EncodeToString([]byte(fileName))
|
||||
return path
|
||||
}
|
||||
|
||||
func inspectHTTPResponse(httpResponse *http.Response) string {
|
||||
/*
|
||||
Helper function to inspect the content of a HTTP response.
|
||||
*/
|
||||
b, err := io.ReadAll(httpResponse.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return "Http Response: " + string(b)
|
||||
}
|
||||
|
||||
func initConsoleServer() (*restapi.Server, error) {
|
||||
// os.Setenv("CONSOLE_MINIO_SERVER", "localhost:9000")
|
||||
|
||||
swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
noLog := func(string, ...interface{}) {
|
||||
// nothing to log
|
||||
}
|
||||
|
||||
// Initialize MinIO loggers
|
||||
restapi.LogInfo = noLog
|
||||
restapi.LogError = noLog
|
||||
|
||||
api := operations.NewConsoleAPI(swaggerSpec)
|
||||
api.Logger = noLog
|
||||
|
||||
server := restapi.NewServer(api)
|
||||
// register all APIs
|
||||
server.ConfigureAPI()
|
||||
|
||||
// restapi.GlobalRootCAs, restapi.GlobalPublicCerts, restapi.GlobalTLSCertsManager = globalRootCAs, globalPublicCerts, globalTLSCerts
|
||||
|
||||
consolePort, _ := strconv.Atoi("9090")
|
||||
|
||||
server.Host = "0.0.0.0"
|
||||
server.Port = consolePort
|
||||
restapi.Port = "9090"
|
||||
restapi.Hostname = "0.0.0.0"
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// start console server
|
||||
go func() {
|
||||
fmt.Println("start server")
|
||||
srv, err := initConsoleServer()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("init fail")
|
||||
return
|
||||
}
|
||||
srv.Serve()
|
||||
}()
|
||||
|
||||
fmt.Println("sleeping")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
// get login credentials
|
||||
|
||||
requestData := map[string]string{
|
||||
"accessKey": "minioadmin",
|
||||
"secretKey": "minioadmin",
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestData)
|
||||
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
|
||||
request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/login", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
for _, cookie := range response.Cookies() {
|
||||
if cookie.Name == "token" {
|
||||
token = cookie.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
log.Println("authentication token not found in cookies response")
|
||||
return
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"name": "test1",
|
||||
}
|
||||
|
||||
requestDataJSON, _ = json.Marshal(requestDataAdd)
|
||||
|
||||
requestDataBody = bytes.NewReader(requestDataJSON)
|
||||
|
||||
// delete bucket
|
||||
request, err = http.NewRequest("DELETE", "http://localhost:9090/api/v1/buckets/test1", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err = client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
fmt.Println("DELETE StatusCode:", response.StatusCode)
|
||||
}
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_ConfigAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Config - Valid",
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/configs", nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetConfigAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get Config - Valid",
|
||||
args: args{
|
||||
name: "storage_class",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Config - Invalid",
|
||||
args: args{
|
||||
name: "asdf",
|
||||
},
|
||||
expectedStatus: 404,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1/configs/%s", tt.args.name), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetConfigAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
name string
|
||||
keyValues []map[string]interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Set Config - Valid",
|
||||
args: args{
|
||||
name: "region",
|
||||
keyValues: []map[string]interface{}{{"key": "name", "value": "testServer"}, {"key": "region", "value": "us-west-1"}},
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Config - Invalid",
|
||||
args: args{
|
||||
name: "regiontest",
|
||||
keyValues: []map[string]interface{}{{"key": "name", "value": "testServer"}, {"key": "region", "value": "us-west-1"}},
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataPolicy["key_values"] = tt.args.keyValues
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", fmt.Sprintf("http://localhost:9090/api/v1/configs/%s", tt.args.name), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ResetConfigAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Reset Config - Valid",
|
||||
args: args{
|
||||
name: "region",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Reset Config - Invalid",
|
||||
args: args{
|
||||
name: "regiontest",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", fmt.Sprintf("http://localhost:9090/api/v1/configs/%s/reset", tt.args.name), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_AddGroupAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("member1", "testtest", []string{}, []string{"consoleAdmin"})
|
||||
|
||||
type args struct {
|
||||
group string
|
||||
members []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Create Group - Valid",
|
||||
args: args{
|
||||
group: "test",
|
||||
members: []string{"member1"},
|
||||
},
|
||||
expectedStatus: 201,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Create Group - Invalid",
|
||||
args: args{
|
||||
group: "test",
|
||||
members: []string{},
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["group"] = tt.args.group
|
||||
requestDataPolicy["members"] = tt.args.members
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", "http://localhost:9090/api/v1/groups", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetGroupAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("member2", "testtest", []string{}, []string{"consoleAdmin"})
|
||||
AddGroup("getgroup1", []string{"member2"})
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get Group - Valid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("getgroup1")),
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Group - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("askfjalkd")),
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListGroupsAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get Group - Valid",
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"GET", "http://localhost:9090/api/v1/groups", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PutGroupsAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("member3", "testtest", []string{}, []string{"consoleAdmin"})
|
||||
AddGroup("putgroup1", []string{})
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
members []string
|
||||
status string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Put Group - Valid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("putgroup1")),
|
||||
members: []string{"member3"},
|
||||
status: "enabled",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Put Group - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("gdgfdfgd")),
|
||||
members: []string{"member3"},
|
||||
status: "enabled",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataPolicy["members"] = tt.args.members
|
||||
requestDataPolicy["status"] = tt.args.status
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteGroupAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddGroup("grouptests1", []string{})
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
verb string
|
||||
}{
|
||||
{
|
||||
name: "Delete Group - Valid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("grouptests1")),
|
||||
},
|
||||
verb: "DELETE",
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Delete Group - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("grouptests12345")),
|
||||
},
|
||||
verb: "DELETE",
|
||||
expectedStatus: 404,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Access Group After Delete - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("grouptests1")),
|
||||
},
|
||||
verb: "GET",
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
tt.verb, fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Inspect(volume string, file string, enc bool) (*http.Response, error) {
|
||||
requestURL := fmt.Sprintf("http://localhost:9090/api/v1/admin/inspect?volume=%s&file=%s&encrypt=%t", volume, file, enc)
|
||||
request, err := http.NewRequest(
|
||||
"GET", requestURL, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestInspect(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
volume string
|
||||
file string
|
||||
encrypt bool
|
||||
}
|
||||
|
||||
// Inspect returns successful response always
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expStatusCode int
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Test Invalid Path",
|
||||
args: args{
|
||||
volume: "/test-with-slash",
|
||||
file: "/test-with-slash",
|
||||
encrypt: false,
|
||||
},
|
||||
expStatusCode: 200,
|
||||
expectedError: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Test Invalid characters in Path",
|
||||
args: args{
|
||||
volume: "//test",
|
||||
file: "//bucket",
|
||||
encrypt: false,
|
||||
},
|
||||
expStatusCode: 200,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "Test valid bucket",
|
||||
args: args{
|
||||
volume: "test-bucket",
|
||||
file: "test.txt",
|
||||
encrypt: true,
|
||||
},
|
||||
expStatusCode: 200,
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Test Empty Path", // Un processable entity error
|
||||
args: args{
|
||||
volume: "",
|
||||
file: "",
|
||||
encrypt: false,
|
||||
},
|
||||
expStatusCode: 422,
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, err := Inspect(tt.args.volume, tt.args.file, tt.args.encrypt)
|
||||
if tt.expectedError {
|
||||
assert.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if resp != nil {
|
||||
assert.Equal(
|
||||
tt.expStatusCode,
|
||||
resp.StatusCode,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLoginStrategy(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// image for now:
|
||||
// minio: 9000
|
||||
// console: 9090
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
// copy query params
|
||||
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/login", nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
response, err := client.Do(request)
|
||||
assert.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
bodyBytes, _ := io.ReadAll(response.Body)
|
||||
|
||||
loginDetails := models.LoginDetails{}
|
||||
|
||||
err = json.Unmarshal(bodyBytes, &loginDetails)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
assert.Nil(err)
|
||||
|
||||
assert.Equal(models.LoginDetailsLoginStrategyForm, loginDetails.LoginStrategy, "Login Details don't match")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// image for now:
|
||||
// minio: 9000
|
||||
// console: 9090
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
requestData := map[string]string{
|
||||
"accessKey": "minioadmin",
|
||||
"secretKey": "minioadmin",
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestData)
|
||||
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
|
||||
request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/login", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
|
||||
assert.NotNil(response, "Login response is nil")
|
||||
assert.Nil(err, "Login errored out")
|
||||
|
||||
var loginToken string
|
||||
|
||||
for _, cookie := range response.Cookies() {
|
||||
if cookie.Name == "token" {
|
||||
loginToken = cookie.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if loginToken == "" {
|
||||
log.Println("authentication token not found in cookies response")
|
||||
return
|
||||
}
|
||||
logoutRequest := bytes.NewReader([]byte("{}"))
|
||||
request, err = http.NewRequest("POST", "http://localhost:9090/api/v1/logout", logoutRequest)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", loginToken))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err = client.Do(request)
|
||||
assert.NotNil(response, "Logout response is nil")
|
||||
assert.Nil(err, "Logout errored out")
|
||||
assert.Equal(response.StatusCode, 200)
|
||||
}
|
||||
|
||||
func TestBadLogin(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
requestData := map[string]string{
|
||||
"accessKey": "minioadmin",
|
||||
"secretKey": "minioadminbad",
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestData)
|
||||
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
|
||||
request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/login", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
|
||||
assert.Equal(401, response.StatusCode, "Login request not rejected")
|
||||
assert.NotNil(response, "Login response is nil")
|
||||
assert.Nil(err, "Login errored out")
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestObjectGet(t *testing.T) {
|
||||
// for setup we'll create a bucket and upload a file
|
||||
endpoint := "localhost:9000"
|
||||
accessKeyID := "minioadmin"
|
||||
secretAccessKey := "minioadmin"
|
||||
|
||||
// Initialize minio client object.
|
||||
minioClient, err := minio.New(endpoint, &minio.Options{
|
||||
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
|
||||
Secure: false,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
bucketName := fmt.Sprintf("testbucket-%d", rand.Intn(1000-1)+1)
|
||||
err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
// upload a simple file
|
||||
fakeFile := "12345678"
|
||||
fileReader := strings.NewReader(fakeFile)
|
||||
|
||||
_, err = minioClient.PutObject(
|
||||
context.Background(),
|
||||
bucketName,
|
||||
"myobject", fileReader, int64(len(fakeFile)), minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
_, err = minioClient.PutObject(
|
||||
context.Background(),
|
||||
bucketName,
|
||||
"myobject.jpg", fileReader, int64(len(fakeFile)), minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
type args struct {
|
||||
encodedPrefix string
|
||||
versionID string
|
||||
bytesRange string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Preview Object",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject")),
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Preview image",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Range of bytes",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
bytesRange: "bytes=1-4",
|
||||
},
|
||||
expectedStatus: 206,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Range of bytes empty start",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
bytesRange: "bytes=-4",
|
||||
},
|
||||
expectedStatus: 206,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Invalid Range of bytes",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
bytesRange: "bytes=9-12",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Larger Range of bytes empty start",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
bytesRange: "bytes=-12",
|
||||
},
|
||||
expectedStatus: 206,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get invalid seek start Range of bytes",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")),
|
||||
bytesRange: "bytes=12-16",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Bad Preview Object",
|
||||
args: args{
|
||||
encodedPrefix: "garble",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Bad Version Preview Object",
|
||||
args: args{
|
||||
encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject")),
|
||||
versionID: "garble",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
destination := fmt.Sprintf("/api/v1/buckets/%s/objects/download?preview=true&prefix=%s&version_id=%s", bucketName, tt.args.encodedPrefix, tt.args.versionID)
|
||||
finalURL := fmt.Sprintf("http://localhost:9090%s", destination)
|
||||
request, err := http.NewRequest("GET", finalURL, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
if tt.args.bytesRange != "" {
|
||||
request.Header.Add("Range", tt.args.bytesRange)
|
||||
}
|
||||
|
||||
response, err := client.Do(request)
|
||||
|
||||
assert.NotNil(response, fmt.Sprintf("%s response object is nil", tt.name))
|
||||
assert.Nil(err, fmt.Sprintf("%s returned an error: %v", tt.name, err))
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, fmt.Sprintf("%s returned the wrong status code", tt.name))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func downloadMultipleFiles(bucketName string, objects []string) (*http.Response, error) {
|
||||
requestURL := fmt.Sprintf("http://localhost:9090/api/v1/buckets/%s/objects/download-multiple", bucketName)
|
||||
|
||||
postReqParams, _ := json.Marshal(objects)
|
||||
reqBody := bytes.NewReader(postReqParams)
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"POST", requestURL, reqBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestDownloadMultipleFiles(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
type args struct {
|
||||
bucketName string
|
||||
objectLis []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Test empty Bucket",
|
||||
args: args{
|
||||
bucketName: "",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "Test empty object list",
|
||||
args: args{
|
||||
bucketName: "test-bucket",
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "Test with bucket and object list",
|
||||
args: args{
|
||||
bucketName: "test-bucket",
|
||||
objectLis: []string{
|
||||
"my-object.txt",
|
||||
"test-prefix/",
|
||||
"test-prefix/nested-prefix/",
|
||||
"test-prefix/nested-prefix/deep-nested/",
|
||||
},
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, err := downloadMultipleFiles(tt.args.bucketName, tt.args.objectLis)
|
||||
if tt.expectedError {
|
||||
assert.Nil(err)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if resp != nil {
|
||||
assert.NotNil(resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,862 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func AddPolicy(name, definition string) (*http.Response, error) {
|
||||
/*
|
||||
This is an atomic function to add user and can be reused across
|
||||
different functions.
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"name": name,
|
||||
"policy": definition,
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", "http://localhost:9090/api/v1/policies", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func SetPolicy(policies []string, entityName, entityType string) (*http.Response, error) {
|
||||
/*
|
||||
This is an atomic function to add user and can be reused across
|
||||
different functions.
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"name": policies,
|
||||
"entityType": entityType,
|
||||
"entityName": entityName,
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", "http://localhost:9090/api/v1/set-policy", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func Test_AddPolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
name string
|
||||
policy *string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Create Policy - Valid",
|
||||
args: args{
|
||||
api: "/policies",
|
||||
name: "test",
|
||||
policy: swag.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
},
|
||||
expectedStatus: 201,
|
||||
expectedError: nil,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Create Policy - Invalid",
|
||||
args: args{
|
||||
api: "/policies",
|
||||
name: "test2",
|
||||
policy: swag.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation"
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Create Policy - Space in Name",
|
||||
args: args{
|
||||
api: "/policies",
|
||||
name: "space test",
|
||||
policy: swag.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
},
|
||||
expectedStatus: 400,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["name"] = tt.args.name
|
||||
if tt.args.policy != nil {
|
||||
requestDataPolicy["policy"] = *tt.args.policy
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetPolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("policyuser1", "testtest", []string{}, []string{"readwrite"})
|
||||
AddGroup("testgroup123", []string{})
|
||||
AddPolicy("setpolicytest", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
entityType string
|
||||
entityName string
|
||||
policyName []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Set Policy - Valid",
|
||||
args: args{
|
||||
api: "/set-policy",
|
||||
policyName: []string{"setpolicytest"},
|
||||
entityType: "user",
|
||||
entityName: "policyuser1",
|
||||
},
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy - Invalid",
|
||||
args: args{
|
||||
api: "/set-policy",
|
||||
policyName: []string{"test3"},
|
||||
entityType: "user",
|
||||
entityName: "policyuser1",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy Group - Valid",
|
||||
args: args{
|
||||
api: "/set-policy",
|
||||
policyName: []string{"setpolicytest"},
|
||||
entityType: "group",
|
||||
entityName: "testgroup123",
|
||||
},
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy Group - Invalid",
|
||||
args: args{
|
||||
api: "/set-policy",
|
||||
policyName: []string{"test3"},
|
||||
entityType: "group",
|
||||
entityName: "testgroup123",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["entityName"] = tt.args.entityName
|
||||
requestDataPolicy["entityType"] = tt.args.entityType
|
||||
if tt.args.policyName != nil {
|
||||
requestDataPolicy["name"] = tt.args.policyName
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetPolicyMultipleAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("policyuser2", "testtest", []string{}, []string{"readwrite"})
|
||||
AddUser("policyuser3", "testtest", []string{}, []string{"readwrite"})
|
||||
AddGroup("testgroup1234", []string{})
|
||||
AddPolicy("setpolicytest2", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
users []string
|
||||
groups []string
|
||||
name []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Set Policy - Valid",
|
||||
args: args{
|
||||
api: "/set-policy-multi",
|
||||
name: []string{"setpolicytest2"},
|
||||
users: []string{"policyuser2", "policyuser3"},
|
||||
},
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy - Invalid",
|
||||
args: args{
|
||||
api: "/set-policy-multi",
|
||||
name: []string{"test3"},
|
||||
users: []string{"policyuser2", "policyuser3"},
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy Group - Valid",
|
||||
args: args{
|
||||
api: "/set-policy-multi",
|
||||
name: []string{"setpolicytest2"},
|
||||
groups: []string{"testgroup1234"},
|
||||
},
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Set Policy Group - Valid",
|
||||
args: args{
|
||||
api: "/set-policy-multi",
|
||||
name: []string{"setpolicytest23"},
|
||||
groups: []string{"testgroup1234"},
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
requestDataPolicy["name"] = tt.args.name
|
||||
requestDataPolicy["users"] = tt.args.users
|
||||
requestDataPolicy["groups"] = tt.args.groups
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ListPoliciesAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "List Policies",
|
||||
args: args{
|
||||
api: "/policies",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetPolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddPolicy("getpolicytest", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get Policies - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("test3")),
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Policies - Valid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("getpolicytest")),
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PolicyListUsersAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddUser("policyuser4", "testtest", []string{}, []string{"readwrite"})
|
||||
AddPolicy("policylistusers", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
SetPolicy([]string{"policylistusers"}, "policyuser4", "user")
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "List Users for Policy - Valid",
|
||||
args: args{
|
||||
api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistusers")) + "/users",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "List Users for Policy - Invalid",
|
||||
args: args{
|
||||
api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test2")) + "/users",
|
||||
},
|
||||
expectedStatus: 404,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
bodyBytes, _ := io.ReadAll(response.Body)
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
if response.StatusCode == 200 {
|
||||
assert.Equal("[\"policyuser4\"]\n", string(bodyBytes))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PolicyListGroupsAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddGroup("testgroup12345", []string{})
|
||||
AddPolicy("policylistgroups", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
SetPolicy([]string{"policylistgroups"}, "testgroup12345", "group")
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "List Users for Policy - Valid",
|
||||
args: args{
|
||||
api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistgroups")) + "/groups",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "List Users for Policy - Invalid",
|
||||
args: args{
|
||||
api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test3")) + "/groups",
|
||||
},
|
||||
expectedStatus: 404,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
bodyBytes, _ := io.ReadAll(response.Body)
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
if response.StatusCode == 200 {
|
||||
assert.Equal("[\"testgroup12345\"]\n", string(bodyBytes))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeletePolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
AddPolicy("testdelete", `
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
type args struct {
|
||||
api string
|
||||
method string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Delete Policies - Valid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("testdelete")),
|
||||
method: "DELETE",
|
||||
},
|
||||
expectedStatus: 204,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get Policy After Delete - Invalid",
|
||||
args: args{
|
||||
api: base64.StdEncoding.EncodeToString([]byte("testdelete")),
|
||||
method: "GET",
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
tt.args.method, fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetAUserPolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// Create a User with a Policy to use for testing
|
||||
groups := []string{}
|
||||
policies := []string{"readwrite"}
|
||||
_, err := AddUser("getuserpolicyuser", "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
// encode usernames to pass to api
|
||||
bName := []byte("getuserpolicyuser")
|
||||
fName := []byte("failname")
|
||||
encodedName := base64.URLEncoding.EncodeToString(bName)
|
||||
encodedFailName := base64.URLEncoding.EncodeToString(fName)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get User Policy - Invalid",
|
||||
args: args{
|
||||
api: "/user/" + encodedFailName + "/policies",
|
||||
},
|
||||
expectedStatus: 401,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Get User Policy - Valid",
|
||||
args: args{
|
||||
api: "/user/" + encodedName + "/policies",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/minio/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStartProfiling(t *testing.T) {
|
||||
testAssert := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
}{
|
||||
{
|
||||
name: "start/stop profiling",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
files := map[string]bool{
|
||||
"profile-127.0.0.1:9000-goroutines.txt": false,
|
||||
"profile-127.0.0.1:9000-goroutines-before.txt": false,
|
||||
"profile-127.0.0.1:9000-goroutines-before,debug=2.txt": false,
|
||||
"profile-127.0.0.1:9000-threads-before.pprof": false,
|
||||
"profile-127.0.0.1:9000-mem.pprof": false,
|
||||
"profile-127.0.0.1:9000-threads.pprof": false,
|
||||
"profile-127.0.0.1:9000-cpu.pprof": false,
|
||||
"profile-127.0.0.1:9000-mem-before.pprof": false,
|
||||
"profile-127.0.0.1:9000-block.pprof": false,
|
||||
"profile-127.0.0.1:9000-trace.trace": false,
|
||||
"profile-127.0.0.1:9000-mutex.pprof": false,
|
||||
"profile-127.0.0.1:9000-mutex-before.pprof": false,
|
||||
}
|
||||
|
||||
wsDestination := "/ws/profile?types=cpu,mem,block,mutex,trace,threads,goroutines"
|
||||
wsFinalURL := fmt.Sprintf("ws://localhost:9090%s", wsDestination)
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.Dial(wsFinalURL, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
_, zipFileBytes, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
filetype := http.DetectContentType(zipFileBytes)
|
||||
testAssert.Equal("application/zip", filetype)
|
||||
|
||||
zipReader, err := zip.NewReader(bytes.NewReader(zipFileBytes), int64(len(zipFileBytes)))
|
||||
if err != nil {
|
||||
testAssert.Nil(err, fmt.Sprintf("%s returned an error: %v", tt.name, err))
|
||||
}
|
||||
|
||||
// Read all the files from zip archive
|
||||
for _, zipFile := range zipReader.File {
|
||||
files[zipFile.Name] = true
|
||||
}
|
||||
|
||||
for k, v := range files {
|
||||
testAssert.Equal(true, v, fmt.Sprintf("%s : compressed file expected to have %v file inside", tt.name, k))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
subnet license= api_key= proxy=
|
||||
# callhome enable=off frequency=24h
|
||||
# site name= region=
|
||||
# api requests_max=0 requests_deadline=10s cluster_deadline=10s cors_allow_origin=* remote_transport_deadline=2h list_quorum=strict replication_priority=auto transition_workers=100 stale_uploads_cleanup_interval=6h stale_uploads_expiry=24h delete_cleanup_interval=5m disable_odirect=off gzip_objects=off
|
||||
# scanner speed=default
|
||||
# compression enable=off allow_encryption=off extensions=.txt,.log,.csv,.json,.tar,.xml,.bin mime_types=text/*,application/json,application/xml,binary/octet-stream
|
||||
# identity_openid enable= display_name= config_url= client_id= client_secret= claim_name=policy claim_userinfo= role_policy= claim_prefix= redirect_uri= redirect_uri_dynamic=off scopes= vendor= keycloak_realm= keycloak_admin_url=
|
||||
# identity_ldap server_addr= srv_record_name= user_dn_search_base_dn= user_dn_search_filter= group_search_filter= group_search_base_dn= tls_skip_verify=off server_insecure=off server_starttls=off lookup_bind_dn= lookup_bind_password=
|
||||
# identity_tls skip_verify=off
|
||||
# identity_plugin url= auth_token= role_policy= role_id=
|
||||
# policy_plugin url= auth_token= enable_http2=off
|
||||
# logger_webhook enable=off endpoint= auth_token= client_cert= client_key= queue_size=100000
|
||||
# audit_webhook enable=off endpoint= auth_token= client_cert= client_key= queue_size=100000
|
||||
# audit_kafka enable=off topic= brokers= sasl_username= sasl_password= sasl_mechanism=plain client_tls_cert= client_tls_key= tls_client_auth=0 sasl=off tls=off tls_skip_verify=off version=
|
||||
# notify_webhook enable=off endpoint= auth_token= queue_limit=0 queue_dir= client_cert= client_key=
|
||||
# notify_amqp enable=off url= exchange= exchange_type= routing_key= mandatory=off durable=off no_wait=off internal=off auto_deleted=off delivery_mode=0 publisher_confirms=off queue_limit=0 queue_dir=
|
||||
# notify_kafka enable=off topic= brokers= sasl_username= sasl_password= sasl_mechanism=plain client_tls_cert= client_tls_key= tls_client_auth=0 sasl=off tls=off tls_skip_verify=off queue_limit=0 queue_dir= version=
|
||||
# notify_mqtt enable=off broker= topic= password= username= qos=0 keep_alive_interval=0s reconnect_interval=0s queue_dir= queue_limit=0
|
||||
# notify_nats enable=off address= subject= username= password= token= tls=off tls_skip_verify=off cert_authority= client_cert= client_key= ping_interval=0 jetstream=off streaming=off streaming_async=off streaming_max_pub_acks_in_flight=0 streaming_cluster_id= queue_dir= queue_limit=0
|
||||
# notify_nsq enable=off nsqd_address= topic= tls=off tls_skip_verify=off queue_dir= queue_limit=0
|
||||
# notify_mysql enable=off format=namespace dsn_string= table= queue_dir= queue_limit=0 max_open_connections=2
|
||||
# notify_postgres enable=off format=namespace connection_string= table= queue_dir= queue_limit=0 max_open_connections=2
|
||||
# notify_elasticsearch enable=off url= format=namespace index= queue_dir= queue_limit=0 username= password=
|
||||
# notify_redis enable=off format=namespace address= key= password= queue_dir= queue_limit=0
|
||||
# etcd endpoints= path_prefix= coredns_path=/skydns client_cert= client_cert_key=
|
||||
# cache drives= exclude= expiry=90 quota=80 after=0 watermark_low=70 watermark_high=80 range=on commit=
|
||||
# storage_class standard= rrs=EC:1
|
||||
# heal bitrotscan=off max_sleep=1s max_io=100
|
||||
@@ -1,349 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddServiceAccount(t *testing.T) {
|
||||
/*
|
||||
This is an atomic API Test to add a user service account, the intention
|
||||
is simple, add a user and make sure the response is 201 meaning that the
|
||||
user got added successfully.
|
||||
After test completion, it is expected that user is removed, so other
|
||||
tests like users.ts can run over clean data and we don't collide against
|
||||
it.
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
// Add service account
|
||||
requestDataAddServiceAccount := map[string]interface{}{
|
||||
"accessKey": "testuser1",
|
||||
"secretKey": "password",
|
||||
"policy": `{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataAddServiceAccount)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", "http://localhost:9090/api/v1/service-account-credentials", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// {{baseUrl}}/user?name=proident velit
|
||||
// Investiga como se borra en el browser.
|
||||
request, err = http.NewRequest(
|
||||
"DELETE", "http://localhost:9090/api/v1/service-accounts/"+base64.StdEncoding.EncodeToString([]byte("testuser1")), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err = client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("DELETE StatusCode:", response.StatusCode)
|
||||
assert.Equal(204, response.StatusCode, "has to be 204 when delete user")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ServiceAccountsAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
policy *string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Create Service Account - Default",
|
||||
args: args{
|
||||
api: "/service-accounts",
|
||||
policy: nil,
|
||||
},
|
||||
expectedStatus: 201,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Create Service Account - Valid Policy",
|
||||
args: args{
|
||||
api: "/service-accounts",
|
||||
policy: swag.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
},
|
||||
expectedStatus: 201,
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "Create Service Account - Invalid Policy",
|
||||
args: args{
|
||||
api: "/service-accounts",
|
||||
policy: swag.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetBucketLocation"
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
},
|
||||
expectedStatus: 500,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
// Add service account
|
||||
|
||||
requestDataPolicy := map[string]interface{}{}
|
||||
if tt.args.policy != nil {
|
||||
requestDataPolicy["policy"] = *tt.args.policy
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataPolicy)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteMultipleServiceAccounts(serviceAccounts []string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to delete multiple service accounts
|
||||
URL: http://localhost:9001/api/v1/service-accounts/delete-multi
|
||||
HTTP Verb: DELETE
|
||||
Data: ["U3RADB7J2ZZHELR0WSBB","ZE8H1HYOA6AVGKFCV6YU"]
|
||||
Response: Status Code: 204 No Content
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(serviceAccounts)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"DELETE", "http://localhost:9090/api/v1/service-accounts/delete-multi", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestCreateServiceAccountForUserWithCredentials(t *testing.T) {
|
||||
/*
|
||||
To test creation of service account for a user.
|
||||
*/
|
||||
|
||||
// Test's variables
|
||||
userName := "testcreateserviceaccountforuserwithcredentials1"
|
||||
assert := assert.New(t)
|
||||
policy := ""
|
||||
|
||||
// 1. Create the user
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
secretKey := "testcreateserviceaccountforuserwithcrede"
|
||||
response, err := AddUser(userName, "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// Table driven testing part
|
||||
type args struct {
|
||||
accessKey string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
name: "Service Account With Valid Credentials",
|
||||
expectedStatus: 201,
|
||||
args: args{
|
||||
accessKey: "testcreateserviceacc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Service Account With Invalid Credentials",
|
||||
expectedStatus: 500,
|
||||
args: args{
|
||||
accessKey: "tooooooooooooooooooooolongggggggggggggggggg",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// 2. Create the service account for the user
|
||||
createServiceAccountWithCredentialsResponse,
|
||||
createServiceAccountWithCredentialsError := CreateServiceAccountForUserWithCredentials(
|
||||
userName,
|
||||
policy,
|
||||
tt.args.accessKey,
|
||||
secretKey,
|
||||
)
|
||||
if createServiceAccountWithCredentialsError != nil {
|
||||
log.Println(createServiceAccountWithCredentialsError)
|
||||
assert.Fail("Error in createServiceAccountWithCredentialsError")
|
||||
}
|
||||
if createServiceAccountWithCredentialsResponse != nil {
|
||||
fmt.Println("StatusCode:", createServiceAccountWithCredentialsResponse.StatusCode)
|
||||
assert.Equal(
|
||||
tt.expectedStatus, // different status expected per table's row
|
||||
createServiceAccountWithCredentialsResponse.StatusCode,
|
||||
inspectHTTPResponse(createServiceAccountWithCredentialsResponse),
|
||||
)
|
||||
}
|
||||
|
||||
// 3. Verify the service account for the user
|
||||
listOfAccountsResponse,
|
||||
listOfAccountsError := ReturnsAListOfServiceAccountsForAUser(userName)
|
||||
if listOfAccountsError != nil {
|
||||
log.Println(listOfAccountsError)
|
||||
assert.Fail("Error in listOfAccountsError")
|
||||
}
|
||||
finalResponse := inspectHTTPResponse(listOfAccountsResponse)
|
||||
if listOfAccountsResponse != nil {
|
||||
fmt.Println("StatusCode:", listOfAccountsResponse.StatusCode)
|
||||
assert.Equal(
|
||||
200, listOfAccountsResponse.StatusCode,
|
||||
finalResponse,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Delete Multiple Service Accounts
|
||||
serviceAccount := make([]string, 1)
|
||||
serviceAccount[0] = "testcreateserviceacc"
|
||||
response, err = DeleteMultipleServiceAccounts(serviceAccount)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("StatusCode:", response.StatusCode)
|
||||
assert.Equal(
|
||||
204,
|
||||
response.StatusCode,
|
||||
inspectHTTPResponse(response),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTiersList(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// image for now:
|
||||
// minio: 9000
|
||||
// console: 9090
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/admin/tiers", nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
|
||||
assert.NotNil(response, "Tiers List response is nil")
|
||||
assert.Nil(err, "Tiers List errored out")
|
||||
assert.Equal(response.StatusCode, 200)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,919 +0,0 @@
|
||||
// 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 integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func AddUser(accessKey, secretKey string, groups, policies []string) (*http.Response, error) {
|
||||
/*
|
||||
This is an atomic function to add user and can be reused across
|
||||
different functions.
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"accessKey": accessKey,
|
||||
"secretKey": secretKey,
|
||||
"groups": groups,
|
||||
"policies": policies,
|
||||
}
|
||||
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST", "http://localhost:9090/api/v1/users", requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func DeleteUser(userName string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
/*
|
||||
This is an atomic function to delete user and can be reused across
|
||||
different functions.
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"DELETE", "http://localhost:9090/api/v1/user/"+userName, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func ListUsers(offset, limit string) (*http.Response, error) {
|
||||
/*
|
||||
This is an atomic function to list users.
|
||||
{{baseUrl}}/users?offset=-5480083&limit=-5480083
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"GET",
|
||||
"http://localhost:9090/api/v1/users?offset="+offset+"&limit="+limit,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func GetUserInformation(userName string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
/*
|
||||
Helper function to get user information via API:
|
||||
{{baseUrl}}/user?name=proident velit
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"GET",
|
||||
"http://localhost:9090/api/v1/user/"+userName,
|
||||
nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func UpdateUserInformation(name, status string, groups []string) (*http.Response, error) {
|
||||
name = base64.StdEncoding.EncodeToString([]byte(name))
|
||||
/*
|
||||
Helper function to update user information:
|
||||
PUT: {{baseUrl}}/user?name=proident velit
|
||||
Body:
|
||||
{
|
||||
"status": "nisi voluptate amet ea",
|
||||
"groups": [
|
||||
"ipsum eu cupidatat",
|
||||
"aliquip non nulla"
|
||||
]
|
||||
}
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"status": status,
|
||||
"groups": groups,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT", "http://localhost:9090/api/v1/user/"+name, requestDataBody)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func RemoveUser(name string) (*http.Response, error) {
|
||||
name = base64.StdEncoding.EncodeToString([]byte(name))
|
||||
/*
|
||||
Helper function to remove user.
|
||||
DELETE: {{baseUrl}}/user?name=proident velit
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"DELETE", "http://localhost:9090/api/v1/user/"+name, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
/*
|
||||
Helper function to update groups for a user
|
||||
PUT: {{baseUrl}}/user/groups?name=username
|
||||
{
|
||||
"groups":[
|
||||
"groupone",
|
||||
"grouptwo"
|
||||
]
|
||||
}
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"groups": groups,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT",
|
||||
"http://localhost:9090/api/v1/user/"+userName+"/groups",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func CreateServiceAccountForUser(userName, policy string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
/*
|
||||
Helper function to Create Service Account for user
|
||||
POST: api/v1/user/username/service-accounts
|
||||
{
|
||||
"policy": "ad magna"
|
||||
}
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"policy": policy,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST",
|
||||
"http://localhost:9090/api/v1/user/"+userName+"/service-accounts",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, secretKey string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
// Helper function to test "Create Service Account for User With Credentials" end point.
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"policy": policy,
|
||||
"accessKey": accessKey,
|
||||
"secretKey": secretKey,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST",
|
||||
"http://localhost:9090/api/v1/user/"+userName+"/service-account-credentials",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func ReturnsAListOfServiceAccountsForAUser(userName string) (*http.Response, error) {
|
||||
userName = base64.StdEncoding.EncodeToString([]byte(userName))
|
||||
/*
|
||||
Helper function to return a list of service accounts for a user.
|
||||
GET: {{baseUrl}}/user/:name/service-accounts
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
"GET",
|
||||
"http://localhost:9090/api/v1/user/"+userName+"/service-accounts",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func AddGroup(group string, members []string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to add a group.
|
||||
*/
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"group": group,
|
||||
"members": members,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"POST",
|
||||
"http://localhost:9090/api/v1/groups",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func UsersGroupsBulk(users, groups []string) (*http.Response, error) {
|
||||
/*
|
||||
Helper function to test Bulk functionality to Add Users to Groups.
|
||||
PUT: {{baseUrl}}/users-groups-bulk
|
||||
{
|
||||
"users": [
|
||||
"magna id",
|
||||
"enim sit tempor incididunt"
|
||||
],
|
||||
"groups": [
|
||||
"nisi est esse",
|
||||
"fugiat eu"
|
||||
]
|
||||
}
|
||||
*/
|
||||
requestDataAdd := map[string]interface{}{
|
||||
"users": users,
|
||||
"groups": groups,
|
||||
}
|
||||
requestDataJSON, _ := json.Marshal(requestDataAdd)
|
||||
requestDataBody := bytes.NewReader(requestDataJSON)
|
||||
request, err := http.NewRequest(
|
||||
"PUT",
|
||||
"http://localhost:9090/api/v1/users-groups-bulk",
|
||||
requestDataBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
response, err := client.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func TestAddUser(t *testing.T) {
|
||||
/*
|
||||
This is an API Test to add a user via api/v1/users, the intention
|
||||
is simple, add a user and make sure the response is 201 meaning that the
|
||||
user got added successfully.
|
||||
After test completion, it is expected that user is removed, so other
|
||||
tests like users.ts can run over clean data and we don't collide against
|
||||
it.
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// With no groups & no policies
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
response, err := AddUser("accessKey", "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
response, err = DeleteUser("accessKey")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("DELETE StatusCode:", response.StatusCode)
|
||||
assert.Equal(204, response.StatusCode, "has to be 204 when delete user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestListUsers(t *testing.T) {
|
||||
/*
|
||||
This test is intended to list users via API.
|
||||
1. First, it creates the users
|
||||
2. Then, it lists the users <------ 200 is expected when listing them.
|
||||
3. Finally, it deletes the users
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// With no groups & no policies
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
|
||||
// 1. Create the users
|
||||
numberOfUsers := 5
|
||||
for i := 1; i < numberOfUsers; i++ {
|
||||
response, err := AddUser(
|
||||
strconv.Itoa(i)+"accessKey"+strconv.Itoa(i),
|
||||
"secretKey"+strconv.Itoa(i), groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode,
|
||||
"Status Code is incorrect on index: "+strconv.Itoa(i))
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
// 2. List the users
|
||||
listResponse, listError := ListUsers("-5480083", "-5480083")
|
||||
if listError != nil {
|
||||
log.Fatalln(listError)
|
||||
}
|
||||
if listResponse != nil {
|
||||
fmt.Println("POST StatusCode:", listResponse.StatusCode)
|
||||
assert.Equal(200, listResponse.StatusCode,
|
||||
"TestListUsers(): Status Code is incorrect when listing users")
|
||||
}
|
||||
b, err := io.ReadAll(listResponse.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
|
||||
// 3. Delete the users
|
||||
for i := 1; i < numberOfUsers; i++ {
|
||||
response, err := DeleteUser(
|
||||
strconv.Itoa(i) + "accessKey" + strconv.Itoa(i))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("DELETE StatusCode:", response.StatusCode)
|
||||
assert.Equal(204,
|
||||
response.StatusCode, "has to be 204 when delete user")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserInfo(t *testing.T) {
|
||||
/*
|
||||
Test to get the user information via API.
|
||||
*/
|
||||
|
||||
// 1. Create the user
|
||||
fmt.Println("TestGetUserInfo(): 1. Create the user")
|
||||
assert := assert.New(t)
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
response, err := AddUser("accessKey", "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Get user information
|
||||
fmt.Println("TestGetUserInfo(): 2. Get user information")
|
||||
response, err = GetUserInformation("accessKey")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
assert.Fail("There was an error in the response")
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Verify user information
|
||||
fmt.Println("TestGetUserInfo(): 3. Verify user information")
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(200, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
b, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
expected := "{\"accessKey\":\"accessKey\",\"memberOf\":null,\"policy\":[],\"status\":\"enabled\"}\n"
|
||||
obtained := string(b)
|
||||
assert.Equal(expected, obtained, "User Information is wrong")
|
||||
}
|
||||
|
||||
func TestUpdateUserInfoSuccessfulResponse(t *testing.T) {
|
||||
/*
|
||||
Update User Information Test with Successful Response
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// 1. Create an active user
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
addUserResponse, addUserError := AddUser(
|
||||
"updateuser", "secretKey", groups, policies)
|
||||
if addUserError != nil {
|
||||
log.Println(addUserError)
|
||||
return
|
||||
}
|
||||
if addUserResponse != nil {
|
||||
fmt.Println("StatusCode:", addUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
201, addUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Deactivate the user
|
||||
// '{"status":"disabled","groups":[]}'
|
||||
updateUserResponse, UpdateUserError := UpdateUserInformation(
|
||||
"updateuser", "disabled", groups)
|
||||
|
||||
// 3. Verify user got deactivated
|
||||
if UpdateUserError != nil {
|
||||
log.Println(UpdateUserError)
|
||||
return
|
||||
}
|
||||
if updateUserResponse != nil {
|
||||
fmt.Println("StatusCode:", updateUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
200, updateUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
b, err := io.ReadAll(updateUserResponse.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
assert.True(strings.Contains(string(b), "disabled"))
|
||||
}
|
||||
|
||||
func TestUpdateUserInfoGenericErrorResponse(t *testing.T) {
|
||||
/*
|
||||
Update User Information Test with Generic Error Response
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// 1. Create an active user
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
addUserResponse, addUserError := AddUser(
|
||||
"updateusererror", "secretKey", groups, policies)
|
||||
if addUserError != nil {
|
||||
log.Println(addUserError)
|
||||
return
|
||||
}
|
||||
if addUserResponse != nil {
|
||||
fmt.Println("StatusCode:", addUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
201, addUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Deactivate the user with wrong status
|
||||
updateUserResponse, UpdateUserError := UpdateUserInformation(
|
||||
"updateusererror", "inactive", groups)
|
||||
|
||||
// 3. Verify user got deactivated
|
||||
if UpdateUserError != nil {
|
||||
log.Println(UpdateUserError)
|
||||
assert.Fail("There was an error while updating user info")
|
||||
return
|
||||
}
|
||||
if updateUserResponse != nil {
|
||||
fmt.Println("StatusCode:", updateUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
500, updateUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
b, err := io.ReadAll(updateUserResponse.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
assert.True(strings.Contains(string(b), "status not valid"))
|
||||
}
|
||||
|
||||
func TestRemoveUserSuccessfulResponse(t *testing.T) {
|
||||
/*
|
||||
To test removing a user from API
|
||||
*/
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// 1. Create an active user
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
addUserResponse, addUserError := AddUser(
|
||||
"testremoveuser1", "secretKey", groups, policies)
|
||||
if addUserError != nil {
|
||||
log.Println(addUserError)
|
||||
return
|
||||
}
|
||||
if addUserResponse != nil {
|
||||
fmt.Println("StatusCode:", addUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
201, addUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Remove the user
|
||||
removeUserResponse, removeUserError := RemoveUser("testremoveuser1")
|
||||
if removeUserError != nil {
|
||||
log.Println(removeUserError)
|
||||
return
|
||||
}
|
||||
if removeUserResponse != nil {
|
||||
fmt.Println("StatusCode:", removeUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
204, removeUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 3. Verify the user got removed
|
||||
getUserInfoResponse, getUserInfoError := GetUserInformation(
|
||||
"testremoveuser1")
|
||||
if getUserInfoError != nil {
|
||||
log.Println(getUserInfoError)
|
||||
assert.Fail("There was an error in the response")
|
||||
return
|
||||
}
|
||||
if getUserInfoResponse != nil {
|
||||
fmt.Println("StatusCode:", getUserInfoResponse.StatusCode)
|
||||
assert.Equal(
|
||||
404, getUserInfoResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
finalResponse := inspectHTTPResponse(getUserInfoResponse)
|
||||
fmt.Println(finalResponse)
|
||||
assert.True(strings.Contains(
|
||||
finalResponse, "The specified user does not exist"), finalResponse)
|
||||
}
|
||||
|
||||
func TestUpdateGroupsForAUser(t *testing.T) {
|
||||
/*
|
||||
To test Update Groups For a User End Point.
|
||||
*/
|
||||
|
||||
// 1. Create the user
|
||||
numberOfGroups := 3
|
||||
groupName := "updategroupforausergroup"
|
||||
userName := "updategroupsforauser1"
|
||||
assert := assert.New(t)
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
response, err := AddUser(userName, "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Update the groups of the created user with newGroups
|
||||
newGroups := make([]string, 3)
|
||||
for i := 0; i < numberOfGroups; i++ {
|
||||
newGroups[i] = groupName + strconv.Itoa(i)
|
||||
}
|
||||
response, err = UpdateGroupsForAUser(userName, newGroups)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("StatusCode:", response.StatusCode)
|
||||
assert.Equal(200, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 3. Verify the newGroups were updated accordingly
|
||||
getUserInfoResponse, getUserInfoErr := GetUserInformation(userName)
|
||||
if getUserInfoErr != nil {
|
||||
log.Println(getUserInfoErr)
|
||||
assert.Fail("There was an error in the response")
|
||||
return
|
||||
}
|
||||
if getUserInfoResponse != nil {
|
||||
fmt.Println("StatusCode:", getUserInfoResponse.StatusCode)
|
||||
assert.Equal(
|
||||
200, getUserInfoResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
finalResponse := inspectHTTPResponse(getUserInfoResponse)
|
||||
for i := 0; i < numberOfGroups; i++ {
|
||||
assert.True(strings.Contains(
|
||||
finalResponse, groupName+strconv.Itoa(i)), finalResponse)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateServiceAccountForUser(t *testing.T) {
|
||||
/*
|
||||
To test creation of service account for a user.
|
||||
*/
|
||||
|
||||
// Test's variables
|
||||
userName := "testcreateserviceaccountforuser1"
|
||||
assert := assert.New(t)
|
||||
policy := ""
|
||||
|
||||
// 1. Create the user
|
||||
groups := []string{}
|
||||
policies := []string{}
|
||||
response, err := AddUser(userName, "secretKey", groups, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
// 2. Create the service account for the user
|
||||
createServiceAccountResponse,
|
||||
createServiceAccountError := CreateServiceAccountForUser(
|
||||
userName,
|
||||
policy,
|
||||
)
|
||||
if createServiceAccountError != nil {
|
||||
log.Println(createServiceAccountError)
|
||||
assert.Fail("Error in createServiceAccountError")
|
||||
}
|
||||
if createServiceAccountResponse != nil {
|
||||
fmt.Println("StatusCode:", createServiceAccountResponse.StatusCode)
|
||||
assert.Equal(
|
||||
201, createServiceAccountResponse.StatusCode,
|
||||
inspectHTTPResponse(createServiceAccountResponse),
|
||||
)
|
||||
}
|
||||
|
||||
// 3. Verify the service account for the user
|
||||
listOfAccountsResponse, listOfAccountsError := ReturnsAListOfServiceAccountsForAUser(userName)
|
||||
|
||||
fmt.Println(listOfAccountsResponse, listOfAccountsError)
|
||||
|
||||
if listOfAccountsError != nil {
|
||||
log.Println(listOfAccountsError)
|
||||
assert.Fail("Error in listOfAccountsError")
|
||||
}
|
||||
finalResponse := inspectHTTPResponse(listOfAccountsResponse)
|
||||
if listOfAccountsResponse != nil {
|
||||
fmt.Println("StatusCode:", listOfAccountsResponse.StatusCode)
|
||||
assert.Equal(
|
||||
200, listOfAccountsResponse.StatusCode,
|
||||
finalResponse,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersGroupsBulk(t *testing.T) {
|
||||
/*
|
||||
To test UsersGroupsBulk End Point
|
||||
*/
|
||||
|
||||
// Vars
|
||||
assert := assert.New(t)
|
||||
numberOfUsers := 5
|
||||
numberOfGroups := 1
|
||||
// var groups = []string{}
|
||||
policies := []string{}
|
||||
username := "testusersgroupbulk"
|
||||
groupName := "testusersgroupsbulkgroupone"
|
||||
members := []string{}
|
||||
users := make([]string, numberOfUsers)
|
||||
groups := make([]string, numberOfGroups)
|
||||
|
||||
// 1. Create some users
|
||||
for i := 0; i < numberOfUsers; i++ {
|
||||
users[i] = username + strconv.Itoa(i)
|
||||
response, err := AddUser(
|
||||
users[i],
|
||||
"secretKey"+strconv.Itoa(i), []string{}, policies)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
fmt.Println("POST StatusCode:", response.StatusCode)
|
||||
assert.Equal(201, response.StatusCode,
|
||||
"Status Code is incorrect on index: "+strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Create a group with no members
|
||||
responseAddGroup, errorAddGroup := AddGroup(groupName, members)
|
||||
if errorAddGroup != nil {
|
||||
log.Println(errorAddGroup)
|
||||
return
|
||||
}
|
||||
finalResponse := inspectHTTPResponse(responseAddGroup)
|
||||
if responseAddGroup != nil {
|
||||
fmt.Println("POST StatusCode:", responseAddGroup.StatusCode)
|
||||
assert.Equal(
|
||||
201,
|
||||
responseAddGroup.StatusCode,
|
||||
finalResponse,
|
||||
)
|
||||
}
|
||||
|
||||
// 3. Add users to the group
|
||||
groups[0] = groupName
|
||||
responseUsersGroupsBulk, errorUsersGroupsBulk := UsersGroupsBulk(
|
||||
users,
|
||||
groups,
|
||||
)
|
||||
if errorUsersGroupsBulk != nil {
|
||||
log.Println(errorUsersGroupsBulk)
|
||||
return
|
||||
}
|
||||
finalResponse = inspectHTTPResponse(responseUsersGroupsBulk)
|
||||
if responseUsersGroupsBulk != nil {
|
||||
fmt.Println("POST StatusCode:", responseUsersGroupsBulk.StatusCode)
|
||||
assert.Equal(
|
||||
200,
|
||||
responseUsersGroupsBulk.StatusCode,
|
||||
finalResponse,
|
||||
)
|
||||
}
|
||||
|
||||
// 4. Verify users got added to the group
|
||||
for i := 0; i < numberOfUsers; i++ {
|
||||
responseGetUserInfo, errGetUserInfo := GetUserInformation(
|
||||
username + strconv.Itoa(i),
|
||||
)
|
||||
if errGetUserInfo != nil {
|
||||
log.Println(errGetUserInfo)
|
||||
assert.Fail("There was an error in the response")
|
||||
return
|
||||
}
|
||||
finalResponse = inspectHTTPResponse(responseGetUserInfo)
|
||||
if responseGetUserInfo != nil {
|
||||
assert.Equal(200, responseGetUserInfo.StatusCode, finalResponse)
|
||||
}
|
||||
// Make sure the user belongs to the created group
|
||||
assert.True(strings.Contains(finalResponse, groupName))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetUserPolicyAPI(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// 1. Create an active user with valid policy
|
||||
groups := []string{}
|
||||
policies := []string{"readwrite"}
|
||||
addUserResponse, addUserError := AddUser(
|
||||
"getpolicyuser", "secretKey", groups, policies)
|
||||
if addUserError != nil {
|
||||
log.Println(addUserError)
|
||||
return
|
||||
}
|
||||
if addUserResponse != nil {
|
||||
fmt.Println("StatusCode:", addUserResponse.StatusCode)
|
||||
assert.Equal(
|
||||
201, addUserResponse.StatusCode, "Status Code is incorrect")
|
||||
}
|
||||
|
||||
type args struct {
|
||||
api string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedStatus int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "Get User Policies",
|
||||
args: args{
|
||||
api: "/user/policy",
|
||||
},
|
||||
expectedStatus: 200,
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(
|
||||
"GET", fmt.Sprintf("http://localhost:9090/api/v1%s", tt.args.api), nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if response != nil {
|
||||
assert.Equal(tt.expectedStatus, response.StatusCode, tt.name+" Failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
// 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
|
||||
11
k8s/console/base/kustomization.yaml
Normal file
11
k8s/console/base/kustomization.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
# beginning of customizations
|
||||
resources:
|
||||
- mcs-service-account.yaml
|
||||
- mcs-cluster-role.yaml
|
||||
- mcs-cluster-role-binding.yaml
|
||||
- mcs-configmap.yaml
|
||||
- mcs-service.yaml
|
||||
- mcs-deployment.yaml
|
||||
- minio-operator.yaml
|
||||
12
k8s/console/base/mcs-cluster-role-binding.yaml
Normal file
12
k8s/console/base/mcs-cluster-role-binding.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: mcs-sa-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: mcs-sa-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: mcs-sa
|
||||
namespace: default
|
||||
77
k8s/console/base/mcs-cluster-role.yaml
Normal file
77
k8s/console/base/mcs-cluster-role.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: mcs-sa-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
- pods
|
||||
- services
|
||||
- events
|
||||
- resourcequotas
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- apiGroups:
|
||||
- "storage.k8s.io"
|
||||
resources:
|
||||
- storageclasses
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- statefulsets
|
||||
- deployments
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- "certificates.k8s.io"
|
||||
resources:
|
||||
- "certificatesigningrequests"
|
||||
- "certificatesigningrequests/approval"
|
||||
- "certificatesigningrequests/status"
|
||||
verbs:
|
||||
- update
|
||||
- create
|
||||
- get
|
||||
- apiGroups:
|
||||
- minio.min.io
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- min.io
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
- "*"
|
||||
7
k8s/console/base/mcs-configmap.yaml
Normal file
7
k8s/console/base/mcs-configmap.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: mcs-env
|
||||
data:
|
||||
MCS_PORT: "9090"
|
||||
MCS_TLS_PORT: "9443"
|
||||
27
k8s/console/base/mcs-deployment.yaml
Normal file
27
k8s/console/base/mcs-deployment.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mcs
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mcs
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mcs
|
||||
spec:
|
||||
serviceAccountName: mcs-sa
|
||||
containers:
|
||||
- name: mcs
|
||||
image: minio/mcs:latest
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
args:
|
||||
- /mcs
|
||||
- server
|
||||
ports:
|
||||
- containerPort: 9090
|
||||
name: http
|
||||
- containerPort: 9433
|
||||
name: https
|
||||
5
k8s/console/base/mcs-service-account.yaml
Normal file
5
k8s/console/base/mcs-service-account.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: mcs-sa
|
||||
namespace: default
|
||||
14
k8s/console/base/mcs-service.yaml
Normal file
14
k8s/console/base/mcs-service.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mcs
|
||||
labels:
|
||||
name: mcs
|
||||
spec:
|
||||
ports:
|
||||
- port: 9090
|
||||
name: http
|
||||
- port: 9443
|
||||
name: https
|
||||
selector:
|
||||
app: mcs
|
||||
282
k8s/console/base/minio-operator.yaml
Normal file
282
k8s/console/base/minio-operator.yaml
Normal file
@@ -0,0 +1,282 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: minio-operator
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tenants.minio.min.io
|
||||
spec:
|
||||
group: minio.min.io
|
||||
scope: Namespaced
|
||||
names:
|
||||
kind: Tenant
|
||||
singular: tenant
|
||||
plural: tenants
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
# openAPIV3Schema is the schema for validating custom objects.
|
||||
# Refer https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
|
||||
# for more details
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
serviceName:
|
||||
type: string
|
||||
serviceAccountName:
|
||||
type: string
|
||||
zones:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
servers:
|
||||
type: integer
|
||||
volumesPerServer:
|
||||
type: integer
|
||||
volumeClaimTemplate:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
resources:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
nodeSelector:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
affinity:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
tolerations:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
mountPath:
|
||||
type: string
|
||||
podManagementPolicy:
|
||||
type: string
|
||||
enum: [Parallel,OrderedReady]
|
||||
default: Parallel
|
||||
requestAutoCert:
|
||||
type: boolean
|
||||
default: false
|
||||
certConfig:
|
||||
type: object
|
||||
properties:
|
||||
commonName:
|
||||
type: string
|
||||
organizationName:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
dnsNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
mountpath:
|
||||
type: string
|
||||
subpath:
|
||||
type: string
|
||||
nodeSelector:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
credsSecret:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
env:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
console:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
default: 2
|
||||
consoleSecret:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
resources:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
env:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
kes:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
default: 2
|
||||
kesSecret:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
liveness:
|
||||
type: object
|
||||
properties:
|
||||
initialDelaySeconds:
|
||||
type: integer
|
||||
periodSeconds:
|
||||
type: integer
|
||||
timeoutSeconds:
|
||||
type: integer
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
currentState:
|
||||
type: string
|
||||
subresources:
|
||||
# status enables the status subresource.
|
||||
status: {}
|
||||
additionalPrinterColumns:
|
||||
- name: Current State
|
||||
type: string
|
||||
jsonPath: ".status.currentState"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: minio-operator-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
- pods
|
||||
- services
|
||||
- events
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- delete
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- statefulsets
|
||||
- deployments
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- certificates.k8s.io
|
||||
resources:
|
||||
- certificatesigningrequests
|
||||
- certificatesigningrequests/approval
|
||||
- certificatesigningrequests/status
|
||||
verbs:
|
||||
- update
|
||||
- create
|
||||
- get
|
||||
- delete
|
||||
- apiGroups:
|
||||
- certificates.k8s.io
|
||||
resourceNames:
|
||||
- kubernetes.io/legacy-unknown
|
||||
resources:
|
||||
- signers
|
||||
verbs:
|
||||
- approve
|
||||
- sign
|
||||
- apiGroups:
|
||||
- minio.min.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- min.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: minio-operator-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: minio-operator-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
name: minio-operator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: minio-operator
|
||||
spec:
|
||||
containers:
|
||||
- image: minio/k8s-operator:v3.0.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: minio-operator
|
||||
serviceAccountName: minio-operator
|
||||
44
k8s/create-kind.sh
Executable file
44
k8s/create-kind.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# setup environment variables based on flags to see if we should build the docker containers again
|
||||
MCS_DOCKER="true"
|
||||
|
||||
# evaluate flags
|
||||
# `-m` for mcs
|
||||
|
||||
|
||||
while getopts ":m:" opt; do
|
||||
case $opt in
|
||||
m)
|
||||
MCS_DOCKER="$OPTARG"
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
exit 1
|
||||
;;
|
||||
:)
|
||||
echo "Option -$OPTARG requires an argument." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Provisioning Kind"
|
||||
kind create cluster --config kind-cluster.yaml
|
||||
echo "Remove Master Taint"
|
||||
kubectl taint nodes --all node-role.kubernetes.io/master-
|
||||
echo "Install Contour"
|
||||
kubectl apply -f https://projectcontour.io/quickstart/contour.yaml
|
||||
kubectl patch daemonsets -n projectcontour envoy -p '{"spec":{"template":{"spec":{"nodeSelector":{"ingress-ready":"true"},"tolerations":[{"key":"node-role.kubernetes.io/master","operator":"Equal","effect":"NoSchedule"}]}}}}'
|
||||
echo "install metrics server"
|
||||
kubectl apply -f metrics-dev.yaml
|
||||
|
||||
# Whether or not to build the m3 container and load it to kind or just load it
|
||||
if [[ $MCS_DOCKER == "true" ]]; then
|
||||
# Build mkube
|
||||
make --directory=".." k8sdev TAG=minio/mcs:latest
|
||||
else
|
||||
kind load docker-image minio/mcs:latest
|
||||
fi
|
||||
|
||||
echo "done"
|
||||
3
k8s/getoperator.sh
Executable file
3
k8s/getoperator.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# Get's the latest deployment file from MinIO Operator
|
||||
curl https://raw.githubusercontent.com/minio/operator/master/minio-operator.yaml > operator-console/base/minio-operator.yaml
|
||||
22
k8s/kind-cluster.yaml
Normal file
22
k8s/kind-cluster.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
# three node (two workers) cluster config
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: InitConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
node-labels: "ingress-ready=true"
|
||||
extraPortMappings:
|
||||
- containerPort: 80
|
||||
hostPort: 8844
|
||||
protocol: TCP
|
||||
- containerPort: 443
|
||||
hostPort: 8843
|
||||
protocol: TCP
|
||||
#- role: worker
|
||||
#- role: worker
|
||||
#- role: worker
|
||||
#- role: worker
|
||||
153
k8s/metrics-dev.yaml
Normal file
153
k8s/metrics-dev.yaml
Normal file
@@ -0,0 +1,153 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: system:aggregated-metrics-reader
|
||||
labels:
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rules:
|
||||
- apiGroups: ["metrics.k8s.io"]
|
||||
resources: ["pods", "nodes"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: metrics-server:system:auth-delegator
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:auth-delegator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: metrics-server-auth-reader
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: extension-apiserver-authentication-reader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: system:metrics-server
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- nodes
|
||||
- nodes/stats
|
||||
- namespaces
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: system:metrics-server
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:metrics-server
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: apiregistration.k8s.io/v1beta1
|
||||
kind: APIService
|
||||
metadata:
|
||||
name: v1beta1.metrics.k8s.io
|
||||
spec:
|
||||
service:
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
group: metrics.k8s.io
|
||||
version: v1beta1
|
||||
insecureSkipTLSVerify: true
|
||||
groupPriorityMinimum: 100
|
||||
versionPriority: 100
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
labels:
|
||||
kubernetes.io/name: "Metrics-server"
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
selector:
|
||||
k8s-app: metrics-server
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
targetPort: main-port
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: metrics-server
|
||||
template:
|
||||
metadata:
|
||||
name: metrics-server
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
spec:
|
||||
serviceAccountName: metrics-server
|
||||
volumes:
|
||||
# mount in tmp so we can safely use from-scratch images and/or read-only containers
|
||||
- name: tmp-dir
|
||||
emptyDir: {}
|
||||
containers:
|
||||
- name: metrics-server
|
||||
image: k8s.gcr.io/metrics-server-amd64:v0.3.6
|
||||
args:
|
||||
- --cert-dir=/tmp
|
||||
- --secure-port=4443
|
||||
- --kubelet-insecure-tls
|
||||
- --kubelet-preferred-address-types=InternalIP
|
||||
ports:
|
||||
- name: main-port
|
||||
containerPort: 4443
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
imagePullPolicy: Always
|
||||
volumeMounts:
|
||||
- name: tmp-dir
|
||||
mountPath: /tmp
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/os: linux
|
||||
kubernetes.io/arch: "amd64"
|
||||
11
k8s/operator-console/base/kustomization.yaml
Normal file
11
k8s/operator-console/base/kustomization.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
# beginning of customizations
|
||||
resources:
|
||||
- mcs-service-account.yaml
|
||||
- mcs-cluster-role.yaml
|
||||
- mcs-cluster-role-binding.yaml
|
||||
- mcs-configmap.yaml
|
||||
- mcs-service.yaml
|
||||
- mcs-deployment.yaml
|
||||
- minio-operator.yaml
|
||||
12
k8s/operator-console/base/mcs-cluster-role-binding.yaml
Normal file
12
k8s/operator-console/base/mcs-cluster-role-binding.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: mcs-sa-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: mcs-sa-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: mcs-sa
|
||||
namespace: default
|
||||
77
k8s/operator-console/base/mcs-cluster-role.yaml
Normal file
77
k8s/operator-console/base/mcs-cluster-role.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: mcs-sa-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
- pods
|
||||
- services
|
||||
- events
|
||||
- resourcequotas
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- apiGroups:
|
||||
- "storage.k8s.io"
|
||||
resources:
|
||||
- storageclasses
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- statefulsets
|
||||
- deployments
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- "certificates.k8s.io"
|
||||
resources:
|
||||
- "certificatesigningrequests"
|
||||
- "certificatesigningrequests/approval"
|
||||
- "certificatesigningrequests/status"
|
||||
verbs:
|
||||
- update
|
||||
- create
|
||||
- get
|
||||
- apiGroups:
|
||||
- minio.min.io
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- min.io
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
- "*"
|
||||
7
k8s/operator-console/base/mcs-configmap.yaml
Normal file
7
k8s/operator-console/base/mcs-configmap.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: mcs-env
|
||||
data:
|
||||
MCS_PORT: "9090"
|
||||
MCS_TLS_PORT: "9443"
|
||||
30
k8s/operator-console/base/mcs-deployment.yaml
Normal file
30
k8s/operator-console/base/mcs-deployment.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mcs
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mcs
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mcs
|
||||
spec:
|
||||
serviceAccountName: mcs-sa
|
||||
containers:
|
||||
- name: mcs
|
||||
image: minio/mcs:latest
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
env:
|
||||
- name: MCS_OPERATOR_MODE
|
||||
value: "on"
|
||||
args:
|
||||
- /mcs
|
||||
- server
|
||||
ports:
|
||||
- containerPort: 9090
|
||||
name: http
|
||||
- containerPort: 9433
|
||||
name: https
|
||||
5
k8s/operator-console/base/mcs-service-account.yaml
Normal file
5
k8s/operator-console/base/mcs-service-account.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: mcs-sa
|
||||
namespace: default
|
||||
14
k8s/operator-console/base/mcs-service.yaml
Normal file
14
k8s/operator-console/base/mcs-service.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mcs
|
||||
labels:
|
||||
name: mcs
|
||||
spec:
|
||||
ports:
|
||||
- port: 9090
|
||||
name: http
|
||||
- port: 9443
|
||||
name: https
|
||||
selector:
|
||||
app: mcs
|
||||
282
k8s/operator-console/base/minio-operator.yaml
Normal file
282
k8s/operator-console/base/minio-operator.yaml
Normal file
@@ -0,0 +1,282 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: minio-operator
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tenants.minio.min.io
|
||||
spec:
|
||||
group: minio.min.io
|
||||
scope: Namespaced
|
||||
names:
|
||||
kind: Tenant
|
||||
singular: tenant
|
||||
plural: tenants
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
# openAPIV3Schema is the schema for validating custom objects.
|
||||
# Refer https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
|
||||
# for more details
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
serviceName:
|
||||
type: string
|
||||
serviceAccountName:
|
||||
type: string
|
||||
zones:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
servers:
|
||||
type: integer
|
||||
volumesPerServer:
|
||||
type: integer
|
||||
volumeClaimTemplate:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
resources:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
nodeSelector:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
affinity:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
tolerations:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
mountPath:
|
||||
type: string
|
||||
podManagementPolicy:
|
||||
type: string
|
||||
enum: [Parallel,OrderedReady]
|
||||
default: Parallel
|
||||
requestAutoCert:
|
||||
type: boolean
|
||||
default: false
|
||||
certConfig:
|
||||
type: object
|
||||
properties:
|
||||
commonName:
|
||||
type: string
|
||||
organizationName:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
dnsNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
mountpath:
|
||||
type: string
|
||||
subpath:
|
||||
type: string
|
||||
nodeSelector:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
credsSecret:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
env:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
console:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
default: 2
|
||||
consoleSecret:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
resources:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
env:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
kes:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
properties:
|
||||
metadata:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
image:
|
||||
type: string
|
||||
replicas:
|
||||
type: integer
|
||||
default: 2
|
||||
kesSecret:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
liveness:
|
||||
type: object
|
||||
properties:
|
||||
initialDelaySeconds:
|
||||
type: integer
|
||||
periodSeconds:
|
||||
type: integer
|
||||
timeoutSeconds:
|
||||
type: integer
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
currentState:
|
||||
type: string
|
||||
subresources:
|
||||
# status enables the status subresource.
|
||||
status: {}
|
||||
additionalPrinterColumns:
|
||||
- name: Current State
|
||||
type: string
|
||||
jsonPath: ".status.currentState"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: minio-operator-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- secrets
|
||||
- pods
|
||||
- services
|
||||
- events
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- create
|
||||
- list
|
||||
- delete
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- statefulsets
|
||||
- deployments
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- apiGroups:
|
||||
- certificates.k8s.io
|
||||
resources:
|
||||
- certificatesigningrequests
|
||||
- certificatesigningrequests/approval
|
||||
- certificatesigningrequests/status
|
||||
verbs:
|
||||
- update
|
||||
- create
|
||||
- get
|
||||
- delete
|
||||
- apiGroups:
|
||||
- certificates.k8s.io
|
||||
resourceNames:
|
||||
- kubernetes.io/legacy-unknown
|
||||
resources:
|
||||
- signers
|
||||
verbs:
|
||||
- approve
|
||||
- sign
|
||||
- apiGroups:
|
||||
- minio.min.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- min.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: minio-operator-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: minio-operator-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: minio-operator
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
name: minio-operator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: minio-operator
|
||||
spec:
|
||||
containers:
|
||||
- image: minio/k8s-operator:v3.0.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: minio-operator
|
||||
serviceAccountName: minio-operator
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2019 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
|
||||
@@ -14,9 +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 { IDashboardPanel } from "./Prometheus/types";
|
||||
// This package imports things required by build scripts, to force `go mod` to see them as dependencies
|
||||
package k8s
|
||||
|
||||
export interface zoomState {
|
||||
openZoom: boolean;
|
||||
widgetRender: null | IDashboardPanel;
|
||||
}
|
||||
//import _ "k8s.io/code-generator"
|
||||
35
k8s/update-codegen.sh
Executable file
35
k8s/update-codegen.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2017 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
||||
CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
|
||||
|
||||
# generate the code with:
|
||||
# --output-base because this script should also be able to run inside the vendor dir of
|
||||
# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
|
||||
# instead of the $GOPATH directly. For normal projects this can be dropped.
|
||||
bash "${CODEGEN_PKG}"/generate-groups.sh "all" \
|
||||
github.com/minio/mcs/pkg/generated \
|
||||
github.com/minio/mcs/pkg/apis \
|
||||
mkube:v1 \
|
||||
--go-header-file "${SCRIPT_ROOT}"/k8s/boilerplate.go.txt
|
||||
|
||||
# To use your own boilerplate text append:
|
||||
# --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt
|
||||
@@ -1,67 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// AUserPolicyResponse a user policy response
|
||||
//
|
||||
// swagger:model aUserPolicyResponse
|
||||
type AUserPolicyResponse struct {
|
||||
|
||||
// policy
|
||||
Policy string `json:"policy,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this a user policy response
|
||||
func (m *AUserPolicyResponse) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this a user policy response based on context it is used
|
||||
func (m *AUserPolicyResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AUserPolicyResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AUserPolicyResponse) UnmarshalBinary(b []byte) error {
|
||||
var res AUserPolicyResponse
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// AccessRule access rule
|
||||
//
|
||||
// swagger:model accessRule
|
||||
type AccessRule struct {
|
||||
|
||||
// access
|
||||
Access string `json:"access,omitempty"`
|
||||
|
||||
// prefix
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this access rule
|
||||
func (m *AccessRule) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this access rule based on context it is used
|
||||
func (m *AccessRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AccessRule) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AccessRule) UnmarshalBinary(b []byte) error {
|
||||
var res AccessRule
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AccountChangePasswordRequest account change password request
|
||||
//
|
||||
// swagger:model accountChangePasswordRequest
|
||||
type AccountChangePasswordRequest struct {
|
||||
|
||||
// current secret key
|
||||
// Required: true
|
||||
CurrentSecretKey *string `json:"current_secret_key"`
|
||||
|
||||
// new secret key
|
||||
// Required: true
|
||||
NewSecretKey *string `json:"new_secret_key"`
|
||||
}
|
||||
|
||||
// Validate validates this account change password request
|
||||
func (m *AccountChangePasswordRequest) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateCurrentSecretKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateNewSecretKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AccountChangePasswordRequest) validateCurrentSecretKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("current_secret_key", "body", m.CurrentSecretKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AccountChangePasswordRequest) validateNewSecretKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("new_secret_key", "body", m.NewSecretKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this account change password request based on context it is used
|
||||
func (m *AccountChangePasswordRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AccountChangePasswordRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AccountChangePasswordRequest) UnmarshalBinary(b []byte) error {
|
||||
var res AccountChangePasswordRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AddBucketLifecycle add bucket lifecycle
|
||||
//
|
||||
// swagger:model addBucketLifecycle
|
||||
type AddBucketLifecycle struct {
|
||||
|
||||
// Non required, toggle to disable or enable rule
|
||||
Disable bool `json:"disable,omitempty"`
|
||||
|
||||
// Non required, toggle to disable or enable rule
|
||||
ExpiredObjectDeleteMarker bool `json:"expired_object_delete_marker,omitempty"`
|
||||
|
||||
// Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM
|
||||
ExpiryDays int32 `json:"expiry_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of expiration is enabled
|
||||
NewerNoncurrentversionExpirationVersions int32 `json:"newer_noncurrentversion_expiration_versions,omitempty"`
|
||||
|
||||
// Non required, can be set in case of expiration is enabled
|
||||
NoncurrentversionExpirationDays int32 `json:"noncurrentversion_expiration_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of transition is enabled
|
||||
NoncurrentversionTransitionDays int32 `json:"noncurrentversion_transition_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of transition is enabled
|
||||
NoncurrentversionTransitionStorageClass string `json:"noncurrentversion_transition_storage_class,omitempty"`
|
||||
|
||||
// Non required field, it matches a prefix to perform ILM operations on it
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
|
||||
// Required only in case of transition is set. it refers to a tier
|
||||
StorageClass string `json:"storage_class,omitempty"`
|
||||
|
||||
// Non required field, tags to match ILM files
|
||||
Tags string `json:"tags,omitempty"`
|
||||
|
||||
// Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM
|
||||
TransitionDays int32 `json:"transition_days,omitempty"`
|
||||
|
||||
// ILM Rule type (Expiry or transition)
|
||||
// Enum: [expiry transition]
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this add bucket lifecycle
|
||||
func (m *AddBucketLifecycle) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateType(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var addBucketLifecycleTypeTypePropEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []string
|
||||
if err := json.Unmarshal([]byte(`["expiry","transition"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
addBucketLifecycleTypeTypePropEnum = append(addBucketLifecycleTypeTypePropEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// AddBucketLifecycleTypeExpiry captures enum value "expiry"
|
||||
AddBucketLifecycleTypeExpiry string = "expiry"
|
||||
|
||||
// AddBucketLifecycleTypeTransition captures enum value "transition"
|
||||
AddBucketLifecycleTypeTransition string = "transition"
|
||||
)
|
||||
|
||||
// prop value enum
|
||||
func (m *AddBucketLifecycle) validateTypeEnum(path, location string, value string) error {
|
||||
if err := validate.EnumCase(path, location, value, addBucketLifecycleTypeTypePropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddBucketLifecycle) validateType(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Type) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
// value enum
|
||||
if err := m.validateTypeEnum("type", "body", m.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add bucket lifecycle based on context it is used
|
||||
func (m *AddBucketLifecycle) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddBucketLifecycle) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AddBucketLifecycle) UnmarshalBinary(b []byte) error {
|
||||
var res AddBucketLifecycle
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// AddBucketReplication add bucket replication
|
||||
//
|
||||
// swagger:model addBucketReplication
|
||||
type AddBucketReplication struct {
|
||||
|
||||
// arn
|
||||
Arn string `json:"arn,omitempty"`
|
||||
|
||||
// destination bucket
|
||||
DestinationBucket string `json:"destination_bucket,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this add bucket replication
|
||||
func (m *AddBucketReplication) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add bucket replication based on context it is used
|
||||
func (m *AddBucketReplication) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddBucketReplication) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AddBucketReplication) UnmarshalBinary(b []byte) error {
|
||||
var res AddBucketReplication
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,8 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
@@ -81,11 +79,6 @@ func (m *AddGroupRequest) validateMembers(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add group request based on context it is used
|
||||
func (m *AddGroupRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddGroupRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AddMultiBucketLifecycle add multi bucket lifecycle
|
||||
//
|
||||
// swagger:model addMultiBucketLifecycle
|
||||
type AddMultiBucketLifecycle struct {
|
||||
|
||||
// buckets
|
||||
// Required: true
|
||||
Buckets []string `json:"buckets"`
|
||||
|
||||
// Non required, toggle to disable or enable rule
|
||||
ExpiredObjectDeleteMarker bool `json:"expired_object_delete_marker,omitempty"`
|
||||
|
||||
// Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM
|
||||
ExpiryDays int32 `json:"expiry_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of expiration is enabled
|
||||
NoncurrentversionExpirationDays int32 `json:"noncurrentversion_expiration_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of transition is enabled
|
||||
NoncurrentversionTransitionDays int32 `json:"noncurrentversion_transition_days,omitempty"`
|
||||
|
||||
// Non required, can be set in case of transition is enabled
|
||||
NoncurrentversionTransitionStorageClass string `json:"noncurrentversion_transition_storage_class,omitempty"`
|
||||
|
||||
// Non required field, it matches a prefix to perform ILM operations on it
|
||||
Prefix string `json:"prefix,omitempty"`
|
||||
|
||||
// Required only in case of transition is set. it refers to a tier
|
||||
StorageClass string `json:"storage_class,omitempty"`
|
||||
|
||||
// Non required field, tags to match ILM files
|
||||
Tags string `json:"tags,omitempty"`
|
||||
|
||||
// Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM
|
||||
TransitionDays int32 `json:"transition_days,omitempty"`
|
||||
|
||||
// ILM Rule type (Expiry or transition)
|
||||
// Required: true
|
||||
// Enum: [expiry transition]
|
||||
Type *string `json:"type"`
|
||||
}
|
||||
|
||||
// Validate validates this add multi bucket lifecycle
|
||||
func (m *AddMultiBucketLifecycle) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateBuckets(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateType(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddMultiBucketLifecycle) validateBuckets(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("buckets", "body", m.Buckets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var addMultiBucketLifecycleTypeTypePropEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []string
|
||||
if err := json.Unmarshal([]byte(`["expiry","transition"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
addMultiBucketLifecycleTypeTypePropEnum = append(addMultiBucketLifecycleTypeTypePropEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// AddMultiBucketLifecycleTypeExpiry captures enum value "expiry"
|
||||
AddMultiBucketLifecycleTypeExpiry string = "expiry"
|
||||
|
||||
// AddMultiBucketLifecycleTypeTransition captures enum value "transition"
|
||||
AddMultiBucketLifecycleTypeTransition string = "transition"
|
||||
)
|
||||
|
||||
// prop value enum
|
||||
func (m *AddMultiBucketLifecycle) validateTypeEnum(path, location string, value string) error {
|
||||
if err := validate.EnumCase(path, location, value, addMultiBucketLifecycleTypeTypePropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddMultiBucketLifecycle) validateType(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("type", "body", m.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// value enum
|
||||
if err := m.validateTypeEnum("type", "body", *m.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add multi bucket lifecycle based on context it is used
|
||||
func (m *AddMultiBucketLifecycle) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddMultiBucketLifecycle) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *AddMultiBucketLifecycle) UnmarshalBinary(b []byte) error {
|
||||
var res AddMultiBucketLifecycle
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,8 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
@@ -81,11 +79,6 @@ func (m *AddPolicyRequest) validatePolicy(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add policy request based on context it is used
|
||||
func (m *AddPolicyRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddPolicyRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,8 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
@@ -44,10 +42,6 @@ type AddUserRequest struct {
|
||||
// Required: true
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// policies
|
||||
// Required: true
|
||||
Policies []string `json:"policies"`
|
||||
|
||||
// secret key
|
||||
// Required: true
|
||||
SecretKey *string `json:"secretKey"`
|
||||
@@ -65,10 +59,6 @@ func (m *AddUserRequest) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validatePolicies(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateSecretKey(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
@@ -97,15 +87,6 @@ func (m *AddUserRequest) validateGroups(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddUserRequest) validatePolicies(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("policies", "body", m.Policies); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddUserRequest) validateSecretKey(formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.Required("secretKey", "body", m.SecretKey); err != nil {
|
||||
@@ -115,11 +96,6 @@ func (m *AddUserRequest) validateSecretKey(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add user request based on context it is used
|
||||
func (m *AddUserRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddUserRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,14 +23,8 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AdminInfoResponse admin info response
|
||||
@@ -38,261 +32,18 @@ import (
|
||||
// swagger:model adminInfoResponse
|
||||
type AdminInfoResponse struct {
|
||||
|
||||
// advanced metrics status
|
||||
// Enum: [not configured available unavailable]
|
||||
AdvancedMetricsStatus string `json:"advancedMetricsStatus,omitempty"`
|
||||
|
||||
// backend
|
||||
Backend *BackendProperties `json:"backend,omitempty"`
|
||||
|
||||
// buckets
|
||||
Buckets int64 `json:"buckets,omitempty"`
|
||||
|
||||
// objects
|
||||
Objects int64 `json:"objects,omitempty"`
|
||||
|
||||
// servers
|
||||
Servers []*ServerProperties `json:"servers"`
|
||||
|
||||
// usage
|
||||
Usage int64 `json:"usage,omitempty"`
|
||||
|
||||
// widgets
|
||||
Widgets []*Widget `json:"widgets"`
|
||||
}
|
||||
|
||||
// Validate validates this admin info response
|
||||
func (m *AdminInfoResponse) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateAdvancedMetricsStatus(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateBackend(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateServers(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateWidgets(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var adminInfoResponseTypeAdvancedMetricsStatusPropEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []string
|
||||
if err := json.Unmarshal([]byte(`["not configured","available","unavailable"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
adminInfoResponseTypeAdvancedMetricsStatusPropEnum = append(adminInfoResponseTypeAdvancedMetricsStatusPropEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// AdminInfoResponseAdvancedMetricsStatusNotConfigured captures enum value "not configured"
|
||||
AdminInfoResponseAdvancedMetricsStatusNotConfigured string = "not configured"
|
||||
|
||||
// AdminInfoResponseAdvancedMetricsStatusAvailable captures enum value "available"
|
||||
AdminInfoResponseAdvancedMetricsStatusAvailable string = "available"
|
||||
|
||||
// AdminInfoResponseAdvancedMetricsStatusUnavailable captures enum value "unavailable"
|
||||
AdminInfoResponseAdvancedMetricsStatusUnavailable string = "unavailable"
|
||||
)
|
||||
|
||||
// prop value enum
|
||||
func (m *AdminInfoResponse) validateAdvancedMetricsStatusEnum(path, location string, value string) error {
|
||||
if err := validate.EnumCase(path, location, value, adminInfoResponseTypeAdvancedMetricsStatusPropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) validateAdvancedMetricsStatus(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.AdvancedMetricsStatus) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
// value enum
|
||||
if err := m.validateAdvancedMetricsStatusEnum("advancedMetricsStatus", "body", m.AdvancedMetricsStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) validateBackend(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Backend) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Backend != nil {
|
||||
if err := m.Backend.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("backend")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("backend")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) validateServers(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Servers) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Servers); i++ {
|
||||
if swag.IsZero(m.Servers[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Servers[i] != nil {
|
||||
if err := m.Servers[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("servers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("servers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) validateWidgets(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Widgets) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.Widgets); i++ {
|
||||
if swag.IsZero(m.Widgets[i]) { // not required
|
||||
continue
|
||||
}
|
||||
|
||||
if m.Widgets[i] != nil {
|
||||
if err := m.Widgets[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("widgets" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("widgets" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this admin info response based on the context it is used
|
||||
func (m *AdminInfoResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateBackend(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateServers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateWidgets(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) contextValidateBackend(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Backend != nil {
|
||||
|
||||
if swag.IsZero(m.Backend) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Backend.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("backend")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("backend")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) contextValidateServers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Servers); i++ {
|
||||
|
||||
if m.Servers[i] != nil {
|
||||
|
||||
if swag.IsZero(m.Servers[i]) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Servers[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("servers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("servers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AdminInfoResponse) contextValidateWidgets(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Widgets); i++ {
|
||||
|
||||
if m.Widgets[i] != nil {
|
||||
|
||||
if swag.IsZero(m.Widgets[i]) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Widgets[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("widgets" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("widgets" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// APIError Api error
|
||||
//
|
||||
// swagger:model ApiError
|
||||
type APIError struct {
|
||||
|
||||
// detailed message
|
||||
DetailedMessage string `json:"detailedMessage,omitempty"`
|
||||
|
||||
// message
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this Api error
|
||||
func (m *APIError) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this Api error based on context it is used
|
||||
func (m *APIError) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *APIError) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *APIError) UnmarshalBinary(b []byte) error {
|
||||
var res APIError
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,8 +23,6 @@ package models
|
||||
// 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"
|
||||
)
|
||||
@@ -43,11 +41,6 @@ func (m *ArnsResponse) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this arns response based on context it is used
|
||||
func (m *ArnsResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ArnsResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// BackendProperties backend properties
|
||||
//
|
||||
// swagger:model BackendProperties
|
||||
type BackendProperties struct {
|
||||
|
||||
// backend type
|
||||
BackendType string `json:"backendType,omitempty"`
|
||||
|
||||
// offline drives
|
||||
OfflineDrives int64 `json:"offlineDrives,omitempty"`
|
||||
|
||||
// online drives
|
||||
OnlineDrives int64 `json:"onlineDrives,omitempty"`
|
||||
|
||||
// rr s c parity
|
||||
RrSCParity int64 `json:"rrSCParity,omitempty"`
|
||||
|
||||
// standard s c parity
|
||||
StandardSCParity int64 `json:"standardSCParity,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this backend properties
|
||||
func (m *BackendProperties) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this backend properties based on context it is used
|
||||
func (m *BackendProperties) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BackendProperties) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BackendProperties) UnmarshalBinary(b []byte) error {
|
||||
var res BackendProperties
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
404
models/bucket.go
404
models/bucket.go
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,9 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
@@ -38,28 +35,16 @@ import (
|
||||
type Bucket struct {
|
||||
|
||||
// access
|
||||
Access *BucketAccess `json:"access,omitempty"`
|
||||
Access BucketAccess `json:"access,omitempty"`
|
||||
|
||||
// creation date
|
||||
CreationDate string `json:"creation_date,omitempty"`
|
||||
|
||||
// definition
|
||||
Definition string `json:"definition,omitempty"`
|
||||
|
||||
// details
|
||||
Details *BucketDetails `json:"details,omitempty"`
|
||||
|
||||
// name
|
||||
// Required: true
|
||||
// Min Length: 3
|
||||
Name *string `json:"name"`
|
||||
|
||||
// objects
|
||||
Objects int64 `json:"objects,omitempty"`
|
||||
|
||||
// rw access
|
||||
RwAccess *BucketRwAccess `json:"rw_access,omitempty"`
|
||||
|
||||
// size
|
||||
Size int64 `json:"size,omitempty"`
|
||||
}
|
||||
@@ -72,18 +57,10 @@ func (m *Bucket) Validate(formats strfmt.Registry) error {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateDetails(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateName(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateRwAccess(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
@@ -91,38 +68,16 @@ func (m *Bucket) Validate(formats strfmt.Registry) error {
|
||||
}
|
||||
|
||||
func (m *Bucket) validateAccess(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Access) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Access != nil {
|
||||
if err := m.Access.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("access")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("access")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Bucket) validateDetails(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Details) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Details != nil {
|
||||
if err := m.Details.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("details")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("details")
|
||||
}
|
||||
return err
|
||||
if err := m.Access.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("access")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -134,117 +89,13 @@ func (m *Bucket) validateName(formats strfmt.Registry) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validate.MinLength("name", "body", *m.Name, 3); err != nil {
|
||||
if err := validate.MinLength("name", "body", string(*m.Name), 3); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Bucket) validateRwAccess(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.RwAccess) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.RwAccess != nil {
|
||||
if err := m.RwAccess.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("rw_access")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("rw_access")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this bucket based on the context it is used
|
||||
func (m *Bucket) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateAccess(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateDetails(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateRwAccess(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Bucket) contextValidateAccess(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Access != nil {
|
||||
|
||||
if swag.IsZero(m.Access) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Access.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("access")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("access")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Bucket) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Details != nil {
|
||||
|
||||
if swag.IsZero(m.Details) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Details.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("details")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("details")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Bucket) contextValidateRwAccess(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.RwAccess != nil {
|
||||
|
||||
if swag.IsZero(m.RwAccess) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.RwAccess.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("rw_access")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("rw_access")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Bucket) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
@@ -262,242 +113,3 @@ func (m *Bucket) UnmarshalBinary(b []byte) error {
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// BucketDetails bucket details
|
||||
//
|
||||
// swagger:model BucketDetails
|
||||
type BucketDetails struct {
|
||||
|
||||
// locking
|
||||
Locking bool `json:"locking,omitempty"`
|
||||
|
||||
// quota
|
||||
Quota *BucketDetailsQuota `json:"quota,omitempty"`
|
||||
|
||||
// replication
|
||||
Replication bool `json:"replication,omitempty"`
|
||||
|
||||
// tags
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
|
||||
// versioning
|
||||
Versioning bool `json:"versioning,omitempty"`
|
||||
|
||||
// versioning suspended
|
||||
VersioningSuspended bool `json:"versioningSuspended,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this bucket details
|
||||
func (m *BucketDetails) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateQuota(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BucketDetails) 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("details" + "." + "quota")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("details" + "." + "quota")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this bucket details based on the context it is used
|
||||
func (m *BucketDetails) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateQuota(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BucketDetails) contextValidateQuota(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Quota != nil {
|
||||
|
||||
if swag.IsZero(m.Quota) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Quota.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("details" + "." + "quota")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("details" + "." + "quota")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BucketDetails) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BucketDetails) UnmarshalBinary(b []byte) error {
|
||||
var res BucketDetails
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// BucketDetailsQuota bucket details quota
|
||||
//
|
||||
// swagger:model BucketDetailsQuota
|
||||
type BucketDetailsQuota struct {
|
||||
|
||||
// quota
|
||||
Quota int64 `json:"quota,omitempty"`
|
||||
|
||||
// type
|
||||
// Enum: [hard]
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this bucket details quota
|
||||
func (m *BucketDetailsQuota) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateType(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var bucketDetailsQuotaTypeTypePropEnum []interface{}
|
||||
|
||||
func init() {
|
||||
var res []string
|
||||
if err := json.Unmarshal([]byte(`["hard"]`), &res); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, v := range res {
|
||||
bucketDetailsQuotaTypeTypePropEnum = append(bucketDetailsQuotaTypeTypePropEnum, v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// BucketDetailsQuotaTypeHard captures enum value "hard"
|
||||
BucketDetailsQuotaTypeHard string = "hard"
|
||||
)
|
||||
|
||||
// prop value enum
|
||||
func (m *BucketDetailsQuota) validateTypeEnum(path, location string, value string) error {
|
||||
if err := validate.EnumCase(path, location, value, bucketDetailsQuotaTypeTypePropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BucketDetailsQuota) validateType(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.Type) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
// value enum
|
||||
if err := m.validateTypeEnum("details"+"."+"quota"+"."+"type", "body", m.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this bucket details quota based on context it is used
|
||||
func (m *BucketDetailsQuota) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BucketDetailsQuota) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BucketDetailsQuota) UnmarshalBinary(b []byte) error {
|
||||
var res BucketDetailsQuota
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// BucketRwAccess bucket rw access
|
||||
//
|
||||
// swagger:model BucketRwAccess
|
||||
type BucketRwAccess struct {
|
||||
|
||||
// read
|
||||
Read bool `json:"read,omitempty"`
|
||||
|
||||
// write
|
||||
Write bool `json:"write,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this bucket rw access
|
||||
func (m *BucketRwAccess) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this bucket rw access based on context it is used
|
||||
func (m *BucketRwAccess) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BucketRwAccess) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BucketRwAccess) UnmarshalBinary(b []byte) error {
|
||||
var res BucketRwAccess
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 MinIO, Inc.
|
||||
// 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
|
||||
@@ -23,7 +23,6 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
@@ -36,15 +35,6 @@ import (
|
||||
// swagger:model bucketAccess
|
||||
type BucketAccess string
|
||||
|
||||
func NewBucketAccess(value BucketAccess) *BucketAccess {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Pointer returns a pointer to a freshly-allocated BucketAccess.
|
||||
func (m BucketAccess) Pointer() *BucketAccess {
|
||||
return &m
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
// BucketAccessPRIVATE captures enum value "PRIVATE"
|
||||
@@ -91,8 +81,3 @@ func (m BucketAccess) Validate(formats strfmt.Registry) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this bucket access based on context it is used
|
||||
func (m BucketAccess) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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"
|
||||
)
|
||||
|
||||
// BucketEncryptionInfo bucket encryption info
|
||||
//
|
||||
// swagger:model bucketEncryptionInfo
|
||||
type BucketEncryptionInfo struct {
|
||||
|
||||
// algorithm
|
||||
Algorithm string `json:"algorithm,omitempty"`
|
||||
|
||||
// kms master key ID
|
||||
KmsMasterKeyID string `json:"kmsMasterKeyID,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this bucket encryption info
|
||||
func (m *BucketEncryptionInfo) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this bucket encryption info based on context it is used
|
||||
func (m *BucketEncryptionInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BucketEncryptionInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BucketEncryptionInfo) UnmarshalBinary(b []byte) error {
|
||||
var res BucketEncryptionInfo
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// BucketEncryptionRequest bucket encryption request
|
||||
//
|
||||
// swagger:model bucketEncryptionRequest
|
||||
type BucketEncryptionRequest struct {
|
||||
|
||||
// enc type
|
||||
EncType *BucketEncryptionType `json:"encType,omitempty"`
|
||||
|
||||
// kms key ID
|
||||
KmsKeyID string `json:"kmsKeyID,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this bucket encryption request
|
||||
func (m *BucketEncryptionRequest) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateEncType(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BucketEncryptionRequest) validateEncType(formats strfmt.Registry) error {
|
||||
if swag.IsZero(m.EncType) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.EncType != nil {
|
||||
if err := m.EncType.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("encType")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("encType")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this bucket encryption request based on the context it is used
|
||||
func (m *BucketEncryptionRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateEncType(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *BucketEncryptionRequest) contextValidateEncType(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.EncType != nil {
|
||||
|
||||
if swag.IsZero(m.EncType) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.EncType.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("encType")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("encType")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *BucketEncryptionRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *BucketEncryptionRequest) UnmarshalBinary(b []byte) error {
|
||||
var res BucketEncryptionRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user