Compare commits

...

358 Commits

Author SHA1 Message Date
Cesar N
e77d1be53e Release v1.5.0 (#3373)
update assets with latest fix

Co-authored-by: cesnietor <cesar.nieto@min.io>
2024-06-07 19:00:37 -07:00
jinapurapu
6765bd0624 Fix remove tier error handling (#3375) 2024-06-07 16:39:18 -06:00
jinapurapu
5f7b563a01 Add Remove Tier feature (#3371) 2024-06-07 10:01:10 -07:00
jinapurapu
3885875149 Add ILM rule tags generated by mc to getBucketLifecycle response (#3369) 2024-06-06 15:22:18 -07:00
Cesar N
cf05d5026f Use sync.Map for websocket cancelContext map (#3368) 2024-06-06 11:38:55 -07:00
Harshavardhana
3e83a30739 go1.22.4 upgrade for vulncheck (#3370) 2024-06-06 10:23:43 -07:00
Ramon de Klein
49c5f5a8f0 Use automatic URI encoding (#3352) 2024-06-05 14:48:27 -07:00
Ramon de Klein
72939e0cd7 Provide workaround for circular dependency (#3361) 2024-06-05 11:36:58 -07:00
Javier Adriel
271560894a Fix mapping over null reference for KMS endpoints (#3367) 2024-06-03 14:03:35 -07:00
Javier Adriel
6a591c1bcd Fix wrong comparisons (#3365) 2024-05-29 15:50:23 -07:00
Victor Bayas
3fdcfef1b4 Set Yarn checksumBehavior to reset (#3366)
* Set Yarn checksumBehavior to reset

* Update .gitignore according to Yarn docs
See https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored

* Update yarn.lock

---------

Co-authored-by: Harshavardhana <harsha@minio.io>
2024-05-29 15:50:12 -07:00
Ramon de Klein
7b8cfa2062 Attempt to fix resolution issues (#3364) 2024-05-29 15:12:02 -07:00
Harshavardhana
cc5921fd74 chore: update all deps (#3363) 2024-05-28 22:19:47 -06:00
Daniel Valdivia
d027b7f759 Release v1.4.1 (#3360)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2024-05-24 12:35:06 -07:00
Aditya Manthramurthy
f1524b0120 Bump up minio/pkg to v3 (#3349) 2024-05-24 10:44:55 -07:00
Kaan Kabalak
9985892751 Update default issue message note (#3358) 2024-05-22 23:16:05 -07:00
Ramon de Klein
cfd60bdd91 Upgrade to Yarn 4 and fix vulnerability check (#3353) 2024-05-22 18:19:32 -07:00
Shireesh Anjal
779f2a86e5 Fix empty version in health report download (#3341) 2024-05-17 14:42:39 -06:00
Pedro Juarez
f47c4445bd Return header with error idp logout (#3346) 2024-05-12 09:30:46 -07:00
Kaan Kabalak
1aeb4cc3d5 Fix SUBNET capitalization in issue template (#3345) 2024-05-10 17:47:38 -06:00
Alex
9e0a0205cc Updated react-pdf dependency (#3342) 2024-05-10 09:11:09 -06:00
Harshavardhana
1058efb17a Remove all unnecessary Dockerfiles from repo (#3340) 2024-05-08 21:53:47 -06:00
Anis Eleuch
d0f744ebef svc: Assume access key creation permission to be available by default (#3306)
Allow SVC creation when CreateServiceAccount is denied with a condition

Adding this policy will make the user not able to create a service account anymore:

```
    {
      "Effect": "Deny",
      "Action": [
              "admin:CreateServiceAccount"
      ],
      "Condition": {
              "NumericGreaterThanIfExists": {"svc:DurationSeconds": "1500"}
      }
    },

```

The reason is that policy.IsAllowedActions() is called with conditions from the user login.

Assume svc account creation to be possible for now until we come up with a better fix

Co-authored-by: Anis Eleuch <anis@min.io>
Co-authored-by: Prakash Senthil Vel <23444145+prakashsvmx@users.noreply.github.com>
2024-05-08 09:47:57 -07:00
Cesar N
a8c043cb16 Use redirect URL in share link if env variable set (#3334) 2024-05-08 09:46:41 -07:00
dependabot[bot]
978e02b5dc Bump react-pdf from 7.7.1 to 7.7.3 in /web-app (#3337)
Bumps [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) from 7.7.1 to 7.7.3.
- [Release notes](https://github.com/wojtekmaj/react-pdf/releases)
- [Commits](https://github.com/wojtekmaj/react-pdf/commits/v7.7.3/packages/react-pdf)

---
updated-dependencies:
- dependency-name: react-pdf
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 09:46:13 -07:00
dependabot[bot]
b39dbfff96 Bump pdfjs-dist from 3.11.174 to 4.2.67 in /web-app (#3335)
Bumps [pdfjs-dist](https://github.com/mozilla/pdfjs-dist) from 3.11.174 to 4.2.67.
- [Commits](https://github.com/mozilla/pdfjs-dist/commits)

---
updated-dependencies:
- dependency-name: pdfjs-dist
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 09:46:03 -07:00
Alex
bd89cfde79 Release v1.4.0 (#3333) 2024-05-06 17:58:31 -06:00
Anis Eleuch
0bd563b2e5 Fix a leak in WS object browser (#3325)
```
goroutine 7399330769 [chan send, 70126 minutes]:
github.com/minio/console/api.(*wsMinioClient).objectManager.func2.1()
        github.com/minio/console@v0.46.0/api/ws_objects.go:135 +0x6f0
created by github.com/minio/console/api.(*wsMinioClient).objectManager.func2 in goroutine 7354918912
        github.com/minio/console@v0.46.0/api/ws_objects.go:95 +0x45e
```
2024-05-06 15:12:31 -07:00
Alex
22fe915629 Changed default Replicate Existing Objects behavior in MinIO UI (#3271)
Changed default Replicate Existing Objects behavior in UI

- Fixed replicate existing objects configuration saving
- Displayed full error message if error case ocurrs.
- Changed wording for this feature & enabled by default this setting

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-05-06 16:02:27 -06:00
Alex
aa161a5365 Added VersionID support to Metadata Details (#3332)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-05-06 14:38:53 -07:00
kcao
0557514cb4 fix: correct metric endpoint from minio_cluster_drive_free_inodes (#3296)
Fixes minio/console#3295
2024-05-06 03:56:08 -07:00
Alex
298203253c Updated UI dependencies (#3329)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-05-03 17:32:11 -06:00
Cesar N
cbeef2b248 Fix URL safe string decoding for DownloadPublicObject API (#3328)
Co-authored-by: cesnietor <cesar.nieto@min.io>
2024-05-03 15:33:46 -07:00
Harshavardhana
e68a74ba48 fix: passing correct httpClient, do not use DefaultClients (#3319)
most of our deployments use custom certificates, using DefaultClient
makes it virtually impossible to make share URL feature work.

this PR fixes this behavior in the implementation.

Bonus: re-use transports inside console, will add more changes to
take custom transport inputs in subsequent PR.
2024-05-01 09:46:35 -07:00
Ramon de Klein
02a0db1408 Use React hook to better deal with websockets (#3299) 2024-05-01 03:42:49 -07:00
dependabot[bot]
348376c672 Bump ejs from 3.1.9 to 3.1.10 in /web-app (#3324)
Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10.
- [Release notes](https://github.com/mde/ejs/releases)
- [Commits](https://github.com/mde/ejs/compare/v3.1.9...v3.1.10)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-01 02:53:56 -07:00
Kaan Kabalak
037b02e268 Make permission tests compatible with minio-js v8 (#3323)
Fixes #3322
2024-05-01 02:45:09 -07:00
Kaan Kabalak
fe534ab4e6 Temporarily fix permission tests failing due to minio-js version bump (#3321)
Fix permission tests failing due to minio-js version bump

Permission tests were failing due to function signature changes
introduced with the latest minio-js release. This is a temporary
measure until a Console PR to update test files is sent.
2024-04-30 14:32:02 -06:00
Cesar N
6625d54d67 Release v1.3.0 (#3313) 2024-04-24 18:15:13 -07:00
Cesar N
ee6d1ed586 Upgrade superagent package to fix vulnerability (#3314) 2024-04-24 17:27:42 -07:00
Cesar N
6de1d88e11 Use url-safe base64 encoding for download-shared-object api (#3305) 2024-04-23 08:36:30 -07:00
jinapurapu
de19b6f17b Make prefix field optional for adding tier (#3301) 2024-04-18 23:51:13 -06:00
jinapurapu
226a90be1d Adds ExpireDeleteMarker status to bucketLifecycleRule UI display (#3302) 2024-04-18 18:36:00 -06:00
Prakash Senthil Vel
6cfb6ff06a add user agent in admin client to display console in audit logs (#3297) 2024-04-17 10:49:15 -06:00
Alex
649c3d74b8 Release v1.2.0 (#3292)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-04-10 13:06:18 -06:00
Alex
662ce3b2f5 Update console dependencies to fix vulnerabilities (#3291)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-04-10 11:52:15 -06:00
dependabot[bot]
0292bc154d Bump express from 4.18.3 to 4.19.2 in /web-app (#3277)
Bumps [express](https://github.com/expressjs/express) from 4.18.3 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.3...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2024-04-10 11:40:56 -06:00
Cesar N
ceee83f03a Use Console as proxy for share object logic (#3284) 2024-04-10 11:16:17 -06:00
Prakash Senthil Vel
144904f0f6 fix ux for keys permissions (#3280) 2024-04-05 10:14:29 -07:00
Alex
963c8f1221 Added missing permissions validation to rewind button (#3282)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-04-04 23:41:20 -06:00
Shireesh Anjal
6c50c38f83 fix health report upload error (#3275) 2024-04-04 13:50:22 -06:00
Shireesh Anjal
3aac62cc81 Reuse GetClusterRegInfo from mc (#3270) 2024-04-01 09:14:54 -07:00
Cesar N
78a05d39c4 Log error if it exists while serving APIs (#3276)
Co-authored-by: cesnietor <>
2024-03-27 13:06:42 -07:00
dependabot[bot]
79bec3880e Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /web-app (#3273) 2024-03-24 05:39:34 +01:00
Alex
bdf7bd6309 Changed Bucket Access Policy default value from n/a to private (#3267)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-03-19 18:28:18 -06:00
dependabot[bot]
4ce1ba999b Bump follow-redirects from 1.15.5 to 1.15.6 in /web-app (#3266) 2024-03-14 21:05:39 -06:00
Alex
d01501703b Release v1.1.1 (#3265)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-03-14 16:34:57 -07:00
Cesar N
6a38a09462 Fix folder download (#3264) 2024-03-14 15:07:15 -06:00
Alex
78990e354f Release v1.1.0 (#3261)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-03-12 11:22:55 -06:00
Harshavardhana
3189ebdfef Update all go-deps (#3259) 2024-03-12 01:47:35 -06:00
Shubhendu
39bf627b0a Enable console to set expired-object-all-versions (#3226)
Signed-off-by: Shubhendu Ram Tripathi <shubhendu@minio.io>
2024-03-11 14:25:06 -06:00
Alex
a838c763ea Release v1.0.0 (#3252)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-02-29 13:45:03 -08:00
Aditya Manthramurthy
0afea63994 Fix: handling of no inline policy for service acc. (#3221) 2024-02-29 14:51:12 -06:00
Phillip Schichtel
0df9487527 Check the blob size instead of the progress reports (#3249) 2024-02-29 08:33:26 -08:00
Victor Bayas
9274ee72ad Fix URL of inspect object API (#3247) 2024-02-28 20:51:09 -06:00
Prakash Senthil Vel
2b6c3debb4 clean up text preview support which was removed earlier (#3251) 2024-02-28 09:00:41 -08:00
Victor Bayas
8dd6dd4e7f Use native WebSocket API (#3248) 2024-02-27 13:34:06 -08:00
dependabot[bot]
5e64c96497 Bump ip from 1.1.8 to 1.1.9 in /web-app (#3241)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.8 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.8...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2024-02-26 13:45:16 -08:00
jinapurapu
54c0b4b8a2 Add bucket replication screen (#3040) 2024-02-26 13:44:55 -08:00
Prakash Senthil Vel
31056e12ba No preview message UI (#3244) 2024-02-26 11:34:21 -06:00
Alex
151c8117a3 Release v0.46.0 (#3238) 2024-02-16 13:58:01 -08:00
Alex
9b5c17c2db Updated failing UI tests in console (#3236)
Updated failing tests in console

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-02-14 17:48:41 -06:00
Alex
23e01b257e Updated mds to v0.18.1 (#3233)
- Updated other project dependencies
- Fixed an issue while pressing enter key in a page that contains a select box
- Fixed an issue while selecting an autocomplete option from an input box

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-02-13 17:53:11 -06:00
jinapurapu
ecc8c7a86e Added latest blog content to help menu (#3223) 2024-02-13 00:28:05 -08:00
Harshavardhana
ee4d7b9b69 upgrade all dependencies for console (#3235)
Signed-off-by: Harshavardhana <harsha@minio.io>
2024-02-12 22:17:21 -08:00
Alex
80c03839a4 Fixed lint issues with files (#3234)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-02-12 21:55:17 -08:00
jinapurapu
f394cb69ce Fixed disabled Create User button if policy has no resource (#3231)
Co-authored-by: Jillian Inapurapu <jillii@Jillians-MBP.attlocal.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2024-02-12 09:54:32 -08:00
Prakash Senthil Vel
52137ba9e5 Logout state clean up (#3219) 2024-02-09 15:36:56 -06:00
Prakash Senthil Vel
942b8101cc Fix lifecycle rule and edit modal to be consistent to display tier (#3227) 2024-02-07 11:35:25 -06:00
jinapurapu
a0a6b33ecd Add HelpTip to clarify Usage calculation (#3143) 2024-01-30 23:15:11 -06:00
Cesar N
d4c5e1b51c Fail request when error occurs during download (#3214) 2024-01-26 15:06:25 -06:00
jinapurapu
96923aed75 Changed DeleteAccessRule to use swagger api (#3213) 2024-01-26 14:59:34 -06:00
Shubhendu
a04f833e3f Query params replicate-ilm-expiry and disable-ilm-expiry-replication (#3065)
Signed-off-by: Shubhendu Ram Tripathi <shubhendu@minio.io>
2024-01-26 14:59:09 -06:00
dependabot[bot]
3b52cc9bd4 Bump github.com/lestrrat-go/jwx from 1.2.27 to 1.2.28 (#3215)
Bumps [github.com/lestrrat-go/jwx](https://github.com/lestrrat-go/jwx) from 1.2.27 to 1.2.28.
- [Release notes](https://github.com/lestrrat-go/jwx/releases)
- [Changelog](https://github.com/lestrrat-go/jwx/blob/v1.2.28/Changes)
- [Commits](https://github.com/lestrrat-go/jwx/compare/v1.2.27...v1.2.28)

---
updated-dependencies:
- dependency-name: github.com/lestrrat-go/jwx
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-26 12:01:41 -06:00
Cesar N
df2e92e451 Use swagger api for Site Replication Status (#3208) 2024-01-24 23:05:27 -06:00
Cesar N
8836fe043b Return proper progress on download error (#3211) 2024-01-23 10:55:41 -06:00
Cesar N
7ce6a58099 Use swagger api for Get API from Subnet (#3207) 2024-01-22 10:42:33 -06:00
Haruaki
57d6aca716 Fix BucketNamingRules button click (#3209) 2024-01-22 10:41:35 -06:00
Cesar N
8d99637455 Use swagger api for Add KMS key in Bucket Encryption (#3205) 2024-01-21 22:16:10 -08:00
Cesar N
abd66780f4 Use swagger api for AirGap Subnet Registration (#3206) 2024-01-19 14:17:23 -06:00
Cesar N
a5175a35ec Use swagger api for import KSM Key (#3204) 2024-01-19 11:07:05 -08:00
Cesar N
d9f945b5df Use swagger api for Add KMS Key (#3202) 2024-01-18 22:41:40 -08:00
Cesar N
0c55e39e8c Use swagger api for Add IDP Configuration (#3201) 2024-01-18 16:03:01 -08:00
Cesar N
b5443952da Use swagger api for IDP configuration details (#3200) 2024-01-18 15:02:11 -08:00
Cesar N
b9f0ccfaba Use swagger api for delete single and multiple Service Accounts (#3199) 2024-01-18 11:55:56 -05:00
Daniel Valdivia
24742325b7 Remove useAPI from DeleteUser and DeleteIDPConfigurationModal (#3191) 2024-01-17 15:37:28 -08:00
Cesar N
c87ebe447f Use swagger api for delete KMS key (#3197) 2024-01-17 15:31:19 -06:00
Cesar N
462cf16db9 Use swagger api for delete Policy (#3198) 2024-01-17 12:06:03 -08:00
Cesar N
edaa4e8754 Use swagger api for delete group (#3196) 2024-01-17 11:49:03 -08:00
Cesar N
76c596c574 Disable KMS Endpoints and Metrics Tabs if using KMS Secret Key (#3193) 2024-01-17 09:05:10 -08:00
Alex
b5554f6dcf Added Dark / Light Mode Status icons (#3194)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-01-16 19:06:58 -06:00
Daniel Valdivia
fc65f1afd1 Add Base URI to Inspect API calls (#3190)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2024-01-16 13:45:27 -08:00
Cesar N
b066b6a920 Kms status endpoints null validation (#3189) 2024-01-12 16:32:37 -06:00
Alex
bc0e63aac8 Release v0.45.0 (#3187)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-01-10 21:48:08 -08:00
Alex
343ff575e6 Removed heal backend (#3188)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-01-10 21:16:08 -08:00
Alex
08c922dca6 Deprecated Heal (Drives) functionality (#3186)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-01-10 22:33:18 -06:00
Alex
4dd6519cc6 Updated Section titles & labels (#3185)
Renamed Subscription to Subnet in menus
Renamed Settings to Configuration
Renamed Diagnostics to Heath

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2024-01-10 22:16:24 -06:00
Prakash Senthil Vel
cdffdae289 Fix life cycle rule edit for transition (#3183) 2024-01-08 08:43:07 -06:00
Shireesh Anjal
27e3b82223 Use subnet package in pkg for license validation (#3156) 2023-12-29 12:12:27 -06:00
Daniel Valdivia
239b31748a Rename portal-ui to web-app (#3178)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-29 11:44:01 -06:00
Daniel Valdivia
b465b74326 Release v0.44.0 (#3177)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-27 00:11:15 -08:00
Daniel Valdivia
616f262d09 Rename restapi to api (#3176)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-26 15:07:30 -06:00
Harshavardhana
8aa0ec17c5 simplify the provider config init, loading and allow reachable IDPs (#3168)
fixes https://github.com/minio/console/issues/3018
2023-12-26 14:38:42 -06:00
Daniel Valdivia
a8c5b53a2c Pkg Subnet Utils Tests (#3173)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-26 14:29:11 -06:00
Cesar Celis Hernandez
e96dbd444e Add all possible tests under restapi (#3174) 2023-12-26 14:17:40 -06:00
Prakash Senthil Vel
939e2acb0b fix event dest icons not loading when subpath is configured (#3169)
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-26 14:03:25 -06:00
Daniel Valdivia
a04955dc70 Save all coverage files to play (#3170)
* Save all coverage files to play

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

* Save them to latest as well

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

---------

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-26 13:52:18 -06:00
Cesar Celis Hernandez
ba04a22492 Adjusting the threshold of the coverage (#3172) 2023-12-26 13:52:03 -06:00
Cesar Celis Hernandez
a281fe129f To include pkg tests in the coverage (#3171)
Execute and include pkg tests in the coverage
2023-12-26 13:34:25 -06:00
Daniel Valdivia
a655cc8d3b Upgrade Go Dependencies (#3167) 2023-12-23 08:26:57 -06:00
Daniel Valdivia
63b584c83d Change Loading Logic for Metrics Page (#3166)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-22 10:25:54 -06:00
Alex
7dffd5f079 Release v0.43.1 (#3161) 2023-12-18 17:00:58 -06:00
Cesar N
044e5702df Update Share Object UI to reflect max expiration time (#3098) 2023-12-14 15:28:11 -06:00
Alex
3c3b9546d9 Release v0.43.0 (#3159)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-12 21:53:25 -06:00
jinapurapu
5bc0e74b53 Omit detailedMessage from login errors (#3136) 2023-12-12 18:09:56 -06:00
Alex
f0d4dddacd Changed PDF file preview behavior (#3144)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-12 14:20:06 -06:00
Prakash Senthil Vel
f4a3f46bcf Fix to prevent extra metadata call when listing at a bucket level (#3158) 2023-12-12 10:56:48 -06:00
Alex
38472e4cd2 Updated Console dependencies (#3157)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-11 18:29:07 -06:00
Daniel Valdivia
9db5d1e4f4 Tests for pkg/utils (#3155)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-11 09:57:02 -08:00
jinapurapu
4cadaf7d49 Cleaned up Tooltips and HelpTips on AddBucket screen (#3154) 2023-12-11 11:33:28 -06:00
Adrian Najera
748486160f FIX: Use STS env variable to increase the IDP token expiration (#3132)
Share link duration is based on the token expiration,
this increases the IDP token expiration so the share link
is able to last longer, by using an env variable called
MINIO_STS_DURATION
2023-12-08 09:58:46 -08:00
Alex
2c0a0b2bc4 Release v0.42.2 (#3153)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-07 15:37:44 -06:00
Daniel Valdivia
7e51d4bebb Don't attempt to show prometheus metrics if URL is empty (#3152)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-07 15:16:03 -06:00
Alex
c011e67122 Release v0.42.1 (#3150)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-06 19:10:28 -06:00
Alex
394b4c403d Rollback to go 1.19 (#3149)
Rollback go version to go 1.19, This is a requirement of MinIO server

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-06 16:55:03 -08:00
Cesar N
74030aa067 Release 0.42.0 (#3148) 2023-12-06 16:04:01 -08:00
Cesar N
07b8c745e6 Remove prints from delete handlers (#3147) 2023-12-06 16:59:10 -06:00
Prakash Senthil Vel
6767bfa2d2 add encoded filename as part of delete api url (#3141) 2023-12-06 14:28:46 -08:00
Prakash Senthil Vel
607d94fef4 add encoded filename as part of upload url (#3140) 2023-12-06 14:14:25 -08:00
Alex
83b060ef94 Updated govuln check to use latest version (#3146)
Updated go vuln check to use latest version

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-12-06 15:13:22 -06:00
dependabot[bot]
cb14cb94ce Bump @adobe/css-tools from 4.3.1 to 4.3.2 in /portal-ui (#3139) 2023-12-06 11:31:55 -06:00
Daniel Valdivia
2b9de49fbe Upgrade to Go 1.21 (#3142)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-12-01 18:23:24 -06:00
Alex
290f273bdf Updated mds version to v0.13.0 (#3138) 2023-11-28 17:11:54 -08:00
Prakash Senthil Vel
7b43779fb0 Fix share option should not be enabled for a prefix (#3135) 2023-11-28 18:45:24 -06:00
Prakash Senthil Vel
924c38faa6 Fix actions on a del marker in object list view (#3134) 2023-11-23 22:32:08 -06:00
Prakash Senthil Vel
e4d5f9610e access keys ui details improvement and edit (#3116) 2023-11-21 22:08:23 -06:00
jinapurapu
04e9cb0ac8 Enable Create Path button on BrowserBreadcrumbs if User can create subPath (#3131) 2023-11-17 13:21:07 -06:00
jinapurapu
da53daff37 Add UI to select number of non-current versions subject to ILM expiry rule (#3088) 2023-11-16 13:34:04 -06:00
Alex
8c26eff2c1 Added matchMedia mock function for Testing purposes (#3130)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-15 15:51:55 -06:00
Alex
044c265423 Enabled Dark Mode in Console (#3129)
- Dark mode will be tied to system settings if not set
- Dark mode will be stored in Application storage once set

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-15 13:33:05 -06:00
jinapurapu
0053658d5d Added OIDC docs and blog to helpMenu (#3127) 2023-11-15 09:30:39 -06:00
Alex
99cf3b378f Removed MUI dependencies from console (#3126)
- Updated DateTime Selector
- Updated last dependency functions
- Removed mui theming tools

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-14 10:22:47 -06:00
jinapurapu
78293eab62 Added new blog and video content to HelpMenu (#3124) 2023-11-13 12:11:55 -06:00
Cesar N
1a84be5782 Ignore server file from swagger-gen make command (#3123) 2023-11-06 14:01:02 -08:00
Alex
178f82b675 Release v0.41.0 (#3121)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-02 16:30:50 -07:00
Alex
ec5fbbcd1e Updated Login Error Callback page to mds (#3120)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-01 15:21:24 -06:00
Alex
78164054d4 Updated HelpMenu components to use only mds subcomponents (#3119)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-01 09:54:14 -06:00
Alex
6d5d11d5b4 Updated common bars (#3118)
- Updated common Loading Bars
- Updated Restart MinIO notification bar

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-11-01 09:53:42 -06:00
nreisingercres
9e3b93d385 Fix days selector to ignore daylight savings (#3117) 2023-10-31 14:30:10 -06:00
jiuker
d77cf93193 update the madmin-go dep (#3115) 2023-10-31 11:03:26 -06:00
Alex
2cca3f3722 Updated Logs Page to use mds components (#3114)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-31 10:12:23 -06:00
Anis Eleuch
36d96a1791 Support resolving of listen addrs to multiple IPv4/IPv6 (#3100)
If you specify --console-address "myaddress:9001" while myaddress can be
resolved to one IPv4 address and another IPv6 address, Console ignores
the IPv6 address. This commit fixes that.

Authored-by: Anis Elleuch <anis@min.io>
2023-10-30 17:47:16 -07:00
Alex
82e34a5df2 Replaced MenuDropdown components with mds variables (#3113)
- Replaced menu dropdown in Files Button
- Input Unit Menu dropdown replacement
- Migrated Download Widget dropdown

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-30 16:46:22 -06:00
Alex
7b83f4b1dc Restored ENV var display support in Console Configuration pages. (#3112)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-30 14:38:33 -06:00
Andreas Auernhammer
7d9910d1ca update docker file to ubi9 base image (#3109)
This commit improves and updates the docker file
to the UBI 9 base image.

Signed-off-by: Andreas Auernhammer <github@aead.dev>
2023-10-30 13:20:43 -06:00
Alex
7a63f6da56 Migrated Object Manager components to mds (#3108) 2023-10-27 06:36:01 -07:00
Alex
0043833f36 Migrated Date Selectors & Chart Tooltips styles (#3107)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-26 22:41:40 -06:00
Alex
3ad3bccadb Autocomplete component replacement (#3104)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-26 11:54:34 -06:00
Alex
39e94c890e Replaced Notification components with mds variants (#3103)
Replaced Notification components for mds variants

- Updated Warning Message components
- Replaced Snackbar component

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-25 11:38:35 -06:00
Alex
701039454a MDS Console improvements (#3102)
- Removed mui badge component
- Updated icons screen
- Migrated Wizard Component
- Improved modals styles
- Updated KMS Status page

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-24 14:09:22 -06:00
Alex
ec77a03d7c Replace missing icons from mui (#3101)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-24 09:28:33 -07:00
Alex
8dbad84a58 Improved error handling in Object Browser (#3097)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-23 10:17:44 -06:00
Cesar N
1767a37162 Add share link exp api (#3095) 2023-10-19 16:03:14 -05:00
Javier Adriel
622c3a067a Add global params for limit and offset (#3096) 2023-10-19 15:38:31 -05:00
Cesar N
4389548b64 Update swagger generated files with latest swagger version (#3094) 2023-10-19 12:49:38 -07:00
Alex
8cb0f1e558 Replaced mui accordion with mds component (#3089)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-17 10:32:23 -05:00
Alex
faafb77c73 Updated mds version to v0.9.6 (#3090)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-16 18:17:05 -05:00
Alex
0ecd1c73c1 Updated styling methods to remove mui and replace it with mds (#3085)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-13 12:02:29 -05:00
Shubhendu
88bf40f9a6 Use the new golang version 1.21.3 (#3087)
Signed-off-by: Shubhendu Ram Tripathi <shubhendu@minio.io>
2023-10-12 11:50:15 -05:00
dependabot[bot]
a025163b34 Bump golang.org/x/net from 0.15.0 to 0.17.0 (#3086) 2023-10-12 11:50:00 -05:00
Alex
07c80462b7 mui Grid component replacement (#3084)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-11 13:59:04 -07:00
Alex
79ac2277d4 Migrated mui Box to use mds component (#3082)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-11 13:58:33 -07:00
Alex
1c27bee9d0 Removed FormSwitchWrapper component (#3081)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-10 12:29:24 -05:00
Alex
56dc58b0b8 Components cleanup (#3079)
Removed old component wrappers and replaced them with their mds equivalent components:

- InputBoxWrapper
- CommentBoxWrapper
- CheckboxWrapper
- PredefinedList

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-09 14:41:23 -05:00
Adrian Najera
4018addd79 Fix: cache clientIP in GetConsoleHTTPClient (#3056) 2023-10-09 14:40:54 -05:00
jinapurapu
429dfb4314 Add HelpTips to Console (#3054) 2023-10-06 15:38:55 -05:00
Alex
1d7bb0bb2b Removed mui support from PasswordSelector component (#3078)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-06 14:09:44 -05:00
Alex
476eb673bb Updated FileSelector and removed old component (#3076)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-06 09:12:13 -07:00
Alex
71681b710c Removed deprecated components and replaced them with mds ones (#3077)
- SectionTitle
- AButton
- ScreenTitle

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-06 09:11:48 -07:00
Alex
fb02a7da06 Updated README file (#3074)
Updated README file

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-05 12:31:06 -05:00
MinIO Bot
5fdc341138 mds-released-v0.9.3 (#3073) 2023-10-04 19:17:16 -05:00
Alex
15de6caf75 Fixed Failing integration test (#3071)
Added a wait time after bucket creation to list the new buckets list
2023-10-04 09:09:55 -07:00
Alex
77bc2d5006 Updated Playwright tests (#3070)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-03 20:09:33 -05:00
Alex
972f5fca9d Release v0.40.0 (#3069) 2023-10-03 12:17:05 -07:00
Alex
083314ee2d Object Browser Refactor (#3066)
- Refactored navigation to be handled only with URL
- Refactored & simplified websocket
- Updated components to use mds
- Fixed an issue with Anonymous access and file selection
- Fixed an issue with anonymous access and download selection click
- Fixed an issue with object details selection on root path from a bucket
- Simplified reducer

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-02 18:02:03 -05:00
Alex
078ce0e546 Updated console dependencies (#3068)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-10-02 15:52:34 -05:00
MinIO Bot
9beca2c226 mds-released-v0.9.2 (#3060) 2023-09-25 11:49:51 -06:00
Prakash Senthil Vel
451f23ae24 Improve change password user experience (#3058) 2023-09-22 13:51:03 -06:00
Alex
300ebfa19f Updated OpenID UX (#3050)
- Display ENV variables set in configuration
- Removed Password empty placeholders
- Added notification to re-enter password when modifying OpenID configuration

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-22 13:50:41 -06:00
Alex
1ce2846c95 AuditLogs page fixes (#3059)
- Added support to endDate
- Converted dates to UTC as required by AuditLogs API

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-22 09:49:36 -06:00
Alex
7fb8c11a9d Added support for Scanner event type (#3055)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-21 13:14:54 -06:00
Prakash Senthil Vel
e7993c2d1b Fix: handle crash in error handling of access keys page (#3051) 2023-09-20 20:45:51 -06:00
Alex
3e93f7ff88 Release v0.39.0 (#3049)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-14 23:43:58 -07:00
Alex
f0580956db Improvements to LDAP Configuration page (#3047)
- Fixed LDAP Enabled / Disabled calculation
- Removed Password Label from main page to avoid confusion
- Display LDAP ENV variables in case of configured

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-14 17:54:59 -06:00
Pedro Juarez
65b0bab26d Load the available CA in logout API (#3044) 2023-09-13 15:26:48 -06:00
Harshavardhana
a559421293 migrate and upgrade all dependencies (#3046) 2023-09-13 13:55:47 -06:00
Cesar N
6ef35c26a4 Remove unused check-version api (#3045) 2023-09-13 13:55:06 -06:00
Alex
8a918324aa Added CONSOLE_PROMETHEUS_AUTH_TOKEN flag support (#3043)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-13 12:02:13 -06:00
Alex
d30c0c8cbb Migrated Metrics pages and components to mds (#3042)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-13 12:01:43 -06:00
Alex
1697c826c0 Fixed an issue while deleting objects with similar prefixes (#3035)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-12 10:05:41 -06:00
Cesar N
b378b8c8ef Fix regression on login path when using redirect url (#3038) 2023-09-11 14:25:34 -07:00
MinIO Bot
2c42d7ff81 mds-released-v0.9.1 (#3041) 2023-09-11 09:58:23 -06:00
Cesar N
e1f36ee54a Upgrade go version in git workflows to 1.21.1 (#3039) 2023-09-07 17:29:22 -06:00
Alex
698f72f828 Migrated Register page components to mds (#3034)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-07 11:48:29 -06:00
jinapurapu
8dd94f5336 Moved EditBucketReplication to screen (#3037) 2023-09-06 17:24:07 -06:00
Alex
1dc21b9a21 Removed TableWrapper (#3032)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-05 11:06:33 -06:00
Alex
248215cc77 Updated Changelog for v0.38.0 (#3031)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-04 11:44:50 -07:00
Alex
a6eee73c11 Release v0.38.0 (#3029)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-02 09:10:10 -07:00
Anis Eleuch
50d6a39312 idp: Use 900 seconds as minimum expiry without returning an error (#3022)
Do not bother the user with an error if the IDP expiry is less than
900 seconds, since the S3 spec sets a minimum of 900 seconds for STS
expiration, use that minimum duration instead of returning an error

Co-authored-by: Anis Elleuch <anis@min.io>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2023-09-02 07:50:45 -07:00
Aditya Manthramurthy
467b6b9bcb Use github.com/minio/pkg/v2 (#3027) 2023-09-01 17:29:07 -06:00
Alex
6e6246797c Renamed Subnet strings to SUBNET (#3026)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-01 15:10:12 -07:00
Alex
f8e4f747f5 Migrated Components loader to mds (#3025)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-09-01 12:06:33 -06:00
Alex
9acd49fcc6 Updated console dependencies (#3024)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-31 09:27:48 -06:00
Alex
636d12d43f Replaced LinearProgress as loader in favor of ProgressBar from mds (#3020)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-31 09:27:29 -06:00
MinIO Bot
5e9383de95 mds-released-v0.9.0 (#3021) 2023-08-30 12:38:11 -06:00
Kaan Kabalak
4863af863e Update minimum Standard plan capacity on License page (#3023) 2023-08-30 11:28:42 -06:00
Martin
b6d4c62edd Fix oauth2Config.Exchange error reporting (#3003) 2023-08-28 15:35:53 -07:00
Alex
bf733f3822 Migrated Heal and Watch pages to mds (#3016)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-25 09:53:02 -06:00
Alex
bbf4027418 Migrated Speedtest components to mds (#3015)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-24 17:08:16 -06:00
Alex
dbffc5fc22 Migrated Site Replication Pages (#3011)
- Improved & Simplified UI elements

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-24 17:07:58 -06:00
Cesar Celis Hernandez
f4a9420002 To properly show error in AddAccessRule.tsx (#3008)
Fixing the shown errors
2023-08-24 06:53:32 -06:00
Alex
657854bd29 Updated generated stylesheet (#3013) 2023-08-23 15:31:22 -06:00
MinIO Bot
cdc9e7d921 mds-released-v0.8.6 (#3012) 2023-08-23 15:21:36 -06:00
Alex
b125121ac8 Migrated available mds components in Tiers Page (#3007)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-21 22:30:04 -06:00
Daniel Valdivia
0c480dd5ec Handle errors for Set Policy for Access keys (#3005)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-08-21 12:00:45 -06:00
MinIO Bot
c07b8dcf73 mds-released-v0.8.4 (#3002)
Co-authored-by: MinIO Bot <minio.bot@minio.io>
2023-08-21 09:25:24 -06:00
Daniel Valdivia
912a4b216f Rename Error to ApiError to avoid ambiguity (#2954)
Rename Error to ApiError to avoide ambiguity and remove redundant status code

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-08-16 14:18:08 -07:00
Prakash Senthil Vel
e7fb205c31 show service account status and expiry in ui (#2992) 2023-08-16 11:55:07 -06:00
Alex
a2ba20e12f Release v0.37.0 (#3000) 2023-08-16 10:03:02 -07:00
Alex
f515dd82fe Migrated Trace page to mds (#2996)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-16 10:23:01 -06:00
Alex
61d3193c41 Migrated available mds components in Logs Page (#2998)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-16 09:42:15 -06:00
Harshavardhana
430ae66955 update disk -> drive change in prometheus metrics in minio master (#2999)
refer to https://github.com/minio/minio/pull/17854
2023-08-15 19:49:53 -07:00
MinIO Bot
3abbbc82b2 mds-released-v0.8.3 (#2995) 2023-08-15 10:09:50 -06:00
Alex
854181f63e Disabled input fields and changed Register label in Subscription features (#2994)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-14 17:07:31 -06:00
Kaan Kabalak
df996794ed Remove duplicate ref=con in License page buttons (#2993) 2023-08-14 10:12:10 -06:00
Cesar N
2d94018e3c Release v0.36.0 (#2988) 2023-08-10 11:59:15 -07:00
Alex
72bb9d0ca1 Update Settings Page components (#2986)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-09 18:30:42 -06:00
Javier Adriel
93bd0d65e2 Show LDAP configuration (#2985) 2023-08-09 12:06:17 -06:00
Prakash Senthil Vel
495b0f0068 truncate prefixes above the selected level to make the download layout flat (#2987) 2023-08-09 10:29:41 -07:00
Cesar Celis Hernandez
3275b6a6d8 Removing unneeded password (#2983) 2023-08-04 13:45:41 -06:00
Harshavardhana
fed5aa1599 fix: dateTime usage only available in go1.20 (#2982)
instead use a simpler normalizer for timestamp
to be user friendly without spaces.

For example

```
selected_files_20091110T230000Z.zip
```
2023-08-03 20:21:44 -07:00
Alex
6bc4efbac1 Release v0.35.0 (#2981) 2023-08-03 14:54:29 -07:00
Alex
cc0164a67b Initial Tools Pages Migrations (#2978)
Tools Pages Migrations

- Call Home
- Inspect
- Profile
- Health

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-03 15:26:17 -06:00
Prakash Senthil Vel
b968cc25ad feat: download multiple object selection as zip ignoring any deleted objects selected (#2965) 2023-08-02 18:28:25 -06:00
jinapurapu
d116a35a6d Fix subpath button (#2977)
Added bucketName to permissions check for subpath
2023-08-02 15:26:39 -07:00
Alex
49f856bdd5 Added Exclude Folders & Exclude Prefixes support (#2973)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-08-02 13:35:00 -06:00
Cesar Celis Hernandez
0d628f589a Removing white spaces from provided values (#2922) 2023-07-31 22:29:11 -06:00
Cesar N
4387b2149f Update Github jobs to use hardcoded testcafe version (#2972) 2023-07-31 16:11:28 -07:00
Alex
8cc602434e Release v0.34.0 (#2969)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-28 16:31:50 -07:00
Anis Eleuch
6411dc9504 auth: Avoid forcing one hour expiration for IDP sts creds (#2966) 2023-07-27 22:25:47 -06:00
Alex
32c34b0a11 Migrated Buckets Pages to mds (#2960) 2023-07-27 19:27:43 -07:00
jinapurapu
6e8f5e0fc2 Fixed subnet Health report upload (#2927)
Fixed subnet file upload to allow upload of different report types
2023-07-27 15:29:30 -07:00
Alex
3ce377dbd1 Changed Download Handler Behavior (#2964)
- Updated Handler for files with size of 49GB or less
- Used Browser Handler tor size of more than 50GB

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-26 21:08:35 -07:00
Alex
ad502b9f18 Fixed issue with folders named as the bucket in rewind mode (#2963)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-26 13:53:04 -07:00
Alex
fde186a5a3 Release v0.33.0 (#2956)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-20 22:26:32 -07:00
Prakash Senthil Vel
0823f623c8 fix configuration page to include configs based on supported config subsystems (#2946) 2023-07-20 14:43:17 -06:00
Prakash Senthil Vel
6cec113304 fix: add new dashboard metrics (#2952) 2023-07-20 07:57:41 -07:00
dependabot[bot]
cd42d77a46 Bump word-wrap from 1.2.3 to 1.2.4 in /portal-ui (#2953) 2023-07-19 11:40:03 -06:00
Alex
35907beaca Updated Prettier to v3.0.0 (#2949)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-18 09:58:21 -06:00
MinIO Bot
a062a59288 mds-released-v0.7.0 (#2948) 2023-07-18 09:53:53 +05:30
Prakash Senthil Vel
842c2decd0 fix console dashboard node io prometheus metric WChar and RChar (#2947) 2023-07-17 10:51:59 -07:00
Prakash Senthil Vel
d1069ed359 fix loading of objects at a path when url is shared opened elsewhere (#2944)
- fix loading of objects at a path when url is shared and opened elsewhere
- fix bug when a path is created and objects are uploaded it is not refreshed
2023-07-17 09:03:31 -07:00
Prakash Senthil Vel
6d81a1b1f8 add support for preview based on content type (#2930) 2023-07-13 18:29:56 -06:00
Alex
b2fe478dae Updated vulnerabilities checks & workflows (#2941) 2023-07-12 22:05:54 -06:00
Prakash Senthil Vel
02ed6a6e8b Fix delete share download options permission check in sidebar (#2935) 2023-07-12 11:07:18 -06:00
jinapurapu
1b271ab467 Removed extra 'Event Destination' text (#2938) 2023-07-12 10:35:39 -06:00
Prakash Senthil Vel
bacb5f8901 Preserve white space in breadcrumb disply and navigation (#2932) 2023-07-11 22:32:03 -06:00
MinIO Bot
ae7371da95 mds-released-v0.6.9 (#2934) 2023-07-10 22:56:44 -06:00
Prakash Senthil Vel
60f5eb603b remove warning message in delete bucket replication rule (#2931) 2023-07-10 14:29:23 -06:00
Prakash Senthil Vel
420ed00f55 Fix object metadata section crash due to un escaped characters (#2928) 2023-07-07 12:21:06 -06:00
Alex
b975871e9d Migrated remaining LDAP subcomponents to mds (#2926)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-06 22:21:19 -06:00
Alex
803ffe2960 Migrated OpenID module components to mds (#2925)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-06 14:14:10 -06:00
Cesar N
c96c95924c Release v0.32.0 (#2924) 2023-07-06 10:32:39 -07:00
Alex
f02786001c Migrated Groups Module components to mds (#2923)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-05 22:29:17 -06:00
Alex
542b7192c3 Migrated Users Module components to mds (#2920)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-07-05 17:21:07 -07:00
Javier Adriel
b31aa10b52 Refactor to swagger TS API (#2903) 2023-07-05 17:27:46 -06:00
jiuker
1eba59954d fix: websockets goroutine leak for object list UI (#2805)
listen on the done channel to ensure that we can clean up 
the WebSocket go-routine, once the caller is done with
writing the response.
2023-07-05 12:17:54 -07:00
jinapurapu
b71d9f05c5 Updated placeholderimage for offline HelpMenu items (#2916) 2023-06-30 18:35:04 -06:00
Daniel Valdivia
fc5e94d55f Remove Cross compile jobs (#2915) 2023-06-29 18:57:14 -06:00
Alex
3875fb3eaa Release v0.31.0 (#2912)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-29 12:21:34 -07:00
Aditya Manthramurthy
b3d4132fe6 Remove goreleaser (#2914)
Not needed any more as standalone console deploys are not supported any more.
2023-06-29 11:15:58 -06:00
Alex
21f20bb9ea Migrated Policies module to mds (#2911)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-28 18:23:58 -06:00
Alex
df937467a0 Fixed Bucket Events Notifications Page (#2906)
- Added missing ilm & replica supported types
- Fixed add screen crash when no arn is selected
- Migrated components to mds

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-28 15:39:02 -06:00
Alex
d1ae271111 Replaced CodeMirrorWrapper internal components (#2910)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-28 12:05:18 -07:00
Alex
e7fb3e0e45 Updated console dependencies (#2909)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-26 14:12:09 -06:00
dependabot[bot]
b7b0271ec7 Bump fast-xml-parser from 4.2.4 to 4.2.5 in /portal-ui (#2904)
Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 21:41:22 -06:00
jinapurapu
9935b839b7 Help menu cleanup (#2905) 2023-06-22 20:25:06 -06:00
Cesar N
0e11098c31 Upgrade semver version to address vulnerability (#2902) 2023-06-22 17:54:14 -04:00
Daniel Valdivia
c55e0a069b Format number of objects (#2901) 2023-06-22 12:59:16 -07:00
jinapurapu
c3da876b04 Added placeholder image to HelpMenu if links unavailable (#2899) 2023-06-22 12:12:13 -07:00
Alex
643a9c6c7c Updated Audit Logs page to use mds (#2897)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-21 14:32:19 -06:00
Aditya Manthramurthy
0c3a94172d Bump up madmin-go to v3.0.2 (#2896) 2023-06-21 10:51:12 -07:00
Javier Adriel
527eb16700 Refactor to swagger TS API (#2888)
Co-authored-by: Prakash Senthil Vel <23444145+prakashsvmx@users.noreply.github.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2023-06-20 12:46:20 -07:00
Alex
e3aec3f094 Updated mds to v0.6.4 (#2895) 2023-06-20 11:49:58 -07:00
Alex
eac2734df4 Update mds to v0.6.2 (#2894) 2023-06-20 11:37:09 -06:00
Allan Roger Reid
a411e7c977 Create bug_report.md (#2893) 2023-06-19 19:58:26 -07:00
Prakash Senthil Vel
28c4abe2d0 audit only the dependencies and exclude dev dependencies in ci for ui (#2892) 2023-06-19 10:55:20 -06:00
Javier Adriel
a9ef6ebf5f Fix download of folders (#2891) 2023-06-19 10:54:18 -06:00
Ali Garajian
c12415c12d Virtualize download/upload object list (#2889) 2023-06-16 13:31:39 -06:00
Cesar N
1f481e690b Add CHANGELOG file for Releases (#2887) 2023-06-15 14:21:27 -07:00
Alex
58aad859e1 Release v0.30.0 (#2886) 2023-06-15 13:13:53 -07:00
jinapurapu
b9ebfe09ee Removed console.log (#2885) 2023-06-15 12:52:24 -06:00
Prakash Senthil Vel
864cf7af99 Apply policy resource restrictions for file extensions (#2842) 2023-06-15 11:33:52 -07:00
Javier Adriel
b76f460979 Remove dead code and add job in CI to find it (#2882) 2023-06-15 10:24:24 -06:00
Cesar N
cbd2c4682d Raise error on upload artifact if no files (#2884)
Raise error on artifact upload if no files to upload

Co-authored-by: cesnietor <>
2023-06-15 09:00:51 -07:00
Javier Adriel
d49bdf7d49 Add staticcheck to console API (#2883) 2023-06-14 21:35:00 -06:00
dependabot[bot]
559a7278a0 Bump github.com/lestrrat-go/jwx from 1.2.25 to 1.2.26 (#2879) 2023-06-14 17:16:17 -06:00
Daniel Valdivia
4a172fae97 Pass Client IP address to MinIO on x-forwarded-for header (#2864) 2023-06-14 12:36:48 -07:00
Cesar N
fc4263e2f9 Define action version to Git action (#2875) 2023-06-13 18:16:46 -06:00
Cesar N
c1b9b4c81b Add Git job to add new issues to project (#2873) 2023-06-13 17:36:21 -06:00
Javier Adriel
aa9b73522e Refactor to swagger ts API (#2860) 2023-06-13 15:00:56 -07:00
Alex
0904f83627 Fix playwright (#2867)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-13 14:43:28 -07:00
Cesar N
253053cc23 Refactor session to avoid duplicate calls to apis (#2868)
Co-authored-by: cesnietor <>
2023-06-13 14:27:48 -07:00
Alex
08a3ff65c7 Updated menu component to use mds (#2866)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-13 15:16:46 -06:00
jinapurapu
ee8fac8be8 Removed debugging line (#2870)
Co-authored-by: Jillian Inapurapu <jillii@Jillians-MacBook-Pro.local>
2023-06-13 11:48:25 -07:00
jinapurapu
9fa49b40b3 Console help menu (#2804)
Authored-by: Jillian Inapurapu <jillii@Jillians-MBP.attlocal.net>
2023-06-12 14:50:25 -07:00
Javier Adriel
de13119e02 Use swagger autogenerated ts API for session endpoint (#2859) 2023-06-12 15:00:40 -06:00
Alex
bf9acd7691 Share File access key / secret key rollback (#2863)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-12 14:02:38 -06:00
Alex
a5066fecc8 Update mds to v0.6.0 (#2862)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-12 11:55:23 -07:00
jinapurapu
6432681440 Minor tooltip fixes (#2861) 2023-06-12 09:54:07 -06:00
jinapurapu
b3b6df9d82 Minor fixes to Config screen tooltips (#2857) 2023-06-08 23:28:28 -06:00
Alex
fe7be4ef62 Fixed an issue with subpaths in resources policies (#2856)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-08 17:37:45 -06:00
Javier Adriel
b4603547f6 Add tests for remote buckets handlers (#2843) 2023-06-08 13:06:49 -06:00
Javier Adriel
b33b9315ea Fix fast-xml-parser vulnerability (#2855) 2023-06-06 11:55:23 -07:00
BlockListed
6ae03fa028 Fix spelling in file sharing menu (#2853) 2023-06-04 12:23:25 -06:00
MinIO Bot
e1bb1e0472 mds-released-v0.5.1 (#2851) 2023-06-02 20:45:08 -06:00
Alex
411670e4f5 Release v0.29.0 (#2850)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2023-06-02 13:51:48 -07:00
Alex
1c55932f84 Updated console dependencies (#2849) 2023-06-02 12:58:07 -06:00
Kaan Kabalak
5a77054d6b Update Service Acct fns based on new ListServiceAccounts type (#2824)
* Update Service Acct fns based on new ListServiceAccounts type
2023-05-30 10:30:02 -07:00
Alex
84c5fd58f9 Display error snack bar on raw policy edit error (#2841)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-05-29 18:05:42 -06:00
Daniel Valdivia
98979911ee Move Login to Typescript Swagger API (#2839)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-05-29 13:52:29 -07:00
Alex
c0cf7358c7 Removed hardcoded background in access keys table (#2837)
## What does this do?

Removed non required classes from access keys table

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-05-28 18:47:10 -07:00
Alex
9053e64dff Fixed multiselection of items after deleting one service account (#2836) 2023-05-26 16:58:01 -06:00
Alex
57bfe97d08 Release v0.28.0 (#2831) 2023-05-26 13:42:42 -07:00
Alex
028570279c Migrated Access Keys page components to mds (#2834)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-05-26 11:24:34 -06:00
MinIO Bot
bda1cd1f25 mds-released-V0.4.3 (#2830)
Co-authored-by: MinIO Bot <minio.bot@minio.io>
2023-05-24 11:37:48 -07:00
Alex
7a9b775b09 Changed Share Object logic to use Access Keys (#2827)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-05-24 10:52:40 -07:00
Daniel Valdivia
17e791afb9 Replace RIGHT-TO-LEFT OVERRIDE unicode (#2828)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-05-23 09:47:12 -06:00
Daniel Valdivia
920fc7d937 Fix Subpath behavior (#2818)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2023-05-22 12:30:59 -07:00
GeekTR
6e314a2fa5 Fix crash when backend has no rrSCParity property (#2826) 2023-05-22 13:14:41 -06:00
Alex
dc90db6591 Changed SSO Login screen to hide login form by default (#2807)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2023-05-22 11:20:45 -06:00
Prakash Senthil Vel
beed4895c1 Apply permission check for create accesskey button (#2822) 2023-05-22 09:26:31 -07:00
Prakash Senthil Vel
629dd669c4 Fix anonymous access rule not displayed due to style (#2820) 2023-05-18 10:54:21 -06:00
Alex
fc9319e55b Added identifier field to Event destinations page & migrated to mds (#2816) 2023-05-16 20:21:31 -06:00
Alex
58b64a5739 Fixed an issue with allowResources & KeyBar (#2817) 2023-05-16 16:53:32 -06:00
Javier Adriel
d93537261e Fix download of large files in Console (#2773) 2023-05-15 11:31:43 -07:00
Prakash Senthil Vel
22ec87d00e improve playwright tests with refactoring and clean up (#2809) 2023-05-15 10:02:40 -06:00
MinIO Bot
b87b4156e7 mds-released-v0.4.2 (#2815)
Co-authored-by: MinIO Bot <minio.bot@minio.io>
2023-05-12 18:55:23 -06:00
2132 changed files with 192277 additions and 66517 deletions

View File

@@ -1,7 +0,0 @@
node_modules/
dist/
target/
console
!console/
portal-ui/node_modules/
.git/

49
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,49 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: community, triage
assignees: ''
---
## NOTE
Please subscribe to our [paid subscription plans](https://min.io/pricing) for 24x7 support from our Engineering team.
<!--- 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`):

18
.github/workflows/issues.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
# @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 }}

File diff suppressed because it is too large Load Diff

60
.github/workflows/vulncheck.yaml vendored Normal file
View File

@@ -0,0 +1,60 @@
# @format
name: Vulnerability Check
on:
pull_request:
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.22.4
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.22.4 ]
os: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Read .nvmrc
id: node_version
run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@v3
with:
node-version: ${{ env.NVMRC }}
- name: Checks for known security issues with the installed packages
working-directory: ./web-app
continue-on-error: false
run: |
# Ignore "pdfjs-dist" advisory, because it's a dependency
# of "react-pdf" that cannot be upgraded. Because the
# "isEvalSupported" value is always set to "false", it
# isn't a security problem. See also
# - https://github.com/wojtekmaj/react-pdf/issues/1789
# - https://github.com/wojtekmaj/react-pdf/discussions/1786
# - https://www.npmjs.com/advisories/1097244
yarn npm audit --recursive --environment production --no-deprecations --ignore 1097244

10
.gitignore vendored
View File

@@ -1,12 +1,12 @@
# Playwright Data
portal-ui/storage/
portal-ui/playwright/.auth/admin.json
web-app/storage/
web-app/playwright/.auth/admin.json
# Report from Playwright
portal-ui/playwright-report/
web-app/playwright-report/
# Coverage from Playwright
portal-ui/.nyc_output/
web-app/.nyc_output/
# Binaries for programs and plugins
*.exe
@@ -37,7 +37,7 @@ dist/
# Ignore node_modules
portal-ui/node_modules/
web-app/node_modules/
# Ignore tls cert and key
private.key

View File

@@ -23,8 +23,8 @@ linters:
- gomodguard
- gofmt
- unused
- staticcheck
- unconvert
- varcheck
- gocritic
- gofumpt
- durationcheck
@@ -46,4 +46,4 @@ run:
skip-dirs:
- pkg/clientgen
- pkg/apis/networking.gke.io
- restapi/operations
- api/operations

View File

@@ -1,191 +0,0 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
project_name: console
release:
name_template: "Release version {{.Tag}}"
github:
owner: minio
name: console
extra_files:
- glob: "*.minisig"
before:
hooks:
# you may remove this if you don't use vgo
- go mod tidy -compat=1.19
builds:
- goos:
- linux
- darwin
- windows
goarch:
- amd64
- ppc64le
- s390x
- arm64
ignore:
- goos: darwin
goarch: arm
- goos: windows
goarch: arm64
- goos: windows
goarch: arm
env:
- CGO_ENABLED=0
main: ./cmd/console/
flags:
- -trimpath
- --tags=kqueue,operator
ldflags:
- -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}}
archives:
- name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}"
format: binary
replacements:
arm: arm
signs:
- signature: "${artifact}.minisig"
cmd: "sh"
args:
- '-c'
- 'minisign -s /media/${USER}/minio/minisign.key -Sm ${artifact} < /media/${USER}/minio/minisign-passphrase'
artifacts: all
snapshot:
name_template: v0.0.0@{{.ShortCommit}}
changelog:
sort: asc
nfpms:
- vendor: MinIO, Inc.
homepage: https://github.com/minio/console
maintainer: MinIO Development <dev@min.io>
description: MinIO Console Server
license: GNU Affero General Public License v3.0
formats:
- deb
- rpm
contents:
# Basic file that applies to all packagers
- src: systemd/console.service
dst: /etc/systemd/system/minio-console.service
dockers:
- image_templates:
- "minio/console:{{ .Tag }}-amd64"
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-ppc64le"
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-s390x"
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-arm64"
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-amd64"
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-ppc64le"
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/ppc64le"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-s390x"
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/s390x"
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-arm64"
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
extra_files:
- LICENSE
- CREDITS
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=TAG={{ .Tag }}"
docker_manifests:
- name_template: minio/console:{{ .Tag }}
image_templates:
- minio/console:{{ .Tag }}-amd64
- minio/console:{{ .Tag }}-arm64
- minio/console:{{ .Tag }}-ppc64le
- minio/console:{{ .Tag }}-s390x
- name_template: quay.io/minio/console:{{ .Tag }}
image_templates:
- quay.io/minio/console:{{ .Tag }}-amd64
- quay.io/minio/console:{{ .Tag }}-arm64
- quay.io/minio/console:{{ .Tag }}-ppc64le
- quay.io/minio/console:{{ .Tag }}-s390x
- name_template: minio/console:latest
image_templates:
- minio/console:{{ .Tag }}-amd64
- minio/console:{{ .Tag }}-arm64
- minio/console:{{ .Tag }}-ppc64le
- minio/console:{{ .Tag }}-s390x

View File

@@ -5,7 +5,7 @@
# Common large paths
node_modules/
portal-ui/node_modules/
web-app/node_modules/
build/
dist/
.idea/

335
CHANGELOG.md Normal file
View File

@@ -0,0 +1,335 @@
<!-- @format -->
# Changelog
## Release v1.5.0
Features:
- Added remove Tier functionality
Bug Fix:
- Fixed ILM rule tags not being shown
- Fixed race condition Object Browser websocket
- Fixed Encryption page crashing on empty response
- Fixed Replication Delete Marker comparisons
Additional Changes:
- Use automatic URI encoding for APIs
- Vulnerability updates
## Release v1.4.0
Features:
- Added VersionID support to metadata details
- Improved Websockets handlers
Bug Fix:
- Fixed vulnerabilities and updated dependencies
- Fixed an issue with Download URL decoding
- Fixed leak in Object Browser Websocket
- Minor UX fixes
## Release v1.3.0
Features:
- Adds ExpireDeleteMarker status to BucketLifecycleRule UI
Bug Fix:
- Fixed vulnerability
- Used URL-safe base64 enconding for Share API
- Made Prefix field optional when Adding Tier
- Added Console user agent in MinIO Admin Client
## Release v1.2.0
Features:
- Updated file share logic to work as Proxy
Bug Fix:
- Updated project dependencies
- Fixed Key Permissions UX
- Added permissions validation to rewind button
- Fixed Health report upload to SUBNET
- Misc Cosmetic fixes
## Release v1.1.1
Bug Fix:
- Fixed folder download issue
## Release v1.1.0
Features:
- Added Set Expired object all versions selector
Bug Fix:
- Updated Go Dependencies
## Release v1.0.0
Features:
- Updated Preview message alert
Bug Fix:
- Updated Websocket API
- Fixed issues with download manager
- Fixed policies issues
## Release v0.46.0
Features:
- Added latest help content to forms
Bug Fix:
- Disabled Create User button in certain policy cases
- Fixed an issue with Logout request
- Upgraded project dependencies
## Release v0.45.0
Deprecated:
- Deprecated Heal / Drives page
Features:
- Updated tines on menus & pages
Bug Fix:
- Upgraded project dependencies
## Release v0.44.0
Bug Fix:
- Upgraded project dependencies
- Fixed events icons not loading in subpaths
## Release v0.43.1
Bug Fix:
- Update Share Object UI to reflect maximum expiration time in UI
## Release v0.43.0
Features:
- Updated PDF preview method
Bug Fix:
- Fixed vulnerabilities
- Prevented non-necessary metadata calls in object browser
## Release v0.42.2
Bug Fix:
- Hidden Prometheus metrics if URL is empty
## Release v0.42.1
Bug Fix:
- Reset go version to 1.19
## 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

View File

@@ -4,56 +4,80 @@ This is a REST portal server created using [go-swagger](https://github.com/go-sw
The API handlers are created using a YAML definition located in `swagger.YAML`.
To add new api, the YAML file needs to be updated with all the desired apis using the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths, parameters, definitions, tags, etc.
To add new api, the YAML file needs to be updated with all the desired apis using
the [Swagger Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/), this includes paths,
parameters, definitions, tags, etc.
## Generate server from YAML
Once the YAML file is ready we can autogenerate the code needed for the new api by just running:
Validate it:
```
swagger validate ./swagger.yml
```
Update server code:
```
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.
`./api/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.
## Unit Tests
`./restapi/handlers_test.go` needs to be updated with the proper tests for the new api.
`./api/handlers_test.go` needs to be updated with the proper tests for the new api.
To run tests:
```
go test ./restapi
go test ./api
```
## Commit changes
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to write useful commit messages
After verification, commit your changes. This is a [great post](https://chris.beams.io/posts/git-commit/) on how to
write useful commit messages
```
$ git commit -am 'Add some feature'
```
### Push to the branch
Push your locally committed changes to the remote origin (your fork)
```
$ git push origin my-new-feature
```
### Create a Pull Request
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.
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?
``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.
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).
``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).

8840
CREDITS

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,20 @@
# 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.
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:
> 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>
@@ -19,8 +24,8 @@ CONSOLE_DEV_MODE=on
```
## Running MinIO Console web app
Refer to `/portal-ui` [instructions](/portal-ui/README.md) to run the web app locally.
Refer to `/web-app` [instructions](/web-app/README.md) to run the web app locally.
# Building with MinIO
@@ -72,25 +77,6 @@ Still in the MinIO folder, run
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
## Setup

View File

@@ -1,43 +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 make build-static
USER node
FROM golang:1.19 as golayer
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/
# 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/
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
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
MAINTAINER MinIO Development "dev@min.io"
EXPOSE 9090
COPY --from=golayer /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=golayer /go/src/github.com/minio/console/console .
ENTRYPOINT ["/console"]

View File

@@ -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

View File

@@ -1,27 +0,0 @@
FROM --platform=linux/amd64 registry.access.redhat.com/ubi8/ubi-minimal:8.7 as build
RUN microdnf update --nodocs && microdnf install ca-certificates --nodocs
RUN curl -s -q https://raw.githubusercontent.com/minio/kes/master/LICENSE -o LICENSE
RUN curl -s -q https://raw.githubusercontent.com/minio/kes/master/CREDITS -o CREDITS
FROM registry.access.redhat.com/ubi8/ubi-micro:8.7
# 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 --from=build LICENSE /LICENSE
COPY --from=build CREDITS /CREDITS
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."
EXPOSE 9090
COPY console /console
ENTRYPOINT ["/console"]

View File

@@ -33,6 +33,10 @@ lint:
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
lint-fix: getdeps ## runs golangci-lint suite of linters with automatic fixes
@echo "Running $@ check"
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml --fix
install: console
@echo "Installing console binary to '$(GOPATH)/bin/console'"
@mkdir -p $(GOPATH)/bin && cp -f $(PWD)/console $(GOPATH)/bin/console
@@ -48,18 +52,19 @@ apply-gofmt:
clean-swagger:
@echo "cleaning"
@rm -rf models
@rm -rf restapi/operations
@rm -rf api/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
@swagger generate server -A console --main-package=management --server-package=api --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
@npx swagger-typescript-api -p ./swagger.yml -o ./web-app/src/api -n consoleApi.ts --custom-config generator.config.js
@git restore api/server.go
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 ..)
cd web-app; corepack enable; yarn install --prefer-offline; make build-static; yarn prettier --write . --loglevel warn; cd ..)
test-integration:
@(docker stop pgsqlcontainer || true)
@@ -77,7 +82,7 @@ test-integration:
@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)
@(cd integration && go test -coverpkg=../api -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)
@@ -125,7 +130,7 @@ test-replication:
$(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)
@(cd replication && go test -coverpkg=../api -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)
@@ -179,45 +184,45 @@ test-sso-integration:
@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)
@(cd sso-integration && go test -coverpkg=../api -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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/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/")
@(env bash $(PWD)/web-app/tests/scripts/permissions.sh "web-app/tests/permissions-7/")
@(docker stop minio)
test-apply-permissions:
@(env bash $(PWD)/portal-ui/tests/scripts/initialize-env.sh)
@(env bash $(PWD)/web-app/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})
@@ -226,20 +231,50 @@ 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)
@(env bash $(PWD)/web-app/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 ./web-app/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)
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
# Note: go test ./... will run tests on the current folder and all subfolders.
# This is needed because tests can be in the folder or sub-folder(s), let's include them all please!.
test:
@echo "execute test and get coverage"
@(cd restapi && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage.out)
@(cd api && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage.out)
# https://stackoverflow.com/questions/19200235/golang-tests-in-sub-directory
# Note: go test ./... will run tests on the current folder and all subfolders.
# This is since tests in pkg folder are in subfolders and were not executed.
test-pkg:
@echo "execute test and get coverage"
@(cd pkg && mkdir coverage && GO111MODULE=on go test -test.v -coverprofile=coverage/coverage-pkg.out)
@(cd pkg && mkdir -p coverage && GO111MODULE=on go test ./... -test.v -coverprofile=coverage/coverage-pkg.out)
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/console/api/... && go tool cover -html=coverage.out && open coverage.html)
clean:
@echo "Cleaning up all the generated files"
@@ -254,4 +289,4 @@ release: swagger-gen
@echo "Generating Release: $(RELEASE)"
@make assets
@git add -u .
@git add portal-ui/build/
@git add web-app/build/

View File

@@ -12,53 +12,30 @@ A graphical user interface for [MinIO](https://github.com/minio/minio)
**Table of Contents**
- [MinIO Console](#minio-console)
- [Install](#install)
- [Binary Releases](#binary-releases)
- [Docker](#docker)
- [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)
- [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
### Binary Releases
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.
| OS | ARCH | Binary |
|:-------:|:-------:|:----------------------------------------------------------------------------------------------------:|
| Linux | amd64 | [linux-amd64](https://github.com/minio/console/releases/latest/download/console-linux-amd64) |
| Linux | arm64 | [linux-arm64](https://github.com/minio/console/releases/latest/download/console-linux-arm64) |
| Linux | ppc64le | [linux-ppc64le](https://github.com/minio/console/releases/latest/download/console-linux-ppc64le) |
| Linux | s390x | [linux-s390x](https://github.com/minio/console/releases/latest/download/console-linux-s390x) |
| Apple | amd64 | [darwin-amd64](https://github.com/minio/console/releases/latest/download/console-darwin-amd64) |
| Windows | amd64 | [windows-amd64](https://github.com/minio/console/releases/latest/download/console-windows-amd64.exe) |
You can also verify the binary with [minisign](https://jedisct1.github.io/minisign/) by downloading the
corresponding [`.minisig`](https://github.com/minio/console/releases/latest) signature file. Then run:
```
minisign -Vm console-<OS>-<ARCH> -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
```
### Docker
Pull the latest release via:
```
docker pull minio/console
```
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
> Minimum version required is go1.21
```
go install github.com/minio/console/cmd/console@latest

View File

@@ -14,16 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
systemApi "github.com/minio/console/restapi/operations/system"
systemApi "github.com/minio/console/api/operations/system"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
)
func registerAdminArnsHandlers(api *operations.ConsoleAPI) {
@@ -31,7 +31,7 @@ func registerAdminArnsHandlers(api *operations.ConsoleAPI) {
api.SystemArnListHandler = systemApi.ArnListHandlerFunc(func(params systemApi.ArnListParams, session *models.Principal) middleware.Responder {
arnsResp, err := getArnsResponse(session, params)
if err != nil {
return systemApi.NewArnListDefault(int(err.Code)).WithPayload(err)
return systemApi.NewArnListDefault(err.Code).WithPayload(err.APIError)
}
return systemApi.NewArnListOK().WithPayload(arnsResp)
})
@@ -50,10 +50,10 @@ func getArns(ctx context.Context, client MinioAdmin) (*models.ArnsResponse, erro
}
// getArnsResponse returns a list of active arns in the instance
func getArnsResponse(session *models.Principal, params systemApi.ArnListParams) (*models.ArnsResponse, *models.Error) {
func getArnsResponse(session *models.Principal, params systemApi.ArnListParams) (*models.ArnsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -25,12 +25,12 @@ import (
"testing"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations/system"
"github.com/go-openapi/loads"
"github.com/minio/console/restapi/operations"
"github.com/minio/madmin-go/v2"
"github.com/minio/console/api/operations"
"github.com/minio/madmin-go/v3"
asrt "github.com/stretchr/testify/assert"
)
@@ -39,7 +39,7 @@ func TestArnsList(t *testing.T) {
assert := asrt.New(t)
adminClient := AdminClientMock{}
// Test-1 : getArns() returns proper arn list
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{
SQSARN: []string{"uno"},
}, nil
@@ -54,7 +54,7 @@ func TestArnsList(t *testing.T) {
assert.Nil(err, "Error should have been nil")
// Test-2 : getArns(ctx) fails for whatever reason
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, errors.New("some reason")
}

View File

@@ -14,15 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"io"
"time"
"github.com/minio/madmin-go/v2"
iampolicy "github.com/minio/pkg/iam/policy"
"github.com/minio/madmin-go/v3"
iampolicy "github.com/minio/pkg/v3/policy"
)
type AdminClientMock struct{}
@@ -47,7 +47,7 @@ var (
minioHealMock func(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error)
minioServerHealthInfoMock func(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error)
minioServerHealthInfoMock func(ctx context.Context, deadline time.Duration) (interface{}, string, error)
minioListPoliciesMock func() (map[string]*iampolicy.Policy, error)
minioGetPolicyMock func(name string) (*iampolicy.Policy, error)
@@ -66,10 +66,11 @@ var (
deleteSiteReplicationInfoMock func(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
getSiteReplicationStatus func(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
minioListTiersMock func(ctx context.Context) ([]*madmin.TierConfig, error)
minioTierStatsMock func(ctx context.Context) ([]madmin.TierInfo, error)
minioAddTiersMock func(ctx context.Context, tier *madmin.TierConfig) error
minioEditTiersMock func(ctx context.Context, tierName string, creds madmin.TierCreds) error
minioListTiersMock func(ctx context.Context) ([]*madmin.TierConfig, error)
minioTierStatsMock func(ctx context.Context) ([]madmin.TierInfo, error)
minioAddTiersMock func(ctx context.Context, tier *madmin.TierConfig) error
minioRemoveTierMock func(ctx context.Context, tierName string) error
minioEditTiersMock func(ctx context.Context, tierName string, creds madmin.TierCreds) error
minioServiceTraceMock func(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo
@@ -80,32 +81,36 @@ var (
minioSetUserStatusMock func(accessKey string, status madmin.AccountStatus) error
minioAccountInfoMock func(ctx context.Context) (madmin.AccountInfo, error)
minioAddServiceAccountMock func(ctx context.Context, policy *iampolicy.Policy, user string, accessKey string, secretKey string) (madmin.Credentials, error)
minioAddServiceAccountMock func(ctx context.Context, policy string, user string, accessKey string, secretKey string, description string, name string, expiry *time.Time, status string) (madmin.Credentials, error)
minioListServiceAccountsMock func(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error)
minioDeleteServiceAccountMock func(ctx context.Context, serviceAccount string) error
minioInfoServiceAccountMock func(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error)
minioUpdateServiceAccountMock func(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error
minioGetLDAPPolicyEntitiesMock func(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error)
minioListRemoteBucketsMock func(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error)
minioGetRemoteBucketMock func(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error)
minioAddRemoteBucketMock func(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error)
)
func (ac AdminClientMock) serverInfo(ctx context.Context) (madmin.InfoMessage, error) {
return MinioServerInfoMock(ctx)
}
func (ac AdminClientMock) listRemoteBuckets(_ context.Context, _, _ string) (targets []madmin.BucketTarget, err error) {
return nil, nil
func (ac AdminClientMock) listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error) {
return minioListRemoteBucketsMock(ctx, bucket, arnType)
}
func (ac AdminClientMock) getRemoteBucket(_ context.Context, _, _ string) (targets *madmin.BucketTarget, err error) {
return nil, nil
func (ac AdminClientMock) getRemoteBucket(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error) {
return minioGetRemoteBucketMock(ctx, bucket, arnType)
}
func (ac AdminClientMock) removeRemoteBucket(_ context.Context, _, _ string) error {
return nil
}
func (ac AdminClientMock) addRemoteBucket(_ context.Context, _ string, _ *madmin.BucketTarget) (string, error) {
return "", nil
func (ac AdminClientMock) addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error) {
return minioAddRemoteBucketMock(ctx, bucket, target)
}
func (ac AdminClientMock) changePassword(ctx context.Context, accessKey, secretKey string) error {
@@ -170,8 +175,8 @@ func (ac AdminClientMock) heal(ctx context.Context, bucket, prefix string, healO
return minioHealMock(ctx, bucket, prefix, healOpts, clientToken, forceStart, forceStop)
}
func (ac AdminClientMock) serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error) {
return minioServerHealthInfoMock(ctx, healthDataTypes, deadline)
func (ac AdminClientMock) serverHealthInfo(ctx context.Context, deadline time.Duration) (interface{}, string, error) {
return minioServerHealthInfoMock(ctx, deadline)
}
func (ac AdminClientMock) addOrUpdateIDPConfig(_ context.Context, _, _, _ string, _ bool) (restart bool, err error) {
@@ -313,11 +318,11 @@ func (ac AdminClientMock) getSiteReplicationInfo(ctx context.Context) (*madmin.S
return getSiteReplicationInfo(ctx)
}
func (ac AdminClientMock) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite) (*madmin.ReplicateAddStatus, error) {
func (ac AdminClientMock) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, _ madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error) {
return addSiteReplicationInfo(ctx, sites)
}
func (ac AdminClientMock) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo) (*madmin.ReplicateEditStatus, error) {
func (ac AdminClientMock) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, _ madmin.SREditOptions) (*madmin.ReplicateEditStatus, error) {
return editSiteReplicationInfo(ctx, site)
}
@@ -341,6 +346,10 @@ func (ac AdminClientMock) addTier(ctx context.Context, tier *madmin.TierConfig)
return minioAddTiersMock(ctx, tier)
}
func (ac AdminClientMock) removeTier(ctx context.Context, tierName string) error {
return minioRemoveTierMock(ctx, tierName)
}
func (ac AdminClientMock) editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error {
return minioEditTiersMock(ctx, tierName, creds)
}
@@ -373,8 +382,8 @@ func (ac AdminClientMock) AccountInfo(ctx context.Context) (madmin.AccountInfo,
return minioAccountInfoMock(ctx)
}
func (ac AdminClientMock) addServiceAccount(ctx context.Context, policy *iampolicy.Policy, user string, accessKey string, secretKey string) (madmin.Credentials, error) {
return minioAddServiceAccountMock(ctx, policy, user, accessKey, secretKey)
func (ac AdminClientMock) addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, description string, name string, expiry *time.Time, status string) (madmin.Credentials, error) {
return minioAddServiceAccountMock(ctx, policy, user, accessKey, secretKey, description, name, expiry, status)
}
func (ac AdminClientMock) listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error) {

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,11 +24,11 @@ import (
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
madmin "github.com/minio/madmin-go/v2"
madmin "github.com/minio/madmin-go/v3"
cfgApi "github.com/minio/console/restapi/operations/configuration"
cfgApi "github.com/minio/console/api/operations/configuration"
)
func registerConfigHandlers(api *operations.ConsoleAPI) {
@@ -36,7 +36,7 @@ func registerConfigHandlers(api *operations.ConsoleAPI) {
api.ConfigurationListConfigHandler = cfgApi.ListConfigHandlerFunc(func(params cfgApi.ListConfigParams, session *models.Principal) middleware.Responder {
configListResp, err := getListConfigResponse(session, params)
if err != nil {
return cfgApi.NewListConfigDefault(int(err.Code)).WithPayload(err)
return cfgApi.NewListConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewListConfigOK().WithPayload(configListResp)
})
@@ -44,7 +44,7 @@ func registerConfigHandlers(api *operations.ConsoleAPI) {
api.ConfigurationConfigInfoHandler = cfgApi.ConfigInfoHandlerFunc(func(params cfgApi.ConfigInfoParams, session *models.Principal) middleware.Responder {
config, err := getConfigResponse(session, params)
if err != nil {
return cfgApi.NewConfigInfoDefault(int(err.Code)).WithPayload(err)
return cfgApi.NewConfigInfoDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewConfigInfoOK().WithPayload(config)
})
@@ -52,7 +52,7 @@ func registerConfigHandlers(api *operations.ConsoleAPI) {
api.ConfigurationSetConfigHandler = cfgApi.SetConfigHandlerFunc(func(params cfgApi.SetConfigParams, session *models.Principal) middleware.Responder {
resp, err := setConfigResponse(session, params)
if err != nil {
return cfgApi.NewSetConfigDefault(int(err.Code)).WithPayload(err)
return cfgApi.NewSetConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewSetConfigOK().WithPayload(resp)
})
@@ -60,7 +60,7 @@ func registerConfigHandlers(api *operations.ConsoleAPI) {
api.ConfigurationResetConfigHandler = cfgApi.ResetConfigHandlerFunc(func(params cfgApi.ResetConfigParams, session *models.Principal) middleware.Responder {
resp, err := resetConfigResponse(session, params)
if err != nil {
return cfgApi.NewResetConfigDefault(int(err.Code)).WithPayload(err)
return cfgApi.NewResetConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewResetConfigOK().WithPayload(resp)
})
@@ -68,14 +68,14 @@ func registerConfigHandlers(api *operations.ConsoleAPI) {
api.ConfigurationExportConfigHandler = cfgApi.ExportConfigHandlerFunc(func(params cfgApi.ExportConfigParams, session *models.Principal) middleware.Responder {
resp, err := exportConfigResponse(session, params)
if err != nil {
return cfgApi.NewExportConfigDefault((int(err.Code))).WithPayload(err)
return cfgApi.NewExportConfigDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewExportConfigOK().WithPayload(resp)
})
api.ConfigurationPostConfigsImportHandler = cfgApi.PostConfigsImportHandlerFunc(func(params cfgApi.PostConfigsImportParams, session *models.Principal) middleware.Responder {
_, err := importConfigResponse(session, params)
if err != nil {
return cfgApi.NewPostConfigsImportDefault((int(err.Code))).WithPayload(err)
return cfgApi.NewPostConfigsImportDefault(err.Code).WithPayload(err.APIError)
}
return cfgApi.NewPostConfigsImportDefault(200)
})
@@ -101,10 +101,10 @@ func listConfig(client MinioAdmin) ([]*models.ConfigDescription, error) {
}
// getListConfigResponse performs listConfig() and serializes it to the handler's output
func getListConfigResponse(session *models.Principal, params cfgApi.ListConfigParams) (*models.ListConfigResponse, *models.Error) {
func getListConfigResponse(session *models.Principal, params cfgApi.ListConfigParams) (*models.ListConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -166,10 +166,10 @@ func getConfig(ctx context.Context, client MinioAdmin, name string) ([]*models.C
}
// getConfigResponse performs getConfig() and serializes it to the handler's output
func getConfigResponse(session *models.Principal, params cfgApi.ConfigInfoParams) ([]*models.Configuration, *models.Error) {
func getConfigResponse(session *models.Principal, params cfgApi.ConfigInfoParams) ([]*models.Configuration, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -230,11 +230,11 @@ func buildConfig(configName *string, kvs []*models.ConfigurationKV) *string {
}
// setConfigResponse implements setConfig() to be used by handler
func setConfigResponse(session *models.Principal, params cfgApi.SetConfigParams) (*models.SetConfigResponse, *models.Error) {
func setConfigResponse(session *models.Principal, params cfgApi.SetConfigParams) (*models.SetConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -256,11 +256,11 @@ func resetConfig(ctx context.Context, client MinioAdmin, configName *string) (er
}
// resetConfigResponse implements resetConfig() to be used by handler
func resetConfigResponse(session *models.Principal, params cfgApi.ResetConfigParams) (*models.SetConfigResponse, *models.Error) {
func resetConfigResponse(session *models.Principal, params cfgApi.ResetConfigParams) (*models.SetConfigResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -269,7 +269,6 @@ func resetConfigResponse(session *models.Principal, params cfgApi.ResetConfigPar
adminClient := AdminClient{Client: mAdmin}
err = resetConfig(ctx, adminClient, &params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -277,11 +276,11 @@ func resetConfigResponse(session *models.Principal, params cfgApi.ResetConfigPar
return &models.SetConfigResponse{Restart: true}, nil
}
func exportConfigResponse(session *models.Principal, params cfgApi.ExportConfigParams) (*models.ConfigExportResponse, *models.Error) {
func exportConfigResponse(session *models.Principal, params cfgApi.ExportConfigParams) (*models.ConfigExportResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -296,19 +295,19 @@ func exportConfigResponse(session *models.Principal, params cfgApi.ExportConfigP
}, nil
}
func importConfigResponse(session *models.Principal, params cfgApi.PostConfigsImportParams) (*cfgApi.PostConfigsImportDefault, *models.Error) {
func importConfigResponse(session *models.Principal, params cfgApi.PostConfigsImportParams) (*cfgApi.PostConfigsImportDefault, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
file, _, err := params.HTTPRequest.FormFile("file")
defer file.Close()
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
defer file.Close()
err = mAdmin.SetConfig(ctx, file)
if err != nil {
return nil, ErrorWithContext(ctx, err)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -28,7 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
const (
@@ -63,7 +63,7 @@ func TestListConfig(t *testing.T) {
}
expectedKeysDesc := mockConfigList.KeysHelp
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return mockConfigList, nil
}
configList, err := listConfig(adminClient)
@@ -80,7 +80,7 @@ func TestListConfig(t *testing.T) {
// Test-2 : listConfig() Return error and see that the error is handled correctly and returned
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return madmin.Help{}, errors.New("error")
}
_, err = listConfig(adminClient)
@@ -94,7 +94,7 @@ func TestSetConfig(t *testing.T) {
adminClient := AdminClientMock{}
function := "setConfig()"
// mock function response from setConfig()
minioSetConfigKVMock = func(kv string) (restart bool, err error) {
minioSetConfigKVMock = func(_ string) (restart bool, err error) {
return false, nil
}
configName := "notify_postgres"
@@ -119,7 +119,7 @@ func TestSetConfig(t *testing.T) {
assert.Equal(restart, false)
// Test-2 : setConfig() returns error, handle properly
minioSetConfigKVMock = func(kv string) (restart bool, err error) {
minioSetConfigKVMock = func(_ string) (restart bool, err error) {
return false, errors.New("error")
}
restart, err = setConfig(ctx, adminClient, &configName, kvs)
@@ -129,7 +129,7 @@ func TestSetConfig(t *testing.T) {
assert.Equal(restart, false)
// Test-4 : setConfig() set config, need restart
minioSetConfigKVMock = func(kv string) (restart bool, err error) {
minioSetConfigKVMock = func(_ string) (restart bool, err error) {
return true, nil
}
restart, err = setConfig(ctx, adminClient, &configName, kvs)
@@ -144,7 +144,7 @@ func TestDelConfig(t *testing.T) {
adminClient := AdminClientMock{}
function := "resetConfig()"
// mock function response from setConfig()
minioDelConfigKVMock = func(name string) (err error) {
minioDelConfigKVMock = func(_ string) (err error) {
return nil
}
configName := "region"
@@ -158,7 +158,7 @@ func TestDelConfig(t *testing.T) {
}
// Test-2 : resetConfig() returns error, handle properly
minioDelConfigKVMock = func(name string) (err error) {
minioDelConfigKVMock = func(_ string) (err error) {
return errors.New("error")
}
@@ -220,7 +220,7 @@ func Test_buildConfig(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
if got := buildConfig(tt.args.configName, tt.args.kvs); !reflect.DeepEqual(got, tt.want) {
t.Errorf("buildConfig() = %s, want %s", *got, *tt.want)
}
@@ -260,7 +260,7 @@ func Test_setConfigWithARN(t *testing.T) {
},
arn: "1",
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
wantErr: false,
@@ -280,7 +280,7 @@ func Test_setConfigWithARN(t *testing.T) {
},
arn: "1",
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return true, nil
},
wantErr: false,
@@ -300,7 +300,7 @@ func Test_setConfigWithARN(t *testing.T) {
},
arn: "",
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
wantErr: false,
@@ -320,7 +320,7 @@ func Test_setConfigWithARN(t *testing.T) {
},
arn: "",
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, errors.New("error")
},
wantErr: true,
@@ -328,7 +328,7 @@ func Test_setConfigWithARN(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
// mock function response from setConfig()
minioSetConfigKVMock = tt.mockSetConfig
restart, err := setConfigWithARNAccountID(tt.args.ctx, tt.args.client, tt.args.configName, tt.args.kvs, tt.args.arn)
@@ -361,7 +361,7 @@ func Test_getConfig(t *testing.T) {
},
mock: func() {
// mock function response from getConfig()
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return []byte(`notify_postgres:_ connection_string="host=localhost dbname=minio_events user=postgres password=password port=5432 sslmode=disable" table=bucketevents`), nil
}
@@ -407,7 +407,7 @@ func Test_getConfig(t *testing.T) {
KeysHelp: configListMock,
}
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return mockConfigList, nil
}
},
@@ -435,7 +435,7 @@ func Test_getConfig(t *testing.T) {
},
mock: func() {
// mock function response from getConfig()
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return []byte(`notify_postgres:_`), nil
}
@@ -481,7 +481,7 @@ func Test_getConfig(t *testing.T) {
KeysHelp: configListMock,
}
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return mockConfigList, nil
}
},
@@ -496,7 +496,7 @@ func Test_getConfig(t *testing.T) {
},
mock: func() {
// mock function response from getConfig()
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
x := make(map[string]string)
x["x"] = "x"
j, _ := json.Marshal(x)
@@ -545,7 +545,7 @@ func Test_getConfig(t *testing.T) {
KeysHelp: configListMock,
}
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return mockConfigList, nil
}
},
@@ -560,13 +560,13 @@ func Test_getConfig(t *testing.T) {
},
mock: func() {
// mock function response from getConfig()
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return nil, errors.New("invalid config")
}
mockConfigList := madmin.Help{}
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return mockConfigList, nil
}
},
@@ -581,11 +581,11 @@ func Test_getConfig(t *testing.T) {
},
mock: func() {
// mock function response from getConfig()
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return nil, errors.New("invalid config")
}
// mock function response from listConfig()
minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) {
minioHelpConfigKVMock = func(_, _ string, _ bool) (madmin.Help, error) {
return madmin.Help{}, errors.New("no help")
}
},
@@ -595,7 +595,7 @@ func Test_getConfig(t *testing.T) {
}
for _, tt := range tests {
tt.mock()
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
got, err := getConfig(context.Background(), tt.args.client, tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("getConfig() error = %v, wantErr %v", err, tt.wantErr)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -22,7 +22,7 @@ import (
"strings"
"time"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/minio/websocket"
)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -22,7 +22,7 @@ import (
"fmt"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -40,7 +40,7 @@ func TestAdminConsoleLog(t *testing.T) {
// Test-1: Serve Console with no errors until Console finishes sending
// define mock function behavior for minio server Console
minioGetLogsMock = func(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo {
minioGetLogsMock = func(_ context.Context, _ string, _ int, _ string) <-chan madmin.LogInfo {
ch := make(chan madmin.LogInfo)
// Only success, start a routine to start reading line by line.
go func(ch chan<- madmin.LogInfo) {
@@ -58,7 +58,7 @@ func TestAdminConsoleLog(t *testing.T) {
}
writesCount := 1
// mock connection WriteMessage() no error
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, data []byte) error {
// emulate that receiver gets the message written
var t madmin.LogInfo
_ = json.Unmarshal(data, &t)
@@ -82,7 +82,7 @@ func TestAdminConsoleLog(t *testing.T) {
}
// Test-2: if error happens while writing, return error
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, _ []byte) error {
return fmt.Errorf("error on write")
}
if err := startConsoleLog(ctx, mockWSConn, adminClient, LogRequest{node: "", logType: "all"}); assert.Error(err) {
@@ -91,7 +91,7 @@ func TestAdminConsoleLog(t *testing.T) {
// Test-3: error happens on GetLogs Minio, Console should stop
// and error shall be returned.
minioGetLogsMock = func(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo {
minioGetLogsMock = func(_ context.Context, _ string, _ int, _ string) <-chan madmin.LogInfo {
ch := make(chan madmin.LogInfo)
// Only success, start a routine to start reading line by line.
go func(ch chan<- madmin.LogInfo) {
@@ -108,7 +108,7 @@ func TestAdminConsoleLog(t *testing.T) {
}(ch)
return ch
}
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, _ []byte) error {
return nil
}
if err := startConsoleLog(ctx, mockWSConn, adminClient, LogRequest{node: "", logType: "all"}); assert.Error(err) {

View File

@@ -14,18 +14,17 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/pkg/utils"
"github.com/minio/console/restapi/operations"
"github.com/minio/madmin-go/v2"
"github.com/minio/console/api/operations"
"github.com/minio/madmin-go/v3"
groupApi "github.com/minio/console/restapi/operations/group"
groupApi "github.com/minio/console/api/operations/group"
"github.com/minio/console/models"
)
@@ -35,7 +34,7 @@ func registerGroupsHandlers(api *operations.ConsoleAPI) {
api.GroupListGroupsHandler = groupApi.ListGroupsHandlerFunc(func(params groupApi.ListGroupsParams, session *models.Principal) middleware.Responder {
listGroupsResponse, err := getListGroupsResponse(session, params)
if err != nil {
return groupApi.NewListGroupsDefault(int(err.Code)).WithPayload(err)
return groupApi.NewListGroupsDefault(err.Code).WithPayload(err.APIError)
}
return groupApi.NewListGroupsOK().WithPayload(listGroupsResponse)
})
@@ -43,21 +42,21 @@ func registerGroupsHandlers(api *operations.ConsoleAPI) {
api.GroupGroupInfoHandler = groupApi.GroupInfoHandlerFunc(func(params groupApi.GroupInfoParams, session *models.Principal) middleware.Responder {
groupInfo, err := getGroupInfoResponse(session, params)
if err != nil {
return groupApi.NewGroupInfoDefault(int(err.Code)).WithPayload(err)
return groupApi.NewGroupInfoDefault(err.Code).WithPayload(err.APIError)
}
return groupApi.NewGroupInfoOK().WithPayload(groupInfo)
})
// Add Group
api.GroupAddGroupHandler = groupApi.AddGroupHandlerFunc(func(params groupApi.AddGroupParams, session *models.Principal) middleware.Responder {
if err := getAddGroupResponse(session, params); err != nil {
return groupApi.NewAddGroupDefault(int(err.Code)).WithPayload(err)
return groupApi.NewAddGroupDefault(err.Code).WithPayload(err.APIError)
}
return groupApi.NewAddGroupCreated()
})
// Remove Group
api.GroupRemoveGroupHandler = groupApi.RemoveGroupHandlerFunc(func(params groupApi.RemoveGroupParams, session *models.Principal) middleware.Responder {
if err := getRemoveGroupResponse(session, params); err != nil {
return groupApi.NewRemoveGroupDefault(int(err.Code)).WithPayload(err)
return groupApi.NewRemoveGroupDefault(err.Code).WithPayload(err.APIError)
}
return groupApi.NewRemoveGroupNoContent()
})
@@ -65,17 +64,17 @@ func registerGroupsHandlers(api *operations.ConsoleAPI) {
api.GroupUpdateGroupHandler = groupApi.UpdateGroupHandlerFunc(func(params groupApi.UpdateGroupParams, session *models.Principal) middleware.Responder {
groupUpdateResp, err := getUpdateGroupResponse(session, params)
if err != nil {
return groupApi.NewUpdateGroupDefault(int(err.Code)).WithPayload(err)
return groupApi.NewUpdateGroupDefault(err.Code).WithPayload(err.APIError)
}
return groupApi.NewUpdateGroupOK().WithPayload(groupUpdateResp)
})
}
// getListGroupsResponse performs listGroups() and serializes it to the handler's output
func getListGroupsResponse(session *models.Principal, params groupApi.ListGroupsParams) (*models.ListGroupsResponse, *models.Error) {
func getListGroupsResponse(session *models.Principal, params groupApi.ListGroupsParams) (*models.ListGroupsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -107,10 +106,10 @@ func groupInfo(ctx context.Context, client MinioAdmin, group string) (*madmin.Gr
}
// getGroupInfoResponse performs groupInfo() and serializes it to the handler's output
func getGroupInfoResponse(session *models.Principal, params groupApi.GroupInfoParams) (*models.Group, *models.Error) {
func getGroupInfoResponse(session *models.Principal, params groupApi.GroupInfoParams) (*models.Group, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -118,12 +117,7 @@ func getGroupInfoResponse(session *models.Principal, params groupApi.GroupInfoPa
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
groupName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
groupDesc, err := groupInfo(ctx, adminClient, groupName)
groupDesc, err := groupInfo(ctx, adminClient, params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -153,7 +147,7 @@ func addGroup(ctx context.Context, client MinioAdmin, group string, members []st
}
// getAddGroupResponse performs addGroup() and serializes it to the handler's output
func getAddGroupResponse(session *models.Principal, params groupApi.AddGroupParams) *models.Error {
func getAddGroupResponse(session *models.Principal, params groupApi.AddGroupParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
// AddGroup request needed to proceed
@@ -161,7 +155,7 @@ func getAddGroupResponse(session *models.Principal, params groupApi.AddGroupPara
return ErrorWithContext(ctx, ErrGroupBodyNotInRequest)
}
groupRequest := params.Body
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -198,13 +192,13 @@ func removeGroup(ctx context.Context, client MinioAdmin, group string) error {
}
// getRemoveGroupResponse performs removeGroup() and serializes it to the handler's output
func getRemoveGroupResponse(session *models.Principal, params groupApi.RemoveGroupParams) *models.Error {
func getRemoveGroupResponse(session *models.Principal, params groupApi.RemoveGroupParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Name == "" {
return ErrorWithContext(ctx, ErrGroupNameNotInRequest)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -212,12 +206,7 @@ func getRemoveGroupResponse(session *models.Principal, params groupApi.RemoveGro
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
groupName, err := utils.DecodeBase64(params.Name)
if err != nil {
return ErrorWithContext(ctx, err)
}
if err := removeGroup(ctx, adminClient, groupName); err != nil {
if err := removeGroup(ctx, adminClient, params.Name); err != nil {
minioError := madmin.ToErrorResponse(err)
err2 := ErrorWithContext(ctx, err)
if minioError.Code == "XMinioAdminNoSuchGroup" {
@@ -282,7 +271,7 @@ func setGroupStatus(ctx context.Context, client MinioAdmin, group, status string
// getUpdateGroupResponse updates a group by adding or removing it's members depending on the request,
// also sets the group's status if status in the request is different than the current one.
// Then serializes the output to be used by the handler.
func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGroupParams) (*models.Group, *models.Error) {
func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGroupParams) (*models.Group, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Name == "" {
@@ -293,12 +282,7 @@ func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGro
}
expectedGroupUpdate := params.Body
groupName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -306,7 +290,7 @@ func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGro
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
groupUpdated, err := groupUpdate(ctx, adminClient, groupName, expectedGroupUpdate)
groupUpdated, err := groupUpdate(ctx, adminClient, params.Name, expectedGroupUpdate)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,7 +24,7 @@ import (
"github.com/go-openapi/swag"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -130,7 +130,7 @@ func TestGroupInfo(t *testing.T) {
Status: "enabled",
}
// mock function response from updateGroupMembers()
minioGetGroupDescriptionMock = func(group string) (*madmin.GroupDesc, error) {
minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) {
return mockResponse, nil
}
function := "groupInfo()"
@@ -144,7 +144,7 @@ func TestGroupInfo(t *testing.T) {
assert.Equal("enabled", info.Status)
// Test-2 : groupInfo() Return error and see that the error is handled correctly and returned
minioGetGroupDescriptionMock = func(group string) (*madmin.GroupDesc, error) {
minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) {
return nil, errors.New("error")
}
_, err = groupInfo(ctx, adminClient, groupName)
@@ -226,7 +226,7 @@ func TestUpdateGroup(t *testing.T) {
// the function twice but the second time returned an error
is2ndRunGroupInfo := false
// mock function response from updateGroupMembers()
minioGetGroupDescriptionMock = func(group string) (*madmin.GroupDesc, error) {
minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) {
if is2ndRunGroupInfo {
return mockResponseAfterUpdate, nil
}
@@ -236,7 +236,7 @@ func TestUpdateGroup(t *testing.T) {
minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error {
return nil
}
minioSetGroupStatusMock = func(group string, status madmin.GroupStatus) error {
minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error {
return nil
}
groupUpdated, err := groupUpdate(ctx, adminClient, groupName, expectedGroupUpdate)
@@ -258,7 +258,7 @@ func TestSetGroupStatus(t *testing.T) {
defer cancel()
// Test-1: setGroupStatus() update valid disabled status
expectedStatus := "disabled"
minioSetGroupStatusMock = func(group string, status madmin.GroupStatus) error {
minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error {
return nil
}
if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); err != nil {
@@ -266,7 +266,7 @@ func TestSetGroupStatus(t *testing.T) {
}
// Test-2: setGroupStatus() update valid enabled status
expectedStatus = "enabled"
minioSetGroupStatusMock = func(group string, status madmin.GroupStatus) error {
minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error {
return nil
}
if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); err != nil {
@@ -274,7 +274,7 @@ func TestSetGroupStatus(t *testing.T) {
}
// Test-3: setGroupStatus() update invalid status, should send error
expectedStatus = "invalid"
minioSetGroupStatusMock = func(group string, status madmin.GroupStatus) error {
minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error {
return nil
}
if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); assert.Error(err) {
@@ -282,7 +282,7 @@ func TestSetGroupStatus(t *testing.T) {
}
// Test-4: setGroupStatus() handler error correctly
expectedStatus = "enabled"
minioSetGroupStatusMock = func(group string, status madmin.GroupStatus) error {
minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error {
return errors.New("error")
}
if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); assert.Error(err) {

View File

@@ -14,23 +14,24 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
"context"
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"net/url"
"os"
"time"
"github.com/klauspost/compress/gzip"
xhttp "github.com/minio/console/pkg/http"
"github.com/minio/console/pkg/logger"
"github.com/minio/console/pkg/utils"
subnet "github.com/minio/console/pkg/subnet"
"github.com/minio/madmin-go/v2"
mc "github.com/minio/mc/cmd"
"github.com/minio/websocket"
)
@@ -42,42 +43,28 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
}
// Fetch info of all servers (cluster or single server)
healthDataTypes := []madmin.HealthDataType{
madmin.HealthDataTypeMinioInfo,
madmin.HealthDataTypeMinioConfig,
madmin.HealthDataTypeSysCPU,
madmin.HealthDataTypeSysDriveHw,
madmin.HealthDataTypeSysDocker,
madmin.HealthDataTypeSysOsInfo,
madmin.HealthDataTypeSysLoad,
madmin.HealthDataTypeSysMem,
madmin.HealthDataTypeSysNet,
madmin.HealthDataTypeSysProcess,
}
var err error
// Fetch info of all servers (cluster or single server)
healthInfo, version, err := client.serverHealthInfo(ctx, healthDataTypes, *deadline)
healthInfo, version, err := client.serverHealthInfo(ctx, *deadline)
if err != nil {
return err
}
compressedDiag, err := tarGZ(healthInfo, version)
compressedDiag, err := mc.TarGZHealthInfo(healthInfo, version)
if err != nil {
return err
}
encodedDiag := b64.StdEncoding.EncodeToString(compressedDiag)
type messageReport struct {
Encoded string `json:"encoded"`
ServerHealthInfo interface{} `json:"serverHealthInfo"`
SubnetResponse string `json:"subnetResponse"`
}
subnetResp, err := sendHealthInfoToSubnet(ctx, healthInfo, client)
ctx = context.WithValue(ctx, utils.ContextClientIP, conn.remoteAddress())
err = sendHealthInfoToSubnet(ctx, compressedDiag, client)
report := messageReport{
Encoded: encodedDiag,
ServerHealthInfo: healthInfo,
SubnetResponse: subnetResp,
SubnetResponse: mc.SubnetBaseURL() + "/health",
}
if err != nil {
report.SubnetResponse = fmt.Sprintf("Error: %s", err.Error())
@@ -92,31 +79,6 @@ func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadli
return conn.writeMessage(websocket.TextMessage, message)
}
// compress and tar MinIO diagnostics output
func tarGZ(healthInfo interface{}, version string) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
gzWriter := gzip.NewWriter(buffer)
enc := json.NewEncoder(gzWriter)
header := struct {
Version string `json:"version"`
}{Version: version}
if err := enc.Encode(header); err != nil {
return nil, err
}
if err := enc.Encode(healthInfo); err != nil {
return nil, err
}
err := gzWriter.Close()
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// getHealthInfoOptionsFromReq gets duration for startHealthInfo request
// path come as : `/health-info?deadline=2h`
func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
@@ -127,34 +89,65 @@ func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
return &deadlineDuration, nil
}
func sendHealthInfoToSubnet(ctx context.Context, healthInfo interface{}, client MinioAdmin) (string, error) {
filename := fmt.Sprintf("health_%d.json", time.Now().Unix())
func updateMcGlobals(subnetTokenConfig subnet.LicenseTokenConfig) error {
mc.GlobalDevMode = getConsoleDevMode()
if len(subnetTokenConfig.Proxy) > 0 {
proxyURL, e := url.Parse(subnetTokenConfig.Proxy)
if e != nil {
return e
}
mc.GlobalSubnetProxyURL = proxyURL
}
return nil
}
subnetUploadURL := subnet.UploadURL("health", filename)
subnetHTTPClient := &xhttp.Client{Client: GetConsoleHTTPClient("")}
func sendHealthInfoToSubnet(ctx context.Context, compressedHealthInfo []byte, client MinioAdmin) error {
filename := fmt.Sprintf("health_%d.json.gz", time.Now().Unix())
subnetTokenConfig, e := GetSubnetKeyFromMinIOConfig(ctx, client)
if e != nil {
return "", e
return e
}
apiKey := subnetTokenConfig.APIKey
headers := subnet.UploadAuthHeaders(apiKey)
resp, e := subnet.UploadFileToSubnet(healthInfo, subnetHTTPClient, filename, subnetUploadURL, headers)
e = updateMcGlobals(*subnetTokenConfig)
if e != nil {
return "", e
return e
}
var apiKey string
if len(subnetTokenConfig.APIKey) != 0 {
apiKey = subnetTokenConfig.APIKey
} else {
apiKey, e = subnet.GetSubnetAPIKeyUsingLicense(subnetTokenConfig.License)
if e != nil {
return e
}
}
e = os.WriteFile(filename, compressedHealthInfo, 0o666)
if e != nil {
return e
}
headers := mc.SubnetAPIKeyAuthHeaders(apiKey)
resp, e := (&mc.SubnetFileUploader{
FilePath: filename,
ReqURL: mc.SubnetUploadURL("health"),
Headers: headers,
DeleteAfterUpload: true,
}).UploadFileToSubnet()
if e != nil {
// file gets deleted only if upload is successful
// so we delete explicitly here as we already have the bytes
logger.LogIf(ctx, os.Remove(filename))
return e
}
type SubnetResponse struct {
ClusterURL string `json:"cluster_url,omitempty"`
LicenseV2 string `json:"license_v2,omitempty"`
APIKey string `json:"api_key,omitempty"`
}
var subnetResp SubnetResponse
e = json.Unmarshal([]byte(resp), &subnetResp)
if e != nil {
return "", e
}
if len(subnetResp.ClusterURL) != 0 {
subnetClusterURL := strings.ReplaceAll(subnetResp.ClusterURL, "%2f", "/")
return subnetClusterURL, nil
return e
}
return "", ErrSubnetUploadFail
return nil
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,7 +24,7 @@ import (
"testing"
"time"
madmin "github.com/minio/madmin-go/v2"
madmin "github.com/minio/madmin-go/v3"
)
func Test_serverHealthInfo(t *testing.T) {
@@ -51,7 +51,7 @@ func Test_serverHealthInfo(t *testing.T) {
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}, {}},
wsWriteMock: func(messageType int, data []byte) error {
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
@@ -67,7 +67,7 @@ func Test_serverHealthInfo(t *testing.T) {
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}},
wsWriteMock: func(messageType int, data []byte) error {
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
@@ -83,7 +83,7 @@ func Test_serverHealthInfo(t *testing.T) {
args: args{
deadline: deadlineDuration,
mockMessages: []madmin.HealthInfo{{}},
wsWriteMock: func(messageType int, data []byte) error {
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
@@ -102,7 +102,7 @@ func Test_serverHealthInfo(t *testing.T) {
Error: "error on healthInfo",
},
},
wsWriteMock: func(messageType int, data []byte) error {
wsWriteMock: func(_ int, data []byte) error {
// mock connection WriteMessage() no error
// emulate that receiver gets the message written
var t madmin.HealthInfo
@@ -115,12 +115,12 @@ func Test_serverHealthInfo(t *testing.T) {
}
for _, tt := range tests {
tt := tt
t.Run(tt.test, func(t *testing.T) {
t.Run(tt.test, func(_ *testing.T) {
// make testReceiver channel
testReceiver = make(chan madmin.HealthInfo, len(tt.args.mockMessages))
// mock function same for all tests, changes mockMessages
minioServerHealthInfoMock = func(ctx context.Context, healthDataTypes []madmin.HealthDataType,
deadline time.Duration,
minioServerHealthInfoMock = func(_ context.Context,
_ time.Duration,
) (interface{}, string, error) {
info := tt.args.mockMessages[0]
return info, madmin.HealthInfoVersion, nil

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package restapi
package api
import (
"context"
@@ -23,10 +23,10 @@ import (
"time"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/api/operations/idp"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/idp"
madmin "github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
var errInvalidIDPType = fmt.Errorf("IDP type must be one of %v", madmin.ValidIDPConfigTypes)
@@ -35,51 +35,51 @@ func registerIDPHandlers(api *operations.ConsoleAPI) {
api.IdpCreateConfigurationHandler = idp.CreateConfigurationHandlerFunc(func(params idp.CreateConfigurationParams, session *models.Principal) middleware.Responder {
response, err := createIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewCreateConfigurationDefault(int(err.Code)).WithPayload(err)
return idp.NewCreateConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewCreateConfigurationCreated().WithPayload(response)
})
api.IdpUpdateConfigurationHandler = idp.UpdateConfigurationHandlerFunc(func(params idp.UpdateConfigurationParams, session *models.Principal) middleware.Responder {
response, err := updateIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewUpdateConfigurationDefault(int(err.Code)).WithPayload(err)
return idp.NewUpdateConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewUpdateConfigurationOK().WithPayload(response)
})
api.IdpListConfigurationsHandler = idp.ListConfigurationsHandlerFunc(func(params idp.ListConfigurationsParams, session *models.Principal) middleware.Responder {
response, err := listIDPConfigurationsResponse(session, params)
if err != nil {
return idp.NewListConfigurationsDefault(int(err.Code)).WithPayload(err)
return idp.NewListConfigurationsDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewListConfigurationsOK().WithPayload(response)
})
api.IdpDeleteConfigurationHandler = idp.DeleteConfigurationHandlerFunc(func(params idp.DeleteConfigurationParams, session *models.Principal) middleware.Responder {
response, err := deleteIDPConfigurationResponse(session, params)
if err != nil {
return idp.NewDeleteConfigurationDefault(int(err.Code)).WithPayload(err)
return idp.NewDeleteConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewDeleteConfigurationOK().WithPayload(response)
})
api.IdpGetConfigurationHandler = idp.GetConfigurationHandlerFunc(func(params idp.GetConfigurationParams, session *models.Principal) middleware.Responder {
response, err := getIDPConfigurationsResponse(session, params)
if err != nil {
return idp.NewGetConfigurationDefault(int(err.Code)).WithPayload(err)
return idp.NewGetConfigurationDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewGetConfigurationOK().WithPayload(response)
})
api.IdpGetLDAPEntitiesHandler = idp.GetLDAPEntitiesHandlerFunc(func(params idp.GetLDAPEntitiesParams, session *models.Principal) middleware.Responder {
response, err := getLDAPEntitiesResponse(session, params)
if err != nil {
return idp.NewGetLDAPEntitiesDefault(int(err.Code)).WithPayload(err)
return idp.NewGetLDAPEntitiesDefault(err.Code).WithPayload(err.APIError)
}
return idp.NewGetLDAPEntitiesOK().WithPayload(response)
})
}
func createIDPConfigurationResponse(session *models.Principal, params idp.CreateConfigurationParams) (*models.SetIDPResponse, *models.Error) {
func createIDPConfigurationResponse(session *models.Principal, params idp.CreateConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -90,10 +90,10 @@ func createIDPConfigurationResponse(session *models.Principal, params idp.Create
return &models.SetIDPResponse{Restart: restart}, nil
}
func updateIDPConfigurationResponse(session *models.Principal, params idp.UpdateConfigurationParams) (*models.SetIDPResponse, *models.Error) {
func updateIDPConfigurationResponse(session *models.Principal, params idp.UpdateConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -115,10 +115,10 @@ func createOrUpdateIDPConfig(ctx context.Context, idpType, name, input string, u
return restart, nil
}
func listIDPConfigurationsResponse(session *models.Principal, params idp.ListConfigurationsParams) (*models.IdpListConfigurationsResponse, *models.Error) {
func listIDPConfigurationsResponse(session *models.Principal, params idp.ListConfigurationsParams) (*models.IdpListConfigurationsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -151,10 +151,10 @@ func parseIDPConfigurations(configs []madmin.IDPListItem) (serverConfigs []*mode
return serverConfigs
}
func deleteIDPConfigurationResponse(session *models.Principal, params idp.DeleteConfigurationParams) (*models.SetIDPResponse, *models.Error) {
func deleteIDPConfigurationResponse(session *models.Principal, params idp.DeleteConfigurationParams) (*models.SetIDPResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -176,10 +176,10 @@ func deleteIDPConfig(ctx context.Context, idpType, name string, client MinioAdmi
return restart, nil
}
func getIDPConfigurationsResponse(session *models.Principal, params idp.GetConfigurationParams) (*models.IdpServerConfiguration, *models.Error) {
func getIDPConfigurationsResponse(session *models.Principal, params idp.GetConfigurationParams) (*models.IdpServerConfiguration, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -198,6 +198,7 @@ func getIDPConfiguration(ctx context.Context, idpType, name string, client Minio
if err != nil {
return nil, err
}
return &models.IdpServerConfiguration{
Name: config.Name,
Type: config.Type,
@@ -217,10 +218,10 @@ func parseIDPConfigurationsInfo(infoList []madmin.IDPCfgInfo) (results []*models
return results
}
func getLDAPEntitiesResponse(session *models.Principal, params idp.GetLDAPEntitiesParams) (*models.LdapEntities, *models.Error) {
func getLDAPEntitiesResponse(session *models.Principal, params idp.GetLDAPEntitiesParams) (*models.LdapEntities, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -25,11 +25,11 @@ import (
"os"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/minio/console/api/operations"
"github.com/minio/console/api/operations/idp"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/idp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
@@ -46,7 +46,7 @@ type IDPTestSuite struct {
func (suite *IDPTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
minioServiceRestartMock = func(ctx context.Context) error {
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
}
@@ -270,7 +270,7 @@ func TestGetEntitiesResult(t *testing.T) {
GroupMappings: groupsMap,
UserMappings: usersMap,
}
minioGetLDAPPolicyEntitiesMock = func(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
minioGetLDAPPolicyEntitiesMock = func(_ context.Context, _ madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return mockResponse, nil
}
@@ -308,7 +308,7 @@ func TestGetEntitiesResult(t *testing.T) {
}
// Test-2: getEntitiesResult error is returned from getLDAPPolicyEntities()
minioGetLDAPPolicyEntitiesMock = func(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
minioGetLDAPPolicyEntitiesMock = func(_ context.Context, _ madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
return madmin.PolicyEntitiesResult{}, errors.New("error")
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -28,11 +28,12 @@ import (
"sync"
"time"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
systemApi "github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
systemApi "github.com/minio/console/restapi/operations/system"
)
func registerAdminInfoHandlers(api *operations.ConsoleAPI) {
@@ -40,15 +41,15 @@ func registerAdminInfoHandlers(api *operations.ConsoleAPI) {
api.SystemAdminInfoHandler = systemApi.AdminInfoHandlerFunc(func(params systemApi.AdminInfoParams, session *models.Principal) middleware.Responder {
infoResp, err := getAdminInfoResponse(session, params)
if err != nil {
return systemApi.NewAdminInfoDefault(int(err.Code)).WithPayload(err)
return systemApi.NewAdminInfoDefault(err.Code).WithPayload(err.APIError)
}
return systemApi.NewAdminInfoOK().WithPayload(infoResp)
})
// return single widget results
api.SystemDashboardWidgetDetailsHandler = systemApi.DashboardWidgetDetailsHandlerFunc(func(params systemApi.DashboardWidgetDetailsParams, session *models.Principal) middleware.Responder {
api.SystemDashboardWidgetDetailsHandler = systemApi.DashboardWidgetDetailsHandlerFunc(func(params systemApi.DashboardWidgetDetailsParams, _ *models.Principal) middleware.Responder {
infoResp, err := getAdminInfoWidgetResponse(params)
if err != nil {
return systemApi.NewDashboardWidgetDetailsDefault(int(err.Code)).WithPayload(err)
return systemApi.NewDashboardWidgetDetailsDefault(err.Code).WithPayload(err.APIError)
}
return systemApi.NewDashboardWidgetDetailsOK().WithPayload(infoResp)
})
@@ -58,7 +59,7 @@ type UsageInfo struct {
Buckets int64
Objects int64
Usage int64
DisksUsage int64
DrivesUsage int64
Servers []*models.ServerProperties
EndpointNotReady bool
Backend *models.BackendProperties
@@ -123,12 +124,12 @@ func GetAdminInfo(ctx context.Context, client MinioAdmin) (*UsageInfo, error) {
OfflineDrives: int64(offlineDrives),
}
return &UsageInfo{
Buckets: int64(serverInfo.Buckets.Count),
Objects: int64(serverInfo.Objects.Count),
Usage: int64(serverInfo.Usage.Size),
DisksUsage: usedSpace,
Servers: serverArray,
Backend: backendData,
Buckets: int64(serverInfo.Buckets.Count),
Objects: int64(serverInfo.Objects.Count),
Usage: int64(serverInfo.Usage.Size),
DrivesUsage: usedSpace,
Servers: serverArray,
Backend: backendData,
}, nil
}
@@ -171,7 +172,7 @@ type WidgetLabel struct {
var labels = []WidgetLabel{
{Name: "instance"},
{Name: "disk"},
{Name: "drive"},
{Name: "server"},
{Name: "api"},
}
@@ -303,7 +304,7 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `sum(minio_bucket_usage_total_bytes{$__query}) by (instance)`,
Expr: `minio_cluster_usage_total_bytes{$__query}`,
LegendFormat: "Used Capacity",
InitialTime: -180,
Step: 10,
@@ -329,7 +330,7 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `max by (range) (minio_bucket_objects_size_distribution{$__query})`,
Expr: `minio_cluster_objects_size_distribution{$__query}`,
LegendFormat: "{{range}}",
Step: 300,
},
@@ -441,7 +442,7 @@ var widgets = []Metric{
},
{
ID: 9,
Title: "Total Online Disks",
Title: "Total Online Drives",
Type: "stat",
MaxDataPoints: 100,
GridPos: GridPos{
@@ -459,8 +460,8 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `minio_cluster_disk_online_total{$__query}`,
LegendFormat: "Total online disks in MinIO Cluster",
Expr: `minio_cluster_drive_online_total{$__query}`,
LegendFormat: "Total online drives in MinIO Cluster",
Step: 60,
},
},
@@ -469,7 +470,7 @@ var widgets = []Metric{
ID: 66,
Title: "Number of Buckets",
Type: "stat",
MaxDataPoints: 100,
MaxDataPoints: 5,
GridPos: GridPos{
H: 3,
W: 3,
@@ -485,8 +486,9 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `count(count by (bucket) (minio_bucket_usage_total_bytes{$__query}))`,
Expr: `minio_cluster_bucket_total{$__query}`,
LegendFormat: "",
Step: 100,
},
},
},
@@ -552,7 +554,7 @@ var widgets = []Metric{
},
{
ID: 78,
Title: "Total Offline Disks",
Title: "Total Offline Drives",
Type: "stat",
MaxDataPoints: 100,
GridPos: GridPos{
@@ -570,7 +572,7 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `minio_cluster_disk_offline_total{$__query}`,
Expr: `minio_cluster_drive_offline_total{$__query}`,
LegendFormat: "",
Step: 60,
},
@@ -596,7 +598,7 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `topk(1, sum(minio_bucket_usage_object_total{$__query}) by (instance))`,
Expr: `minio_cluster_usage_object_total{$__query}`,
LegendFormat: "",
},
},
@@ -756,8 +758,8 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `minio_node_disk_used_bytes{$__query}`,
LegendFormat: "Used Capacity [{{server}}:{{disk}}]",
Expr: `minio_node_drive_used_bytes{$__query}`,
LegendFormat: "Used Capacity [{{server}}:{{drive}}]",
},
},
},
@@ -773,8 +775,8 @@ var widgets = []Metric{
},
Targets: []Target{
{
Expr: `minio_cluster_disk_free_inodes{$__query}`,
LegendFormat: "Free Inodes [{{server}}:{{disk}}]",
Expr: `minio_node_drive_free_inodes{$__query}`,
LegendFormat: "Free Inodes [{{server}}:{{drive}}]",
},
},
},
@@ -835,8 +837,8 @@ var widgets = []Metric{
},
{
Expr: `rate(minio_node_io_rchar_bytes{$__query}[$__rate_interval])`,
LegendFormat: "Node RChar [{{server}}]",
Expr: `rate(minio_node_io_wchar_bytes{$__query}[$__rate_interval])`,
LegendFormat: "Node WChar [{{server}}]",
},
},
},
@@ -873,16 +875,19 @@ type LabelResults struct {
}
// getAdminInfoResponse returns the response containing total buckets, objects and usage.
func getAdminInfoResponse(session *models.Principal, params systemApi.AdminInfoParams) (*models.AdminInfoResponse, *models.Error) {
func getAdminInfoResponse(session *models.Principal, params systemApi.AdminInfoParams) (*models.AdminInfoResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
prometheusURL := ""
if !*params.DefaultOnly {
prometheusURL = getPrometheusURL()
promURL := getPrometheusURL()
if promURL != "" {
prometheusURL = promURL
}
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -954,15 +959,19 @@ func getUsageWidgetsForDeployment(ctx context.Context, prometheusURL string, adm
return sessionResp, nil
}
func unmarshalPrometheus(ctx context.Context, endpoint string, data interface{}) bool {
httpClnt := GetConsoleHTTPClient(endpoint)
func unmarshalPrometheus(ctx context.Context, httpClnt *http.Client, endpoint string, data interface{}) bool {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("Unable to create the request to fetch labels from prometheus: %w", err))
return true
}
prometheusBearer := getPrometheusAuthToken()
if prometheusBearer != "" {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", prometheusBearer))
}
resp, err := httpClnt.Do(req)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("Unable to fetch labels from prometheus: %w", err))
@@ -990,7 +999,16 @@ func testPrometheusURL(ctx context.Context, url string) bool {
ErrorWithContext(ctx, fmt.Errorf("error Building Request: (%v)", err))
return false
}
response, err := GetConsoleHTTPClient(url).Do(req)
prometheusBearer := getPrometheusAuthToken()
if prometheusBearer != "" {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", prometheusBearer))
}
clientIP := utils.ClientIPFromContext(ctx)
httpClnt := GetConsoleHTTPClient(clientIP)
response, err := httpClnt.Do(req)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("default Prometheus URL not reachable, trying root testing: (%v)", err))
newTestURL := req.URL.Scheme + "://" + req.URL.Host + "/-/healthy"
@@ -999,7 +1017,7 @@ func testPrometheusURL(ctx context.Context, url string) bool {
ErrorWithContext(ctx, fmt.Errorf("error Building Root Request: (%v)", err))
return false
}
rootResponse, err := GetConsoleHTTPClient(newTestURL).Do(req2)
rootResponse, err := httpClnt.Do(req2)
if err != nil {
// URL & Root tests didn't work. Prometheus not reachable
ErrorWithContext(ctx, fmt.Errorf("root Prometheus URL not reachable: (%v)", err))
@@ -1010,7 +1028,7 @@ func testPrometheusURL(ctx context.Context, url string) bool {
return response.StatusCode == http.StatusOK
}
func getAdminInfoWidgetResponse(params systemApi.DashboardWidgetDetailsParams) (*models.WidgetDetails, *models.Error) {
func getAdminInfoWidgetResponse(params systemApi.DashboardWidgetDetailsParams) (*models.WidgetDetails, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
prometheusURL := getPrometheusURL()
@@ -1021,14 +1039,19 @@ func getAdminInfoWidgetResponse(params systemApi.DashboardWidgetDetailsParams) (
if strings.TrimSpace(prometheusExtraLabels) != "" {
selector = fmt.Sprintf(`job="%s",%s`, prometheusJobID, prometheusExtraLabels)
}
clientIP := getClientIP(params.HTTPRequest)
ctx = context.WithValue(ctx, utils.ContextClientIP, clientIP)
return getWidgetDetails(ctx, prometheusURL, selector, params.WidgetID, params.Step, params.Start, params.End)
}
func getWidgetDetails(ctx context.Context, prometheusURL string, selector string, widgetID int32, step *int32, start *int64, end *int64) (*models.WidgetDetails, *models.Error) {
func getWidgetDetails(ctx context.Context, prometheusURL string, selector string, widgetID int32, step *int32, start *int64, end *int64) (*models.WidgetDetails, *CodedAPIError) {
// We test if prometheus URL is reachable. this is meant to avoid unuseful calls and application hang.
if !testPrometheusURL(ctx, prometheusURL) {
return nil, ErrorWithContext(ctx, errors.New("prometheus URL is unreachable"))
}
clientIP := utils.ClientIPFromContext(ctx)
httpClnt := GetConsoleHTTPClient(clientIP)
labelResultsCh := make(chan LabelResults)
for _, lbl := range labels {
@@ -1036,7 +1059,7 @@ func getWidgetDetails(ctx context.Context, prometheusURL string, selector string
endpoint := fmt.Sprintf("%s/api/v1/label/%s/values", prometheusURL, lbl.Name)
var response LabelResponse
if unmarshalPrometheus(ctx, endpoint, &response) {
if unmarshalPrometheus(ctx, httpClnt, endpoint, &response) {
return
}
@@ -1122,7 +1145,7 @@ LabelsWaitLoop:
endpoint := fmt.Sprintf("%s/api/v1/%s?query=%s%s", prometheusURL, apiType, url.QueryEscape(queryExpr), extraParamters)
var response PromResp
if unmarshalPrometheus(ctx, endpoint, &response) {
if unmarshalPrometheus(ctx, httpClnt, endpoint, &response) {
return
}
@@ -1165,5 +1188,5 @@ LabelsWaitLoop:
return &wdgtResult, nil
}
return nil, &models.Error{Code: 404, Message: swag.String("Widget not found")}
return nil, &CodedAPIError{Code: 404, APIError: &models.APIError{Message: "Widget not found"}}
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -23,10 +23,12 @@ import (
"os"
"testing"
"github.com/minio/console/pkg/utils"
"github.com/minio/console/api/operations"
systemApi "github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
systemApi "github.com/minio/console/restapi/operations/system"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
@@ -44,7 +46,7 @@ type AdminInfoTestSuite struct {
func (suite *AdminInfoTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{
Servers: []madmin.ServerProperties{{
Disks: []madmin.Disk{{}},
@@ -125,7 +127,7 @@ func (suite *AdminInfoTestSuite) initSystemDashboardWidgetDetailsRequest() (para
}
func (suite *AdminInfoTestSuite) TestGetUsageWidgetsForDeploymentWithoutError() {
ctx := context.Background()
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
suite.isPrometheusRequest = true
res, err := getUsageWidgetsForDeployment(ctx, suite.server.URL, suite.adminClient)
suite.assert.Nil(err)
@@ -134,7 +136,7 @@ func (suite *AdminInfoTestSuite) TestGetUsageWidgetsForDeploymentWithoutError()
}
func (suite *AdminInfoTestSuite) TestGetWidgetDetailsWithoutError() {
ctx := context.Background()
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
suite.isPrometheusRequest = true
var step int32 = 1
var start int64

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"encoding/base64"
@@ -22,39 +22,30 @@ import (
"io"
"net/http"
"strings"
"unicode/utf8"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
inspectApi "github.com/minio/console/api/operations/inspect"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
inspectApi "github.com/minio/console/restapi/operations/inspect"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/secure-io/sio-go"
)
func registerInspectHandler(api *operations.ConsoleAPI) {
api.InspectInspectHandler = inspectApi.InspectHandlerFunc(func(params inspectApi.InspectParams, principal *models.Principal) middleware.Responder {
if v, err := base64.URLEncoding.DecodeString(params.File); err == nil && utf8.Valid(v) {
params.File = string(v)
}
if v, err := base64.URLEncoding.DecodeString(params.Volume); err == nil && utf8.Valid(v) {
params.Volume = string(v)
}
k, r, err := getInspectResult(principal, &params)
if err != nil {
return inspectApi.NewInspectDefault(int(err.Code)).WithPayload(err)
return inspectApi.NewInspectDefault(err.Code).WithPayload(err.APIError)
}
return middleware.ResponderFunc(processInspectResponse(&params, k, r))
})
}
func getInspectResult(session *models.Principal, params *inspectApi.InspectParams) ([]byte, io.ReadCloser, *models.Error) {
func getInspectResult(session *models.Principal, params *inspectApi.InspectParams) ([]byte, io.ReadCloser, *CodedAPIError) {
ctx := params.HTTPRequest.Context()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, nil, ErrorWithContext(ctx, err)
}
@@ -120,7 +111,7 @@ func processInspectResponse(params *inspectApi.InspectParams, k []byte, r io.Rea
_, err := io.Copy(w, r)
if err != nil {
LogError("Unable to write all the data: %v", err)
LogError("unable to write all the data: %v", err)
}
}
}

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package restapi
package api
import (
"context"
@@ -23,10 +23,10 @@ import (
"sort"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
kmsAPI "github.com/minio/console/api/operations/k_m_s"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
kmsAPI "github.com/minio/console/restapi/operations/k_m_s"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
func registerKMSHandlers(api *operations.ConsoleAPI) {
@@ -40,7 +40,7 @@ func registerKMSStatusHandlers(api *operations.ConsoleAPI) {
api.KmsKMSStatusHandler = kmsAPI.KMSStatusHandlerFunc(func(params kmsAPI.KMSStatusParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSStatusResponse(session, params)
if err != nil {
return kmsAPI.NewKMSStatusDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSStatusDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSStatusOK().WithPayload(resp)
})
@@ -48,7 +48,7 @@ func registerKMSStatusHandlers(api *operations.ConsoleAPI) {
api.KmsKMSMetricsHandler = kmsAPI.KMSMetricsHandlerFunc(func(params kmsAPI.KMSMetricsParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSMetricsResponse(session, params)
if err != nil {
return kmsAPI.NewKMSMetricsDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSMetricsDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSMetricsOK().WithPayload(resp)
})
@@ -56,7 +56,7 @@ func registerKMSStatusHandlers(api *operations.ConsoleAPI) {
api.KmsKMSAPIsHandler = kmsAPI.KMSAPIsHandlerFunc(func(params kmsAPI.KMSAPIsParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSAPIsResponse(session, params)
if err != nil {
return kmsAPI.NewKMSAPIsDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSAPIsDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSAPIsOK().WithPayload(resp)
})
@@ -64,23 +64,23 @@ func registerKMSStatusHandlers(api *operations.ConsoleAPI) {
api.KmsKMSVersionHandler = kmsAPI.KMSVersionHandlerFunc(func(params kmsAPI.KMSVersionParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSVersionResponse(session, params)
if err != nil {
return kmsAPI.NewKMSVersionDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSVersionDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSVersionOK().WithPayload(resp)
})
}
func GetKMSStatusResponse(session *models.Principal, params kmsAPI.KMSStatusParams) (*models.KmsStatusResponse, *models.Error) {
func GetKMSStatusResponse(session *models.Principal, params kmsAPI.KMSStatusParams) (*models.KmsStatusResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsStatus(ctx, AdminClient{Client: mAdmin})
}
func kmsStatus(ctx context.Context, minioClient MinioAdmin) (*models.KmsStatusResponse, *models.Error) {
func kmsStatus(ctx context.Context, minioClient MinioAdmin) (*models.KmsStatusResponse, *CodedAPIError) {
st, err := minioClient.kmsStatus(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -99,17 +99,17 @@ func parseStatusEndpoints(endpoints map[string]madmin.ItemState) (kmsEndpoints [
return kmsEndpoints
}
func GetKMSMetricsResponse(session *models.Principal, params kmsAPI.KMSMetricsParams) (*models.KmsMetricsResponse, *models.Error) {
func GetKMSMetricsResponse(session *models.Principal, params kmsAPI.KMSMetricsParams) (*models.KmsMetricsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsMetrics(ctx, AdminClient{Client: mAdmin})
}
func kmsMetrics(ctx context.Context, minioClient MinioAdmin) (*models.KmsMetricsResponse, *models.Error) {
func kmsMetrics(ctx context.Context, minioClient MinioAdmin) (*models.KmsMetricsResponse, *CodedAPIError) {
metrics, err := minioClient.kmsMetrics(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -143,17 +143,17 @@ func parseHistogram(histogram map[int64]int64) (records []*models.KmsLatencyHist
return records
}
func GetKMSAPIsResponse(session *models.Principal, params kmsAPI.KMSAPIsParams) (*models.KmsAPIsResponse, *models.Error) {
func GetKMSAPIsResponse(session *models.Principal, params kmsAPI.KMSAPIsParams) (*models.KmsAPIsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsAPIs(ctx, AdminClient{Client: mAdmin})
}
func kmsAPIs(ctx context.Context, minioClient MinioAdmin) (*models.KmsAPIsResponse, *models.Error) {
func kmsAPIs(ctx context.Context, minioClient MinioAdmin) (*models.KmsAPIsResponse, *CodedAPIError) {
apis, err := minioClient.kmsAPIs(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -175,17 +175,17 @@ func parseApis(apis []madmin.KMSAPI) (data []*models.KmsAPI) {
return data
}
func GetKMSVersionResponse(session *models.Principal, params kmsAPI.KMSVersionParams) (*models.KmsVersionResponse, *models.Error) {
func GetKMSVersionResponse(session *models.Principal, params kmsAPI.KMSVersionParams) (*models.KmsVersionResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return kmsVersion(ctx, AdminClient{Client: mAdmin})
}
func kmsVersion(ctx context.Context, minioClient MinioAdmin) (*models.KmsVersionResponse, *models.Error) {
func kmsVersion(ctx context.Context, minioClient MinioAdmin) (*models.KmsVersionResponse, *CodedAPIError) {
version, err := minioClient.kmsVersion(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -199,7 +199,7 @@ func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSCreateKeyHandler = kmsAPI.KMSCreateKeyHandlerFunc(func(params kmsAPI.KMSCreateKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSCreateKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSCreateKeyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSCreateKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSCreateKeyCreated()
})
@@ -207,7 +207,7 @@ func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSImportKeyHandler = kmsAPI.KMSImportKeyHandlerFunc(func(params kmsAPI.KMSImportKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSImportKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSImportKeyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSImportKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSImportKeyCreated()
})
@@ -215,7 +215,7 @@ func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSListKeysHandler = kmsAPI.KMSListKeysHandlerFunc(func(params kmsAPI.KMSListKeysParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListKeysResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListKeysDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSListKeysDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListKeysOK().WithPayload(resp)
})
@@ -223,7 +223,7 @@ func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSKeyStatusHandler = kmsAPI.KMSKeyStatusHandlerFunc(func(params kmsAPI.KMSKeyStatusParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSKeyStatusResponse(session, params)
if err != nil {
return kmsAPI.NewKMSKeyStatusDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSKeyStatusDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSKeyStatusOK().WithPayload(resp)
})
@@ -231,33 +231,33 @@ func registerKMSKeyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDeleteKeyHandler = kmsAPI.KMSDeleteKeyHandlerFunc(func(params kmsAPI.KMSDeleteKeyParams, session *models.Principal) middleware.Responder {
err := GetKMSDeleteKeyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeleteKeyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDeleteKeyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeleteKeyOK()
})
}
func GetKMSCreateKeyResponse(session *models.Principal, params kmsAPI.KMSCreateKeyParams) *models.Error {
func GetKMSCreateKeyResponse(session *models.Principal, params kmsAPI.KMSCreateKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return createKey(ctx, *params.Body.Key, AdminClient{Client: mAdmin})
}
func createKey(ctx context.Context, key string, minioClient MinioAdmin) *models.Error {
func createKey(ctx context.Context, key string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.createKey(ctx, key); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSImportKeyResponse(session *models.Principal, params kmsAPI.KMSImportKeyParams) *models.Error {
func GetKMSImportKeyResponse(session *models.Principal, params kmsAPI.KMSImportKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -268,17 +268,17 @@ func GetKMSImportKeyResponse(session *models.Principal, params kmsAPI.KMSImportK
return importKey(ctx, params.Name, bytes, AdminClient{Client: mAdmin})
}
func importKey(ctx context.Context, key string, bytes []byte, minioClient MinioAdmin) *models.Error {
func importKey(ctx context.Context, key string, bytes []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.importKey(ctx, key, bytes); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSListKeysResponse(session *models.Principal, params kmsAPI.KMSListKeysParams) (*models.KmsListKeysResponse, *models.Error) {
func GetKMSListKeysResponse(session *models.Principal, params kmsAPI.KMSListKeysParams) (*models.KmsListKeysResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -289,7 +289,7 @@ func GetKMSListKeysResponse(session *models.Principal, params kmsAPI.KMSListKeys
return listKeys(ctx, pattern, AdminClient{Client: mAdmin})
}
func listKeys(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListKeysResponse, *models.Error) {
func listKeys(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListKeysResponse, *CodedAPIError) {
results, err := minioClient.listKeys(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -308,17 +308,17 @@ func parseKeys(results []madmin.KMSKeyInfo) (data []*models.KmsKeyInfo) {
return data
}
func GetKMSKeyStatusResponse(session *models.Principal, params kmsAPI.KMSKeyStatusParams) (*models.KmsKeyStatusResponse, *models.Error) {
func GetKMSKeyStatusResponse(session *models.Principal, params kmsAPI.KMSKeyStatusParams) (*models.KmsKeyStatusResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return keyStatus(ctx, params.Name, AdminClient{Client: mAdmin})
}
func keyStatus(ctx context.Context, key string, minioClient MinioAdmin) (*models.KmsKeyStatusResponse, *models.Error) {
func keyStatus(ctx context.Context, key string, minioClient MinioAdmin) (*models.KmsKeyStatusResponse, *CodedAPIError) {
ks, err := minioClient.keyStatus(ctx, key)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -330,17 +330,17 @@ func keyStatus(ctx context.Context, key string, minioClient MinioAdmin) (*models
}, nil
}
func GetKMSDeleteKeyResponse(session *models.Principal, params kmsAPI.KMSDeleteKeyParams) *models.Error {
func GetKMSDeleteKeyResponse(session *models.Principal, params kmsAPI.KMSDeleteKeyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deleteKey(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deleteKey(ctx context.Context, key string, minioClient MinioAdmin) *models.Error {
func deleteKey(ctx context.Context, key string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deleteKey(ctx, key); err != nil {
return ErrorWithContext(ctx, err)
}
@@ -351,7 +351,7 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSSetPolicyHandler = kmsAPI.KMSSetPolicyHandlerFunc(func(params kmsAPI.KMSSetPolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSSetPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSSetPolicyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSSetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSSetPolicyOK()
})
@@ -359,7 +359,7 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSAssignPolicyHandler = kmsAPI.KMSAssignPolicyHandlerFunc(func(params kmsAPI.KMSAssignPolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSAssignPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSAssignPolicyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSAssignPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSAssignPolicyOK()
})
@@ -367,7 +367,7 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDescribePolicyHandler = kmsAPI.KMSDescribePolicyHandlerFunc(func(params kmsAPI.KMSDescribePolicyParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribePolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribePolicyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDescribePolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribePolicyOK().WithPayload(resp)
})
@@ -375,7 +375,7 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSGetPolicyHandler = kmsAPI.KMSGetPolicyHandlerFunc(func(params kmsAPI.KMSGetPolicyParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSGetPolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSGetPolicyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSGetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSGetPolicyOK().WithPayload(resp)
})
@@ -383,7 +383,7 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSListPoliciesHandler = kmsAPI.KMSListPoliciesHandlerFunc(func(params kmsAPI.KMSListPoliciesParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListPoliciesResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListPoliciesDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSListPoliciesDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListPoliciesOK().WithPayload(resp)
})
@@ -391,16 +391,16 @@ func registerKMSPolicyHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDeletePolicyHandler = kmsAPI.KMSDeletePolicyHandlerFunc(func(params kmsAPI.KMSDeletePolicyParams, session *models.Principal) middleware.Responder {
err := GetKMSDeletePolicyResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeletePolicyDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDeletePolicyDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeletePolicyOK()
})
}
func GetKMSSetPolicyResponse(session *models.Principal, params kmsAPI.KMSSetPolicyParams) *models.Error {
func GetKMSSetPolicyResponse(session *models.Principal, params kmsAPI.KMSSetPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -411,17 +411,17 @@ func GetKMSSetPolicyResponse(session *models.Principal, params kmsAPI.KMSSetPoli
return setPolicy(ctx, *params.Body.Policy, bytes, AdminClient{Client: mAdmin})
}
func setPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *models.Error {
func setPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.setKMSPolicy(ctx, policy, content); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSAssignPolicyResponse(session *models.Principal, params kmsAPI.KMSAssignPolicyParams) *models.Error {
func GetKMSAssignPolicyResponse(session *models.Principal, params kmsAPI.KMSAssignPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -432,24 +432,24 @@ func GetKMSAssignPolicyResponse(session *models.Principal, params kmsAPI.KMSAssi
return assignPolicy(ctx, params.Name, bytes, AdminClient{Client: mAdmin})
}
func assignPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *models.Error {
func assignPolicy(ctx context.Context, policy string, content []byte, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.assignPolicy(ctx, policy, content); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}
func GetKMSDescribePolicyResponse(session *models.Principal, params kmsAPI.KMSDescribePolicyParams) (*models.KmsDescribePolicyResponse, *models.Error) {
func GetKMSDescribePolicyResponse(session *models.Principal, params kmsAPI.KMSDescribePolicyParams) (*models.KmsDescribePolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describePolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func describePolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsDescribePolicyResponse, *models.Error) {
func describePolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsDescribePolicyResponse, *CodedAPIError) {
dp, err := minioClient.describePolicy(ctx, policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -461,17 +461,17 @@ func describePolicy(ctx context.Context, policy string, minioClient MinioAdmin)
}, nil
}
func GetKMSGetPolicyResponse(session *models.Principal, params kmsAPI.KMSGetPolicyParams) (*models.KmsGetPolicyResponse, *models.Error) {
func GetKMSGetPolicyResponse(session *models.Principal, params kmsAPI.KMSGetPolicyParams) (*models.KmsGetPolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return getPolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func getPolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsGetPolicyResponse, *models.Error) {
func getPolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*models.KmsGetPolicyResponse, *CodedAPIError) {
p, err := minioClient.getKMSPolicy(ctx, policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -482,10 +482,10 @@ func getPolicy(ctx context.Context, policy string, minioClient MinioAdmin) (*mod
}, nil
}
func GetKMSListPoliciesResponse(session *models.Principal, params kmsAPI.KMSListPoliciesParams) (*models.KmsListPoliciesResponse, *models.Error) {
func GetKMSListPoliciesResponse(session *models.Principal, params kmsAPI.KMSListPoliciesParams) (*models.KmsListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -496,7 +496,7 @@ func GetKMSListPoliciesResponse(session *models.Principal, params kmsAPI.KMSList
return listKMSPolicies(ctx, pattern, AdminClient{Client: mAdmin})
}
func listKMSPolicies(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListPoliciesResponse, *models.Error) {
func listKMSPolicies(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListPoliciesResponse, *CodedAPIError) {
results, err := minioClient.listKMSPolicies(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -515,17 +515,17 @@ func parsePolicies(results []madmin.KMSPolicyInfo) (data []*models.KmsPolicyInfo
return data
}
func GetKMSDeletePolicyResponse(session *models.Principal, params kmsAPI.KMSDeletePolicyParams) *models.Error {
func GetKMSDeletePolicyResponse(session *models.Principal, params kmsAPI.KMSDeletePolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deletePolicy(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deletePolicy(ctx context.Context, policy string, minioClient MinioAdmin) *models.Error {
func deletePolicy(ctx context.Context, policy string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deletePolicy(ctx, policy); err != nil {
return ErrorWithContext(ctx, err)
}
@@ -536,7 +536,7 @@ func registerKMSIdentityHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDescribeIdentityHandler = kmsAPI.KMSDescribeIdentityHandlerFunc(func(params kmsAPI.KMSDescribeIdentityParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribeIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribeIdentityDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDescribeIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribeIdentityOK().WithPayload(resp)
})
@@ -544,7 +544,7 @@ func registerKMSIdentityHandlers(api *operations.ConsoleAPI) {
api.KmsKMSDescribeSelfIdentityHandler = kmsAPI.KMSDescribeSelfIdentityHandlerFunc(func(params kmsAPI.KMSDescribeSelfIdentityParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSDescribeSelfIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDescribeSelfIdentityDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDescribeSelfIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDescribeSelfIdentityOK().WithPayload(resp)
})
@@ -552,30 +552,30 @@ func registerKMSIdentityHandlers(api *operations.ConsoleAPI) {
api.KmsKMSListIdentitiesHandler = kmsAPI.KMSListIdentitiesHandlerFunc(func(params kmsAPI.KMSListIdentitiesParams, session *models.Principal) middleware.Responder {
resp, err := GetKMSListIdentitiesResponse(session, params)
if err != nil {
return kmsAPI.NewKMSListIdentitiesDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSListIdentitiesDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSListIdentitiesOK().WithPayload(resp)
})
api.KmsKMSDeleteIdentityHandler = kmsAPI.KMSDeleteIdentityHandlerFunc(func(params kmsAPI.KMSDeleteIdentityParams, session *models.Principal) middleware.Responder {
err := GetKMSDeleteIdentityResponse(session, params)
if err != nil {
return kmsAPI.NewKMSDeleteIdentityDefault(int(err.Code)).WithPayload(err)
return kmsAPI.NewKMSDeleteIdentityDefault(err.Code).WithPayload(err.APIError)
}
return kmsAPI.NewKMSDeleteIdentityOK()
})
}
func GetKMSDescribeIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeIdentityParams) (*models.KmsDescribeIdentityResponse, *models.Error) {
func GetKMSDescribeIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeIdentityParams) (*models.KmsDescribeIdentityResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describeIdentity(ctx, params.Name, AdminClient{Client: mAdmin})
}
func describeIdentity(ctx context.Context, identity string, minioClient MinioAdmin) (*models.KmsDescribeIdentityResponse, *models.Error) {
func describeIdentity(ctx context.Context, identity string, minioClient MinioAdmin) (*models.KmsDescribeIdentityResponse, *CodedAPIError) {
i, err := minioClient.describeIdentity(ctx, identity)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -589,17 +589,17 @@ func describeIdentity(ctx context.Context, identity string, minioClient MinioAdm
}, nil
}
func GetKMSDescribeSelfIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeSelfIdentityParams) (*models.KmsDescribeSelfIdentityResponse, *models.Error) {
func GetKMSDescribeSelfIdentityResponse(session *models.Principal, params kmsAPI.KMSDescribeSelfIdentityParams) (*models.KmsDescribeSelfIdentityResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return describeSelfIdentity(ctx, AdminClient{Client: mAdmin})
}
func describeSelfIdentity(ctx context.Context, minioClient MinioAdmin) (*models.KmsDescribeSelfIdentityResponse, *models.Error) {
func describeSelfIdentity(ctx context.Context, minioClient MinioAdmin) (*models.KmsDescribeSelfIdentityResponse, *CodedAPIError) {
i, err := minioClient.describeSelfIdentity(ctx)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -616,10 +616,10 @@ func describeSelfIdentity(ctx context.Context, minioClient MinioAdmin) (*models.
}, nil
}
func GetKMSListIdentitiesResponse(session *models.Principal, params kmsAPI.KMSListIdentitiesParams) (*models.KmsListIdentitiesResponse, *models.Error) {
func GetKMSListIdentitiesResponse(session *models.Principal, params kmsAPI.KMSListIdentitiesParams) (*models.KmsListIdentitiesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -630,7 +630,7 @@ func GetKMSListIdentitiesResponse(session *models.Principal, params kmsAPI.KMSLi
return listIdentities(ctx, pattern, AdminClient{Client: mAdmin})
}
func listIdentities(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListIdentitiesResponse, *models.Error) {
func listIdentities(ctx context.Context, pattern string, minioClient MinioAdmin) (*models.KmsListIdentitiesResponse, *CodedAPIError) {
results, err := minioClient.listIdentities(ctx, pattern)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -651,17 +651,17 @@ func parseIdentities(results []madmin.KMSIdentityInfo) (data []*models.KmsIdenti
return data
}
func GetKMSDeleteIdentityResponse(session *models.Principal, params kmsAPI.KMSDeleteIdentityParams) *models.Error {
func GetKMSDeleteIdentityResponse(session *models.Principal, params kmsAPI.KMSDeleteIdentityParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
return deleteIdentity(ctx, params.Name, AdminClient{Client: mAdmin})
}
func deleteIdentity(ctx context.Context, identity string, minioClient MinioAdmin) *models.Error {
func deleteIdentity(ctx context.Context, identity string, minioClient MinioAdmin) *CodedAPIError {
if err := minioClient.deleteIdentity(ctx, identity); err != nil {
return ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -23,9 +23,9 @@ import (
"os"
"testing"
"github.com/minio/console/api/operations"
kmsAPI "github.com/minio/console/api/operations/k_m_s"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
kmsAPI "github.com/minio/console/restapi/operations/k_m_s"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

View File

@@ -14,32 +14,32 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
systemApi "github.com/minio/console/api/operations/system"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
systemApi "github.com/minio/console/restapi/operations/system"
)
func registerNodesHandler(api *operations.ConsoleAPI) {
api.SystemListNodesHandler = systemApi.ListNodesHandlerFunc(func(params systemApi.ListNodesParams, session *models.Principal) middleware.Responder {
listNodesResponse, err := getListNodesResponse(session, params)
if err != nil {
return systemApi.NewListNodesDefault(int(err.Code)).WithPayload(err)
return systemApi.NewListNodesDefault(err.Code).WithPayload(err.APIError)
}
return systemApi.NewListNodesOK().WithPayload(listNodesResponse)
})
}
// getListNodesResponse returns a list of available node endpoints .
func getListNodesResponse(session *models.Principal, params systemApi.ListNodesParams) ([]string, *models.Error) {
func getListNodesResponse(session *models.Principal, params systemApi.ListNodesParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,16 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"errors"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
configurationApi "github.com/minio/console/api/operations/configuration"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
configurationApi "github.com/minio/console/restapi/operations/configuration"
)
func registerAdminNotificationEndpointsHandlers(api *operations.ConsoleAPI) {
@@ -31,7 +31,7 @@ func registerAdminNotificationEndpointsHandlers(api *operations.ConsoleAPI) {
api.ConfigurationNotificationEndpointListHandler = configurationApi.NotificationEndpointListHandlerFunc(func(params configurationApi.NotificationEndpointListParams, session *models.Principal) middleware.Responder {
notifEndpoints, err := getNotificationEndpointsResponse(session, params)
if err != nil {
return configurationApi.NewNotificationEndpointListDefault(int(err.Code)).WithPayload(err)
return configurationApi.NewNotificationEndpointListDefault(err.Code).WithPayload(err.APIError)
}
return configurationApi.NewNotificationEndpointListOK().WithPayload(notifEndpoints)
})
@@ -39,7 +39,7 @@ func registerAdminNotificationEndpointsHandlers(api *operations.ConsoleAPI) {
api.ConfigurationAddNotificationEndpointHandler = configurationApi.AddNotificationEndpointHandlerFunc(func(params configurationApi.AddNotificationEndpointParams, session *models.Principal) middleware.Responder {
notifEndpoints, err := getAddNotificationEndpointResponse(session, params)
if err != nil {
return configurationApi.NewAddNotificationEndpointDefault(int(err.Code)).WithPayload(err)
return configurationApi.NewAddNotificationEndpointDefault(err.Code).WithPayload(err.APIError)
}
return configurationApi.NewAddNotificationEndpointCreated().WithPayload(notifEndpoints)
})
@@ -73,10 +73,10 @@ func getNotificationEndpoints(ctx context.Context, client MinioAdmin) (*models.N
}
// getNotificationEndpointsResponse returns a list of notification endpoints in the instance
func getNotificationEndpointsResponse(session *models.Principal, params configurationApi.NotificationEndpointListParams) (*models.NotifEndpointResponse, *models.Error) {
func getNotificationEndpointsResponse(session *models.Principal, params configurationApi.NotificationEndpointListParams) (*models.NotifEndpointResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -143,10 +143,10 @@ func addNotificationEndpoint(ctx context.Context, client MinioAdmin, params *con
}
// getNotificationEndpointsResponse returns a list of notification endpoints in the instance
func getAddNotificationEndpointResponse(session *models.Principal, params configurationApi.AddNotificationEndpointParams) (*models.SetNotificationEndpointResponse, *models.Error) {
func getAddNotificationEndpointResponse(session *models.Principal, params configurationApi.AddNotificationEndpointParams) (*models.SetNotificationEndpointResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,8 +24,8 @@ import (
"github.com/go-openapi/swag"
cfgApi "github.com/minio/console/api/operations/configuration"
"github.com/minio/console/models"
cfgApi "github.com/minio/console/restapi/operations/configuration"
)
func Test_addNotificationEndpoint(t *testing.T) {
@@ -61,7 +61,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -94,7 +94,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, errors.New("error")
},
want: nil,
@@ -118,7 +118,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -149,7 +149,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -178,7 +178,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -208,7 +208,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -240,7 +240,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -273,7 +273,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -305,7 +305,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -335,7 +335,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -365,7 +365,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -397,7 +397,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return false, errors.New("invalid config")
},
want: nil,
@@ -421,7 +421,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
},
},
mockSetConfig: func(kv string) (restart bool, err error) {
mockSetConfig: func(_ string) (restart bool, err error) {
return true, nil
},
want: &models.SetNotificationEndpointResponse{
@@ -438,7 +438,7 @@ func Test_addNotificationEndpoint(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
// mock function response from setConfig()
minioSetConfigKVMock = tt.mockSetConfig
got, err := addNotificationEndpoint(tt.args.ctx, tt.args.client, tt.args.params)

View File

@@ -14,11 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"encoding/base64"
"time"
"github.com/minio/mc/cmd"
@@ -32,7 +31,7 @@ type objectsListOpts struct {
}
type ObjectsRequest struct {
Mode string `json:"mode,nonempty"`
Mode string `json:"mode,omitempty"`
BucketName string `json:"bucket_name"`
Prefix string `json:"prefix"`
Date string `json:"date"`
@@ -40,18 +39,19 @@ type ObjectsRequest struct {
}
type WSResponse struct {
RequestID int64 `json:"request_id,nonempty"`
Error string `json:"error,omitempty"`
RequestID int64 `json:"request_id,omitempty"`
Error *CodedAPIError `json:"error,omitempty"`
RequestEnd bool `json:"request_end,omitempty"`
Prefix string `json:"prefix,omitempty"`
BucketName string `json:"bucketName,omitempty"`
Data []ObjectResponse `json:"data,omitempty"`
}
type ObjectResponse struct {
Name string `json:"name,nonempty"`
LastModified string `json:"last_modified,nonempty"`
Size int64 `json:"size,nonempty"`
VersionID string `json:"version_id,nonempty"`
Name string `json:"name,omitempty"`
LastModified string `json:"last_modified,omitempty"`
Size int64 `json:"size,omitempty"`
VersionID string `json:"version_id,omitempty"`
DeleteMarker bool `json:"delete_flag,omitempty"`
IsLatest bool `json:"is_latest,omitempty"`
}
@@ -59,20 +59,7 @@ type ObjectResponse struct {
func getObjectsOptionsFromReq(request ObjectsRequest) (*objectsListOpts, error) {
pOptions := objectsListOpts{
BucketName: request.BucketName,
Prefix: "",
}
prefix := request.Prefix
if prefix != "" {
encodedPrefix := SanitizeEncodedPrefix(prefix)
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
if err != nil {
LogError("error decoding prefix: %v", err)
return nil, err
}
pOptions.Prefix = string(decodedPrefix)
Prefix: request.Prefix,
}
if request.Mode == "rewind" {

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -97,11 +97,11 @@ func TestWSRewindObjects(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mcListMock = func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
mcListMock = func(_ context.Context, _ mc.ListOptions) <-chan *mc.ClientContent {
ch := make(chan *mc.ClientContent)
go func() {
defer close(ch)
@@ -206,11 +206,11 @@ func TestWSListObjects(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
minioListObjectsMock = func(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo {
minioListObjectsMock = func(_ context.Context, _ string, _ minio.ListObjectsOptions) <-chan minio.ObjectInfo {
ch := make(chan minio.ObjectInfo)
go func() {
defer close(ch)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
@@ -24,17 +24,16 @@ import (
"sort"
"strings"
"github.com/minio/console/pkg/utils"
bucketApi "github.com/minio/console/restapi/operations/bucket"
policyApi "github.com/minio/console/restapi/operations/policy"
bucketApi "github.com/minio/console/api/operations/bucket"
policyApi "github.com/minio/console/api/operations/policy"
s3 "github.com/minio/minio-go/v7"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
iampolicy "github.com/minio/pkg/iam/policy"
iampolicy "github.com/minio/pkg/v3/policy"
policies "github.com/minio/console/restapi/policy"
policies "github.com/minio/console/api/policy"
)
func registersPoliciesHandler(api *operations.ConsoleAPI) {
@@ -42,7 +41,7 @@ func registersPoliciesHandler(api *operations.ConsoleAPI) {
api.PolicyListPoliciesHandler = policyApi.ListPoliciesHandlerFunc(func(params policyApi.ListPoliciesParams, session *models.Principal) middleware.Responder {
listPoliciesResponse, err := getListPoliciesResponse(session, params)
if err != nil {
return policyApi.NewListPoliciesDefault(int(err.Code)).WithPayload(err)
return policyApi.NewListPoliciesDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListPoliciesOK().WithPayload(listPoliciesResponse)
})
@@ -50,7 +49,7 @@ func registersPoliciesHandler(api *operations.ConsoleAPI) {
api.PolicyPolicyInfoHandler = policyApi.PolicyInfoHandlerFunc(func(params policyApi.PolicyInfoParams, session *models.Principal) middleware.Responder {
policyInfo, err := getPolicyInfoResponse(session, params)
if err != nil {
return policyApi.NewPolicyInfoDefault(int(err.Code)).WithPayload(err)
return policyApi.NewPolicyInfoDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewPolicyInfoOK().WithPayload(policyInfo)
})
@@ -58,78 +57,78 @@ func registersPoliciesHandler(api *operations.ConsoleAPI) {
api.PolicyAddPolicyHandler = policyApi.AddPolicyHandlerFunc(func(params policyApi.AddPolicyParams, session *models.Principal) middleware.Responder {
policyResponse, err := getAddPolicyResponse(session, params)
if err != nil {
return policyApi.NewAddPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewAddPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewAddPolicyCreated().WithPayload(policyResponse)
})
// Remove Policy
api.PolicyRemovePolicyHandler = policyApi.RemovePolicyHandlerFunc(func(params policyApi.RemovePolicyParams, session *models.Principal) middleware.Responder {
if err := getRemovePolicyResponse(session, params); err != nil {
return policyApi.NewRemovePolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewRemovePolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewRemovePolicyNoContent()
})
// Set Policy
api.PolicySetPolicyHandler = policyApi.SetPolicyHandlerFunc(func(params policyApi.SetPolicyParams, session *models.Principal) middleware.Responder {
if err := getSetPolicyResponse(session, params); err != nil {
return policyApi.NewSetPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewSetPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewSetPolicyNoContent()
})
// Set Policy Multiple User/Groups
api.PolicySetPolicyMultipleHandler = policyApi.SetPolicyMultipleHandlerFunc(func(params policyApi.SetPolicyMultipleParams, session *models.Principal) middleware.Responder {
if err := getSetPolicyMultipleResponse(session, params); err != nil {
return policyApi.NewSetPolicyMultipleDefault(int(err.Code)).WithPayload(err)
return policyApi.NewSetPolicyMultipleDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewSetPolicyMultipleNoContent()
})
api.BucketListPoliciesWithBucketHandler = bucketApi.ListPoliciesWithBucketHandlerFunc(func(params bucketApi.ListPoliciesWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getListPoliciesWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewListPoliciesWithBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewListPoliciesWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListPoliciesWithBucketOK().WithPayload(policyResponse)
})
api.BucketListAccessRulesWithBucketHandler = bucketApi.ListAccessRulesWithBucketHandlerFunc(func(params bucketApi.ListAccessRulesWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getListAccessRulesWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewListAccessRulesWithBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewListAccessRulesWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListAccessRulesWithBucketOK().WithPayload(policyResponse)
})
api.BucketSetAccessRuleWithBucketHandler = bucketApi.SetAccessRuleWithBucketHandlerFunc(func(params bucketApi.SetAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getSetAccessRuleWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewSetAccessRuleWithBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewSetAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewSetAccessRuleWithBucketOK().WithPayload(policyResponse)
})
api.BucketDeleteAccessRuleWithBucketHandler = bucketApi.DeleteAccessRuleWithBucketHandlerFunc(func(params bucketApi.DeleteAccessRuleWithBucketParams, session *models.Principal) middleware.Responder {
policyResponse, err := getDeleteAccessRuleWithBucketResponse(session, params)
if err != nil {
return bucketApi.NewDeleteAccessRuleWithBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewDeleteAccessRuleWithBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteAccessRuleWithBucketOK().WithPayload(policyResponse)
})
api.PolicyListUsersForPolicyHandler = policyApi.ListUsersForPolicyHandlerFunc(func(params policyApi.ListUsersForPolicyParams, session *models.Principal) middleware.Responder {
policyUsersResponse, err := getListUsersForPolicyResponse(session, params)
if err != nil {
return policyApi.NewListUsersForPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewListUsersForPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListUsersForPolicyOK().WithPayload(policyUsersResponse)
})
api.PolicyListGroupsForPolicyHandler = policyApi.ListGroupsForPolicyHandlerFunc(func(params policyApi.ListGroupsForPolicyParams, session *models.Principal) middleware.Responder {
policyGroupsResponse, err := getListGroupsForPolicyResponse(session, params)
if err != nil {
return policyApi.NewListGroupsForPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewListGroupsForPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewListGroupsForPolicyOK().WithPayload(policyGroupsResponse)
})
// Gets policies for currently logged in user
api.PolicyGetUserPolicyHandler = policyApi.GetUserPolicyHandlerFunc(func(params policyApi.GetUserPolicyParams, session *models.Principal) middleware.Responder {
userPolicyResponse, err := getUserPolicyResponse(session)
userPolicyResponse, err := getUserPolicyResponse(params.HTTPRequest.Context(), session)
if err != nil {
return policyApi.NewGetUserPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewGetUserPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewGetUserPolicyOK().WithPayload(userPolicyResponse)
})
@@ -137,17 +136,17 @@ func registersPoliciesHandler(api *operations.ConsoleAPI) {
api.PolicyGetSAUserPolicyHandler = policyApi.GetSAUserPolicyHandlerFunc(func(params policyApi.GetSAUserPolicyParams, session *models.Principal) middleware.Responder {
userPolicyResponse, err := getSAUserPolicyResponse(session, params)
if err != nil {
return policyApi.NewGetSAUserPolicyDefault(int(err.Code)).WithPayload(err)
return policyApi.NewGetSAUserPolicyDefault(err.Code).WithPayload(err.APIError)
}
return policyApi.NewGetSAUserPolicyOK().WithPayload(userPolicyResponse)
})
}
func getListAccessRulesWithBucketResponse(session *models.Principal, params bucketApi.ListAccessRulesWithBucketParams) (*models.ListAccessRulesResponse, *models.Error) {
func getListAccessRulesWithBucketResponse(session *models.Principal, params bucketApi.ListAccessRulesWithBucketParams) (*models.ListAccessRulesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
bucket := params.Bucket
client, err := newS3BucketClient(session, bucket, "")
client, err := newS3BucketClient(session, bucket, "", getClientIP(params.HTTPRequest))
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -159,11 +158,11 @@ func getListAccessRulesWithBucketResponse(session *models.Principal, params buck
return &models.ListAccessRulesResponse{AccessRules: accessRuleList}, nil
}
func getSetAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.SetAccessRuleWithBucketParams) (bool, *models.Error) {
func getSetAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.SetAccessRuleWithBucketParams) (bool, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
prefixAccess := params.Prefixaccess
client, err := newS3BucketClient(session, params.Bucket, prefixAccess.Prefix)
client, err := newS3BucketClient(session, params.Bucket, prefixAccess.Prefix, getClientIP(params.HTTPRequest))
if err != nil {
return false, ErrorWithContext(ctx, err)
}
@@ -179,12 +178,12 @@ func getSetAccessRuleWithBucketResponse(session *models.Principal, params bucket
return true, nil
}
func getDeleteAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.DeleteAccessRuleWithBucketParams) (bool, *models.Error) {
func getDeleteAccessRuleWithBucketResponse(session *models.Principal, params bucketApi.DeleteAccessRuleWithBucketParams) (bool, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
bucket := params.Bucket
prefix := params.Prefix
client, err := newS3BucketClient(session, bucket, prefix.Prefix)
client, err := newS3BucketClient(session, bucket, prefix.Prefix, getClientIP(params.HTTPRequest))
if err != nil {
return false, ErrorWithContext(ctx, err)
}
@@ -195,10 +194,10 @@ func getDeleteAccessRuleWithBucketResponse(session *models.Principal, params buc
return true, nil
}
func getListPoliciesWithBucketResponse(session *models.Principal, params bucketApi.ListPoliciesWithBucketParams) (*models.ListPoliciesResponse, *models.Error) {
func getListPoliciesWithBucketResponse(session *models.Principal, params bucketApi.ListPoliciesWithBucketParams) (*models.ListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -281,10 +280,10 @@ func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, err
}
// getListPoliciesResponse performs listPolicies() and serializes it to the handler's output
func getListPoliciesResponse(session *models.Principal, params policyApi.ListPoliciesParams) (*models.ListPoliciesResponse, *models.Error) {
func getListPoliciesResponse(session *models.Principal, params policyApi.ListPoliciesParams) (*models.ListPoliciesResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -305,14 +304,10 @@ func getListPoliciesResponse(session *models.Principal, params policyApi.ListPol
}
// getListUsersForPoliciesResponse performs lists users affected by a given policy.
func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *models.Error) {
func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
policy, err := utils.DecodeBase64(params.Policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -325,12 +320,12 @@ func getListUsersForPolicyResponse(session *models.Principal, params policyApi.L
}
found := false
for i := range policies {
if policies[i].Name == policy {
if policies[i].Name == params.Policy {
found = true
}
}
if !found {
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", params.Policy))
}
users, err := listUsers(ctx, adminClient)
if err != nil {
@@ -340,7 +335,7 @@ func getListUsersForPolicyResponse(session *models.Principal, params policyApi.L
var filteredUsers []string
for _, user := range users {
for _, upolicy := range user.Policy {
if upolicy == policy {
if upolicy == params.Policy {
filteredUsers = append(filteredUsers, user.AccessKey)
break
}
@@ -350,8 +345,8 @@ func getListUsersForPolicyResponse(session *models.Principal, params policyApi.L
return filteredUsers, nil
}
func getUserPolicyResponse(session *models.Principal) (string, *models.Error) {
ctx, cancel := context.WithCancel(context.Background())
func getUserPolicyResponse(ctx context.Context, session *models.Principal) (string, *CodedAPIError) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// serialize output
if session == nil {
@@ -360,7 +355,7 @@ func getUserPolicyResponse(session *models.Principal) (string, *models.Error) {
tokenClaims, _ := getClaimsFromToken(session.STSSessionToken)
// initialize admin client
mAdminClient, err := NewMinioAdminClient(&models.Principal{
mAdminClient, err := NewMinioAdminClient(ctx, &models.Principal{
STSAccessKeyID: session.STSAccessKeyID,
STSSecretAccessKey: session.STSSecretAccessKey,
STSSessionToken: session.STSSessionToken,
@@ -379,7 +374,7 @@ func getUserPolicyResponse(session *models.Principal) (string, *models.Error) {
return string(rawPolicy), nil
}
func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUserPolicyParams) (*models.AUserPolicyResponse, *models.Error) {
func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUserPolicyParams) (*models.AUserPolicyResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
// serialize output
@@ -387,7 +382,7 @@ func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUs
return nil, ErrorWithContext(ctx, ErrPolicyNotFound)
}
// initialize admin client
mAdminClient, err := NewMinioAdminClient(&models.Principal{
mAdminClient, err := NewMinioAdminClient(params.HTTPRequest.Context(), &models.Principal{
STSAccessKeyID: session.STSAccessKeyID,
STSSecretAccessKey: session.STSSecretAccessKey,
STSSessionToken: session.STSSessionToken,
@@ -397,12 +392,7 @@ func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUs
}
userAdminClient := AdminClient{Client: mAdminClient}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
user, err := getUserInfo(ctx, userAdminClient, userName)
user, err := getUserInfo(ctx, userAdminClient, params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -458,19 +448,15 @@ func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUs
return getUserPoliciesResponse, nil
}
func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.ListGroupsForPolicyParams) ([]string, *models.Error) {
func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.ListGroupsForPolicyParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
policy, err := utils.DecodeBase64(params.Policy)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
adminClient := AdminClient{Client: mAdmin}
policies, err := listPolicies(ctx, adminClient)
if err != nil {
@@ -478,12 +464,12 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.
}
found := false
for i := range policies {
if policies[i].Name == policy {
if policies[i].Name == params.Policy {
found = true
}
}
if !found {
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy))
return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", params.Policy))
}
groups, err := adminClient.listGroups(ctx)
@@ -499,7 +485,7 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi.
}
groupPolicies := strings.Split(info.Policy, ",")
for _, groupPolicy := range groupPolicies {
if groupPolicy == policy {
if groupPolicy == params.Policy {
filteredGroups = append(filteredGroups, group)
}
}
@@ -518,17 +504,13 @@ func removePolicy(ctx context.Context, client MinioAdmin, name string) error {
}
// getRemovePolicyResponse() performs removePolicy() and serializes it to the handler's output
func getRemovePolicyResponse(session *models.Principal, params policyApi.RemovePolicyParams) *models.Error {
func getRemovePolicyResponse(session *models.Principal, params policyApi.RemovePolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Name == "" {
return ErrorWithContext(ctx, ErrPolicyNameNotInRequest)
}
policyName, err := utils.DecodeBase64(params.Name)
if err != nil {
return ErrorWithContext(ctx, err)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -536,7 +518,7 @@ func getRemovePolicyResponse(session *models.Principal, params policyApi.RemoveP
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := removePolicy(ctx, adminClient, policyName); err != nil {
if err := removePolicy(ctx, adminClient, params.Name); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
@@ -562,7 +544,7 @@ func addPolicy(ctx context.Context, client MinioAdmin, name, policy string) (*mo
}
// getAddPolicyResponse performs addPolicy() and serializes it to the handler's output
func getAddPolicyResponse(session *models.Principal, params policyApi.AddPolicyParams) (*models.Policy, *models.Error) {
func getAddPolicyResponse(session *models.Principal, params policyApi.AddPolicyParams) (*models.Policy, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
if params.Body == nil {
@@ -571,7 +553,7 @@ func getAddPolicyResponse(session *models.Principal, params policyApi.AddPolicyP
if strings.Contains(*params.Body.Name, " ") {
return nil, ErrorWithContext(ctx, ErrPolicyNameContainsSpace)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -613,21 +595,17 @@ func getPolicyStatements(ctx context.Context, client MinioAdmin, name string) ([
}
// getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output
func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInfoParams) (*models.Policy, *models.Error) {
func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInfoParams) (*models.Policy, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
policyName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
policy, err := policyInfo(ctx, adminClient, policyName)
policy, err := policyInfo(ctx, adminClient, params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -644,11 +622,11 @@ func SetPolicy(ctx context.Context, client MinioAdmin, name, entityName string,
}
// getSetPolicyResponse() performs SetPolicy() and serializes it to the handler's output
func getSetPolicyResponse(session *models.Principal, params policyApi.SetPolicyParams) *models.Error {
func getSetPolicyResponse(session *models.Principal, params policyApi.SetPolicyParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
// Removing this section
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -662,10 +640,10 @@ func getSetPolicyResponse(session *models.Principal, params policyApi.SetPolicyP
return nil
}
func getSetPolicyMultipleResponse(session *models.Principal, params policyApi.SetPolicyMultipleParams) *models.Error {
func getSetPolicyMultipleResponse(session *models.Principal, params policyApi.SetPolicyMultipleParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
@@ -26,7 +26,7 @@ import (
"testing"
"github.com/minio/console/models"
iampolicy "github.com/minio/pkg/iam/policy"
iampolicy "github.com/minio/pkg/v3/policy"
"github.com/stretchr/testify/assert"
)
@@ -83,7 +83,7 @@ func TestRemovePolicy(t *testing.T) {
adminClient := AdminClientMock{}
// Test-1 : removePolicy() remove an existing policy
policyToRemove := "console-policy"
minioRemovePolicyMock = func(name string) error {
minioRemovePolicyMock = func(_ string) error {
return nil
}
function := "removePolicy()"
@@ -91,7 +91,7 @@ func TestRemovePolicy(t *testing.T) {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// Test-2 : removePolicy() Return error and see that the error is handled correctly and returned
minioRemovePolicyMock = func(name string) error {
minioRemovePolicyMock = func(_ string) error {
return errors.New("error")
}
if err := removePolicy(ctx, adminClient, policyToRemove); funcAssert.Error(err) {
@@ -106,10 +106,10 @@ func TestAddPolicy(t *testing.T) {
adminClient := AdminClientMock{}
policyName := "new-policy"
policyDefinition := "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}"
minioAddPolicyMock = func(name string, policy *iampolicy.Policy) error {
minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error {
return nil
}
minioGetPolicyMock = func(name string) (*iampolicy.Policy, error) {
minioGetPolicyMock = func(_ string) (*iampolicy.Policy, error) {
policy := "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:GetBucketLocation\",\"s3:GetObject\",\"s3:ListAllMyBuckets\"],\"Resource\":[\"arn:aws:s3:::*\"]}]}"
iamp, err := iampolicy.ParseConfig(bytes.NewReader([]byte(policy)))
if err != nil {
@@ -138,17 +138,17 @@ func TestAddPolicy(t *testing.T) {
funcAssert.Equal(expectedPolicy, actualPolicy)
}
// Test-2 : addPolicy() got an error while adding policy
minioAddPolicyMock = func(name string, policy *iampolicy.Policy) error {
minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error {
return errors.New("error")
}
if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); funcAssert.Error(err) {
funcAssert.Equal("error", err.Error())
}
// Test-3 : addPolicy() got an error while retrieving policy
minioAddPolicyMock = func(name string, policy *iampolicy.Policy) error {
minioAddPolicyMock = func(_ string, _ *iampolicy.Policy) error {
return nil
}
minioGetPolicyMock = func(name string) (*iampolicy.Policy, error) {
minioGetPolicyMock = func(_ string) (*iampolicy.Policy, error) {
return nil, errors.New("error")
}
if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); funcAssert.Error(err) {
@@ -164,7 +164,7 @@ func TestSetPolicy(t *testing.T) {
policyName := "readOnly"
entityName := "alevsk"
entityObject := models.PolicyEntityUser
minioSetPolicyMock = func(policyName, entityName string, isGroup bool) error {
minioSetPolicyMock = func(_, _ string, _ bool) error {
return nil
}
// Test-1 : SetPolicy() set policy to user
@@ -181,7 +181,7 @@ func TestSetPolicy(t *testing.T) {
}
// Test-3 : SetPolicy() set policy to user and get error
entityObject = models.PolicyEntityUser
minioSetPolicyMock = func(policyName, entityName string, isGroup bool) error {
minioSetPolicyMock = func(_, _ string, _ bool) error {
return errors.New("error")
}
if err := SetPolicy(ctx, adminClient, policyName, entityName, entityObject); funcAssert.Error(err) {
@@ -189,7 +189,7 @@ func TestSetPolicy(t *testing.T) {
}
// Test-4 : SetPolicy() set policy to group and get error
entityObject = models.PolicyEntityGroup
minioSetPolicyMock = func(policyName, entityName string, isGroup bool) error {
minioSetPolicyMock = func(_, _ string, _ bool) error {
return errors.New("error")
}
if err := SetPolicy(ctx, adminClient, policyName, entityName, entityObject); funcAssert.Error(err) {
@@ -219,7 +219,7 @@ func Test_SetPolicyMultiple(t *testing.T) {
policyName: "readonly",
users: []models.IamEntity{"user1", "user2"},
groups: []models.IamEntity{"group1", "group2"},
setPolicyFunc: func(policyName, entityName string, isGroup bool) error {
setPolicyFunc: func(_, _ string, _ bool) error {
return nil
},
},
@@ -231,7 +231,7 @@ func Test_SetPolicyMultiple(t *testing.T) {
policyName: "readonly",
users: []models.IamEntity{"user1", "user2"},
groups: []models.IamEntity{"group1", "group2"},
setPolicyFunc: func(policyName, entityName string, isGroup bool) error {
setPolicyFunc: func(_, _ string, _ bool) error {
return errors.New("error set")
},
},
@@ -244,7 +244,7 @@ func Test_SetPolicyMultiple(t *testing.T) {
policyName: "readonly",
users: []models.IamEntity{},
groups: []models.IamEntity{},
setPolicyFunc: func(policyName, entityName string, isGroup bool) error {
setPolicyFunc: func(_, _ string, _ bool) error {
return nil
},
},
@@ -252,7 +252,7 @@ func Test_SetPolicyMultiple(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
minioSetPolicyMock = tt.args.setPolicyFunc
got := setPolicyMultipleEntities(ctx, adminClient, tt.args.policyName, tt.args.users, tt.args.groups)
if !reflect.DeepEqual(got, tt.errorExpected) {
@@ -373,7 +373,7 @@ func Test_policyMatchesBucket(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
if got := policyMatchesBucket(tt.args.ctx, tt.args.policy, tt.args.bucket); got != tt.want {
t.Errorf("policyMatchesBucket() = %v, want %v", got, tt.want)
}

View File

@@ -14,15 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"io/ioutil"
"io"
"net/http"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/minio/websocket"
)
@@ -55,7 +55,7 @@ func startProfiling(ctx context.Context, conn WSConn, client MinioAdmin, pOpts *
if err != nil {
return err
}
message, err := ioutil.ReadAll(zippedData)
message, err := io.ReadAll(zippedData)
if err != nil {
return err
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
@@ -25,7 +25,7 @@ import (
"net/url"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -52,7 +52,7 @@ func TestStartProfiling(t *testing.T) {
// Test-1 : startProfiling() Get response from MinIO server with one profiling object without errors
// mock function response from startProfiling()
minioStartProfiling = func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
minioStartProfiling = func(_ madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return []madmin.StartProfilingResult{
{
NodeName: "http://127.0.0.1:9000/",
@@ -71,7 +71,7 @@ func TestStartProfiling(t *testing.T) {
return &ClosingBuffer{bytes.NewBufferString("In memory string eaeae")}, nil
}
// mock function response from mockConn.writeMessage()
connWriteMessageMock = func(messageType int, p []byte) error {
connWriteMessageMock = func(_ int, _ []byte) error {
return nil
}
err := startProfiling(ctx, mockWSConn, adminClient, testOptions)
@@ -82,7 +82,7 @@ func TestStartProfiling(t *testing.T) {
// Test-2 : startProfiling() Correctly handles errors returned by MinIO
// mock function response from startProfiling()
minioStartProfiling = func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
minioStartProfiling = func(_ madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
return nil, errors.New("error")
}
err = startProfiling(ctx, mockWSConn, adminClient, testOptions)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,11 +24,13 @@ import (
"net/url"
"time"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
release "github.com/minio/console/api/operations/release"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
release "github.com/minio/console/restapi/operations/release"
"github.com/minio/pkg/env"
"github.com/minio/pkg/v3/env"
)
var (
@@ -40,13 +42,13 @@ func registerReleasesHandlers(api *operations.ConsoleAPI) {
api.ReleaseListReleasesHandler = release.ListReleasesHandlerFunc(func(params release.ListReleasesParams, session *models.Principal) middleware.Responder {
resp, err := GetReleaseListResponse(session, params)
if err != nil {
return release.NewListReleasesDefault(int(err.Code)).WithPayload(err)
return release.NewListReleasesDefault(err.Code).WithPayload(err.APIError)
}
return release.NewListReleasesOK().WithPayload(resp)
})
}
func GetReleaseListResponse(_ *models.Principal, params release.ListReleasesParams) (*models.ReleaseListResponse, *models.Error) {
func GetReleaseListResponse(_ *models.Principal, params release.ListReleasesParams) (*models.ReleaseListResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
repo := params.Repo
@@ -62,12 +64,14 @@ func GetReleaseListResponse(_ *models.Principal, params release.ListReleasesPara
if params.Filter != nil {
filter = *params.Filter
}
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(params.HTTPRequest))
return releaseList(ctx, repo, currentRelease, search, filter)
}
func releaseList(ctx context.Context, repo, currentRelease, search, filter string) (*models.ReleaseListResponse, *models.Error) {
func releaseList(ctx context.Context, repo, currentRelease, search, filter string) (*models.ReleaseListResponse, *CodedAPIError) {
serviceURL := getReleaseServiceURL()
releases, err := getReleases(serviceURL, repo, currentRelease, search, filter)
clientIP := utils.ClientIPFromContext(ctx)
releases, err := getReleases(serviceURL, repo, currentRelease, search, filter, clientIP)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -79,7 +83,7 @@ func getReleaseServiceURL() string {
return fmt.Sprintf("%s/releases", host)
}
func getReleases(endpoint, repo, currentRelease, search, filter string) (*models.ReleaseListResponse, error) {
func getReleases(endpoint, repo, currentRelease, search, filter, clientIP string) (*models.ReleaseListResponse, error) {
rl := &models.ReleaseListResponse{}
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
@@ -93,7 +97,7 @@ func getReleases(endpoint, repo, currentRelease, search, filter string) (*models
req.URL.RawQuery = q.Encode()
req.Header.Set("Content-Type", "application/json")
client := GetConsoleHTTPClient("")
client := GetConsoleHTTPClient(clientIP)
client.Timeout = time.Second * 5
resp, err := client.Do(req)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"encoding/json"
@@ -24,9 +24,9 @@ import (
"os"
"testing"
"github.com/minio/console/api/operations"
release "github.com/minio/console/api/operations/release"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
release "github.com/minio/console/restapi/operations/release"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,13 +24,15 @@ import (
"strconv"
"time"
"github.com/minio/madmin-go/v2"
"github.com/minio/console/pkg/utils"
"github.com/minio/madmin-go/v3"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
bucketApi "github.com/minio/console/api/operations/bucket"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
bucketApi "github.com/minio/console/restapi/operations/bucket"
"github.com/minio/minio-go/v7/pkg/replication"
)
@@ -45,7 +47,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketListRemoteBucketsHandler = bucketApi.ListRemoteBucketsHandlerFunc(func(params bucketApi.ListRemoteBucketsParams, session *models.Principal) middleware.Responder {
listResp, err := getListRemoteBucketsResponse(session, params)
if err != nil {
return bucketApi.NewListRemoteBucketsDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewListRemoteBucketsDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListRemoteBucketsOK().WithPayload(listResp)
})
@@ -54,7 +56,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketRemoteBucketDetailsHandler = bucketApi.RemoteBucketDetailsHandlerFunc(func(params bucketApi.RemoteBucketDetailsParams, session *models.Principal) middleware.Responder {
response, err := getRemoteBucketDetailsResponse(session, params)
if err != nil {
return bucketApi.NewRemoteBucketDetailsDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewRemoteBucketDetailsDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewRemoteBucketDetailsOK().WithPayload(response)
})
@@ -63,7 +65,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketDeleteRemoteBucketHandler = bucketApi.DeleteRemoteBucketHandlerFunc(func(params bucketApi.DeleteRemoteBucketParams, session *models.Principal) middleware.Responder {
err := getDeleteRemoteBucketResponse(session, params)
if err != nil {
return bucketApi.NewDeleteRemoteBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewDeleteRemoteBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteRemoteBucketNoContent()
})
@@ -72,7 +74,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketAddRemoteBucketHandler = bucketApi.AddRemoteBucketHandlerFunc(func(params bucketApi.AddRemoteBucketParams, session *models.Principal) middleware.Responder {
err := getAddRemoteBucketResponse(session, params)
if err != nil {
return bucketApi.NewAddRemoteBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewAddRemoteBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewAddRemoteBucketCreated()
})
@@ -81,17 +83,17 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketSetMultiBucketReplicationHandler = bucketApi.SetMultiBucketReplicationHandlerFunc(func(params bucketApi.SetMultiBucketReplicationParams, session *models.Principal) middleware.Responder {
response, err := setMultiBucketReplicationResponse(session, params)
if err != nil {
return bucketApi.NewSetMultiBucketReplicationDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewSetMultiBucketReplicationDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewSetMultiBucketReplicationOK().WithPayload(response)
})
// list external buckets
api.BucketListExternalBucketsHandler = bucketApi.ListExternalBucketsHandlerFunc(func(params bucketApi.ListExternalBucketsParams, session *models.Principal) middleware.Responder {
api.BucketListExternalBucketsHandler = bucketApi.ListExternalBucketsHandlerFunc(func(params bucketApi.ListExternalBucketsParams, _ *models.Principal) middleware.Responder {
response, err := listExternalBucketsResponse(params)
if err != nil {
return bucketApi.NewListExternalBucketsDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewListExternalBucketsDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListExternalBucketsOK().WithPayload(response)
@@ -101,7 +103,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketDeleteBucketReplicationRuleHandler = bucketApi.DeleteBucketReplicationRuleHandlerFunc(func(params bucketApi.DeleteBucketReplicationRuleParams, session *models.Principal) middleware.Responder {
err := deleteReplicationRuleResponse(session, params)
if err != nil {
return bucketApi.NewDeleteBucketReplicationRuleDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewDeleteBucketReplicationRuleDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteBucketReplicationRuleNoContent()
@@ -111,13 +113,13 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketDeleteAllReplicationRulesHandler = bucketApi.DeleteAllReplicationRulesHandlerFunc(func(params bucketApi.DeleteAllReplicationRulesParams, session *models.Principal) middleware.Responder {
err := deleteBucketReplicationRulesResponse(session, params)
if err != nil {
if err.Code == 500 && *err.DetailedMessage == "The remote target does not exist" {
if err.Code == 500 && err.APIError.DetailedMessage == "The remote target does not exist" {
// We should ignore this MinIO error when deleting all replication rules
return bucketApi.NewDeleteAllReplicationRulesNoContent() // This will return 204 as per swagger spec
}
// If there is a different error, then we should handle it
// This will return a generic error with err.Code (likely a 500 or 404) and its *err.DetailedMessage
return bucketApi.NewDeleteAllReplicationRulesDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewDeleteAllReplicationRulesDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteAllReplicationRulesNoContent()
})
@@ -126,7 +128,7 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketDeleteSelectedReplicationRulesHandler = bucketApi.DeleteSelectedReplicationRulesHandlerFunc(func(params bucketApi.DeleteSelectedReplicationRulesParams, session *models.Principal) middleware.Responder {
err := deleteSelectedReplicationRulesResponse(session, params)
if err != nil {
return bucketApi.NewDeleteSelectedReplicationRulesDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewDeleteSelectedReplicationRulesDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewDeleteSelectedReplicationRulesNoContent()
@@ -136,49 +138,38 @@ func registerAdminBucketRemoteHandlers(api *operations.ConsoleAPI) {
api.BucketUpdateMultiBucketReplicationHandler = bucketApi.UpdateMultiBucketReplicationHandlerFunc(func(params bucketApi.UpdateMultiBucketReplicationParams, session *models.Principal) middleware.Responder {
err := updateBucketReplicationResponse(session, params)
if err != nil {
return bucketApi.NewUpdateMultiBucketReplicationDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewUpdateMultiBucketReplicationDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewUpdateMultiBucketReplicationCreated()
})
}
func getListRemoteBucketsResponse(session *models.Principal, params bucketApi.ListRemoteBucketsParams) (*models.ListRemoteBucketsResponse, *models.Error) {
func getListRemoteBucketsResponse(session *models.Principal, params bucketApi.ListRemoteBucketsParams) (*models.ListRemoteBucketsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error creating Madmin Client: %v", err))
}
adminClient := AdminClient{Client: mAdmin}
buckets, err := listRemoteBuckets(ctx, adminClient)
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error listing remote buckets: %v", err))
}
return &models.ListRemoteBucketsResponse{
Buckets: buckets,
Total: int64(len(buckets)),
}, nil
return listRemoteBuckets(ctx, adminClient)
}
func getRemoteBucketDetailsResponse(session *models.Principal, params bucketApi.RemoteBucketDetailsParams) (*models.RemoteBucket, *models.Error) {
func getRemoteBucketDetailsResponse(session *models.Principal, params bucketApi.RemoteBucketDetailsParams) (*models.RemoteBucket, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error creating Madmin Client: %v", err))
}
adminClient := AdminClient{Client: mAdmin}
bucket, err := getRemoteBucket(ctx, adminClient, params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error getting remote bucket details: %v", err))
}
return bucket, nil
return getRemoteBucket(ctx, adminClient, params.Name)
}
func getDeleteRemoteBucketResponse(session *models.Principal, params bucketApi.DeleteRemoteBucketParams) *models.Error {
func getDeleteRemoteBucketResponse(session *models.Principal, params bucketApi.DeleteRemoteBucketParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, fmt.Errorf("error creating Madmin Client: %v", err))
}
@@ -190,10 +181,10 @@ func getDeleteRemoteBucketResponse(session *models.Principal, params bucketApi.D
return nil
}
func getAddRemoteBucketResponse(session *models.Principal, params bucketApi.AddRemoteBucketParams) *models.Error {
func getAddRemoteBucketResponse(session *models.Principal, params bucketApi.AddRemoteBucketParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, fmt.Errorf("error creating Madmin Client: %v", err))
}
@@ -205,11 +196,11 @@ func getAddRemoteBucketResponse(session *models.Principal, params bucketApi.AddR
return nil
}
func listRemoteBuckets(ctx context.Context, client MinioAdmin) ([]*models.RemoteBucket, error) {
func listRemoteBuckets(ctx context.Context, client MinioAdmin) (*models.ListRemoteBucketsResponse, *CodedAPIError) {
var remoteBuckets []*models.RemoteBucket
buckets, err := client.listRemoteBuckets(ctx, "", "")
if err != nil {
return nil, err
return nil, ErrorWithContext(ctx, fmt.Errorf("error listing remote buckets: %v", err))
}
for _, bucket := range buckets {
remoteBucket := &models.RemoteBucket{
@@ -230,16 +221,20 @@ func listRemoteBuckets(ctx context.Context, client MinioAdmin) ([]*models.Remote
}
remoteBuckets = append(remoteBuckets, remoteBucket)
}
return remoteBuckets, nil
return &models.ListRemoteBucketsResponse{
Buckets: remoteBuckets,
Total: int64(len(remoteBuckets)),
}, nil
}
func getRemoteBucket(ctx context.Context, client MinioAdmin, name string) (*models.RemoteBucket, error) {
func getRemoteBucket(ctx context.Context, client MinioAdmin, name string) (*models.RemoteBucket, *CodedAPIError) {
remoteBucket, err := client.getRemoteBucket(ctx, name, "")
if err != nil {
return nil, err
return nil, ErrorWithContext(ctx, fmt.Errorf("error getting remote bucket details: %v", err))
}
if remoteBucket == nil {
return nil, errors.New("bucket not found")
return nil, ErrorWithContext(ctx, "error getting remote bucket details: bucket not found")
}
return &models.RemoteBucket{
AccessKey: &remoteBucket.Credentials.AccessKey,
@@ -297,7 +292,7 @@ func addRemoteBucket(ctx context.Context, client MinioAdmin, params models.Creat
return bucketARN, err
}
func addBucketReplicationItem(ctx context.Context, session *models.Principal, minClient minioClient, bucketName, prefix, destinationARN string, repDelMark, repDels, repMeta bool, tags string, priority int32, storageClass string) error {
func addBucketReplicationItem(ctx context.Context, session *models.Principal, minClient minioClient, bucketName, prefix, destinationARN string, repExistingObj, repDelMark, repDels, repMeta bool, tags string, priority int32, storageClass string) error {
// we will tolerate this call failing
cfg, err := minClient.getBucketReplication(ctx, bucketName)
if err != nil {
@@ -317,8 +312,8 @@ func addBucketReplicationItem(ctx context.Context, session *models.Principal, mi
} else { // User picked priority, we try to set this manually
maxPrio = int(priority)
}
s3Client, err := newS3BucketClient(session, bucketName, prefix)
clientIP := utils.ClientIPFromContext(ctx)
s3Client, err := newS3BucketClient(session, bucketName, prefix, clientIP)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("error creating S3Client: %v", err))
return err
@@ -342,13 +337,18 @@ func addBucketReplicationItem(ctx context.Context, session *models.Principal, mi
repMetaStatus = "enable"
}
existingRepStatus := "disable"
if repExistingObj {
existingRepStatus = "enable"
}
opts := replication.Options{
Priority: fmt.Sprintf("%d", maxPrio),
RuleStatus: "enable",
DestBucket: destinationARN,
Op: replication.AddOption,
TagString: tags,
ExistingObjectReplicate: "enable", // enabled by default
ExistingObjectReplicate: existingRepStatus,
ReplicateDeleteMarkers: repDelMarkStatus,
ReplicateDeletes: repDelsStatus,
ReplicaSync: repMetaStatus,
@@ -372,7 +372,8 @@ func editBucketReplicationItem(ctx context.Context, session *models.Principal, m
maxPrio := int(priority)
s3Client, err := newS3BucketClient(session, bucketName, prefix)
clientIP := utils.ClientIPFromContext(ctx)
s3Client, err := newS3BucketClient(session, bucketName, prefix, clientIP)
if err != nil {
return fmt.Errorf("error creating S3Client: %v", err)
}
@@ -463,6 +464,7 @@ func setMultiBucketReplication(ctx context.Context, session *models.Principal, c
sourceBucket,
params.Body.Prefix,
arn,
params.Body.ReplicateExistingObjects,
params.Body.ReplicateDeleteMarkers,
params.Body.ReplicateDeletes,
params.Body.ReplicateMetadata,
@@ -506,17 +508,17 @@ func setMultiBucketReplication(ctx context.Context, session *models.Principal, c
return resultsList
}
func setMultiBucketReplicationResponse(session *models.Principal, params bucketApi.SetMultiBucketReplicationParams) (*models.MultiBucketResponseState, *models.Error) {
func setMultiBucketReplicationResponse(session *models.Principal, params bucketApi.SetMultiBucketReplicationParams) (*models.MultiBucketResponseState, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error creating Madmin Client: %v", err))
}
adminClient := AdminClient{Client: mAdmin}
mClient, err := newMinioClient(session)
mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
if err != nil {
return nil, ErrorWithContext(ctx, fmt.Errorf("error creating MinIO Client: %v", err))
}
@@ -549,27 +551,26 @@ func setMultiBucketReplicationResponse(session *models.Principal, params bucketA
return &resultsParsed, nil
}
func listExternalBucketsResponse(params bucketApi.ListExternalBucketsParams) (*models.ListBucketsResponse, *models.Error) {
func listExternalBucketsResponse(params bucketApi.ListExternalBucketsParams) (*models.ListBucketsResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
remoteAdmin, err := newAdminFromCreds(*params.Body.AccessKey, *params.Body.SecretKey, *params.Body.TargetURL, *params.Body.UseTLS)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
remoteClient := AdminClient{Client: remoteAdmin}
buckets, err := getAccountBuckets(ctx, remoteClient)
return listExternalBuckets(ctx, AdminClient{Client: remoteAdmin})
}
func listExternalBuckets(ctx context.Context, client MinioAdmin) (*models.ListBucketsResponse, *CodedAPIError) {
buckets, err := getAccountBuckets(ctx, client)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
// serialize output
listBucketsResponse := &models.ListBucketsResponse{
return &models.ListBucketsResponse{
Buckets: buckets,
Total: int64(len(buckets)),
}
return listBucketsResponse, nil
}, nil
}
func getARNFromID(conf *replication.Config, rule string) string {
@@ -596,7 +597,8 @@ func getARNsFromIDs(conf *replication.Config, rules []string) []string {
}
func deleteReplicationRule(ctx context.Context, session *models.Principal, bucketName, ruleID string) error {
mClient, err := newMinioClient(session)
clientIP := utils.ClientIPFromContext(ctx)
mClient, err := newMinioClient(session, clientIP)
if err != nil {
return fmt.Errorf("error creating MinIO Client: %v", err)
}
@@ -609,12 +611,11 @@ func deleteReplicationRule(ctx context.Context, session *models.Principal, bucke
ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err))
}
s3Client, err := newS3BucketClient(session, bucketName, "")
s3Client, err := newS3BucketClient(session, bucketName, "", clientIP)
if err != nil {
return fmt.Errorf("error creating S3Client: %v", err)
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(ctx, session)
if err != nil {
return fmt.Errorf("error creating Admin Client: %v", err)
}
@@ -644,15 +645,16 @@ func deleteReplicationRule(ctx context.Context, session *models.Principal, bucke
}
func deleteAllReplicationRules(ctx context.Context, session *models.Principal, bucketName string) error {
s3Client, err := newS3BucketClient(session, bucketName, "")
clientIP := utils.ClientIPFromContext(ctx)
s3Client, err := newS3BucketClient(session, bucketName, "", clientIP)
if err != nil {
return fmt.Errorf("error creating S3Client: %v", err)
}
// create a mc S3Client interface implementation
// defining the client to be used
mcClient := mcClient{client: s3Client}
mClient, err := newMinioClient(session)
mClient, err := newMinioClient(session, clientIP)
if err != nil {
return fmt.Errorf("error creating MinIO Client: %v", err)
}
@@ -665,7 +667,7 @@ func deleteAllReplicationRules(ctx context.Context, session *models.Principal, b
ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err))
}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(ctx, session)
if err != nil {
return fmt.Errorf("error creating Admin Client: %v", err)
}
@@ -674,7 +676,7 @@ func deleteAllReplicationRules(ctx context.Context, session *models.Principal, b
err2 := mcClient.deleteAllReplicationRules(ctx)
if err2 != nil {
return err
return err2.ToGoError()
}
for i := range cfg.Rules {
@@ -688,7 +690,8 @@ func deleteAllReplicationRules(ctx context.Context, session *models.Principal, b
}
func deleteSelectedReplicationRules(ctx context.Context, session *models.Principal, bucketName string, rules []string) error {
mClient, err := newMinioClient(session)
clientIP := utils.ClientIPFromContext(ctx)
mClient, err := newMinioClient(session, clientIP)
if err != nil {
return fmt.Errorf("error creating MinIO Client: %v", err)
}
@@ -701,7 +704,7 @@ func deleteSelectedReplicationRules(ctx context.Context, session *models.Princip
ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err))
}
s3Client, err := newS3BucketClient(session, bucketName, "")
s3Client, err := newS3BucketClient(session, bucketName, "", clientIP)
if err != nil {
return fmt.Errorf("error creating S3Client: %v", err)
}
@@ -709,7 +712,7 @@ func deleteSelectedReplicationRules(ctx context.Context, session *models.Princip
// defining the client to be used
mcClient := mcClient{client: s3Client}
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(ctx, session)
if err != nil {
return fmt.Errorf("error creating Admin Client: %v", err)
}
@@ -736,10 +739,10 @@ func deleteSelectedReplicationRules(ctx context.Context, session *models.Princip
return nil
}
func deleteReplicationRuleResponse(session *models.Principal, params bucketApi.DeleteBucketReplicationRuleParams) *models.Error {
func deleteReplicationRuleResponse(session *models.Principal, params bucketApi.DeleteBucketReplicationRuleParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(params.HTTPRequest))
err := deleteReplicationRule(ctx, session, params.BucketName, params.RuleID)
if err != nil {
return ErrorWithContext(ctx, err)
@@ -747,10 +750,10 @@ func deleteReplicationRuleResponse(session *models.Principal, params bucketApi.D
return nil
}
func deleteBucketReplicationRulesResponse(session *models.Principal, params bucketApi.DeleteAllReplicationRulesParams) *models.Error {
func deleteBucketReplicationRulesResponse(session *models.Principal, params bucketApi.DeleteAllReplicationRulesParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(params.HTTPRequest))
err := deleteAllReplicationRules(ctx, session, params.BucketName)
if err != nil {
return ErrorWithContext(ctx, err)
@@ -758,10 +761,12 @@ func deleteBucketReplicationRulesResponse(session *models.Principal, params buck
return nil
}
func deleteSelectedReplicationRulesResponse(session *models.Principal, params bucketApi.DeleteSelectedReplicationRulesParams) *models.Error {
func deleteSelectedReplicationRulesResponse(session *models.Principal, params bucketApi.DeleteSelectedReplicationRulesParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(params.HTTPRequest))
err := deleteSelectedReplicationRules(ctx, session, params.BucketName, params.Rules.Rules)
if err != nil {
return ErrorWithContext(ctx, err)
@@ -769,11 +774,11 @@ func deleteSelectedReplicationRulesResponse(session *models.Principal, params bu
return nil
}
func updateBucketReplicationResponse(session *models.Principal, params bucketApi.UpdateMultiBucketReplicationParams) *models.Error {
func updateBucketReplicationResponse(session *models.Principal, params bucketApi.UpdateMultiBucketReplicationParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mClient, err := newMinioClient(session)
mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -797,7 +802,6 @@ func updateBucketReplicationResponse(session *models.Principal, params bucketApi
params.Body.Tags,
params.Body.Priority,
params.Body.StorageClass)
if err != nil {
return ErrorWithContext(ctx, err)
}

View File

@@ -0,0 +1,386 @@
// 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 api
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
bucketApi "github.com/minio/console/api/operations/bucket"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type RemoteBucketsTestSuite struct {
suite.Suite
assert *assert.Assertions
currentServer string
isServerSet bool
server *httptest.Server
adminClient AdminClientMock
minioClient minioClientMock
mockRemoteBucket *models.RemoteBucket
mockBucketTarget *madmin.BucketTarget
mockListBuckets *models.ListBucketsResponse
}
func (suite *RemoteBucketsTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
suite.minioClient = minioClientMock{}
suite.mockObjects()
}
func (suite *RemoteBucketsTestSuite) mockObjects() {
suite.mockListBuckets = &models.ListBucketsResponse{
Buckets: []*models.Bucket{},
Total: 0,
}
suite.mockRemoteBucket = &models.RemoteBucket{
AccessKey: swag.String("accessKey"),
SecretKey: "secretKey",
RemoteARN: swag.String("remoteARN"),
Service: "replication",
SourceBucket: swag.String("sourceBucket"),
TargetBucket: "targetBucket",
TargetURL: "targetURL",
Status: "",
}
suite.mockBucketTarget = &madmin.BucketTarget{
Credentials: &madmin.Credentials{
AccessKey: *suite.mockRemoteBucket.AccessKey,
SecretKey: suite.mockRemoteBucket.SecretKey,
},
Arn: *suite.mockRemoteBucket.RemoteARN,
SourceBucket: *suite.mockRemoteBucket.SourceBucket,
TargetBucket: suite.mockRemoteBucket.TargetBucket,
Endpoint: suite.mockRemoteBucket.TargetURL,
}
}
func (suite *RemoteBucketsTestSuite) SetupTest() {
suite.server = httptest.NewServer(http.HandlerFunc(suite.serverHandler))
suite.currentServer, suite.isServerSet = os.LookupEnv(ConsoleMinIOServer)
os.Setenv(ConsoleMinIOServer, suite.server.URL)
}
func (suite *RemoteBucketsTestSuite) serverHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(400)
}
func (suite *RemoteBucketsTestSuite) TearDownSuite() {
}
func (suite *RemoteBucketsTestSuite) TearDownTest() {
if suite.isServerSet {
os.Setenv(ConsoleMinIOServer, suite.currentServer)
} else {
os.Unsetenv(ConsoleMinIOServer)
}
}
func (suite *RemoteBucketsTestSuite) TestRegisterRemoteBucketsHandlers() {
api := &operations.ConsoleAPI{}
suite.assertHandlersAreNil(api)
registerAdminBucketRemoteHandlers(api)
suite.assertHandlersAreNotNil(api)
}
func (suite *RemoteBucketsTestSuite) assertHandlersAreNil(api *operations.ConsoleAPI) {
suite.assert.Nil(api.BucketListRemoteBucketsHandler)
suite.assert.Nil(api.BucketRemoteBucketDetailsHandler)
suite.assert.Nil(api.BucketDeleteRemoteBucketHandler)
suite.assert.Nil(api.BucketAddRemoteBucketHandler)
suite.assert.Nil(api.BucketSetMultiBucketReplicationHandler)
suite.assert.Nil(api.BucketListExternalBucketsHandler)
suite.assert.Nil(api.BucketDeleteBucketReplicationRuleHandler)
suite.assert.Nil(api.BucketDeleteAllReplicationRulesHandler)
suite.assert.Nil(api.BucketDeleteSelectedReplicationRulesHandler)
suite.assert.Nil(api.BucketUpdateMultiBucketReplicationHandler)
}
func (suite *RemoteBucketsTestSuite) assertHandlersAreNotNil(api *operations.ConsoleAPI) {
suite.assert.NotNil(api.BucketListRemoteBucketsHandler)
suite.assert.NotNil(api.BucketRemoteBucketDetailsHandler)
suite.assert.NotNil(api.BucketDeleteRemoteBucketHandler)
suite.assert.NotNil(api.BucketAddRemoteBucketHandler)
suite.assert.NotNil(api.BucketSetMultiBucketReplicationHandler)
suite.assert.NotNil(api.BucketListExternalBucketsHandler)
suite.assert.NotNil(api.BucketDeleteBucketReplicationRuleHandler)
suite.assert.NotNil(api.BucketDeleteAllReplicationRulesHandler)
suite.assert.NotNil(api.BucketDeleteSelectedReplicationRulesHandler)
suite.assert.NotNil(api.BucketUpdateMultiBucketReplicationHandler)
}
func (suite *RemoteBucketsTestSuite) TestListRemoteBucketsHandlerWithError() {
params, api := suite.initListRemoteBucketsRequest()
response := api.BucketListRemoteBucketsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.ListRemoteBucketsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initListRemoteBucketsRequest() (params bucketApi.ListRemoteBucketsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListRemoteBucketsWithoutError() {
ctx := context.Background()
minioListRemoteBucketsMock = func(_ context.Context, _, _ string) (targets []madmin.BucketTarget, err error) {
return []madmin.BucketTarget{{
Credentials: &madmin.Credentials{
AccessKey: "accessKey",
SecretKey: "secretKey",
},
}}, nil
}
res, err := listRemoteBuckets(ctx, &suite.adminClient)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *RemoteBucketsTestSuite) TestRemoteBucketDetailsHandlerWithError() {
params, api := suite.initRemoteBucketDetailsRequest()
response := api.BucketRemoteBucketDetailsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.RemoteBucketDetailsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initRemoteBucketDetailsRequest() (params bucketApi.RemoteBucketDetailsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestGetRemoteBucketWithoutError() {
ctx := context.Background()
minioGetRemoteBucketMock = func(_ context.Context, _, _ string) (targets *madmin.BucketTarget, err error) {
return suite.mockBucketTarget, nil
}
res, err := getRemoteBucket(ctx, &suite.adminClient, "bucketName")
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.assert.Equal(suite.mockRemoteBucket, res)
}
func (suite *RemoteBucketsTestSuite) TestDeleteRemoteBucketHandlerWithError() {
params, api := suite.initDeleteRemoteBucketRequest()
response := api.BucketDeleteRemoteBucketHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteRemoteBucketDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteRemoteBucketRequest() (params bucketApi.DeleteRemoteBucketParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestAddRemoteBucketHandlerWithError() {
params, api := suite.initAddRemoteBucketRequest()
response := api.BucketAddRemoteBucketHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.AddRemoteBucketDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initAddRemoteBucketRequest() (params bucketApi.AddRemoteBucketParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
url := "^&*&^%^"
accessKey := "accessKey"
secretKey := "secretKey"
params.HTTPRequest = &http.Request{}
params.Body = &models.CreateRemoteBucket{
TargetURL: &url,
AccessKey: &accessKey,
SecretKey: &secretKey,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestAddRemoteBucketWithoutError() {
ctx := context.Background()
minioAddRemoteBucketMock = func(_ context.Context, _ string, _ *madmin.BucketTarget) (string, error) {
return "bucketName", nil
}
url := "https://localhost"
accessKey := "accessKey"
secretKey := "secretKey"
targetBucket := "targetBucket"
syncMode := "async"
sourceBucket := "sourceBucket"
data := models.CreateRemoteBucket{
TargetURL: &url,
TargetBucket: &targetBucket,
AccessKey: &accessKey,
SecretKey: &secretKey,
SyncMode: &syncMode,
HealthCheckPeriod: 10,
SourceBucket: &sourceBucket,
}
res, err := addRemoteBucket(ctx, &suite.adminClient, data)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}
func (suite *RemoteBucketsTestSuite) TestSetMultiBucketReplicationHandlerWithError() {
params, api := suite.initSetMultiBucketReplicationRequest()
response := api.BucketSetMultiBucketReplicationHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.SetMultiBucketReplicationOK)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initSetMultiBucketReplicationRequest() (params bucketApi.SetMultiBucketReplicationParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
accessKey := "accessKey"
secretKey := "secretKey"
targetURL := "https://localhost"
syncMode := "async"
params.HTTPRequest = &http.Request{}
params.Body = &models.MultiBucketReplication{
BucketsRelation: []*models.MultiBucketsRelation{{}},
AccessKey: &accessKey,
SecretKey: &secretKey,
Region: "region",
TargetURL: &targetURL,
SyncMode: &syncMode,
Bandwidth: 10,
HealthCheckPeriod: 10,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsHandlerWithError() {
params, api := suite.initListExternalBucketsRequest()
response := api.BucketListExternalBucketsHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.ListExternalBucketsDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initListExternalBucketsRequest() (params bucketApi.ListExternalBucketsParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
url := "http://localhost:9000"
accessKey := "accessKey"
secretKey := "secretKey"
tls := false
params.HTTPRequest = &http.Request{}
params.Body = &models.ListExternalBucketsParams{
TargetURL: &url,
AccessKey: &accessKey,
SecretKey: &secretKey,
UseTLS: &tls,
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsWithError() {
ctx := context.Background()
minioAccountInfoMock = func(_ context.Context) (madmin.AccountInfo, error) {
return madmin.AccountInfo{}, errors.New("error")
}
res, err := listExternalBuckets(ctx, &suite.adminClient)
suite.assert.NotNil(err)
suite.assert.Nil(res)
}
func (suite *RemoteBucketsTestSuite) TestListExternalBucketsWithoutError() {
ctx := context.Background()
minioAccountInfoMock = func(_ context.Context) (madmin.AccountInfo, error) {
return madmin.AccountInfo{
Buckets: []madmin.BucketAccessInfo{},
}, nil
}
res, err := listExternalBuckets(ctx, &suite.adminClient)
suite.assert.Nil(err)
suite.assert.NotNil(res)
suite.assert.Equal(suite.mockListBuckets, res)
}
func (suite *RemoteBucketsTestSuite) TestDeleteBucketReplicationRuleHandlerWithError() {
params, api := suite.initDeleteBucketReplicationRuleRequest()
response := api.BucketDeleteBucketReplicationRuleHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteBucketReplicationRuleDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteBucketReplicationRuleRequest() (params bucketApi.DeleteBucketReplicationRuleParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestDeleteAllReplicationRulesHandlerWithError() {
params, api := suite.initDeleteAllReplicationRulesRequest()
response := api.BucketDeleteAllReplicationRulesHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteAllReplicationRulesDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteAllReplicationRulesRequest() (params bucketApi.DeleteAllReplicationRulesParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestDeleteSelectedReplicationRulesHandlerWithError() {
params, api := suite.initDeleteSelectedReplicationRulesRequest()
response := api.BucketDeleteSelectedReplicationRulesHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.DeleteSelectedReplicationRulesDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initDeleteSelectedReplicationRulesRequest() (params bucketApi.DeleteSelectedReplicationRulesParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
params.HTTPRequest = &http.Request{}
params.BucketName = "bucketName"
params.Rules = &models.BucketReplicationRuleList{
Rules: []string{"rule1", "rule2"},
}
return params, api
}
func (suite *RemoteBucketsTestSuite) TestUpdateMultiBucketReplicationHandlerWithError() {
params, api := suite.initUpdateMultiBucketReplicationRequest()
response := api.BucketUpdateMultiBucketReplicationHandler.Handle(params, &models.Principal{})
_, ok := response.(*bucketApi.UpdateMultiBucketReplicationDefault)
suite.assert.True(ok)
}
func (suite *RemoteBucketsTestSuite) initUpdateMultiBucketReplicationRequest() (params bucketApi.UpdateMultiBucketReplicationParams, api operations.ConsoleAPI) {
registerAdminBucketRemoteHandlers(&api)
r := &http.Request{}
ctx := context.WithValue(context.Background(), utils.ContextClientIP, "127.0.0.1")
rc := r.WithContext(ctx)
params.HTTPRequest = rc
params.Body = &models.MultiBucketReplicationEdit{}
return params, api
}
func TestRemoteBuckets(t *testing.T) {
suite.Run(t, new(RemoteBucketsTestSuite))
}

View File

@@ -14,32 +14,32 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
siteRepApi "github.com/minio/console/api/operations/site_replication"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
siteRepApi "github.com/minio/console/restapi/operations/site_replication"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
func registerSiteReplicationStatusHandler(api *operations.ConsoleAPI) {
api.SiteReplicationGetSiteReplicationStatusHandler = siteRepApi.GetSiteReplicationStatusHandlerFunc(func(params siteRepApi.GetSiteReplicationStatusParams, session *models.Principal) middleware.Responder {
rInfo, err := getSRStatusResponse(session, params)
if err != nil {
return siteRepApi.NewGetSiteReplicationStatusDefault(int(err.Code)).WithPayload(err)
return siteRepApi.NewGetSiteReplicationStatusDefault(err.Code).WithPayload(err.APIError)
}
return siteRepApi.NewGetSiteReplicationStatusOK().WithPayload(rInfo)
})
}
func getSRStatusResponse(session *models.Principal, params siteRepApi.GetSiteReplicationStatusParams) (*models.SiteReplicationStatusResponse, *models.Error) {
func getSRStatusResponse(session *models.Principal, params siteRepApi.GetSiteReplicationStatusParams) (*models.SiteReplicationStatusResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,24 +14,24 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"time"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
svcApi "github.com/minio/console/restapi/operations/service"
svcApi "github.com/minio/console/api/operations/service"
)
func registerServiceHandlers(api *operations.ConsoleAPI) {
// Restart Service
api.ServiceRestartServiceHandler = svcApi.RestartServiceHandlerFunc(func(params svcApi.RestartServiceParams, session *models.Principal) middleware.Responder {
if err := getRestartServiceResponse(session, params); err != nil {
return svcApi.NewRestartServiceDefault(int(err.Code)).WithPayload(err)
return svcApi.NewRestartServiceDefault(err.Code).WithPayload(err.APIError)
}
return svcApi.NewRestartServiceNoContent()
})
@@ -59,10 +59,10 @@ func serviceRestart(ctx context.Context, client MinioAdmin) error {
}
// getRestartServiceResponse performs serviceRestart()
func getRestartServiceResponse(session *models.Principal, params svcApi.RestartServiceParams) *models.Error {
func getRestartServiceResponse(session *models.Principal, params svcApi.RestartServiceParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}

View File

@@ -14,14 +14,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"errors"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -32,10 +32,10 @@ func TestServiceRestart(t *testing.T) {
function := "serviceRestart()"
// Test-1 : serviceRestart() restart services no errors
// mock function response from listGroups()
minioServiceRestartMock = func(ctx context.Context) error {
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, nil
}
if err := serviceRestart(ctx, adminClient); err != nil {
@@ -44,10 +44,10 @@ func TestServiceRestart(t *testing.T) {
// Test-2 : serviceRestart() returns errors on client.serviceRestart call
// and see that the errors is handled correctly and returned
minioServiceRestartMock = func(ctx context.Context) error {
minioServiceRestartMock = func(_ context.Context) error {
return errors.New("error")
}
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, nil
}
if err := serviceRestart(ctx, adminClient); assert.Error(err) {
@@ -56,10 +56,10 @@ func TestServiceRestart(t *testing.T) {
// Test-3 : serviceRestart() returns errors on client.serverInfo() call
// and see that the errors is handled correctly and returned
minioServiceRestartMock = func(ctx context.Context) error {
minioServiceRestartMock = func(_ context.Context) error {
return nil
}
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{}, errors.New("error on server info")
}
if err := serviceRestart(ctx, adminClient); assert.Error(err) {

View File

@@ -14,23 +14,24 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
siteRepApi "github.com/minio/console/api/operations/site_replication"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
siteRepApi "github.com/minio/console/restapi/operations/site_replication"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
func registerSiteReplicationHandler(api *operations.ConsoleAPI) {
api.SiteReplicationGetSiteReplicationInfoHandler = siteRepApi.GetSiteReplicationInfoHandlerFunc(func(params siteRepApi.GetSiteReplicationInfoParams, session *models.Principal) middleware.Responder {
rInfo, err := getSRInfoResponse(session, params)
if err != nil {
return siteRepApi.NewGetSiteReplicationInfoDefault(int(err.Code)).WithPayload(err)
return siteRepApi.NewGetSiteReplicationInfoDefault(err.Code).WithPayload(err.APIError)
}
return siteRepApi.NewGetSiteReplicationInfoOK().WithPayload(rInfo)
})
@@ -38,7 +39,7 @@ func registerSiteReplicationHandler(api *operations.ConsoleAPI) {
api.SiteReplicationSiteReplicationInfoAddHandler = siteRepApi.SiteReplicationInfoAddHandlerFunc(func(params siteRepApi.SiteReplicationInfoAddParams, session *models.Principal) middleware.Responder {
eInfo, err := getSRAddResponse(session, params)
if err != nil {
return siteRepApi.NewSiteReplicationInfoAddDefault(int(err.Code)).WithPayload(err)
return siteRepApi.NewSiteReplicationInfoAddDefault(err.Code).WithPayload(err.APIError)
}
return siteRepApi.NewSiteReplicationInfoAddOK().WithPayload(eInfo)
})
@@ -46,7 +47,7 @@ func registerSiteReplicationHandler(api *operations.ConsoleAPI) {
api.SiteReplicationSiteReplicationRemoveHandler = siteRepApi.SiteReplicationRemoveHandlerFunc(func(params siteRepApi.SiteReplicationRemoveParams, session *models.Principal) middleware.Responder {
remRes, err := getSRRemoveResponse(session, params)
if err != nil {
return siteRepApi.NewSiteReplicationRemoveDefault(int(err.Code)).WithPayload(err)
return siteRepApi.NewSiteReplicationRemoveDefault(err.Code).WithPayload(err.APIError)
}
return siteRepApi.NewSiteReplicationRemoveNoContent().WithPayload(remRes)
})
@@ -54,16 +55,16 @@ func registerSiteReplicationHandler(api *operations.ConsoleAPI) {
api.SiteReplicationSiteReplicationEditHandler = siteRepApi.SiteReplicationEditHandlerFunc(func(params siteRepApi.SiteReplicationEditParams, session *models.Principal) middleware.Responder {
eInfo, err := getSREditResponse(session, params)
if err != nil {
return siteRepApi.NewSiteReplicationRemoveDefault(int(err.Code)).WithPayload(err)
return siteRepApi.NewSiteReplicationRemoveDefault(err.Code).WithPayload(err.APIError)
}
return siteRepApi.NewSiteReplicationEditOK().WithPayload(eInfo)
})
}
func getSRInfoResponse(session *models.Principal, params siteRepApi.GetSiteReplicationInfoParams) (*models.SiteReplicationInfoResponse, *models.Error) {
func getSRInfoResponse(session *models.Principal, params siteRepApi.GetSiteReplicationInfoParams) (*models.SiteReplicationInfoResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -76,10 +77,10 @@ func getSRInfoResponse(session *models.Principal, params siteRepApi.GetSiteRepli
return res, nil
}
func getSRAddResponse(session *models.Principal, params siteRepApi.SiteReplicationInfoAddParams) (*models.SiteReplicationAddResponse, *models.Error) {
func getSRAddResponse(session *models.Principal, params siteRepApi.SiteReplicationInfoAddParams) (*models.SiteReplicationAddResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -92,10 +93,10 @@ func getSRAddResponse(session *models.Principal, params siteRepApi.SiteReplicati
return res, nil
}
func getSREditResponse(session *models.Principal, params siteRepApi.SiteReplicationEditParams) (*models.PeerSiteEditResponse, *models.Error) {
func getSREditResponse(session *models.Principal, params siteRepApi.SiteReplicationEditParams) (*models.PeerSiteEditResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -107,10 +108,10 @@ func getSREditResponse(session *models.Principal, params siteRepApi.SiteReplicat
return eRes, nil
}
func getSRRemoveResponse(session *models.Principal, params siteRepApi.SiteReplicationRemoveParams) (*models.PeerSiteRemoveResponse, *models.Error) {
func getSRRemoveResponse(session *models.Principal, params siteRepApi.SiteReplicationRemoveParams) (*models.PeerSiteRemoveResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -162,7 +163,13 @@ func addSiteReplication(ctx context.Context, client MinioAdmin, params *siteRepA
rSites = append(rSites, *pInfo)
}
}
cc, err := client.addSiteReplicationInfo(ctx, rSites)
qs := runtime.Values(params.HTTPRequest.URL.Query())
_, qhkReplicateILMExpiry, _ := qs.GetOK("replicate-ilm-expiry")
var opts madmin.SRAddOptions
if qhkReplicateILMExpiry {
opts.ReplicateILMExpiry = true
}
cc, err := client.addSiteReplicationInfo(ctx, rSites, opts)
if err != nil {
return nil, err
}
@@ -183,7 +190,17 @@ func editSiteReplication(ctx context.Context, client MinioAdmin, params *siteRep
Name: params.Body.Name, // does not get updated.
DeploymentID: params.Body.DeploymentID, // readonly
}
eRes, err := client.editSiteReplicationInfo(ctx, *peerSiteInfo)
qs := runtime.Values(params.HTTPRequest.URL.Query())
_, qhkDisableILMExpiryReplication, _ := qs.GetOK("disable-ilm-expiry-replication")
_, qhkEnableILMExpiryReplication, _ := qs.GetOK("enable-ilm-expiry-replication")
var opts madmin.SREditOptions
if qhkDisableILMExpiryReplication {
opts.DisableILMExpiryReplication = true
}
if qhkEnableILMExpiryReplication {
opts.EnableILMExpiryReplication = true
}
eRes, err := client.editSiteReplicationInfo(ctx, *peerSiteInfo, opts)
if err != nil {
return nil, err
}

View File

@@ -16,14 +16,14 @@
// These tests are for AdminAPI Tag based on swagger-console.yml
package restapi
package api
import (
"context"
"fmt"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -72,7 +72,7 @@ func TestGetSiteReplicationInfo(t *testing.T) {
ServiceAccountAccessKey: "test-key",
}
getSiteReplicationInfo = func(ctx context.Context) (info *madmin.SiteReplicationInfo, err error) {
getSiteReplicationInfo = func(_ context.Context) (info *madmin.SiteReplicationInfo, err error) {
return &retValueMock, nil
}
@@ -104,7 +104,7 @@ func TestAddSiteReplicationInfo(t *testing.T) {
InitialSyncErrorMessage: "",
}
addSiteReplicationInfo = func(ctx context.Context, sites []madmin.PeerSite) (res *madmin.ReplicateAddStatus, err error) {
addSiteReplicationInfo = func(_ context.Context, _ []madmin.PeerSite) (res *madmin.ReplicateAddStatus, err error) {
return retValueMock, nil
}
@@ -123,7 +123,7 @@ func TestAddSiteReplicationInfo(t *testing.T) {
},
}
srInfo, err := adminClient.addSiteReplicationInfo(ctx, sites)
srInfo, err := adminClient.addSiteReplicationInfo(ctx, sites, madmin.SRAddOptions{})
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
@@ -149,7 +149,7 @@ func TestEditSiteReplicationInfo(t *testing.T) {
ErrDetail: "",
}
editSiteReplicationInfo = func(ctx context.Context, site madmin.PeerInfo) (res *madmin.ReplicateEditStatus, err error) {
editSiteReplicationInfo = func(_ context.Context, _ madmin.PeerInfo) (res *madmin.ReplicateEditStatus, err error) {
return retValueMock, nil
}
@@ -159,7 +159,7 @@ func TestEditSiteReplicationInfo(t *testing.T) {
DeploymentID: "12345",
}
srInfo, err := adminClient.editSiteReplicationInfo(ctx, site)
srInfo, err := adminClient.editSiteReplicationInfo(ctx, site, madmin.SREditOptions{})
assert.Nil(err)
assert.Equal(expValueMock, srInfo, fmt.Sprintf("Failed on %s: length of lists is not the same", function))
}
@@ -183,7 +183,7 @@ func TestDeleteSiteReplicationInfo(t *testing.T) {
ErrDetail: "",
}
deleteSiteReplicationInfoMock = func(ctx context.Context, removeReq madmin.SRRemoveReq) (res *madmin.ReplicateRemoveStatus, err error) {
deleteSiteReplicationInfoMock = func(_ context.Context, _ madmin.SRRemoveReq) (res *madmin.ReplicateRemoveStatus, err error) {
return retValueMock, nil
}
@@ -236,7 +236,7 @@ func TestSiteReplicationStatus(t *testing.T) {
GroupStats: nil,
}
getSiteReplicationStatus = func(ctx context.Context, params madmin.SRStatusOptions) (info *madmin.SRStatusInfo, err error) {
getSiteReplicationStatus = func(_ context.Context, _ madmin.SRStatusOptions) (info *madmin.SRStatusInfo, err error) {
return &retValueMock, nil
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -25,7 +25,7 @@ import (
"time"
"github.com/dustin/go-humanize"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/minio/websocket"
)
@@ -64,10 +64,6 @@ func getSpeedtestOptionsFromReq(req *http.Request) (*madmin.SpeedtestOpts, error
return nil, fmt.Errorf("unable to parse object size")
}
if size < 0 {
return nil, fmt.Errorf("size is expected to be atleast 0 bytes")
}
optionsSet.Size = int(size)
paramConcurrent := queryPairs.Get("concurrent")

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package restapi
package api
import (
"context"
@@ -25,14 +25,16 @@ import (
"net/url"
"os"
"github.com/minio/console/pkg/utils"
xhttp "github.com/minio/console/pkg/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
subnetApi "github.com/minio/console/api/operations/subnet"
"github.com/minio/console/models"
"github.com/minio/console/pkg/subnet"
"github.com/minio/console/restapi/operations"
subnetApi "github.com/minio/console/restapi/operations/subnet"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
func registerSubnetHandlers(api *operations.ConsoleAPI) {
@@ -40,7 +42,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetLoginHandler = subnetApi.SubnetLoginHandlerFunc(func(params subnetApi.SubnetLoginParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetLoginResponse(session, params)
if err != nil {
return subnetApi.NewSubnetLoginDefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetLoginDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetLoginOK().WithPayload(resp)
})
@@ -48,7 +50,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetLoginMFAHandler = subnetApi.SubnetLoginMFAHandlerFunc(func(params subnetApi.SubnetLoginMFAParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetLoginWithMFAResponse(session, params)
if err != nil {
return subnetApi.NewSubnetLoginMFADefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetLoginMFADefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetLoginMFAOK().WithPayload(resp)
})
@@ -56,7 +58,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetRegisterHandler = subnetApi.SubnetRegisterHandlerFunc(func(params subnetApi.SubnetRegisterParams, session *models.Principal) middleware.Responder {
err := GetSubnetRegisterResponse(session, params)
if err != nil {
return subnetApi.NewSubnetRegisterDefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetRegisterDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetRegisterOK()
})
@@ -64,7 +66,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetInfoHandler = subnetApi.SubnetInfoHandlerFunc(func(params subnetApi.SubnetInfoParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetInfoResponse(session, params)
if err != nil {
return subnetApi.NewSubnetInfoDefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetInfoDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetInfoOK().WithPayload(resp)
})
@@ -72,7 +74,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetRegTokenHandler = subnetApi.SubnetRegTokenHandlerFunc(func(params subnetApi.SubnetRegTokenParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetRegTokenResponse(session, params)
if err != nil {
return subnetApi.NewSubnetRegTokenDefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetRegTokenDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetRegTokenOK().WithPayload(resp)
})
@@ -80,7 +82,7 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
api.SubnetSubnetAPIKeyHandler = subnetApi.SubnetAPIKeyHandlerFunc(func(params subnetApi.SubnetAPIKeyParams, session *models.Principal) middleware.Responder {
resp, err := GetSubnetAPIKeyResponse(session, params)
if err != nil {
return subnetApi.NewSubnetAPIKeyDefault(int(err.Code)).WithPayload(err)
return subnetApi.NewSubnetAPIKeyDefault(err.Code).WithPayload(err.APIError)
}
return subnetApi.NewSubnetAPIKeyOK().WithPayload(resp)
})
@@ -93,7 +95,8 @@ func SubnetRegisterWithAPIKey(ctx context.Context, minioClient MinioAdmin, apiKe
if err != nil {
return false, err
}
registerResult, err := subnet.Register(GetConsoleHTTPClient(""), serverInfo, apiKey, "", "")
clientIP := utils.ClientIPFromContext(ctx)
registerResult, err := subnet.Register(GetConsoleHTTPClient(clientIP), serverInfo, apiKey, "", "")
if err != nil {
return false, err
}
@@ -127,17 +130,17 @@ func SubnetLogin(client xhttp.ClientI, username, password string) (string, strin
return "", "", errors.New("something went wrong")
}
func GetSubnetLoginResponse(session *models.Principal, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *models.Error) {
func GetSubnetLoginResponse(session *models.Principal, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
return subnetLoginResponse(ctx, AdminClient{Client: mAdmin}, params)
}
func subnetLoginResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *models.Error) {
func subnetLoginResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginParams) (*models.SubnetLoginResponse, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -195,7 +198,7 @@ func SubnetLoginWithMFA(client xhttp.ClientI, username, mfaToken, otp string) (*
// GetSubnetHTTPClient will return a client with proxy if configured, otherwise will return the default console http client
func GetSubnetHTTPClient(ctx context.Context, minioClient MinioAdmin) (*xhttp.Client, error) {
subnetHTTPClient := GetConsoleHTTPClient("")
clientIP := utils.ClientIPFromContext(ctx)
subnetKey, err := GetSubnetKeyFromMinIOConfig(ctx, minioClient)
if err != nil {
return nil, err
@@ -205,25 +208,30 @@ func GetSubnetHTTPClient(ctx context.Context, minioClient MinioAdmin) (*xhttp.Cl
if subnetKey.Proxy != "" {
proxy = subnetKey.Proxy
}
tr := GlobalTransport.Clone()
if proxy != "" {
subnetProxyURL, err := url.Parse(proxy)
u, err := url.Parse(proxy)
if err != nil {
return nil, err
}
subnetHTTPClient.Transport.(*http.Transport).Proxy = http.ProxyURL(subnetProxyURL)
} else {
subnetHTTPClient = GetConsoleHTTPClient("")
tr.Proxy = http.ProxyURL(u)
}
clientI := &xhttp.Client{
Client: subnetHTTPClient,
}
return clientI, nil
return &xhttp.Client{
Client: &http.Client{
Transport: &ConsoleTransport{
Transport: tr,
ClientIP: clientIP,
},
},
}, nil
}
func GetSubnetLoginWithMFAResponse(session *models.Principal, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *models.Error) {
func GetSubnetLoginWithMFAResponse(session *models.Principal, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -231,7 +239,7 @@ func GetSubnetLoginWithMFAResponse(session *models.Principal, params subnetApi.S
return subnetLoginWithMFAResponse(ctx, minioClient, params)
}
func subnetLoginWithMFAResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *models.Error) {
func subnetLoginWithMFAResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetLoginMFAParams) (*models.SubnetLoginResponse, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -289,10 +297,10 @@ func GetSubnetRegister(ctx context.Context, minioClient MinioAdmin, httpClient x
return nil
}
func GetSubnetRegisterResponse(session *models.Principal, params subnetApi.SubnetRegisterParams) *models.Error {
func GetSubnetRegisterResponse(session *models.Principal, params subnetApi.SubnetRegisterParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -300,7 +308,7 @@ func GetSubnetRegisterResponse(session *models.Principal, params subnetApi.Subne
return subnetRegisterResponse(ctx, adminClient, params)
}
func subnetRegisterResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetRegisterParams) *models.Error {
func subnetRegisterResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetRegisterParams) *CodedAPIError {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return ErrorWithContext(ctx, err)
@@ -314,17 +322,18 @@ func subnetRegisterResponse(ctx context.Context, minioClient MinioAdmin, params
var ErrSubnetLicenseNotFound = errors.New("license not found")
func GetSubnetInfoResponse(session *models.Principal, params subnetApi.SubnetInfoParams) (*models.License, *models.Error) {
func GetSubnetInfoResponse(session *models.Principal, params subnetApi.SubnetInfoParams) (*models.License, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
clientIP := utils.ClientIPFromContext(ctx)
client := &xhttp.Client{
Client: GetConsoleHTTPClient(""),
Client: GetConsoleHTTPClient(clientIP),
}
// license gets seeded to us by MinIO
seededLicense := os.Getenv(EnvSubnetLicense)
// if it's missing, we will gracefully fallback to attempt to fetch it from MinIO
if seededLicense == "" {
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -352,7 +361,7 @@ func GetSubnetInfoResponse(session *models.Principal, params subnetApi.SubnetInf
return nil, ErrorWithContext(ctx, ErrSubnetLicenseNotFound)
}
licenseInfo, err := subnet.ParseLicense(client, seededLicense)
licenseInfo, err := getLicenseInfo(*client.Client, seededLicense)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -380,10 +389,10 @@ func GetSubnetRegToken(ctx context.Context, minioClient MinioAdmin) (string, err
return regToken, nil
}
func GetSubnetRegTokenResponse(session *models.Principal, params subnetApi.SubnetRegTokenParams) (*models.SubnetRegTokenResponse, *models.Error) {
func GetSubnetRegTokenResponse(session *models.Principal, params subnetApi.SubnetRegTokenParams) (*models.SubnetRegTokenResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -391,7 +400,7 @@ func GetSubnetRegTokenResponse(session *models.Principal, params subnetApi.Subne
return subnetRegTokenResponse(ctx, adminClient)
}
func subnetRegTokenResponse(ctx context.Context, minioClient MinioAdmin) (*models.SubnetRegTokenResponse, *models.Error) {
func subnetRegTokenResponse(ctx context.Context, minioClient MinioAdmin) (*models.SubnetRegTokenResponse, *CodedAPIError) {
token, err := GetSubnetRegToken(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)
@@ -401,10 +410,10 @@ func subnetRegTokenResponse(ctx context.Context, minioClient MinioAdmin) (*model
}, nil
}
func GetSubnetAPIKeyResponse(session *models.Principal, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *models.Error) {
func GetSubnetAPIKeyResponse(session *models.Principal, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -412,7 +421,7 @@ func GetSubnetAPIKeyResponse(session *models.Principal, params subnetApi.SubnetA
return subnetAPIKeyResponse(ctx, adminClient, params)
}
func subnetAPIKeyResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *models.Error) {
func subnetAPIKeyResponse(ctx context.Context, minioClient MinioAdmin, params subnetApi.SubnetAPIKeyParams) (*models.APIKey, *CodedAPIError) {
subnetHTTPClient, err := GetSubnetHTTPClient(ctx, minioClient)
if err != nil {
return nil, ErrorWithContext(ctx, err)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -24,10 +24,10 @@ import (
"os"
"testing"
"github.com/minio/console/api/operations"
subnetApi "github.com/minio/console/api/operations/subnet"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
subnetApi "github.com/minio/console/restapi/operations/subnet"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
@@ -44,10 +44,10 @@ type AdminSubnetTestSuite struct {
func (suite *AdminSubnetTestSuite) SetupSuite() {
suite.assert = assert.New(suite.T())
suite.adminClient = AdminClientMock{}
minioGetConfigKVMock = func(key string) ([]byte, error) {
minioGetConfigKVMock = func(_ string) ([]byte, error) {
return []byte("subnet license=mock api_key=mock proxy=http://mock.com"), nil
}
MinioServerInfoMock = func(ctx context.Context) (madmin.InfoMessage, error) {
MinioServerInfoMock = func(_ context.Context) (madmin.InfoMessage, error) {
return madmin.InfoMessage{Servers: []madmin.ServerProperties{{}}}, nil
}
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -23,10 +23,10 @@ import (
"github.com/dustin/go-humanize"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
tieringApi "github.com/minio/console/api/operations/tiering"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
tieringApi "github.com/minio/console/restapi/operations/tiering"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
)
func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
@@ -34,7 +34,7 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
api.TieringTiersListHandler = tieringApi.TiersListHandlerFunc(func(params tieringApi.TiersListParams, session *models.Principal) middleware.Responder {
tierList, err := getTiersResponse(session, params)
if err != nil {
return tieringApi.NewTiersListDefault(int(err.Code)).WithPayload(err)
return tieringApi.NewTiersListDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewTiersListOK().WithPayload(tierList)
})
@@ -42,7 +42,7 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
api.TieringAddTierHandler = tieringApi.AddTierHandlerFunc(func(params tieringApi.AddTierParams, session *models.Principal) middleware.Responder {
err := getAddTierResponse(session, params)
if err != nil {
return tieringApi.NewAddTierDefault(int(err.Code)).WithPayload(err)
return tieringApi.NewAddTierDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewAddTierCreated()
})
@@ -50,7 +50,7 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
api.TieringGetTierHandler = tieringApi.GetTierHandlerFunc(func(params tieringApi.GetTierParams, session *models.Principal) middleware.Responder {
notifEndpoints, err := getGetTierResponse(session, params)
if err != nil {
return tieringApi.NewGetTierDefault(int(err.Code)).WithPayload(err)
return tieringApi.NewGetTierDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewGetTierOK().WithPayload(notifEndpoints)
})
@@ -58,10 +58,18 @@ func registerAdminTiersHandlers(api *operations.ConsoleAPI) {
api.TieringEditTierCredentialsHandler = tieringApi.EditTierCredentialsHandlerFunc(func(params tieringApi.EditTierCredentialsParams, session *models.Principal) middleware.Responder {
err := getEditTierCredentialsResponse(session, params)
if err != nil {
return tieringApi.NewEditTierCredentialsDefault(int(err.Code)).WithPayload(err)
return tieringApi.NewEditTierCredentialsDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewEditTierCredentialsOK()
})
// remove an empty tier
api.TieringRemoveTierHandler = tieringApi.RemoveTierHandlerFunc(func(params tieringApi.RemoveTierParams, session *models.Principal) middleware.Responder {
err := getRemoveTierResponse(session, params)
if err != nil {
return tieringApi.NewRemoveTierDefault(err.Code).WithPayload(err.APIError)
}
return tieringApi.NewRemoveTierNoContent()
})
}
// getNotificationEndpoints invokes admin info and returns a list of notification endpoints
@@ -174,10 +182,10 @@ func getTiers(ctx context.Context, client MinioAdmin) (*models.TierListResponse,
}
// getTiersResponse returns a response with a list of tiers
func getTiersResponse(session *models.Principal, params tieringApi.TiersListParams) (*models.TierListResponse, *models.Error) {
func getTiersResponse(session *models.Principal, params tieringApi.TiersListParams) (*models.TierListResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -276,10 +284,10 @@ func addTier(ctx context.Context, client MinioAdmin, params *tieringApi.AddTierP
}
// getAddTierResponse returns the response of admin tier
func getAddTierResponse(session *models.Principal, params tieringApi.AddTierParams) *models.Error {
func getAddTierResponse(session *models.Principal, params tieringApi.AddTierParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -358,10 +366,10 @@ func getTier(ctx context.Context, client MinioAdmin, params *tieringApi.GetTierP
}
// getGetTierResponse returns a tier
func getGetTierResponse(session *models.Principal, params tieringApi.GetTierParams) (*models.Tier, *models.Error) {
func getGetTierResponse(session *models.Principal, params tieringApi.GetTierParams) (*models.Tier, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -392,10 +400,10 @@ func editTierCredentials(ctx context.Context, client MinioAdmin, params *tiering
}
// getEditTierCredentialsResponse returns the result of editing credentials for a tier
func getEditTierCredentialsResponse(session *models.Principal, params tieringApi.EditTierCredentialsParams) *models.Error {
func getEditTierCredentialsResponse(session *models.Principal, params tieringApi.EditTierCredentialsParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -409,3 +417,25 @@ func getEditTierCredentialsResponse(session *models.Principal, params tieringApi
}
return nil
}
func removeTier(ctx context.Context, client MinioAdmin, params *tieringApi.RemoveTierParams) error {
return client.removeTier(ctx, params.Name)
}
func getRemoveTierResponse(session *models.Principal, params tieringApi.RemoveTierParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
// serialize output
err = removeTier(ctx, adminClient, &params)
if err != nil {
return ErrorWithContext(ctx, err)
}
return nil
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -22,9 +22,9 @@ import (
"fmt"
"testing"
tieringApi "github.com/minio/console/api/operations/tiering"
"github.com/minio/console/models"
tieringApi "github.com/minio/console/restapi/operations/tiering"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -89,11 +89,11 @@ func TestGetTiers(t *testing.T) {
},
}
minioListTiersMock = func(ctx context.Context) ([]*madmin.TierConfig, error) {
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMock, nil
}
minioTierStatsMock = func(ctx context.Context) ([]madmin.TierInfo, error) {
minioTierStatsMock = func(_ context.Context) ([]madmin.TierInfo, error) {
return returnStatsMock, nil
}
@@ -138,7 +138,7 @@ func TestGetTiers(t *testing.T) {
// Test-2 : getBucketLifecycle() list is empty
returnListMockT2 := []*madmin.TierConfig{}
minioListTiersMock = func(ctx context.Context) ([]*madmin.TierConfig, error) {
minioListTiersMock = func(_ context.Context) ([]*madmin.TierConfig, error) {
return returnListMockT2, nil
}
@@ -161,7 +161,7 @@ func TestAddTier(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1: addTier() add new Tier
minioAddTiersMock = func(ctx context.Context, tier *madmin.TierConfig) error {
minioAddTiersMock = func(_ context.Context, _ *madmin.TierConfig) error {
return nil
}
@@ -185,7 +185,7 @@ func TestAddTier(t *testing.T) {
assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
// Test-2: addTier() error adding Tier
minioAddTiersMock = func(ctx context.Context, tier *madmin.TierConfig) error {
minioAddTiersMock = func(_ context.Context, _ *madmin.TierConfig) error {
return errors.New("error setting new tier")
}
@@ -203,7 +203,7 @@ func TestUpdateTierCreds(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Test-1: editTierCredentials() update Tier configuration
minioEditTiersMock = func(ctx context.Context, tierName string, creds madmin.TierCreds) error {
minioEditTiersMock = func(_ context.Context, _ string, _ madmin.TierCreds) error {
return nil
}
@@ -220,7 +220,7 @@ func TestUpdateTierCreds(t *testing.T) {
assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
// Test-2: editTierCredentials() update Tier configuration failure
minioEditTiersMock = func(ctx context.Context, tierName string, creds madmin.TierCreds) error {
minioEditTiersMock = func(_ context.Context, _ string, _ madmin.TierCreds) error {
return errors.New("error message")
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -23,7 +23,7 @@ import (
"strings"
"time"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/minio/websocket"
)

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -22,7 +22,7 @@ import (
"fmt"
"testing"
"github.com/minio/madmin-go/v2"
"github.com/minio/madmin-go/v3"
"github.com/stretchr/testify/assert"
)
@@ -41,7 +41,7 @@ func TestAdminTrace(t *testing.T) {
// Test-1: Serve Trace with no errors until trace finishes sending
// define mock function behavior for minio server Trace
minioServiceTraceMock = func(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo {
minioServiceTraceMock = func(_ context.Context, _ int64, _, _, _, _, _ bool) <-chan madmin.ServiceTraceInfo {
ch := make(chan madmin.ServiceTraceInfo)
// Only success, start a routine to start reading line by line.
go func(ch chan<- madmin.ServiceTraceInfo) {
@@ -59,7 +59,7 @@ func TestAdminTrace(t *testing.T) {
}
writesCount := 1
// mock connection WriteMessage() no error
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, data []byte) error {
// emulate that receiver gets the message written
var t shortTraceMsg
_ = json.Unmarshal(data, &t)
@@ -84,7 +84,7 @@ func TestAdminTrace(t *testing.T) {
}
// Test-2: if error happens while writing, return error
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, _ []byte) error {
return fmt.Errorf("error on write")
}
if err := startTraceInfo(ctx, mockWSConn, adminClient, TraceRequest{}); assert.Error(err) {
@@ -93,7 +93,7 @@ func TestAdminTrace(t *testing.T) {
// Test-3: error happens on serviceTrace Minio, trace should stop
// and error shall be returned.
minioServiceTraceMock = func(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo {
minioServiceTraceMock = func(_ context.Context, _ int64, _, _, _, _, _ bool) <-chan madmin.ServiceTraceInfo {
ch := make(chan madmin.ServiceTraceInfo)
// Only success, start a routine to start reading line by line.
go func(ch chan<- madmin.ServiceTraceInfo) {
@@ -110,7 +110,7 @@ func TestAdminTrace(t *testing.T) {
}(ch)
return ch
}
connWriteMessageMock = func(messageType int, data []byte) error {
connWriteMessageMock = func(_ int, _ []byte) error {
return nil
}
if err := startTraceInfo(ctx, mockWSConn, adminClient, TraceRequest{}); assert.Error(err) {

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -22,19 +22,15 @@ import (
"sort"
"strings"
"github.com/minio/console/pkg/utils"
"github.com/go-openapi/swag"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/api/operations"
accountApi "github.com/minio/console/api/operations/account"
bucketApi "github.com/minio/console/api/operations/bucket"
userApi "github.com/minio/console/api/operations/user"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
accountApi "github.com/minio/console/restapi/operations/account"
bucketApi "github.com/minio/console/restapi/operations/bucket"
userApi "github.com/minio/console/restapi/operations/user"
"github.com/minio/madmin-go/v2"
iampolicy "github.com/minio/pkg/iam/policy"
"github.com/minio/madmin-go/v3"
iampolicy "github.com/minio/pkg/v3/policy"
)
// Policy evaluated constants
@@ -49,7 +45,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserListUsersHandler = userApi.ListUsersHandlerFunc(func(params userApi.ListUsersParams, session *models.Principal) middleware.Responder {
listUsersResponse, err := getListUsersResponse(session, params)
if err != nil {
return userApi.NewListUsersDefault(int(err.Code)).WithPayload(err)
return userApi.NewListUsersDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewListUsersOK().WithPayload(listUsersResponse)
})
@@ -57,7 +53,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserAddUserHandler = userApi.AddUserHandlerFunc(func(params userApi.AddUserParams, session *models.Principal) middleware.Responder {
userResponse, err := getUserAddResponse(session, params)
if err != nil {
return userApi.NewAddUserDefault(int(err.Code)).WithPayload(err)
return userApi.NewAddUserDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewAddUserCreated().WithPayload(userResponse)
})
@@ -65,7 +61,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserRemoveUserHandler = userApi.RemoveUserHandlerFunc(func(params userApi.RemoveUserParams, session *models.Principal) middleware.Responder {
err := getRemoveUserResponse(session, params)
if err != nil {
return userApi.NewRemoveUserDefault(int(err.Code)).WithPayload(err)
return userApi.NewRemoveUserDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewRemoveUserNoContent()
})
@@ -73,7 +69,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserUpdateUserGroupsHandler = userApi.UpdateUserGroupsHandlerFunc(func(params userApi.UpdateUserGroupsParams, session *models.Principal) middleware.Responder {
userUpdateResponse, err := getUpdateUserGroupsResponse(session, params)
if err != nil {
return userApi.NewUpdateUserGroupsDefault(int(err.Code)).WithPayload(err)
return userApi.NewUpdateUserGroupsDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewUpdateUserGroupsOK().WithPayload(userUpdateResponse)
@@ -82,7 +78,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserGetUserInfoHandler = userApi.GetUserInfoHandlerFunc(func(params userApi.GetUserInfoParams, session *models.Principal) middleware.Responder {
userInfoResponse, err := getUserInfoResponse(session, params)
if err != nil {
return userApi.NewGetUserInfoDefault(int(err.Code)).WithPayload(err)
return userApi.NewGetUserInfoDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewGetUserInfoOK().WithPayload(userInfoResponse)
@@ -91,7 +87,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserUpdateUserInfoHandler = userApi.UpdateUserInfoHandlerFunc(func(params userApi.UpdateUserInfoParams, session *models.Principal) middleware.Responder {
userUpdateResponse, err := getUpdateUserResponse(session, params)
if err != nil {
return userApi.NewUpdateUserInfoDefault(int(err.Code)).WithPayload(err)
return userApi.NewUpdateUserInfoDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewUpdateUserInfoOK().WithPayload(userUpdateResponse)
@@ -100,7 +96,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserBulkUpdateUsersGroupsHandler = userApi.BulkUpdateUsersGroupsHandlerFunc(func(params userApi.BulkUpdateUsersGroupsParams, session *models.Principal) middleware.Responder {
err := getAddUsersListToGroupsResponse(session, params)
if err != nil {
return userApi.NewBulkUpdateUsersGroupsDefault(int(err.Code)).WithPayload(err)
return userApi.NewBulkUpdateUsersGroupsDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewBulkUpdateUsersGroupsOK()
@@ -108,7 +104,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.BucketListUsersWithAccessToBucketHandler = bucketApi.ListUsersWithAccessToBucketHandlerFunc(func(params bucketApi.ListUsersWithAccessToBucketParams, session *models.Principal) middleware.Responder {
response, err := getListUsersWithAccessToBucketResponse(session, params)
if err != nil {
return bucketApi.NewListUsersWithAccessToBucketDefault(int(err.Code)).WithPayload(err)
return bucketApi.NewListUsersWithAccessToBucketDefault(err.Code).WithPayload(err.APIError)
}
return bucketApi.NewListUsersWithAccessToBucketOK().WithPayload(response)
})
@@ -116,7 +112,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.AccountChangeUserPasswordHandler = accountApi.ChangeUserPasswordHandlerFunc(func(params accountApi.ChangeUserPasswordParams, session *models.Principal) middleware.Responder {
err := getChangeUserPasswordResponse(session, params)
if err != nil {
return accountApi.NewChangeUserPasswordDefault(int(err.Code)).WithPayload(err)
return accountApi.NewChangeUserPasswordDefault(err.Code).WithPayload(err.APIError)
}
return accountApi.NewChangeUserPasswordCreated()
})
@@ -124,7 +120,7 @@ func registerUsersHandlers(api *operations.ConsoleAPI) {
api.UserCheckUserServiceAccountsHandler = userApi.CheckUserServiceAccountsHandlerFunc(func(params userApi.CheckUserServiceAccountsParams, session *models.Principal) middleware.Responder {
userSAList, err := getCheckUserSAResponse(session, params)
if err != nil {
return userApi.NewCheckUserServiceAccountsDefault(int(err.Code)).WithPayload(err)
return userApi.NewCheckUserServiceAccountsDefault(err.Code).WithPayload(err.APIError)
}
return userApi.NewCheckUserServiceAccountsOK().WithPayload(userSAList)
})
@@ -154,10 +150,10 @@ func listUsers(ctx context.Context, client MinioAdmin) ([]*models.User, error) {
}
// getListUsersResponse performs listUsers() and serializes it to the handler's output
func getListUsersResponse(session *models.Principal, params userApi.ListUsersParams) (*models.ListUsersResponse, *models.Error) {
func getListUsersResponse(session *models.Principal, params userApi.ListUsersParams) (*models.ListUsersResponse, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -215,10 +211,10 @@ func addUser(ctx context.Context, client MinioAdmin, accessKey, secretKey *strin
return userRet, nil
}
func getUserAddResponse(session *models.Principal, params userApi.AddUserParams) (*models.User, *models.Error) {
func getUserAddResponse(session *models.Principal, params userApi.AddUserParams) (*models.User, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -252,24 +248,20 @@ func removeUser(ctx context.Context, client MinioAdmin, accessKey string) error
return client.removeUser(ctx, accessKey)
}
func getRemoveUserResponse(session *models.Principal, params userApi.RemoveUserParams) *models.Error {
func getRemoveUserResponse(session *models.Principal, params userApi.RemoveUserParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return ErrorWithContext(ctx, err)
}
if session.AccountAccessKey == userName {
if session.AccountAccessKey == params.Name {
return ErrorWithContext(ctx, ErrAvoidSelfAccountDelete)
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
if err := removeUser(ctx, adminClient, userName); err != nil {
if err := removeUser(ctx, adminClient, params.Name); err != nil {
return ErrorWithContext(ctx, err)
}
return nil
@@ -284,11 +276,11 @@ func getUserInfo(ctx context.Context, client MinioAdmin, accessKey string) (*mad
return &userInfo, nil
}
func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoParams) (*models.User, *models.Error) {
func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoParams) (*models.User, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -297,18 +289,13 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
user, err := getUserInfo(ctx, adminClient, userName)
user, err := getUserInfo(ctx, adminClient, params.Name)
if err != nil {
// User doesn't exist, return 404
if madmin.ToErrorResponse(err).Code == "XMinioAdminNoSuchUser" {
var errorCode int32 = 404
errorCode := 404
errorMessage := "User doesn't exist"
return nil, &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err.Error())}
return nil, &CodedAPIError{Code: errorCode, APIError: &models.APIError{Message: errorMessage, DetailedMessage: err.Error()}}
}
return nil, ErrorWithContext(ctx, err)
}
@@ -337,7 +324,7 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa
}
userInformation := &models.User{
AccessKey: userName,
AccessKey: params.Name,
MemberOf: user.MemberOf,
Policy: policies,
Status: string(user.Status),
@@ -435,11 +422,11 @@ func updateUserGroups(ctx context.Context, client MinioAdmin, user string, group
return userReturn, nil
}
func getUpdateUserGroupsResponse(session *models.Principal, params userApi.UpdateUserGroupsParams) (*models.User, *models.Error) {
func getUpdateUserGroupsResponse(session *models.Principal, params userApi.UpdateUserGroupsParams) (*models.User, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -448,12 +435,7 @@ func getUpdateUserGroupsResponse(session *models.Principal, params userApi.Updat
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
user, err := updateUserGroups(ctx, adminClient, userName, params.Body.Groups)
user, err := updateUserGroups(ctx, adminClient, params.Name, params.Body.Groups)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -476,11 +458,11 @@ func setUserStatus(ctx context.Context, client MinioAdmin, user string, status s
return client.setUserStatus(ctx, user, setStatus)
}
func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserInfoParams) (*models.User, *models.Error) {
func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserInfoParams) (*models.User, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -488,18 +470,14 @@ func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserI
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient{Client: mAdmin}
userName, err := utils.DecodeBase64(params.Name)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
status := *params.Body.Status
groups := params.Body.Groups
if err := setUserStatus(ctx, adminClient, userName, status); err != nil {
if err := setUserStatus(ctx, adminClient, params.Name, status); err != nil {
return nil, ErrorWithContext(ctx, err)
}
userElem, errUG := updateUserGroups(ctx, adminClient, userName, groups)
userElem, errUG := updateUserGroups(ctx, adminClient, params.Name, groups)
if errUG != nil {
return nil, ErrorWithContext(ctx, errUG)
@@ -550,11 +528,11 @@ func addUsersListToGroups(ctx context.Context, client MinioAdmin, usersToUpdate
return nil
}
func getAddUsersListToGroupsResponse(session *models.Principal, params userApi.BulkUpdateUsersGroupsParams) *models.Error {
func getAddUsersListToGroupsResponse(session *models.Principal, params userApi.BulkUpdateUsersGroupsParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -573,10 +551,10 @@ func getAddUsersListToGroupsResponse(session *models.Principal, params userApi.B
return nil
}
func getListUsersWithAccessToBucketResponse(session *models.Principal, params bucketApi.ListUsersWithAccessToBucketParams) ([]string, *models.Error) {
func getListUsersWithAccessToBucketResponse(session *models.Principal, params bucketApi.ListUsersWithAccessToBucketParams) ([]string, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
@@ -684,10 +662,10 @@ func changeUserPassword(ctx context.Context, client MinioAdmin, selectedUser str
}
// getChangeUserPasswordResponse will change the password of selctedUser to newSecretKey
func getChangeUserPasswordResponse(session *models.Principal, params accountApi.ChangeUserPasswordParams) *models.Error {
func getChangeUserPasswordResponse(session *models.Principal, params accountApi.ChangeUserPasswordParams) *CodedAPIError {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return ErrorWithContext(ctx, err)
}
@@ -706,10 +684,10 @@ func getChangeUserPasswordResponse(session *models.Principal, params accountApi.
return nil
}
func getCheckUserSAResponse(session *models.Principal, params userApi.CheckUserServiceAccountsParams) (*models.UserServiceAccountSummary, *models.Error) {
func getCheckUserSAResponse(session *models.Principal, params userApi.CheckUserServiceAccountsParams) (*models.UserServiceAccountSummary, *CodedAPIError) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
mAdmin, err := NewMinioAdminClient(session)
mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
if err != nil {
return nil, ErrorWithContext(ctx, err)
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
@@ -24,8 +24,8 @@ import (
"strings"
"testing"
"github.com/minio/madmin-go/v2"
iampolicy "github.com/minio/pkg/iam/policy"
"github.com/minio/madmin-go/v3"
iampolicy "github.com/minio/pkg/v3/policy"
asrt "github.com/stretchr/testify/assert"
)
@@ -102,15 +102,15 @@ func TestAddUser(t *testing.T) {
}
// mock function response from addUser() return no error
minioAddUserMock = func(accessKey, secretKey string) error {
minioAddUserMock = func(_, _ string) error {
return nil
}
minioGetUserInfoMock = func(accessKey string) (madmin.UserInfo, error) {
minioGetUserInfoMock = func(_ string) (madmin.UserInfo, error) {
return *mockResponse, nil
}
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return nil
}
// Test-1: Add a user
@@ -135,7 +135,7 @@ func TestAddUser(t *testing.T) {
accessKey = "AB"
secretKey = "ABCDEFGHIABCDEFGHI"
// mock function response from addUser() return no error
minioAddUserMock = func(accessKey, secretKey string) error {
minioAddUserMock = func(_, _ string) error {
return errors.New("error")
}
@@ -150,7 +150,7 @@ func TestAddUser(t *testing.T) {
}
// Test-4: add groups function returns an error
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return errors.New("error")
}
@@ -175,7 +175,7 @@ func TestRemoveUser(t *testing.T) {
// Test-1: removeUser() delete a user
// mock function response from removeUser(accessKey)
minioRemoveUserMock = func(accessKey string) error {
minioRemoveUserMock = func(_ string) error {
return nil
}
@@ -185,7 +185,7 @@ func TestRemoveUser(t *testing.T) {
// Test-2: removeUser() make sure errors are handled correctly when error on DeleteUser()
// mock function response from removeUser(accessKey)
minioRemoveUserMock = func(accessKey string) error {
minioRemoveUserMock = func(_ string) error {
return errors.New("error")
}
@@ -220,11 +220,11 @@ func TestUserGroups(t *testing.T) {
// Test-1: updateUserGroups() updates the groups for a user
// mock function response from updateUserGroups(accessKey, groupsToAssign)
minioGetUserInfoMock = func(accessKey string) (madmin.UserInfo, error) {
minioGetUserInfoMock = func(_ string) (madmin.UserInfo, error) {
return *mockResponse, nil
}
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return nil
}
@@ -235,7 +235,7 @@ func TestUserGroups(t *testing.T) {
// Test-2: updateUserGroups() make sure errors are handled correctly when error on UpdateGroupMembersMock()
// mock function response from removeUser(accessKey)
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return errors.New("error")
}
@@ -244,11 +244,11 @@ func TestUserGroups(t *testing.T) {
}
// Test-3: updateUserGroups() make sure we return the correct error when getUserInfo returns error
minioGetUserInfoMock = func(accessKey string) (madmin.UserInfo, error) {
minioGetUserInfoMock = func(_ string) (madmin.UserInfo, error) {
return *mockEmptyResponse, errors.New("error getting user ")
}
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return nil
}
@@ -279,7 +279,7 @@ func TestGetUserInfo(t *testing.T) {
}
// mock function response from getUserInfo()
minioGetUserInfoMock = func(username string) (madmin.UserInfo, error) {
minioGetUserInfoMock = func(_ string) (madmin.UserInfo, error) {
return *mockResponse, nil
}
function := "getUserInfo()"
@@ -294,7 +294,7 @@ func TestGetUserInfo(t *testing.T) {
assert.Equal(mockResponse.Status, info.Status)
// Test-2 : getUserInfo() Return error and see that the error is handled correctly and returned
minioGetUserInfoMock = func(username string) (madmin.UserInfo, error) {
minioGetUserInfoMock = func(_ string) (madmin.UserInfo, error) {
return *emptyMockResponse, errors.New("error")
}
_, err = getUserInfo(ctx, adminClient, userName)
@@ -313,7 +313,7 @@ func TestSetUserStatus(t *testing.T) {
// Test-1: setUserStatus() update valid disabled status
expectedStatus := "disabled"
minioSetUserStatusMock = func(accessKey string, status madmin.AccountStatus) error {
minioSetUserStatusMock = func(_ string, _ madmin.AccountStatus) error {
return nil
}
if err := setUserStatus(ctx, adminClient, userName, expectedStatus); err != nil {
@@ -321,7 +321,7 @@ func TestSetUserStatus(t *testing.T) {
}
// Test-2: setUserStatus() update valid enabled status
expectedStatus = "enabled"
minioSetUserStatusMock = func(accessKey string, status madmin.AccountStatus) error {
minioSetUserStatusMock = func(_ string, _ madmin.AccountStatus) error {
return nil
}
if err := setUserStatus(ctx, adminClient, userName, expectedStatus); err != nil {
@@ -329,7 +329,7 @@ func TestSetUserStatus(t *testing.T) {
}
// Test-3: setUserStatus() update invalid status, should send error
expectedStatus = "invalid"
minioSetUserStatusMock = func(accessKey string, status madmin.AccountStatus) error {
minioSetUserStatusMock = func(_ string, _ madmin.AccountStatus) error {
return nil
}
if err := setUserStatus(ctx, adminClient, userName, expectedStatus); assert.Error(err) {
@@ -337,7 +337,7 @@ func TestSetUserStatus(t *testing.T) {
}
// Test-4: setUserStatus() handler error correctly
expectedStatus = "enabled"
minioSetUserStatusMock = func(accessKey string, status madmin.AccountStatus) error {
minioSetUserStatusMock = func(_ string, _ madmin.AccountStatus) error {
return errors.New("error")
}
if err := setUserStatus(ctx, adminClient, userName, expectedStatus); assert.Error(err) {
@@ -358,7 +358,7 @@ func TestUserGroupsBulk(t *testing.T) {
// Test-1: addUsersListToGroups() updates the groups for a users list
// mock function response from updateUserGroups(accessKey, groupsToAssign)
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return nil
}
@@ -368,7 +368,7 @@ func TestUserGroupsBulk(t *testing.T) {
// Test-2: addUsersListToGroups() make sure errors are handled correctly when error on updateGroupMembers()
// mock function response from removeUser(accessKey)
minioUpdateGroupMembersMock = func(remove madmin.GroupAddRemove) error {
minioUpdateGroupMembersMock = func(_ madmin.GroupAddRemove) error {
return errors.New("error")
}
@@ -527,7 +527,7 @@ func TestListUsersWithAccessToBucket(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
got, _ := listUsersWithAccessToBucket(ctx, adminClient, tt.args.bucket)
assert.Equal(got, tt.want)
})

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"bytes"
@@ -24,45 +24,22 @@ import (
"net"
"net/http"
"net/url"
"sync"
"regexp"
"strings"
"time"
"github.com/minio/console/models"
"github.com/minio/console/pkg"
"github.com/minio/madmin-go/v2"
mcCmd "github.com/minio/mc/cmd"
"github.com/minio/mc/pkg/probe"
"github.com/minio/console/pkg/utils"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio-go/v7/pkg/credentials"
iampolicy "github.com/minio/pkg/iam/policy"
iampolicy "github.com/minio/pkg/v3/policy"
)
const globalAppName = "MinIO Console"
// NewAdminClientWithInsecure gives a new madmin client interface either secure or insecure based on parameter
func NewAdminClientWithInsecure(url, accessKey, secretKey, sessionToken string, insecure bool) (*madmin.AdminClient, *probe.Error) {
admClient, err := s3AdminNew(&mcCmd.Config{
HostURL: url,
AccessKey: accessKey,
SecretKey: secretKey,
SessionToken: sessionToken,
AppName: globalAppName,
AppVersion: pkg.Version,
Insecure: insecure,
})
if err != nil {
return nil, err.Trace(url)
}
stsClient := PrepareConsoleHTTPClient(insecure)
admClient.SetCustomTransport(stsClient.Transport)
// set user-agent to differentiate Console UI requests for auditing.
admClient.SetAppInfo("MinIO Console", pkg.Version)
return admClient, nil
}
// s3AdminNew returns an initialized minioAdmin structure. If debug is enabled,
// it also enables an internal trace transport.
var s3AdminNew = mcCmd.NewAdminFactory()
// MinioAdmin interface with all functions to be implemented
// by mock when testing, it should include all MinioAdmin respective api calls
// that are used within this project.
@@ -86,7 +63,6 @@ type MinioAdmin interface {
helpConfigKVGlobal(ctx context.Context, envOnly bool) (madmin.Help, error)
setConfigKV(ctx context.Context, kv string) (restart bool, err error)
delConfigKV(ctx context.Context, kv string) (err error)
serviceRestart(ctx context.Context) error
serverInfo(ctx context.Context) (madmin.InfoMessage, error)
startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
@@ -97,7 +73,7 @@ type MinioAdmin interface {
heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
forceStart, forceStop bool) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error)
// Service Accounts
addServiceAccount(ctx context.Context, policy *iampolicy.Policy, user string, accessKey string, secretKey string) (madmin.Credentials, error)
addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error)
listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error)
deleteServiceAccount(ctx context.Context, serviceAccount string) error
infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error)
@@ -109,7 +85,7 @@ type MinioAdmin interface {
addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error)
// Account password management
changePassword(ctx context.Context, accessKey, secretKey string) error
serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error)
serverHealthInfo(ctx context.Context, deadline time.Duration) (interface{}, string, error)
// List Tiers
listTiers(ctx context.Context) ([]*madmin.TierConfig, error)
// Tier Info
@@ -120,12 +96,14 @@ type MinioAdmin interface {
editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error
// verify Tier status
verifyTierStatus(ctx context.Context, tierName string) error
// remove empty Tier
removeTier(ctx context.Context, tierName string) error
// Speedtest
speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error)
// Site Relication
getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error)
addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite) (*madmin.ReplicateAddStatus, error)
editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo) (*madmin.ReplicateEditStatus, error)
addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error)
editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error)
deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
// Replication status
@@ -238,11 +216,11 @@ func (ac AdminClient) listPolicies(ctx context.Context) (map[string]*iampolicy.P
// implements madmin.ListCannedPolicies()
func (ac AdminClient) getPolicy(ctx context.Context, name string) (*iampolicy.Policy, error) {
praw, err := ac.Client.InfoCannedPolicy(ctx, name)
info, err := ac.Client.InfoCannedPolicyV2(ctx, name)
if err != nil {
return nil, err
}
return iampolicy.ParseConfig(bytes.NewReader(praw))
return iampolicy.ParseConfig(bytes.NewReader(info.Policy))
}
// implements madmin.RemoveCannedPolicy()
@@ -261,6 +239,7 @@ func (ac AdminClient) addPolicy(ctx context.Context, name string, policy *iampol
// implements madmin.SetPolicy()
func (ac AdminClient) setPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error {
// nolint:staticcheck // ignore SA1019
return ac.Client.SetPolicy(ctx, policyName, entityName, isGroup)
}
@@ -332,22 +311,21 @@ func (ac AdminClient) getLogs(ctx context.Context, node string, lineCnt int, log
}
// implements madmin.AddServiceAccount()
func (ac AdminClient) addServiceAccount(ctx context.Context, policy *iampolicy.Policy, user string, accessKey string, secretKey string) (madmin.Credentials, error) {
buf, err := json.Marshal(policy)
if err != nil {
return madmin.Credentials{}, err
}
func (ac AdminClient) addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error) {
return ac.Client.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
Policy: buf,
TargetUser: user,
AccessKey: accessKey,
SecretKey: secretKey,
Policy: []byte(policy),
TargetUser: user,
AccessKey: accessKey,
SecretKey: secretKey,
Name: name,
Description: description,
Expiration: expiry,
Comment: comment,
})
}
// implements madmin.ListServiceAccounts()
func (ac AdminClient) listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error) {
// TODO: Fix this
return ac.Client.ListServiceAccounts(ctx, user)
}
@@ -413,44 +391,31 @@ func (ac AdminClient) getBucketQuota(ctx context.Context, bucket string) (madmin
}
// serverHealthInfo implements mc.ServerHealthInfo - Connect to a minio server and call Health Info Management API
func (ac AdminClient) serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error) {
resp, version, err := ac.Client.ServerHealthInfo(ctx, healthDataTypes, deadline)
if err != nil {
return nil, version, err
}
func (ac AdminClient) serverHealthInfo(ctx context.Context, deadline time.Duration) (interface{}, string, error) {
info := madmin.HealthInfo{}
var healthInfo interface{}
decoder := json.NewDecoder(resp.Body)
switch version {
case madmin.HealthInfoVersion0:
info := madmin.HealthInfoV0{}
for {
if err = decoder.Decode(&info); err != nil {
break
}
}
// Old minio versions don't return the MinIO info in
// response of the healthinfo api. So fetch it separately
minioInfo, err := ac.Client.ServerInfo(ctx)
var version string
var tryCount int
for info.Version == "" && tryCount < 10 {
var resp *http.Response
var err error
resp, version, err = ac.Client.ServerHealthInfo(ctx, madmin.HealthDataTypesList, deadline, "")
if err != nil {
info.Minio.Error = err.Error()
} else {
info.Minio.Info = minioInfo
return nil, version, err
}
healthInfo = mcCmd.MapHealthInfoToV1(info, nil)
version = madmin.HealthInfoVersion1
case madmin.HealthInfoVersion:
info := madmin.HealthInfo{}
decoder := json.NewDecoder(resp.Body)
for {
if err = decoder.Decode(&info); err != nil {
break
}
}
healthInfo = info
tryCount++
time.Sleep(2 * time.Second)
}
if info.Version == "" {
return nil, "", ErrHealthReportFail
}
healthInfo = info
return healthInfo, version, nil
}
@@ -485,16 +450,23 @@ func (ac AdminClient) verifyTierStatus(ctx context.Context, tierName string) err
return ac.Client.VerifyTier(ctx, tierName)
}
func NewMinioAdminClient(sessionClaims *models.Principal) (*madmin.AdminClient, error) {
adminClient, err := newAdminFromClaims(sessionClaims)
// implements madmin.RemoveTier()
func (ac AdminClient) removeTier(ctx context.Context, tierName string) error {
return ac.Client.RemoveTier(ctx, tierName)
}
func NewMinioAdminClient(ctx context.Context, sessionClaims *models.Principal) (*madmin.AdminClient, error) {
clientIP := utils.ClientIPFromContext(ctx)
adminClient, err := newAdminFromClaims(sessionClaims, clientIP)
if err != nil {
return nil, err
}
adminClient.SetAppInfo(globalAppName, pkg.Version)
return adminClient, nil
}
// newAdminFromClaims creates a minio admin from Decrypted claims using Assume role credentials
func newAdminFromClaims(claims *models.Principal) (*madmin.AdminClient, error) {
func newAdminFromClaims(claims *models.Principal, clientIP string) (*madmin.AdminClient, error) {
tlsEnabled := getMinIOEndpointIsSecure()
endpoint := getMinIOEndpoint()
@@ -505,7 +477,8 @@ func newAdminFromClaims(claims *models.Principal) (*madmin.AdminClient, error) {
if err != nil {
return nil, err
}
adminClient.SetCustomTransport(GetConsoleHTTPClient(getMinIOServer()).Transport)
adminClient.SetAppInfo(globalAppName, pkg.Version)
adminClient.SetCustomTransport(PrepareSTSClientTransport(clientIP))
return adminClient, nil
}
@@ -518,23 +491,14 @@ func newAdminFromCreds(accessKey, secretKey, endpoint string, tlsEnabled bool) (
if err != nil {
return nil, err
}
minioClient.SetAppInfo(globalAppName, pkg.Version)
return minioClient, nil
}
// httpClient is a custom http client, this client should not be called directly and instead be
// called using GetConsoleHTTPClient() to ensure is initialized and the certificates are loaded correctly
var httpClients = struct {
sync.Mutex
m map[string]*http.Client
}{
m: make(map[string]*http.Client),
}
// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
// that points to the local machine - FQDN are not supported
func isLocalIPEndpoint(addr string) bool {
u, err := url.Parse(addr)
func isLocalIPEndpoint(endpoint string) bool {
u, err := url.Parse(endpoint)
if err != nil {
return false
}
@@ -547,6 +511,9 @@ func isLocalIPAddress(ipAddr string) bool {
if ipAddr == "" {
return false
}
if ipAddr == "localhost" {
return true
}
ip := net.ParseIP(ipAddr)
return ip != nil && ip.IsLoopback()
}
@@ -554,24 +521,75 @@ func isLocalIPAddress(ipAddr string) bool {
// GetConsoleHTTPClient caches different http clients depending on the target endpoint while taking
// in consideration CA certs stored in ${HOME}/.console/certs/CAs and ${HOME}/.minio/certs/CAs
// If the target endpoint points to a loopback device, skip the TLS verification.
func GetConsoleHTTPClient(address string) *http.Client {
u, err := url.Parse(address)
if err == nil {
address = u.Hostname()
func GetConsoleHTTPClient(clientIP string) *http.Client {
return PrepareConsoleHTTPClient(clientIP)
}
var (
// De-facto standard header keys.
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
)
var (
// RFC7239 defines a new "Forwarded: " header designed to replace the
// existing use of X-Forwarded-* headers.
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
forwarded = http.CanonicalHeaderKey("Forwarded")
// Allows for a sub-match of the first value after 'for=' to the next
// comma, semi-colon or space. The match is case-insensitive.
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)(.*)`)
)
// getSourceIPFromHeaders retrieves the IP from the X-Forwarded-For, X-Real-IP
// and RFC7239 Forwarded headers (in that order)
func getSourceIPFromHeaders(r *http.Request) string {
var addr string
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
// Only grab the first (client) address. Note that '192.168.0.1,
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
// the first may represent forwarding proxies earlier in the chain.
s := strings.Index(fwd, ", ")
if s == -1 {
s = len(fwd)
}
addr = fwd[:s]
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
// X-Real-IP should only contain one IP address (the client making the
// request).
addr = fwd
} else if fwd := r.Header.Get(forwarded); fwd != "" {
// match should contain at least two elements if the protocol was
// specified in the Forwarded header. The first element will always be
// the 'for=' capture, which we ignore. In the case of multiple IP
// addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only
// extract the first, which should be the client IP.
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
// these quotes.
addr = strings.Trim(match[1], `"`)
}
}
httpClients.Lock()
client, ok := httpClients.m[address]
httpClients.Unlock()
if ok {
return client
return addr
}
// getClientIP retrieves the IP from the request headers
// and falls back to r.RemoteAddr when necessary.
// however returns without bracketing.
func getClientIP(r *http.Request) string {
addr := getSourceIPFromHeaders(r)
if addr == "" {
addr = r.RemoteAddr
}
client = PrepareConsoleHTTPClient(isLocalIPAddress(address))
httpClients.Lock()
httpClients.m[address] = client
httpClients.Unlock()
return client
// Default to remote address if headers not set.
raddr, _, _ := net.SplitHostPort(addr)
if raddr == "" {
return addr
}
return raddr
}
func (ac AdminClient) speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error) {
@@ -592,8 +610,8 @@ func (ac AdminClient) getSiteReplicationInfo(ctx context.Context) (*madmin.SiteR
}, nil
}
func (ac AdminClient) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite) (*madmin.ReplicateAddStatus, error) {
res, err := ac.Client.SiteReplicationAdd(ctx, sites)
func (ac AdminClient) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error) {
res, err := ac.Client.SiteReplicationAdd(ctx, sites, opts)
if err != nil {
return nil, err
}
@@ -606,8 +624,8 @@ func (ac AdminClient) addSiteReplicationInfo(ctx context.Context, sites []madmin
}, nil
}
func (ac AdminClient) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo) (*madmin.ReplicateEditStatus, error) {
res, err := ac.Client.SiteReplicationEdit(ctx, site)
func (ac AdminClient) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error) {
res, err := ac.Client.SiteReplicationEdit(ctx, site, opts)
if err != nil {
return nil, err
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
@@ -27,7 +27,7 @@ import (
"github.com/minio/minio-go/v7/pkg/replication"
"github.com/minio/minio-go/v7/pkg/sse"
xnet "github.com/minio/pkg/net"
xnet "github.com/minio/pkg/v3/net"
"github.com/minio/console/models"
"github.com/minio/console/pkg"
@@ -232,7 +232,7 @@ type MCClient interface {
list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error)
shareDownload(ctx context.Context, versionID string, expires time.Duration) (string, *probe.Error)
setVersioning(ctx context.Context, status string) *probe.Error
setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error
}
// Interface implementation
@@ -265,8 +265,8 @@ func (c mcClient) deleteAllReplicationRules(ctx context.Context) *probe.Error {
return c.client.RemoveReplication(ctx)
}
func (c mcClient) setVersioning(ctx context.Context, status string) *probe.Error {
return c.client.SetVersion(ctx, status, []string{}, false)
func (c mcClient) setVersioning(ctx context.Context, status string, excludePrefix []string, excludeFolders bool) *probe.Error {
return c.client.SetVersion(ctx, status, excludePrefix, excludeFolders)
}
func (c mcClient) remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass, forceDelete bool, contentCh <-chan *mc.ClientContent) <-chan mc.RemoveResult {
@@ -278,7 +278,8 @@ func (c mcClient) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.Clie
}
func (c mcClient) get(ctx context.Context, opts mc.GetOptions) (io.ReadCloser, *probe.Error) {
return c.client.Get(ctx, opts)
rd, _, err := c.client.Get(ctx, opts)
return rd, err
}
func (c mcClient) shareDownload(ctx context.Context, versionID string, expires time.Duration) (string, *probe.Error) {
@@ -329,7 +330,7 @@ func (s consoleSTSAssumeRole) IsExpired() bool {
return s.stsAssumeRole.IsExpired()
}
func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentials.Credentials, error) {
func stsCredentials(minioURL, accessKey, secretKey, location, clientIP string) (*credentials.Credentials, error) {
if accessKey == "" || secretKey == "" {
return nil, errors.New("credentials endpoint, access and secret key are mandatory for AssumeRoleSTS")
}
@@ -340,7 +341,7 @@ func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentia
DurationSeconds: int(xjwt.GetConsoleSTSDuration().Seconds()),
}
stsAssumeRole := &credentials.STSAssumeRole{
Client: GetConsoleHTTPClient(minioURL),
Client: GetConsoleHTTPClient(clientIP),
STSEndpoint: minioURL,
Options: opts,
}
@@ -348,7 +349,7 @@ func stsCredentials(minioURL, accessKey, secretKey, location string) (*credentia
return credentials.New(consoleSTSWrapper), nil
}
func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
func NewConsoleCredentials(accessKey, secretKey, location, clientIP string) (*credentials.Credentials, error) {
minioURL := getMinIOServer()
// Future authentication methods can be added under this switch statement
@@ -356,7 +357,7 @@ func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.
// LDAP authentication for Console
case ldap.GetLDAPEnabled():
{
creds, err := auth.GetCredentialsFromLDAP(GetConsoleHTTPClient(minioURL), minioURL, accessKey, secretKey)
creds, err := auth.GetCredentialsFromLDAP(GetConsoleHTTPClient(clientIP), minioURL, accessKey, secretKey)
if err != nil {
return nil, err
}
@@ -366,7 +367,7 @@ func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.
if err != nil && strings.Contains(strings.ToLower(err.Error()), "not found") {
// We try to use STS Credentials in case LDAP credentials are incorrect.
stsCreds, errSTS := stsCredentials(minioURL, accessKey, secretKey, location)
stsCreds, errSTS := stsCredentials(minioURL, accessKey, secretKey, location, clientIP)
// If there is an error with STS too, then we return the original LDAP error
if errSTS != nil {
@@ -390,7 +391,7 @@ func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.
// default authentication for Console is via STS (Security Token Service) against MinIO
default:
{
return stsCredentials(minioURL, accessKey, secretKey, location)
return stsCredentials(minioURL, accessKey, secretKey, location, clientIP)
}
}
}
@@ -406,14 +407,14 @@ func getConsoleCredentialsFromSession(claims *models.Principal) *credentials.Cre
// newMinioClient creates a new MinIO client based on the ConsoleCredentials extracted
// from the provided session token
func newMinioClient(claims *models.Principal) (*minio.Client, error) {
func newMinioClient(claims *models.Principal, clientIP string) (*minio.Client, error) {
creds := getConsoleCredentialsFromSession(claims)
endpoint := getMinIOEndpoint()
secure := getMinIOEndpointIsSecure()
minioClient, err := minio.New(endpoint, &minio.Options{
Creds: creds,
Secure: secure,
Transport: GetConsoleHTTPClient(getMinIOServer()).Transport,
Transport: GetConsoleHTTPClient(clientIP).Transport,
})
if err != nil {
return nil, err
@@ -425,10 +426,9 @@ func newMinioClient(claims *models.Principal) (*minio.Client, error) {
// computeObjectURLWithoutEncode returns a MinIO url containing the object filename without encoding
func computeObjectURLWithoutEncode(bucketName, prefix string) (string, error) {
endpoint := getMinIOServer()
u, err := xnet.ParseHTTPURL(endpoint)
u, err := xnet.ParseHTTPURL(getMinIOServer())
if err != nil {
return "", fmt.Errorf("the provided endpoint is invalid")
return "", fmt.Errorf("the provided endpoint: '%s' is invalid", getMinIOServer())
}
var p string
if strings.TrimSpace(bucketName) != "" {
@@ -437,11 +437,11 @@ func computeObjectURLWithoutEncode(bucketName, prefix string) (string, error) {
if strings.TrimSpace(prefix) != "" {
p = pathJoinFinalSlash(p, prefix)
}
return fmt.Sprintf("%s://%s/%s", u.Scheme, u.Host, p), nil
return u.String() + "/" + p, nil
}
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
func newS3BucketClient(claims *models.Principal, bucketName string, prefix string) (*mc.S3Client, error) {
func newS3BucketClient(claims *models.Principal, bucketName string, prefix string, clientIP string) (*mc.S3Client, error) {
if claims == nil {
return nil, fmt.Errorf("the provided credentials are invalid")
}
@@ -450,7 +450,7 @@ func newS3BucketClient(claims *models.Principal, bucketName string, prefix strin
if err != nil {
return nil, fmt.Errorf("the provided endpoint is invalid")
}
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken)
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken, clientIP)
client, pErr := mc.S3New(s3Config)
if pErr != nil {
return nil, pErr.Cause
@@ -472,27 +472,24 @@ func pathJoinFinalSlash(elem ...string) string {
return path.Join(elem...)
}
// Deprecated
// newS3Config simply creates a new Config struct using the passed
// parameters.
func newS3Config(endpoint, accessKey, secretKey, sessionToken string) *mc.Config {
func newS3Config(endpoint, accessKey, secretKey, sessionToken string, clientIP string) *mc.Config {
// We have a valid alias and hostConfig. We populate the/
// consoleCredentials from the match found in the config file.
s3Config := new(mc.Config)
s3Config.AppName = globalAppName
s3Config.AppVersion = pkg.Version
s3Config.Debug = false
s3Config.HostURL = endpoint
s3Config.AccessKey = accessKey
s3Config.SecretKey = secretKey
s3Config.SessionToken = sessionToken
s3Config.Signature = "S3v4"
insecure := isLocalIPEndpoint(endpoint)
s3Config.Insecure = insecure
s3Config.Transport = PrepareSTSClientTransport(insecure)
return s3Config
return &mc.Config{
HostURL: endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
SessionToken: sessionToken,
Signature: "S3v4",
AppName: globalAppName,
AppVersion: pkg.Version,
Insecure: isLocalIPEndpoint(endpoint),
Transport: &ConsoleTransport{
ClientIP: clientIP,
Transport: GlobalTransport,
},
}
}

View File

@@ -1,5 +1,5 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
// Copyright (c) 2024 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,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import "testing"
@@ -76,14 +76,15 @@ func Test_computeObjectURLWithoutEncode(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
got, err := computeObjectURLWithoutEncode(tt.args.bucketName, tt.args.prefix)
if (err != nil) != tt.wantErr {
t.Errorf("computeObjectURLWithoutEncode() errors = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("computeObjectURLWithoutEncode() got = %v, want %v", got, tt.want)
if err == nil {
if got != tt.want {
t.Errorf("computeObjectURLWithoutEncode() got = %v, want %v", got, tt.want)
}
}
})
}

View File

@@ -14,18 +14,21 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"crypto/tls"
"crypto/x509"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/minio/console/pkg/auth/idp/oauth2"
xcerts "github.com/minio/pkg/certs"
"github.com/minio/pkg/env"
xnet "github.com/minio/pkg/net"
xcerts "github.com/minio/pkg/v3/certs"
"github.com/minio/pkg/v3/env"
xnet "github.com/minio/pkg/v3/net"
)
var (
@@ -54,6 +57,31 @@ var (
GlobalPublicCerts []*x509.Certificate
// GlobalTLSCertsManager custom TLS Manager for SNI support
GlobalTLSCertsManager *xcerts.Manager
// GlobalTransport is common transport used for all HTTP calls, this is set via
// MinIO server to be the correct transport, however we still define some defaults
// here just in case.
GlobalTransport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 15 * time.Second,
}).DialContext,
MaxIdleConns: 1024,
MaxIdleConnsPerHost: 1024,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 10 * time.Second,
DisableCompression: true, // Set to avoid auto-decompression
TLSClientConfig: &tls.Config{
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
MinVersion: tls.VersionTLS12,
// Console runs in the same pod/node as MinIO this is acceptable.
InsecureSkipVerify: true,
RootCAs: GlobalRootCAs,
},
}
)
// MinIOConfig represents application configuration passed in from the MinIO
@@ -213,11 +241,6 @@ func GetSecureForceSTSHeader() bool {
return strings.ToLower(env.Get(ConsoleSecureForceSTSHeader, "off")) == "on"
}
// PublicKey implements HPKP to prevent MITM attacks with forged certificates. Default is "".
func GetSecurePublicKey() string {
return env.Get(ConsoleSecurePublicKey, "")
}
// ReferrerPolicy allows the Referrer-Policy header with the value to be set with a custom value. Default is "".
func GetSecureReferrerPolicy() string {
return env.Get(ConsoleSecureReferrerPolicy, "")
@@ -228,10 +251,6 @@ func GetSecureFeaturePolicy() string {
return env.Get(ConsoleSecureFeaturePolicy, "")
}
func GetSecureExpectCTHeader() string {
return env.Get(ConsoleSecureExpectCTHeader, "")
}
func getLogSearchAPIToken() string {
if v := env.Get(ConsoleLogQueryAuthToken, ""); v != "" {
return v
@@ -247,6 +266,10 @@ func getPrometheusURL() string {
return env.Get(PrometheusURL, "")
}
func getPrometheusAuthToken() string {
return env.Get(PrometheusAuthToken, "")
}
func getPrometheusJobID() string {
return env.Get(PrometheusJobID, "minio-job")
}
@@ -280,3 +303,7 @@ func getConsoleDevMode() bool {
func getConsoleAnimatedLogin() bool {
return strings.ToLower(env.Get(ConsoleAnimatedLogin, "on")) == "on"
}
func getConsoleBrowserRedirectURL() string {
return env.Get(ConsoleBrowserRedirectURL, "")
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"os"
@@ -54,7 +54,7 @@ func TestGetPort(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsolePort, tt.args.env)
assert.Equalf(t, tt.want, GetPort(), "GetPort()")
os.Unsetenv(ConsolePort)
@@ -87,7 +87,7 @@ func TestGetTLSPort(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleTLSPort, tt.args.env)
assert.Equalf(t, tt.want, GetTLSPort(), "GetTLSPort()")
os.Unsetenv(ConsoleTLSPort)
@@ -120,7 +120,7 @@ func TestGetSecureAllowedHosts(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureAllowedHosts, tt.args.env)
assert.Equalf(t, tt.want, GetSecureAllowedHosts(), "GetSecureAllowedHosts()")
os.Unsetenv(ConsoleSecureAllowedHosts)
@@ -153,7 +153,7 @@ func TestGetSecureHostsProxyHeaders(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureHostsProxyHeaders, tt.args.env)
assert.Equalf(t, tt.want, GetSecureHostsProxyHeaders(), "GetSecureHostsProxyHeaders()")
os.Unsetenv(ConsoleSecureHostsProxyHeaders)
@@ -186,7 +186,7 @@ func TestGetSecureSTSSeconds(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleSecureSTSSeconds, tt.args.env)
assert.Equalf(t, tt.want, GetSecureSTSSeconds(), "GetSecureSTSSeconds()")
os.Unsetenv(ConsoleSecureSTSSeconds)
@@ -219,7 +219,7 @@ func Test_getLogSearchAPIToken(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
assert.Equalf(t, tt.want, getLogSearchAPIToken(), "getLogSearchAPIToken()")
os.Setenv(ConsoleLogQueryAuthToken, tt.args.env)
@@ -252,7 +252,7 @@ func Test_getPrometheusURL(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(PrometheusURL, tt.args.env)
assert.Equalf(t, tt.want, getPrometheusURL(), "getPrometheusURL()")
os.Setenv(PrometheusURL, tt.args.env)
@@ -285,7 +285,7 @@ func Test_getPrometheusJobID(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(PrometheusJobID, tt.args.env)
assert.Equalf(t, tt.want, getPrometheusJobID(), "getPrometheusJobID()")
os.Setenv(PrometheusJobID, tt.args.env)
@@ -318,7 +318,7 @@ func Test_getMaxConcurrentUploadsLimit(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleMaxConcurrentUploads, tt.args.env)
assert.Equalf(t, tt.want, getMaxConcurrentUploadsLimit(), "getMaxConcurrentUploadsLimit()")
os.Unsetenv(ConsoleMaxConcurrentUploads)
@@ -351,7 +351,7 @@ func Test_getMaxConcurrentDownloadsLimit(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleMaxConcurrentDownloads, tt.args.env)
assert.Equalf(t, tt.want, getMaxConcurrentDownloadsLimit(), "getMaxConcurrentDownloadsLimit()")
os.Unsetenv(ConsoleMaxConcurrentDownloads)
@@ -384,7 +384,7 @@ func Test_getConsoleDevMode(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
os.Setenv(ConsoleDevMode, tt.args.env)
assert.Equalf(t, tt.want, getConsoleDevMode(), "getConsoleDevMode()")
os.Unsetenv(ConsoleDevMode)

View File

@@ -16,7 +16,7 @@
// This file is safe to edit. Once it exists it will not be overwritten
package restapi
package api
import (
"bytes"
@@ -35,22 +35,24 @@ import (
"sync"
"time"
"github.com/google/uuid"
"github.com/minio/console/pkg/logger"
"github.com/minio/console/pkg/utils"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/klauspost/compress/gzhttp"
portal_ui "github.com/minio/console/portal-ui"
"github.com/minio/pkg/env"
"github.com/minio/pkg/mimedb"
xnet "github.com/minio/pkg/net"
portal_ui "github.com/minio/console/web-app"
"github.com/minio/pkg/v3/env"
"github.com/minio/pkg/v3/mimedb"
xnet "github.com/minio/pkg/v3/net"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/minio/console/api/operations"
"github.com/minio/console/models"
"github.com/minio/console/pkg/auth"
"github.com/minio/console/restapi/operations"
"github.com/unrolled/secure"
)
@@ -65,7 +67,7 @@ const (
)
var (
subPath = "/"
cfgSubPath = "/"
subPathOnce sync.Once
)
@@ -80,7 +82,7 @@ func configureFlags(api *operations.ConsoleAPI) {
func configureAPI(api *operations.ConsoleAPI) http.Handler {
// Applies when the "x-token" header is set
api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) {
api.KeyAuth = func(token string, _ []string) (*models.Principal, error) {
// we are validating the session token by decrypting the claims inside, if the operation succeed that means the jwt
// was generated and signed by us in the first place
if token == "Anonymous" {
@@ -101,7 +103,7 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
CustomStyleOb: claims.CustomStyleOB,
}, nil
}
api.AnonymousAuth = func(s string) (*models.Principal, error) {
api.AnonymousAuth = func(_ string) (*models.Principal, error) {
return &models.Principal{}, nil
}
@@ -127,8 +129,6 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
registerServiceHandlers(api)
// Register session handlers
registerSessionHandlers(api)
// Register version handlers
registerVersionHandlers(api)
// Register admin info handlers
registerAdminInfoHandlers(api)
// Register admin arns handlers
@@ -170,6 +170,8 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
registerReleasesHandlers(api)
registerPublicObjectsHandlers(api)
api.PreServerShutdown = func() {}
api.ServerShutdown = func() {}
@@ -194,15 +196,12 @@ func setupMiddlewares(handler http.Handler) http.Handler {
func ContextMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestID, err := utils.NewUUID()
if err != nil && err != auth.ErrNoAuthToken {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
requestID := uuid.NewString()
ctx := context.WithValue(r.Context(), utils.ContextRequestID, requestID)
ctx = context.WithValue(ctx, utils.ContextRequestUserAgent, r.UserAgent())
ctx = context.WithValue(ctx, utils.ContextRequestHost, r.Host)
ctx = context.WithValue(ctx, utils.ContextRequestRemoteAddr, r.RemoteAddr)
ctx = context.WithValue(ctx, utils.ContextClientIP, getClientIP(r))
next.ServeHTTP(w, r.WithContext(ctx))
})
}
@@ -257,10 +256,8 @@ func setupGlobalMiddleware(handler http.Handler) http.Handler {
BrowserXssFilter: GetSecureBrowserXSSFilter(),
ContentSecurityPolicy: GetSecureContentSecurityPolicy(),
ContentSecurityPolicyReportOnly: GetSecureContentSecurityPolicyReportOnly(),
PublicKey: GetSecurePublicKey(),
ReferrerPolicy: GetSecureReferrerPolicy(),
FeaturePolicy: GetSecureFeaturePolicy(),
ExpectCTHeader: GetSecureExpectCTHeader(),
IsDevelopment: false,
}
secureMiddleware := secure.New(secureOptions)
@@ -471,9 +468,9 @@ func configureServer(s *http.Server, _, _ string) {
func getSubPath() string {
subPathOnce.Do(func() {
subPath = parseSubPath(env.Get(SubPath, ""))
cfgSubPath = parseSubPath(env.Get(SubPath, ""))
})
return subPath
return cfgSubPath
}
func parseSubPath(v string) string {
@@ -483,7 +480,7 @@ func parseSubPath(v string) string {
}
// Replace all unnecessary `\` to `/`
// also add pro-actively at the end.
subPath = path.Clean(filepath.ToSlash(v))
subPath := path.Clean(filepath.ToSlash(v))
if !strings.HasPrefix(subPath, SlashSeparator) {
subPath = SlashSeparator + subPath
}
@@ -511,7 +508,7 @@ func replaceBaseInIndex(indexPageBytes []byte, basePath string) []byte {
func replaceLicense(indexPageBytes []byte) []byte {
indexPageStr := string(indexPageBytes)
newPlan := fmt.Sprintf("<meta name=\"minio-license\" content=\"%s\" />", InstanceLicensePlan.String())
indexPageStr = strings.Replace(indexPageStr, "<meta name=\"minio-license\" content=\"apgl\"/>", newPlan, 1)
indexPageStr = strings.Replace(indexPageStr, "<meta name=\"minio-license\" content=\"agpl\"/>", newPlan, 1)
indexPageBytes = []byte(indexPageStr)
return indexPageBytes
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"os"
@@ -70,7 +70,7 @@ func Test_parseSubPath(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
assert.Equalf(t, tt.want, parseSubPath(tt.args.v), "parseSubPath(%v)", tt.args.v)
})
}
@@ -115,7 +115,7 @@ func Test_getSubPath(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
t.Setenv(SubPath, tt.args.envValue)
defer os.Unsetenv(SubPath)
subPathOnce = sync.Once{}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
// list of all console environment constants
const (
@@ -47,6 +47,7 @@ const (
ConsoleSecureFeaturePolicy = "CONSOLE_SECURE_FEATURE_POLICY"
ConsoleSecureExpectCTHeader = "CONSOLE_SECURE_EXPECT_CT_HEADER"
PrometheusURL = "CONSOLE_PROMETHEUS_URL"
PrometheusAuthToken = "CONSOLE_PROMETHEUS_AUTH_TOKEN"
PrometheusJobID = "CONSOLE_PROMETHEUS_JOB_ID"
PrometheusExtraLabels = "CONSOLE_PROMETHEUS_EXTRA_LABELS"
ConsoleLogQueryURL = "CONSOLE_LOG_QUERY_URL"
@@ -55,6 +56,8 @@ const (
ConsoleMaxConcurrentDownloads = "CONSOLE_MAX_CONCURRENT_DOWNLOADS"
ConsoleDevMode = "CONSOLE_DEV_MODE"
ConsoleAnimatedLogin = "CONSOLE_ANIMATED_LOGIN"
ConsoleBrowserRedirectURL = "CONSOLE_BROWSER_REDIRECT_URL"
LogSearchQueryAuthToken = "LOGSEARCH_QUERY_AUTH_TOKEN"
SlashSeparator = "/"
LocalAddress = "127.0.0.1"
)

556
api/custom-server.go Normal file
View File

@@ -0,0 +1,556 @@
// 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 api
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"strconv"
"sync"
"sync/atomic"
"syscall"
"time"
"github.com/go-openapi/runtime/flagext"
"github.com/go-openapi/swag"
flags "github.com/jessevdk/go-flags"
"golang.org/x/net/netutil"
"github.com/minio/console/api/operations"
)
const (
schemeHTTP = "http"
schemeHTTPS = "https"
schemeUnix = "unix"
)
var defaultSchemes []string
func init() {
defaultSchemes = []string{
schemeHTTP,
}
}
// NewServer creates a new api console server but does not configure it
func NewServer(api *operations.ConsoleAPI) *Server {
s := new(Server)
s.shutdown = make(chan struct{})
s.api = api
s.interrupt = make(chan os.Signal, 1)
return s
}
// ConfigureAPI configures the API and handlers.
func (s *Server) ConfigureAPI() {
if s.api != nil {
s.handler = configureAPI(s.api)
}
}
// ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse
func (s *Server) ConfigureFlags() {
if s.api != nil {
configureFlags(s.api)
}
}
// Server for the console API
type Server struct {
EnabledListeners []string `long:"scheme" description:"the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec"`
CleanupTimeout time.Duration `long:"cleanup-timeout" description:"grace period for which to wait before killing idle connections" default:"10s"`
GracefulTimeout time.Duration `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`
MaxHeaderSize flagext.ByteSize `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`
SocketPath flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/console.sock"`
domainSocketL net.Listener
Host string `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`
Port int `long:"port" description:"the port to listen on for insecure connections, defaults to a random value" env:"PORT"`
ListenLimit int `long:"listen-limit" description:"limit the number of outstanding requests"`
KeepAlive time.Duration `long:"keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)" default:"3m"`
ReadTimeout time.Duration `long:"read-timeout" description:"maximum duration before timing out read of the request" default:"30s"`
WriteTimeout time.Duration `long:"write-timeout" description:"maximum duration before timing out write of the response" default:"60s"`
httpServerL []net.Listener
TLSHost string `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`
TLSPort int `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`
TLSCertificate flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`
TLSCertificateKey flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`
TLSCACertificate flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`
TLSListenLimit int `long:"tls-listen-limit" description:"limit the number of outstanding requests"`
TLSKeepAlive time.Duration `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`
TLSReadTimeout time.Duration `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`
TLSWriteTimeout time.Duration `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`
httpsServerL []net.Listener
api *operations.ConsoleAPI
handler http.Handler
hasListeners bool
shutdown chan struct{}
shuttingDown int32
interrupted bool
interrupt chan os.Signal
}
// Logf logs message either via defined user logger or via system one if no user logger is defined.
func (s *Server) Logf(f string, args ...interface{}) {
if s.api != nil && s.api.Logger != nil {
s.api.Logger(f, args...)
} else {
log.Printf(f, args...)
}
}
// Fatalf logs message either via defined user logger or via system one if no user logger is defined.
// Exits with non-zero status after printing
func (s *Server) Fatalf(f string, args ...interface{}) {
if s.api != nil && s.api.Logger != nil {
s.api.Logger(f, args...)
os.Exit(1)
}
log.Fatalf(f, args...)
}
// SetAPI configures the server with the specified API. Needs to be called before Serve
func (s *Server) SetAPI(api *operations.ConsoleAPI) {
if api == nil {
s.api = nil
s.handler = nil
return
}
s.api = api
s.handler = configureAPI(api)
}
func (s *Server) hasScheme(scheme string) bool {
schemes := s.EnabledListeners
if len(schemes) == 0 {
schemes = defaultSchemes
}
for _, v := range schemes {
if v == scheme {
return true
}
}
return false
}
// Serve the api
func (s *Server) Serve() (err error) {
if !s.hasListeners {
if err = s.Listen(); err != nil {
return err
}
}
// set default handler, if none is set
if s.handler == nil {
if s.api == nil {
return errors.New("can't create the default handler, as no api is set")
}
s.SetHandler(s.api.Serve(nil))
}
wg := new(sync.WaitGroup)
once := new(sync.Once)
signalNotify(s.interrupt)
go handleInterrupt(once, s)
servers := []*http.Server{}
if s.hasScheme(schemeUnix) {
domainSocket := new(http.Server)
domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize)
domainSocket.Handler = s.handler
if int64(s.CleanupTimeout) > 0 {
domainSocket.IdleTimeout = s.CleanupTimeout
}
configureServer(domainSocket, "unix", string(s.SocketPath))
servers = append(servers, domainSocket)
wg.Add(1)
s.Logf("Serving console at unix://%s", s.SocketPath)
go func(l net.Listener) {
defer wg.Done()
if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at unix://%s", s.SocketPath)
}(s.domainSocketL)
}
if s.hasScheme(schemeHTTP) {
httpServer := new(http.Server)
httpServer.MaxHeaderBytes = int(s.MaxHeaderSize)
httpServer.ReadTimeout = s.ReadTimeout
httpServer.WriteTimeout = s.WriteTimeout
httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0)
if s.ListenLimit > 0 {
for i := range s.httpServerL {
s.httpServerL[i] = netutil.LimitListener(s.httpServerL[i], s.ListenLimit)
}
}
if int64(s.CleanupTimeout) > 0 {
httpServer.IdleTimeout = s.CleanupTimeout
}
httpServer.Handler = s.handler
configureServer(httpServer, "http", s.httpServerL[0].Addr().String())
servers = append(servers, httpServer)
s.Logf("Serving console at http://%s", s.httpServerL[0].Addr())
for i := range s.httpServerL {
wg.Add(1)
go func(l net.Listener) {
defer wg.Done()
if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at http://%s", l.Addr())
}(s.httpServerL[i])
}
}
if s.hasScheme(schemeHTTPS) {
httpsServer := new(http.Server)
httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize)
httpsServer.ReadTimeout = s.TLSReadTimeout
httpsServer.WriteTimeout = s.TLSWriteTimeout
httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0)
if s.TLSListenLimit > 0 {
for i := range s.httpsServerL {
s.httpsServerL[i] = netutil.LimitListener(s.httpsServerL[i], s.TLSListenLimit)
}
}
if int64(s.CleanupTimeout) > 0 {
httpsServer.IdleTimeout = s.CleanupTimeout
}
httpsServer.Handler = s.handler
// Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
httpsServer.TLSConfig = &tls.Config{
// Causes servers to use Go's default ciphersuite preferences,
// which are tuned to avoid attacks. Does nothing on clients.
PreferServerCipherSuites: true,
// Only use curves which have assembly implementations
// https://github.com/golang/go/tree/master/src/crypto/elliptic
CurvePreferences: []tls.CurveID{tls.CurveP256},
// Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
NextProtos: []string{"h2", "http/1.1"},
// https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols
MinVersion: tls.VersionTLS12,
// These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
}
// build standard config from server options
if s.TLSCertificate != "" && s.TLSCertificateKey != "" {
httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1)
httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(string(s.TLSCertificate), string(s.TLSCertificateKey))
if err != nil {
return err
}
}
if s.TLSCACertificate != "" {
// include specified CA certificate
caCert, caCertErr := os.ReadFile(string(s.TLSCACertificate))
if caCertErr != nil {
return caCertErr
}
caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(caCert)
if !ok {
return fmt.Errorf("cannot parse CA certificate")
}
httpsServer.TLSConfig.ClientCAs = caCertPool
httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
// call custom TLS configurator
configureTLS(httpsServer.TLSConfig)
if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil {
// after standard and custom config are passed, this ends up with no certificate
if s.TLSCertificate == "" {
if s.TLSCertificateKey == "" {
s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified")
}
s.Fatalf("the required flag `--tls-certificate` was not specified")
}
if s.TLSCertificateKey == "" {
s.Fatalf("the required flag `--tls-key` was not specified")
}
// this happens with a wrong custom TLS configurator
s.Fatalf("no certificate was configured for TLS")
}
configureServer(httpsServer, "https", s.httpsServerL[0].Addr().String())
servers = append(servers, httpsServer)
s.Logf("Serving console at https://%s", s.httpsServerL[0].Addr())
for i := range s.httpsServerL {
wg.Add(1)
go func(l net.Listener) {
defer wg.Done()
if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed {
s.Fatalf("%v", err)
}
s.Logf("Stopped serving console at https://%s", l.Addr())
}(tls.NewListener(s.httpsServerL[i], httpsServer.TLSConfig))
}
}
wg.Add(1)
go s.handleShutdown(wg, &servers)
wg.Wait()
return nil
}
// Listen creates the listeners for the server
func (s *Server) Listen() error {
if s.hasListeners { // already done this
return nil
}
if s.hasScheme(schemeHTTPS) {
// Use http host if https host wasn't defined
if s.TLSHost == "" {
s.TLSHost = s.Host
}
// Use http listen limit if https listen limit wasn't defined
if s.TLSListenLimit == 0 {
s.TLSListenLimit = s.ListenLimit
}
// Use http tcp keep alive if https tcp keep alive wasn't defined
if int64(s.TLSKeepAlive) == 0 {
s.TLSKeepAlive = s.KeepAlive
}
// Use http read timeout if https read timeout wasn't defined
if int64(s.TLSReadTimeout) == 0 {
s.TLSReadTimeout = s.ReadTimeout
}
// Use http write timeout if https write timeout wasn't defined
if int64(s.TLSWriteTimeout) == 0 {
s.TLSWriteTimeout = s.WriteTimeout
}
}
if s.hasScheme(schemeUnix) {
domSockListener, err := net.Listen("unix", string(s.SocketPath))
if err != nil {
return err
}
s.domainSocketL = domSockListener
}
lookup := func(addr string) []net.IP {
ips, err := net.LookupIP(addr)
if err == nil {
return ips
}
return []net.IP{net.ParseIP(addr)}
}
convert := func(ip net.IP) (string, string) {
if ip == nil {
return "", "tcp"
}
proto := "tcp4"
if ip.To4() == nil {
proto = "tcp6"
}
return ip.String(), proto
}
if s.hasScheme(schemeHTTP) {
for _, ip := range lookup(s.Host) {
host, proto := convert(ip)
listener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.Port)))
if err != nil {
return err
}
if s.Host == "" || s.Port == 0 {
h, p, err := swag.SplitHostPort(listener.Addr().String())
if err != nil {
return err
}
s.Host = h
s.Port = p
}
s.httpServerL = append(s.httpServerL, listener)
}
}
if s.hasScheme(schemeHTTPS) {
for _, ip := range lookup(s.TLSHost) {
host, proto := convert(ip)
tlsListener, err := net.Listen(proto, net.JoinHostPort(host, strconv.Itoa(s.TLSPort)))
if err != nil {
return err
}
if s.TLSHost == "" || s.TLSPort == 0 {
sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String())
if err != nil {
return err
}
s.TLSHost = sh
s.TLSPort = sp
}
s.httpsServerL = append(s.httpsServerL, tlsListener)
}
}
s.hasListeners = true
return nil
}
// Shutdown server and clean up resources
func (s *Server) Shutdown() error {
if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) {
close(s.shutdown)
}
return nil
}
func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) {
// wg.Done must occur last, after s.api.ServerShutdown()
// (to preserve old behavior)
defer wg.Done()
<-s.shutdown
servers := *serversPtr
ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout)
defer cancel()
// first execute the pre-shutdown hook
s.api.PreServerShutdown()
shutdownChan := make(chan bool)
for i := range servers {
server := servers[i]
go func() {
var success bool
defer func() {
shutdownChan <- success
}()
if err := server.Shutdown(ctx); err != nil {
// Error from closing listeners, or context timeout:
s.Logf("HTTP server Shutdown: %v", err)
} else {
success = true
}
}()
}
// Wait until all listeners have successfully shut down before calling ServerShutdown
success := true
for range servers {
success = success && <-shutdownChan
}
if success {
s.api.ServerShutdown()
}
}
// GetHandler returns a handler useful for testing
func (s *Server) GetHandler() http.Handler {
return s.handler
}
// SetHandler allows for setting a http handler on this server
func (s *Server) SetHandler(handler http.Handler) {
s.handler = handler
}
// UnixListener returns the domain socket listener
func (s *Server) UnixListener() (net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.domainSocketL, nil
}
// HTTPListener returns the http listener
func (s *Server) HTTPListener() ([]net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.httpServerL, nil
}
// TLSListener returns the https listener
func (s *Server) TLSListener() ([]net.Listener, error) {
if !s.hasListeners {
if err := s.Listen(); err != nil {
return nil, err
}
}
return s.httpsServerL, nil
}
func handleInterrupt(once *sync.Once, s *Server) {
once.Do(func() {
for range s.interrupt {
if s.interrupted {
s.Logf("Server already shutting down")
continue
}
s.interrupted = true
s.Logf("Shutting down... ")
if err := s.Shutdown(); err != nil {
s.Logf("HTTP server Shutdown: %v", err)
}
}
})
}
func signalNotify(interrupt chan<- os.Signal) {
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
}

View File

@@ -16,7 +16,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Package restapi MinIO Console Server
// Package api MinIO Console Server
//
// Schemes:
// http
@@ -35,4 +35,4 @@
// - application/json
//
// swagger:meta
package restapi
package api

File diff suppressed because it is too large Load Diff

View File

@@ -14,17 +14,17 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"errors"
"strings"
"github.com/go-openapi/swag"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v2"
"github.com/minio/minio-go/v7"
"github.com/minio/console/models"
"github.com/minio/madmin-go/v3"
)
var (
@@ -53,6 +53,7 @@ var (
ErrAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself")
ErrAccessDenied = errors.New("access denied")
ErrOauth2Provider = errors.New("unable to contact configured identity provider")
ErrOauth2Login = errors.New("unable to login using configured identity provider")
ErrNonUniqueAccessKey = errors.New("access key already in use")
ErrRemoteTierExists = errors.New("specified remote tier already exists")
ErrRemoteTierNotFound = errors.New("specified remote tier was not found")
@@ -71,17 +72,24 @@ var (
ErrEncryptionConfigNotFound = errors.New("encryption configuration not found")
ErrPolicyNotFound = errors.New("policy does not exist")
ErrLoginNotAllowed = errors.New("login not allowed")
ErrSubnetUploadFail = errors.New("Subnet upload failed")
ErrHealthReportFail = errors.New("failure to generate Health report")
)
type CodedAPIError struct {
Code int
APIError *models.APIError
}
// ErrorWithContext :
func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
errorCode := int32(500)
func ErrorWithContext(ctx context.Context, err ...interface{}) *CodedAPIError {
errorCode := 500
errorMessage := ErrDefault.Error()
var detailedMessage string
var err1 error
var exists bool
if len(err) > 0 {
if err1, exists = err[0].(error); exists {
detailedMessage = err1.Error()
var lastError error
if len(err) > 1 {
if err2, lastExists := err[1].(error); lastExists {
@@ -99,15 +107,22 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
errorMessage = ErrNotFound.Error()
}
if errors.Is(err1, ErrInvalidLogin) {
detailedMessage = ""
errorCode = 401
errorMessage = ErrInvalidLogin.Error()
}
if strings.Contains(strings.ToLower(err1.Error()), ErrAccessDenied.Error()) {
errorCode = 403
errorMessage = err1.Error()
}
// If the last error is ErrInvalidLogin, this is a login failure
if errors.Is(lastError, ErrInvalidLogin) {
detailedMessage = ""
errorCode = 401
errorMessage = err1.Error()
}
if strings.Contains(err1.Error(), ErrLoginNotAllowed.Error()) {
detailedMessage = ""
errorCode = 400
errorMessage = ErrLoginNotAllowed.Error()
}
@@ -201,6 +216,7 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
errorMessage = ErrAccessDenied.Error()
}
if madmin.ToErrorResponse(err1).Code == "InvalidAccessKeyId" {
errorCode = 401
errorMessage = ErrInvalidSession.Error()
}
@@ -240,6 +256,7 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
errorCode = 400
errorMessage = "Bucket already exists"
}
LogError("ErrorWithContext:%v", err...)
LogIf(ctx, err1, err...)
}
@@ -250,11 +267,11 @@ func ErrorWithContext(ctx context.Context, err ...interface{}) *models.Error {
}
}
}
return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err1.Error())}
return &CodedAPIError{Code: errorCode, APIError: &models.APIError{Message: errorMessage, DetailedMessage: detailedMessage}}
}
// Error receives an errors object and parse it against k8sErrors, returns the right errors code paired with a generic errors message
func Error(err ...interface{}) *models.Error {
func Error(err ...interface{}) *CodedAPIError {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
return ErrorWithContext(ctx, err...)

View File

@@ -14,14 +14,13 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"context"
"fmt"
"testing"
"github.com/go-openapi/swag"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
)
@@ -34,7 +33,7 @@ func TestError(t *testing.T) {
type testError struct {
name string
args args
want *models.Error
want *CodedAPIError
}
var tests []testError
@@ -45,37 +44,38 @@ func TestError(t *testing.T) {
}
appErrors := map[string]expectedError{
"ErrDefault": {code: 500, err: ErrDefault},
"ErrInvalidLogin": {code: 401, err: ErrInvalidLogin},
"ErrForbidden": {code: 403, err: ErrForbidden},
"ErrFileTooLarge": {code: 413, err: ErrFileTooLarge},
"ErrInvalidSession": {code: 401, err: ErrInvalidSession},
"ErrNotFound": {code: 404, err: ErrNotFound},
"ErrGroupAlreadyExists": {code: 400, err: ErrGroupAlreadyExists},
"ErrInvalidErasureCodingValue": {code: 400, err: ErrInvalidErasureCodingValue},
"ErrBucketBodyNotInRequest": {code: 400, err: ErrBucketBodyNotInRequest},
"ErrBucketNameNotInRequest": {code: 400, err: ErrBucketNameNotInRequest},
"ErrGroupBodyNotInRequest": {code: 400, err: ErrGroupBodyNotInRequest},
"ErrGroupNameNotInRequest": {code: 400, err: ErrGroupNameNotInRequest},
"ErrPolicyNameNotInRequest": {code: 400, err: ErrPolicyNameNotInRequest},
"ErrPolicyBodyNotInRequest": {code: 400, err: ErrPolicyBodyNotInRequest},
"ErrInvalidEncryptionAlgorithm": {code: 500, err: ErrInvalidEncryptionAlgorithm},
"ErrSSENotConfigured": {code: 404, err: ErrSSENotConfigured},
"ErrBucketLifeCycleNotConfigured": {code: 404, err: ErrBucketLifeCycleNotConfigured},
"ErrChangePassword": {code: 403, err: ErrChangePassword},
"ErrInvalidLicense": {code: 404, err: ErrInvalidLicense},
"ErrLicenseNotFound": {code: 404, err: ErrLicenseNotFound},
"ErrAvoidSelfAccountDelete": {code: 403, err: ErrAvoidSelfAccountDelete},
"ErrAccessDenied": {code: 403, err: ErrAccessDenied},
"ErrDefault": {code: 500, err: ErrDefault},
"ErrForbidden": {code: 403, err: ErrForbidden},
"ErrFileTooLarge": {code: 413, err: ErrFileTooLarge},
"ErrInvalidSession": {code: 401, err: ErrInvalidSession},
"ErrNotFound": {code: 404, err: ErrNotFound},
"ErrGroupAlreadyExists": {code: 400, err: ErrGroupAlreadyExists},
"ErrInvalidErasureCodingValue": {code: 400, err: ErrInvalidErasureCodingValue},
"ErrBucketBodyNotInRequest": {code: 400, err: ErrBucketBodyNotInRequest},
"ErrBucketNameNotInRequest": {code: 400, err: ErrBucketNameNotInRequest},
"ErrGroupBodyNotInRequest": {code: 400, err: ErrGroupBodyNotInRequest},
"ErrGroupNameNotInRequest": {code: 400, err: ErrGroupNameNotInRequest},
"ErrPolicyNameNotInRequest": {code: 400, err: ErrPolicyNameNotInRequest},
"ErrPolicyBodyNotInRequest": {code: 400, err: ErrPolicyBodyNotInRequest},
"ErrInvalidEncryptionAlgorithm": {code: 500, err: ErrInvalidEncryptionAlgorithm},
"ErrSSENotConfigured": {code: 404, err: ErrSSENotConfigured},
"ErrBucketLifeCycleNotConfigured": {code: 404, err: ErrBucketLifeCycleNotConfigured},
"ErrChangePassword": {code: 403, err: ErrChangePassword},
"ErrInvalidLicense": {code: 404, err: ErrInvalidLicense},
"ErrLicenseNotFound": {code: 404, err: ErrLicenseNotFound},
"ErrAvoidSelfAccountDelete": {code: 403, err: ErrAvoidSelfAccountDelete},
"ErrNonUniqueAccessKey": {code: 500, err: ErrNonUniqueAccessKey},
"ErrRemoteTierExists": {code: 400, err: ErrRemoteTierExists},
"ErrRemoteTierNotFound": {code: 400, err: ErrRemoteTierNotFound},
"ErrRemoteTierUppercase": {code: 400, err: ErrRemoteTierUppercase},
"ErrRemoteTierBucketNotFound": {code: 400, err: ErrRemoteTierBucketNotFound},
"ErrRemoteInvalidCredentials": {code: 403, err: ErrRemoteInvalidCredentials},
"ErrTooFewNodes": {code: 500, err: ErrTooFewNodes},
"ErrUnableToGetTenantUsage": {code: 500, err: ErrUnableToGetTenantUsage},
"ErrTooManyNodes": {code: 500, err: ErrTooManyNodes},
"ErrTooFewNodes": {code: 500, err: ErrTooFewNodes},
"ErrAccessDenied": {code: 403, err: ErrAccessDenied},
"ErrTooFewAvailableNodes": {code: 500, err: ErrTooFewAvailableNodes},
"ErrFewerThanFourNodes": {code: 500, err: ErrFewerThanFourNodes},
"ErrUnableToGetTenantLogs": {code: 500, err: ErrUnableToGetTenantLogs},
@@ -91,22 +91,41 @@ func TestError(t *testing.T) {
args: args{
err: []interface{}{e.err},
},
want: &models.Error{Code: int32(e.code), Message: swag.String(e.err.Error()), DetailedMessage: swag.String(e.err.Error())},
want: &CodedAPIError{
Code: e.code,
APIError: &models.APIError{Message: e.err.Error(), DetailedMessage: e.err.Error()},
},
})
}
tests = append(tests,
testError{
name: "passing multiple errors but ErrInvalidLogin is last",
args: args{
err: []interface{}{ErrDefault, ErrInvalidLogin},
},
want: &models.Error{Code: int32(401), Message: swag.String(ErrDefault.Error()), DetailedMessage: swag.String(ErrDefault.Error())},
want: &CodedAPIError{
Code: int(401),
APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ""},
},
})
tests = append(tests,
testError{
name: "login error omits detailedMessage",
args: args{
err: []interface{}{ErrInvalidLogin},
},
want: &CodedAPIError{
Code: int(401),
APIError: &models.APIError{Message: ErrInvalidLogin.Error(), DetailedMessage: ""},
},
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
got := Error(tt.args.err...)
assert.Equalf(t, tt.want.Code, got.Code, "Error(%v) Got (%v)", tt.want.Code, got.Code)
assert.Equalf(t, *tt.want.DetailedMessage, *got.DetailedMessage, "Error(%s) Got (%s)", *tt.want.DetailedMessage, *got.DetailedMessage)
assert.Equalf(t, tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage, "Error(%s) Got (%s)", tt.want.APIError.DetailedMessage, got.APIError.DetailedMessage)
})
}
}
@@ -119,7 +138,7 @@ func TestErrorWithContext(t *testing.T) {
tests := []struct {
name string
args args
want *models.Error
want *CodedAPIError
}{
{
name: "default error",
@@ -127,11 +146,13 @@ func TestErrorWithContext(t *testing.T) {
ctx: context.Background(),
err: []interface{}{ErrDefault},
},
want: &models.Error{Code: 500, Message: swag.String(ErrDefault.Error()), DetailedMessage: swag.String(ErrDefault.Error())},
want: &CodedAPIError{
Code: 500, APIError: &models.APIError{Message: ErrDefault.Error(), DetailedMessage: ErrDefault.Error()},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
assert.Equalf(t, tt.want, ErrorWithContext(tt.args.ctx, tt.args.err...), "ErrorWithContext(%v, %v)", tt.args.ctx, tt.args.err)
})
}

View File

@@ -14,12 +14,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"net/http"
"os"
"github.com/minio/console/pkg/subnet"
"github.com/minio/pkg/v3/licverifier"
"github.com/minio/pkg/v3/subnet"
)
type SubnetPlan int
@@ -43,8 +45,18 @@ func (sp SubnetPlan) String() string {
var InstanceLicensePlan = PlanAGPL
func getLicenseInfo(client http.Client, license string) (*licverifier.LicenseInfo, error) {
lv := subnet.LicenseValidator{
Client: client,
ExpiryGracePeriod: 0,
}
lv.Init(getConsoleDevMode())
return lv.ParseLicense(license)
}
func fetchLicensePlan() {
licenseInfo, err := subnet.ParseLicense(GetConsoleHTTPClient(""), os.Getenv(EnvSubnetLicense))
client := GetConsoleHTTPClient("127.0.0.1")
licenseInfo, err := getLicenseInfo(*client, os.Getenv(EnvSubnetLicense))
if err != nil {
return
}

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package restapi
package api
import (
"context"
@@ -58,7 +58,7 @@ type Context struct {
TLSCertificate, TLSKey, TLSca string
}
// Load loads restapi Context from command line context.
// Load loads api Context from command line context.
func (c *Context) Load(ctx *cli.Context) error {
*c = Context{
Host: ctx.String("host"),

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package restapi
package api
import (
"flag"
@@ -85,7 +85,7 @@ func TestContext_Load(t *testing.T) {
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
c := &Context{}
fs := flag.NewFlagSet("flags", flag.ContinueOnError)

View File

@@ -66,7 +66,7 @@ type AccountChangePasswordDefault struct {
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
Payload *models.APIError `json:"body,omitempty"`
}
// NewAccountChangePasswordDefault creates AccountChangePasswordDefault with default headers values
@@ -92,13 +92,13 @@ func (o *AccountChangePasswordDefault) SetStatusCode(code int) {
}
// WithPayload adds the payload to the account change password default response
func (o *AccountChangePasswordDefault) WithPayload(payload *models.Error) *AccountChangePasswordDefault {
func (o *AccountChangePasswordDefault) WithPayload(payload *models.APIError) *AccountChangePasswordDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the account change password default response
func (o *AccountChangePasswordDefault) SetPayload(payload *models.Error) {
func (o *AccountChangePasswordDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}

View File

@@ -66,7 +66,7 @@ type ChangeUserPasswordDefault struct {
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
Payload *models.APIError `json:"body,omitempty"`
}
// NewChangeUserPasswordDefault creates ChangeUserPasswordDefault with default headers values
@@ -92,13 +92,13 @@ func (o *ChangeUserPasswordDefault) SetStatusCode(code int) {
}
// WithPayload adds the payload to the change user password default response
func (o *ChangeUserPasswordDefault) WithPayload(payload *models.Error) *ChangeUserPasswordDefault {
func (o *ChangeUserPasswordDefault) WithPayload(payload *models.APIError) *ChangeUserPasswordDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the change user password default response
func (o *ChangeUserPasswordDefault) SetPayload(payload *models.Error) {
func (o *ChangeUserPasswordDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}

View File

@@ -86,7 +86,7 @@ type LoginDetailDefault struct {
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
Payload *models.APIError `json:"body,omitempty"`
}
// NewLoginDetailDefault creates LoginDetailDefault with default headers values
@@ -112,13 +112,13 @@ func (o *LoginDetailDefault) SetStatusCode(code int) {
}
// WithPayload adds the payload to the login detail default response
func (o *LoginDetailDefault) WithPayload(payload *models.Error) *LoginDetailDefault {
func (o *LoginDetailDefault) WithPayload(payload *models.APIError) *LoginDetailDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login detail default response
func (o *LoginDetailDefault) SetPayload(payload *models.Error) {
func (o *LoginDetailDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}

View File

@@ -66,7 +66,7 @@ type LoginOauth2AuthDefault struct {
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
Payload *models.APIError `json:"body,omitempty"`
}
// NewLoginOauth2AuthDefault creates LoginOauth2AuthDefault with default headers values
@@ -92,13 +92,13 @@ func (o *LoginOauth2AuthDefault) SetStatusCode(code int) {
}
// WithPayload adds the payload to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) WithPayload(payload *models.Error) *LoginOauth2AuthDefault {
func (o *LoginOauth2AuthDefault) WithPayload(payload *models.APIError) *LoginOauth2AuthDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login oauth2 auth default response
func (o *LoginOauth2AuthDefault) SetPayload(payload *models.Error) {
func (o *LoginOauth2AuthDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}

View File

@@ -66,7 +66,7 @@ type LoginDefault struct {
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
Payload *models.APIError `json:"body,omitempty"`
}
// NewLoginDefault creates LoginDefault with default headers values
@@ -92,13 +92,13 @@ func (o *LoginDefault) SetStatusCode(code int) {
}
// WithPayload adds the payload to the login default response
func (o *LoginDefault) WithPayload(payload *models.Error) *LoginDefault {
func (o *LoginDefault) WithPayload(payload *models.APIError) *LoginDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the login default response
func (o *LoginDefault) SetPayload(payload *models.Error) {
func (o *LoginDefault) SetPayload(payload *models.APIError) {
o.Payload = payload
}

Some files were not shown because too many files have changed in this diff Show More