Compare commits

...

166 Commits

Author SHA1 Message Date
Daniel Valdivia
b21aceed7b Release v0.11.0 (#1131)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-20 13:26:21 -07:00
Lenin Alevski
3b82079b8c Adding additional fields for openid configuration (#1132)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-20 11:33:07 -07:00
Klaus Post
854468a713 Return parseable error on S3 requests (#1120)
Return S3 compatible error when an S3 API request is made to the console port.

Before:
```
λ mc ls local9090
mc: <ERROR> Unable to list folder. XML syntax error on line 1: invalid character entity &display (no semicolon)
```

After:
```
λ mc ls local9090
mc: <ERROR> Unable to list folder. S3 API Request made to Console port. S3 Requests should be sent to MinIO API port.
```
2021-10-20 02:18:16 -07:00
Daniel Valdivia
1d69024e3a Add Help Box to multiple Screens (#1129) 2021-10-19 19:15:58 -07:00
Alex
67082e1b1d Fixed file download in list (#1130)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-10-19 18:57:07 -07:00
Lenin Alevski
95f622a597 fix: more fixes related to object name encoding (#1128)
- removing limitation of characters for paths/folders
- fixed object names with international characters inside paths

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-19 19:42:59 -05:00
Daniel Valdivia
37d7f0025b Remove tabs on Settings (#1127)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 17:14:59 -05:00
Daniel Valdivia
137170521c Limit add Tier and Add Notification Endpoint width (#1125)
* Limit add Tier and Add Notification Endpoint width

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

* Backlink component

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 13:12:13 -07:00
Daniel Valdivia
ba9f4d094b Fix base64 encoded prefix received on the server side for chinese characters (#1126)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 13:00:13 -07:00
Lenin Alevski
c62fecbac1 Fixes object name encoding/decoding crashing because of weird characters (#1124)
Fixes uploading, listing and managing objects with characters outside of
Latin1 range in file name

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-19 14:19:06 -05:00
Daniel Valdivia
3d858ac04a Limit Max Width of all containers to 1180px (#1123)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 12:47:28 -05:00
David Regla
573049e53c Add some missing config keys to settings panel (#1064)
Added missing keys: api, heal, scanner. Some 'api' keys were left out. Didn't add identity_tls as it isn't always available
2021-10-19 12:30:06 -05:00
Daniel Valdivia
9625d4679c Remove Review Step on Add Tenant (#1121)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 10:23:11 -07:00
Daniel Valdivia
790c6b0e2f Fix License Page Styles (#1122)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-19 10:16:29 -07:00
Lenin Alevski
ff433549b6 Operator-UI security context configuration (#1089)
- fix: check all pages are valid in  Add tenant wizard before enabling
  Create button
- Added: security context menu configuration for MinIO, logsearch api,
  postgres, prometheus and KES

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-19 09:42:36 -07:00
Daniel Valdivia
ccebc17f3f Fix Loading Quota stuck spinner (#1117)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-18 13:22:08 -07:00
Lenin Alevski
7c82306cc0 Fix: download objects and delete tags for object browser (#1118)
- fixed: download object from object browser fails because of file name
  not encoded in request
- fixed: deleting tags for object fails

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-18 13:05:10 -07:00
Alex
4d458c4f8c Updated Tiers module to be its own page (#1113)
Also refactored & did some cleanup in the code

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-15 12:35:04 -07:00
Alex
aadc66a739 Changed styles for range date selector in Prometheus dashboard (#1111)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-10-15 11:53:55 -07:00
Daniel Valdivia
ed73d99590 Make Lambda Notification Targets a page (#1105)
* Make Lambda Notification Targets a page

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

* Error messasge tweak

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

* Updated test cases

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-10-13 12:37:32 -07:00
Lenin Alevski
410b4555e3 Refactor session token (#1109)
- Update operator dependency
- Don't store policy on session token, instead obtain it during session
  validation

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-10-12 21:25:02 -07:00
Daniel Valdivia
2cae87aaed Release v0.10.4 (#1108)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-12 16:41:25 -07:00
Harshavardhana
b82441813d update to new minio/pkg v1.1.5 (#1107)
this update fixes dropping valid statements
as duplicates during iampolicy.ParseConfig()

fixes situations when users have overlapping
policies, then server should apply both
policies together.
2021-10-12 16:21:13 -07:00
Daniel Valdivia
5dfba3f6c8 Fix Broken Hop Cookies (#1106)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-12 14:35:12 -07:00
jinapurapu
1b9902a5be Prevent adding user with access key already in use (#1103)
* Release v0.10.3 (#1098)

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

WIP check if accesskey exists before adding user

* Added error when duplicate access key attempted

* Removed unneeded code

* Changed api to getUserInfo

* Corrected error messages

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-12 11:18:56 -07:00
Alex
d6944ccd3b Added zoom option to line charts & bar charts in prometheus dashboard (#1104) 2021-10-11 19:17:18 -07:00
Alex
ebaa1947de Changed number representations in Prometheus dashboard (#1101)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-10-11 12:32:27 -07:00
Daniel Valdivia
9d61af7060 Release v0.10.3 (#1098)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-05 13:00:12 -07:00
Daniel Valdivia
1b225e0901 fix: broken STS Sessions with large policies (#1096)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-10-04 14:25:00 -07:00
Alex
7a864d2631 Changed error modal snackbar (#1093)
Changed error modal snackbar to use a simplified style of global error snackbar. also fixed an issue where error was persistent if you closed the modalbox with an error present

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-30 09:25:34 -07:00
Daniel Valdivia
dfca19092a Dashboard Tweaks (#1091)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-28 16:36:59 -07:00
Alex
61cf397a02 Loaded correct version of the file for sharing (#1090)
Loaded correct version of the file for sharing when undefined is received in share window, this fixes an issue with objects list where non version was retrieved from backend

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-28 16:28:02 -07:00
Daniel Valdivia
d31528e2b5 Uptime Icon (#1088)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-09-28 16:23:25 -07:00
Alex
8fd1e0db9c Fixed widgets overlaps & some style adjustments in Dashboard (#1087)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-28 14:51:38 -05:00
Lenin Alevski
3d27cd2bd3 Multiple fixes for sub path and objects filename encoding (#1086)
- fix: objects with special characters (ie: /,&,%,*) won't open
- fix: create subdolders with special characters won't work, ie: /,&,%,*
- fix: view subfolders with special characters (ie: /,&,%,*) won't work
- refactor: browser breadcrumb
- fix: rewind enable/disable toggle button not working
- fix: undefined style for add bucket button in buckets page
- Added: validation for folder path naming
- refactor: encode prefix parameter using base64 to avoid url encode
  issues
- fix: share link for versioned object won't work because of wrong
  version_id

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-09-28 12:25:28 -07:00
Daniel Valdivia
2269af829f Release v0.10.2 (#1085)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-27 12:39:54 -07:00
Alex
8658ac2914 Improved the Share File modal (#1083) 2021-09-25 01:00:32 -07:00
Alex
19f034adf4 Embedded lato font in console project & removed google fonts dependency (#1080)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-24 14:27:05 -05:00
Alex
3034803054 Console portal-ui improvements (#1079)
- Updated dependencies in yarn lock

- Quick common card adjustment

- Warnings cleanup

- Updated assets

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-24 14:22:01 -05:00
Ravind Kumar
403f8caa8b Minor Typo Fix (#1081) 2021-09-24 09:29:06 -05:00
Alex
cb886f0130 Updated styles in Prometheus dashboard (#1078)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-23 10:01:56 -07:00
Daniel Valdivia
951a041bc5 Release v0.10.1 (#1076)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-22 16:08:06 -07:00
Lenin Alevski
8d203f4797 Case insensitive search for list objects (#1077)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-09-22 14:31:01 -07:00
Daniel Valdivia
401a051b8e Object Details Loading + NPE (#1075)
* Object Details Loading + NPE

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

* remove commented line

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-22 12:10:50 -07:00
Harshavardhana
2e300dba7d support multisite replication setup (#1072) 2021-09-22 12:04:27 -07:00
Daniel Valdivia
4cdb862ae6 Fix folder icon (#1074)
* Compute Pool Fields on Refresh

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

* Fix Folder Icon

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

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-09-22 11:44:58 -07:00
Lenin Alevski
e6f4ac1e6c Adds Azure support for KES configuration in operator-ui (#1070)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-21 20:56:07 -07:00
Lenin Alevski
137ff41be2 Display detailed errors when login fails (#1069)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-21 20:48:24 -07:00
Daniel Valdivia
e7665fae85 Compute Pool Fields on Refresh (#1067)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-09-21 20:40:40 -07:00
Harshavardhana
4b262f2a89 turn-off prefix-usage information per account for console (#1071) 2021-09-21 18:57:38 -07:00
dependabot[bot]
4ab1cf1bf2 Bump tmpl from 1.0.4 to 1.0.5 in /portal-ui (#1068)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  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: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-21 17:49:52 -07:00
Harshavardhana
27689a17f3 change server side uploader to fully streaming based (#1066)
this PR fixes the behavior to avoid `/tmp` folder as
staging directory for large uploads, instead rely on
the client upload stream itself to upload the object
entirely.
2021-09-21 17:43:43 -07:00
Lenin Alevski
2b6d5e5128 Fix oauth flow and remove go-oidc library (#1063)
- Update transport to use the same from Console in IDP Auth
- Validate provided idp URL

Co-authored-by: Harshavardhana <harsha@minio.io>
Signed-off-by: Ricardo Katz <rkatz@vmware.com>
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Ricardo Katz <rkatz@vmware.com>
Co-authored-by: Harshavardhana <harsha@minio.io>
2021-09-20 16:13:16 -07:00
Daniel Valdivia
64e38ca8d3 List buckets re-design (#1058)
* New Bucket Listing

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

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-09-20 11:13:34 -07:00
Lenin Alevski
d85b693751 Add share action to listed objects (#1052)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-09-20 10:42:50 -05:00
Harshavardhana
00752d2bb1 use cluster endpoint API to detect erasure coded setup (#1057) 2021-09-17 23:11:28 -07:00
Daniel Valdivia
4cc57fe440 Browser Theme Styling (#1056)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-17 19:23:00 -07:00
Minio Trusted
4c16789bab rename use_buildx -> use: buildx 2021-09-16 10:48:57 -07:00
Alex
2ade4ca1cf Added New styles to Dashboard (#1054)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-16 09:43:37 -07:00
Daniel Valdivia
52ee9bb49b Reactive Tenant Details and Summary (#1051)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-15 21:11:46 -07:00
Daniel Valdivia
c93f1ba564 Release v0.10.0 (#1049)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-14 16:32:39 -07:00
Harshavardhana
b6f818bdd3 fix: add support for userInfo endpoint (#1048)
With support for GitLab OpenID service,
we need to make sure to support userInfo
endpoint for this MinIO server requires that
access_token is additionally sent along with
id_token as before to make sure we can fetch
additional claims from /userinfo endpoint.

This PR brings support on console for this
feature.

Refer https://github.com/minio/minio/pull/12469
2021-09-14 16:16:29 -07:00
Lenin Alevski
77eff6ce91 Additional image, music and video file formats for object preview (#1047)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-14 15:39:51 -07:00
Daniel Valdivia
15a9e72192 File Type Icons (#1046)
* File Type Icons

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

* One more font extension

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

* Fix FileZipIcon

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-14 15:33:03 -07:00
Daniel Valdivia
9f070d9ebb Fix Users with + in the name (#1045)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-14 15:23:38 -07:00
Daniel Valdivia
2077004bd3 Release v0.9.9 (#1042)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-14 09:06:51 -07:00
Harshavardhana
9067e85b55 fix: TLS issues with console (#1043)
This PR fixes two bugs one is

- incorrect termination of the HTTP connections
  when the resource URL path is `/`, since `/`
  doesn't exist we should never call h.ServeHTTP()
  instead should be directly served from public assets.

- add SSLHostFunc() such that if the Hostname is empty
  redirection is not empty and this value is handled
  properly when redirecting from 9090 to 9443.

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 20:09:19 -07:00
Daniel Valdivia
c30f1cee92 Policies Routing Wildcard (#1041)
* Policies Routing Wildcard

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

* Remove Console.log

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 18:08:02 -07:00
Daniel Valdivia
a060ddbef2 Collapsed Menu Icon (#1040)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 18:01:55 -07:00
adfost
8f202ef5a4 Allow set policy to none (#1039)
* policy bug fix

* rename button

Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
2021-09-13 17:46:09 -07:00
Daniel Valdivia
0fdf5ee0fc Add Tenant in non-linear way (#1027)
* Add Tenant in non-linear way

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 16:00:44 -07:00
Daniel Valdivia
875647577a Dashboard MinIO Version Icon (#1037)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 17:29:19 -05:00
Daniel Valdivia
46d504cddc Integration Test (#1012)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 12:45:54 -07:00
Lenin Alevski
27ac6db99a Preview WEBM files on object details (#1033)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-13 11:40:12 -07:00
Harshavardhana
3c8de3a8cf update prometheus request_total/request_errors dashboard queries (#1032) 2021-09-12 23:07:35 -07:00
adfost
e6086afdbe adding volumes page (#1019) 2021-09-10 21:13:30 -07:00
Daniel Valdivia
59f5f6a9f0 Default background color (#1030)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-10 22:44:23 -05:00
Daniel Valdivia
67b0261b0b Make Menu Collapsable (#1025) 2021-09-10 18:33:50 -07:00
Daniel Valdivia
e104c4a48e Fix Endpoints for Object Browser (#1028)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-10 16:31:41 -07:00
Alex
ba051dfb7d Added verification to server & drive cards for missing fields (#1022)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-10 16:14:24 -07:00
Harshavardhana
c26928516d fix: leaking fd's large object uploads (#1026)
Fixes multiple things

- Closes the local open files properly staged
  during multipart form upload.

- Removes these files upon upload properly, otherwise
  we run out of disk space on /tmp/ due to staging
  of these objects.

Co-authored-by: Minio Trusted <trusted@minio.io>
2021-09-10 14:36:58 -07:00
Daniel Valdivia
4135b27cfd Menu Re-Design Part 1 (#1021)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-09 16:45:37 -07:00
Alex
755e0b49e9 Cleanup of non used icons (#1018)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-09 11:41:33 -07:00
Alex
605f4d4a62 Object browser migrated into bucket details (#1017)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-09-09 12:39:03 -05:00
Daniel Valdivia
33acf45264 Release v0.9.8 (#1016)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-08 13:38:29 -07:00
jinapurapu
f229fee3ee Added version card to BasicDashboard (#1013)
* Added version card to BasicDashboard

* Added length check for servers array on version card render

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-09-08 11:38:32 -07:00
Bian Jiaping
21b3ed67af Eliminate usage of String.prototype.replaceAll to avoid incompatibility with old browsers (#1015) 2021-09-08 10:58:37 -07:00
Alex
90cadc76bb Applied workaround for MIME issue on windows (#1014) 2021-09-07 17:57:00 -07:00
Daniel Valdivia
b13b6db6f7 Share Icon updated (#1008) 2021-09-07 17:48:34 -05:00
adfost
1d88bb491d Disable create service account button if no policy (#1006)
* disable button if no policies

* merge fix

* finding group policies

* fixing style

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-09-07 15:02:04 -07:00
Daniel Valdivia
13cf3e6fa1 Release v0.9.7 (#1010)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-04 22:58:44 -07:00
Daniel Valdivia
50c1fe8298 Fix NPE on ServerInfoCard (#1009)
* Fix NPE on ServerInfoCard

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

* missing import

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-04 21:37:53 -07:00
Daniel Valdivia
39eeedec2c Add, Preview and Lock icons applied (#1005)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-03 12:37:53 -07:00
Daniel Valdivia
0f2a09d5f1 Release v0.9.6 (#1004)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-01 22:43:45 -05:00
Daniel Valdivia
6cf657a0e1 Add support for additional images (#1003)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-01 20:23:56 -07:00
Daniel Valdivia
1ba2627810 Two Column Basic Dashboard (#1002)
* Two Column Basic Dashboard

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

* Change title

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

* Remove Flex Grow

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-01 19:23:25 -07:00
Minio Trusted
1ab37e0b00 fix: update assets refresh 2021-09-01 17:53:55 -07:00
Alex
63dac87a75 misc small fixes warnings and imports (#1001) 2021-09-01 17:37:53 -07:00
jinapurapu
7bf3a6e3f1 Basic dashboard drives (#998)
* Added Disk properties to admin_info

* Added Disk properties to admin_info

* Created DriveInfo cards

* Fixed drive card formatting

* Added Disk properties to admin_info

Created DriveInfo cards

Added Disk properties to admin_info

Fixed drive card formatting

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-01 17:07:15 -07:00
Daniel Valdivia
2fd4be91ad Fix Navigation when reloading on a virtual path (#1000)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-09-01 16:56:06 -07:00
Alex
296129db02 File details preview (#997)
* Added support to object browser for file preview

* Added preview file content in object details

* Added support to object browser for file preview (#995)

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Jill <jill@minio.io>
2021-09-01 15:14:58 -07:00
Daniel Valdivia
5ece5ba8a7 Upscaled Icons (#996) 2021-09-01 17:09:26 -05:00
Lenin Alevski
96e9bce331 fix: Check if console is deployed with external certs for metrics proxy (#999)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-09-01 13:40:16 -07:00
Alex
ddd4ab54a7 Added support to object browser for file preview (#995) 2021-09-01 10:39:17 -07:00
adfost
849132fa19 Adding accesskey and secretkey for service accounts (#985)
* adding accesskey and secretkey for service accounts

* simplifying functions

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
2021-09-01 11:54:13 -05:00
Kaan Kabalak
d23a7a4fba Fix error not being displayed on faulty upload (#991) 2021-08-30 23:12:53 -05:00
Daniel Valdivia
af2a64d0d2 Fix icon for object browser and download icon (#989)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-30 12:43:16 -05:00
Alex
6cb8c51754 Restructured basic dashboard elements (#988)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-08-27 12:59:41 -05:00
Alex
48313d6cd9 Removed prometheus URL from error responses to avoid data leak (#986) 2021-08-26 14:36:57 -07:00
jinapurapu
bb8460a118 Created ServerInfoCard element (#984) 2021-08-26 12:22:46 -07:00
Daniel Valdivia
3e55683c2c Release v0.9.5 (#983) 2021-08-25 22:20:49 -07:00
Alex
d86fc2f73c Add missing slash for some API calls (#982) 2021-08-25 16:27:38 -07:00
Daniel Valdivia
24a2edf6a3 Implement New Icons (#981)
* Implement New Icons

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

* Update portal-ui/src/icons/TenantsOutlineIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/LicenseIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/screens/Console/Common/TableWrapper/TableActionButton.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/StorageIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/screens/Console/Common/TableWrapper/TableActionButton.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/IAMPoliciesIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/IAMPoliciesIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/IAMPoliciesIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/IAMPoliciesIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/icons/IAMPoliciesIcon.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>

* Update portal-ui/src/screens/Console/Common/TableWrapper/TableActionButton.tsx

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-25 14:56:59 -07:00
Lenin Alevski
07bef3280d Remove ConsoleImage references (#980)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-08-25 11:23:11 -07:00
Daniel Valdivia
fa465d0ef3 Release v0.9.4 (#979)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-24 17:01:01 -07:00
adfost
1f1537fd60 access rule delete bug fix (#978)
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
2021-08-24 16:22:47 -07:00
Daniel Valdivia
597855364c Fix Bug Deleting Tenant PVCs (#977)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-24 16:01:25 -07:00
jinapurapu
4306d0f661 Added Server Info array to Basic dashboard (#963)
* Added Servers array to admin_info api

* Added TableWrapper, wrap

* Created Server table

* Added Servers array to admin_info api

Added TableWrapper, wrap

Created Server table

* Removed testing element

* Formatted server uptime with niceDays

* Added Servers array to admin_info api

Added TableWrapper, wrap

Created Server table

* Removed testing element

* Formatted server uptime with niceDays

* Formatted uptime using niceDays

* Sorted server table by endpoint

Co-authored-by: Harshavardhana <harsha@minio.io>
2021-08-24 11:13:26 -07:00
Daniel Valdivia
4c01be21ca Release v0.9.3 (#974)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-23 23:29:48 -07:00
adfost
7ec391b6e0 Add user service account (#966)
* add user service account

* changing API

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-23 21:36:55 -07:00
Daniel Valdivia
8c82124a57 Prometheus Security Context (#973)
* Prometheus Security Context

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

* Missing files

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-23 21:06:32 -07:00
Lenin Alevski
0ae0338a8f Delete Postgres & Prometheus PVCs (#972)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-08-23 14:09:21 -07:00
Harshavardhana
e05c724553 fix: probe content-type before upload (#968) 2021-08-23 12:59:04 -05:00
Daniel Valdivia
deda36a8b5 Fix Add Buckets button on Object Browser (#970)
* Fix Add Buckets button on Object Browser

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

* Comments

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

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-23 10:23:36 -07:00
Daniel Valdivia
d32ab25ffd Add missing Delete Pods roles for console-sa (#969)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-22 22:14:01 -05:00
Daniel Valdivia
2332a13477 Release v0.9.2 (#960) 2021-08-18 14:31:03 -07:00
adfost
c417cc31c8 Edit access rules (#959)
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-18 13:58:18 -07:00
Lenin Alevski
ec47df3cc1 Multiple fixes for operator-ui (#948)
- fix: create tenant from operator-ui was broken due to migration from
  standalone console to embedded console
- fix: refresh, activate and attach license in subscription page was
  broken
- fix: tenant usage report in operator-ui
- fix: show tenant encryption enabled if MINIO_KMS_SECRET_KEY is present

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-08-18 13:23:03 -07:00
Alex
a09be99ae6 Changed labels in create folder modal / button (#958)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-08-17 14:52:15 -07:00
Daniel Valdivia
2debb11f03 Release v0.9.1 (#957)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-17 13:39:28 -07:00
Alex
ba3a0d6cd6 Added pre validation of prometheus URL (#956)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
2021-08-17 12:02:42 -07:00
adfost
4e8763995e Access Rules for bucket (#941)
* access rules

* separate DELETE API call

Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
2021-08-16 19:41:35 -07:00
Alex
dfe7e5aa58 Removed warnings from code (#955)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-16 17:47:45 -05:00
Daniel Valdivia
d2ed375efb Policy Details Update to look like the rest (#946)
* Policy Details Update to look like the rest

* Clear imports

* Address comments

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-16 15:10:07 -07:00
Daniel Valdivia
cabb60bd3f Remove Dupplicate Swagger definitions (#954)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-16 16:07:18 -05:00
Harshavardhana
0980bd38e7 use proper TLS transport for prometheus, log_search (#951) 2021-08-16 12:09:03 -07:00
Daniel Valdivia
6e1a23e0d6 Release v0.9.0 (#944) 2021-08-12 12:17:56 -07:00
Daniel Valdivia
6ea1d51913 New Page Title Look (#940)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-12 09:52:28 -07:00
Alex
4369e6e779 Adjusted Tenants wizard main height (#937)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-08-09 22:55:30 -07:00
Harshavardhana
79a476712f fix: handle crash in retention handler for object locked buckets (#936) 2021-08-09 23:23:40 -05:00
Daniel Valdivia
4e38a54dd8 Remove Console Field from Operator UI (#931)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-09 15:54:18 -07:00
Daniel Valdivia
33610a5269 Logos as React Components (#935)
* Select policies while creating new user

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

* Fix add user error

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

* Fix tests

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

* Logo as React Components

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-09 11:53:34 -07:00
Daniel Valdivia
a5a8d2ef62 Select policies while creating new user (#928)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-06 16:41:38 -07:00
Lenin Alevski
d357ef9bcb fix: proxy has to read credentials from configuration secret (#929)
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-08-05 21:17:28 -05:00
Daniel Valdivia
3952ab0c4b Prepare Release v0.8.3 (#926)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-05 11:49:03 -07:00
adfost
c41c532d0f bug fix (#919)
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
2021-08-04 12:01:41 -07:00
Daniel Valdivia
023622d95e Fix mixed buttons (#925)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-04 11:55:54 -07:00
Daniel Valdivia
e5dc8fea3a Fix Hop File Upload and Query Params (#920)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-04 11:37:45 -07:00
Lenin Alevski
56436f20e2 Operator Console bug fixes and MinIO configuration file support (#898)
- Added support for MinIO configuration file
- fix: tenant deployment with oidc integration
- fix: tenant deployment with ldap integration
- fix: certificate parsing for domains and IP addresses on security tab
- fix: console certificate upload was not working

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-08-03 17:36:26 -07:00
Daniel Valdivia
fcb74aee77 Fix Node Number validation (#918)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-03 11:18:51 -05:00
Daniel Valdivia
7e4d34958e Release v0.8.2 (#917)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-02 11:40:02 -07:00
adfost
9d6ee7f9b0 Changing error for too few nodes (#899)
* changing error

* change variable name

Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
Co-authored-by: Adam Stafford <adamstafford@Adams-MacBook-Pro.local>
Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-02 11:33:15 -07:00
Daniel Valdivia
aa16e75b39 Update Tenant Details and Fix Warnings (#915)
* Update Tenant Details and Fix Warnings

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

* Storage

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-08-02 10:50:41 -07:00
Alex
283a00bde2 Added custom metadata to object details (#914)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-08-02 10:20:29 -07:00
Daniel Valdivia
0c78359832 Tabs to Lists for Configurations, Policy (#913)
* Tabs to Lists for Configurations, Policy

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

* Fix Tests

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

* Logs

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-30 17:01:55 -07:00
Minio Trusted
ac7cefde39 update to v0.8.1 2021-07-29 14:58:36 -07:00
Daniel Valdivia
4f7f81bfb0 Improve error handling on proxy (#911)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

Co-authored-by: Lenin Alevski <alevsk.8772@gmail.com>
2021-07-29 12:48:24 -07:00
Daniel Valdivia
64154cae38 Fix Bug Delete Folder (#912)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-29 12:18:50 -07:00
Daniel Valdivia
1689a73809 Tenant Details Tabs (#910)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-29 11:12:49 -07:00
Alex
e20ef0cfb8 Display Retention Policy details inside bucket details (#905) 2021-07-29 10:37:33 -07:00
Daniel Valdivia
e6dec7aa46 Style Background (#909)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-29 12:27:05 -05:00
Alex
efae5f6ae2 Enforced error type (#904)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-07-28 18:09:48 -07:00
Daniel Valdivia
988958f131 Redesigned Bucket Details. User Details. Account Screen. Login Error. (#903)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-28 17:53:53 -05:00
Alex
13844e10f8 Added new implementation for error handling (#901)
Now errors will display detailed information, modal box errors will prioritize detailed errors
2021-07-27 23:27:27 -07:00
Daniel Valdivia
87917e618c Fix bug not allowing to add webhooks (#900)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
2021-07-27 23:26:54 -07:00
Alex
a2cde72347 Returned full error to browser. (#897)
This is first step of new error handling. UI rework will be done

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2021-07-26 16:25:55 -07:00
613 changed files with 136618 additions and 18728 deletions

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.16.x]
go-version: [1.16.x, 1.17.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}

39
.github/workflows/integration.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Go
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build:
name: Integration Tests with Latest Distributed MinIO
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.16.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Build on ${{ matrix.os }}
env:
GO111MODULE: on
GOOS: linux
CGO_ENABLED: 0
run: |
wget -O /tmp/minio https://dl.minio.io/server/minio/release/linux-amd64/minio
chmod +x /tmp/minio
mkdir -p /tmp/certs-dir
/tmp/minio server --quiet -S /tmp/certs-dir /tmp/fs{1...4} &
go test github.com/minio/console/integration/...

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.16.x]
go-version: [1.16.x, 1.17.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}

View File

@@ -86,7 +86,7 @@ nfpms:
dockers:
- image_templates:
- "minio/console:{{ .Tag }}-amd64"
use_buildx: true
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
@@ -97,7 +97,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-ppc64le"
use_buildx: true
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
@@ -108,7 +108,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-s390x"
use_buildx: true
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
@@ -119,7 +119,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "minio/console:{{ .Tag }}-arm64"
use_buildx: true
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release
@@ -131,7 +131,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-amd64"
use_buildx: true
use: buildx
goarch: amd64
dockerfile: Dockerfile.release
extra_files:
@@ -142,7 +142,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-ppc64le"
use_buildx: true
use: buildx
goarch: ppc64le
dockerfile: Dockerfile.release
extra_files:
@@ -153,7 +153,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-s390x"
use_buildx: true
use: buildx
goarch: s390x
dockerfile: Dockerfile.release
extra_files:
@@ -164,7 +164,7 @@ dockers:
- "--build-arg=TAG={{ .Tag }}"
- image_templates:
- "quay.io/minio/console:{{ .Tag }}-arm64"
use_buildx: true
use: buildx
goarch: arm64
goos: linux
dockerfile: Dockerfile.release

View File

@@ -1,61 +0,0 @@
## PostgreSQL related variables
# Postgres Docker image
POSTGRES_IMAGE=library/postgres
# Postgres user
POSTGRES_USER=postgres
# Postgres password
POSTGRES_PASSWORD=magical_password
# Postgres port number
POSTGRES_PORT=5432
# Postgres data directory
PGDATA=/data/postgres
## Logsearch related variables
# Logsearch Docker image
LOGSEARCH_IMAGE=minio/logsearchapi:v4.1.2
# Logsearch storage max
LOGSEARCH_DISK_CAPACITY_GB=5
# Logsearch port number
LOGSEARCH_PORT=8080
# Log retention duration
LOGSEARCH_MAX_RETENTION_MONTHS=1
# Logsearch audit authentication token
LOGSEARCH_AUDIT_AUTH_TOKEN=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
# Logsearch query authentication token
LOGSEARCH_QUERY_AUTH_TOKEN=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
## Console related variables
# Console Docker image
CONSOLE_IMAGE=minio/console:v0.8.0
# Salt to encrypt JWT payload
CONSOLE_PBKDF_PASSPHRASE=top_secret
# Required to encrypt JWT payload
CONSOLE_PBKDF_SALT=top_secret1
# MinIO Server URL
CONSOLE_MINIO_SERVER=http://localhost:9000
## Prometheus related variables
# Prometheus Docker image
PROMETHEUS_IMAGE=prom/prometheus:latest
# Prometheus port number
PROMETHEUS_PORT=9999

View File

@@ -1,64 +0,0 @@
## Console Docker Compose
This compose file allows users to quickly deploy MinIO Console, LogSearch & Prometheus in a baremetal (non Kubernetes) environment.
### Pre-requisites
1. [MinIO](https://docs.minio.io/docs/distributed-minio-quickstart-guide.html) cluster up and running.
2. [mc](https://docs.minio.io/docs/minio-client-quickstart-guide.html) configured for this MinIO cluster.
3. [Docker-Compose](https://docs.docker.com/compose/) installed on the server.
### Getting Started
- Download the contents of `compose` directory on your machine.
- Edit the `prometheus.yaml` file and fill in the correct target (MinIO Endpoint). Optionally setup the `bearer_token` as explained [here](https://github.com/minio/minio/tree/master/docs/metrics/prometheus#31-authenticated-prometheus-config).
- Setup a console admin policy.
```sh
cat > admin.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"admin:*"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
}
EOF
```
Then create this policy on MinIO server: `mc admin policy add myminio consoleAdmin admin.json`.
- Setup user and policy for Console
```
mc admin user add myminio console console123
mc admin policy set myminio consoleAdmin user=console
```
- Configure Webhook target on the MinIO server. Remember to change the `token` value in below URL to the actual token value as set in the `.env` file.
```
mc admin config set myminio audit_webhook:1 endpoint=http://localhost:8080/api/ingest?token=c6rkqjZ03ElEUKQ7MtSeYBJ8q_p3GDFPBQAQJlcbBLA=
mc admin service restart myminio
```
### Configuration
To configure the Console Compose file to custom setup, please take a look at the [`.env`](./.env) file.

View File

@@ -1,62 +0,0 @@
version: '3.4'
services:
pg_database:
image: ${POSTGRES_IMAGE}
network_mode: host
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- PGDATA=${PGDATA}
- POSTGRES_DB=minio_logs
volumes:
- database:${PGDATA}
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
log_search:
image: ${LOGSEARCH_IMAGE}
network_mode: host
environment:
- LOGSEARCH_AUDIT_AUTH_TOKEN=${LOGSEARCH_AUDIT_AUTH_TOKEN}
- LOGSEARCH_QUERY_AUTH_TOKEN=${LOGSEARCH_QUERY_AUTH_TOKEN}
- LOGSEARCH_DISK_CAPACITY_GB=${LOGSEARCH_DISK_CAPACITY_GB}
- LOGSEARCH_MAX_RETENTION_MONTHS=${LOGSEARCH_MAX_RETENTION_MONTHS}
- LOGSEARCH_PG_CONN_STR=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/minio_logs?sslmode=disable
ports:
- ${LOGSEARCH_PORT}:${LOGSEARCH_PORT}
command: ["/usr/bin/wait-for-it.sh", "localhost:${POSTGRES_PORT}", "--", "/logsearchapi"]
volumes:
- ./wait-for-it.sh:/usr/bin/wait-for-it.sh
depends_on:
- pg_database
console:
image: ${CONSOLE_IMAGE}
network_mode: host
environment:
- CONSOLE_PBKDF_PASSPHRASE=${CONSOLE_PBKDF_PASSPHRASE}
- CONSOLE_PBKDF_SALT=${CONSOLE_PBKDF_SALT}
- LOGSEARCH_QUERY_AUTH_TOKEN=${LOGSEARCH_QUERY_AUTH_TOKEN}
- CONSOLE_MINIO_SERVER=${CONSOLE_MINIO_SERVER}
- CONSOLE_LOG_QUERY_URL=http://localhost:${LOGSEARCH_PORT}
- CONSOLE_PROMETHEUS_URL=http://localhost:${PROMETHEUS_PORT}
ports:
- "9090:9090"
command: server
depends_on:
- log_search
- prometheus
prometheus:
image: ${PROMETHEUS_IMAGE}
network_mode: host
ports:
- ${PROMETHEUS_PORT}:${PROMETHEUS_PORT}
command:
- --config.file=/etc/prometheus/prometheus.yml
- --web.listen-address=:${PROMETHEUS_PORT}
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
volumes:
database:

View File

@@ -1,15 +0,0 @@
global:
scrape_interval: 10s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 30s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: minio-job
metrics_path: /minio/v2/metrics/cluster
scheme: http
static_configs:
- targets:
- 'localhost:9000'

View File

@@ -1,182 +0,0 @@
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi

14
go.mod
View File

@@ -5,7 +5,6 @@ go 1.16
require (
github.com/blang/semver/v4 v4.0.0
github.com/cheggaaa/pb/v3 v3.0.6
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/go-openapi/errors v0.19.9
github.com/go-openapi/loads v0.20.2
@@ -19,19 +18,18 @@ require (
github.com/minio/cli v1.22.0
github.com/minio/direct-csi v1.3.5-0.20210601185811-f7776f7961bf
github.com/minio/kes v0.11.0
github.com/minio/madmin-go v1.0.17
github.com/minio/madmin-go v1.1.6
github.com/minio/mc v0.0.0-20210626002108-cebf3318546f
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e
github.com/minio/operator v0.0.0-20210616045941-65f31f5f78ae
github.com/minio/operator/logsearchapi v0.0.0-20210604224119-7e256f98cf90
github.com/minio/pkg v1.0.8
github.com/minio/minio-go/v7 v7.0.14
github.com/minio/operator v0.0.0-20211011212245-31460bbbc4b7
github.com/minio/operator/logsearchapi v0.0.0-20211011212245-31460bbbc4b7
github.com/minio/pkg v1.1.5
github.com/minio/selfupdate v0.3.1
github.com/mitchellh/go-homedir v1.1.0
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/rs/xid v1.2.1
github.com/secure-io/sio-go v0.3.1
github.com/stretchr/testify v1.7.0
github.com/unrolled/secure v1.0.7
github.com/unrolled/secure v1.0.9
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
golang.org/x/net v0.0.0-20210421230115-4e50805a0758
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d

63
go.sum
View File

@@ -14,6 +14,7 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -196,8 +197,6 @@ github.com/cockroachdb/cockroach-go/v2 v2.0.3 h1:ZA346ACHIZctef6trOTwBAEvPVm1k0u
github.com/cockroachdb/cockroach-go/v2 v2.0.3/go.mod h1:hAuDgiVgDVkfirP9JnhXEfcXEPRKBpYdGz+l7mvYSzw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/container-storage-interface/spec v1.3.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -206,8 +205,6 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -416,6 +413,7 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
@@ -469,6 +467,8 @@ github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -553,6 +553,7 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
@@ -628,6 +629,7 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -876,10 +878,9 @@ github.com/minio/filepath v1.0.0 h1:fvkJu1+6X+ECRA6G3+JJETj4QeAYO9sV43I79H8ubDY=
github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEXx9T/Bw=
github.com/minio/kes v0.11.0 h1:8ma6OCVSxKT50b1uYXLJro3m7PmZtCLxBaTddQexI5k=
github.com/minio/kes v0.11.0/go.mod h1:mTF1Bv8YVEtQqF/B7Felp4tLee44Pp+dgI0rhCvgNg8=
github.com/minio/madmin-go v1.0.6/go.mod h1:BK+z4XRx7Y1v8SFWXsuLNqQqnq5BO/axJ8IDJfgyvfs=
github.com/minio/madmin-go v1.0.12/go.mod h1:BK+z4XRx7Y1v8SFWXsuLNqQqnq5BO/axJ8IDJfgyvfs=
github.com/minio/madmin-go v1.0.17 h1:VMEn4nMKf0X3uNH0u+fZcn17KSwVkQGwyER/igG556E=
github.com/minio/madmin-go v1.0.17/go.mod h1:4nl9hvLWFnwCjkLfZSsZXEHgDODa2XSG6xGlIZyQ2oA=
github.com/minio/madmin-go v1.1.6 h1:L53ALIbAilaEvuvMMT4XkJpd6mtaorkMBwCQ+zraYBA=
github.com/minio/madmin-go v1.1.6/go.mod h1:vw+c3/u+DeVKqReEavo///Cl2OO8nt5s4ee843hJeLs=
github.com/minio/mc v0.0.0-20210626002108-cebf3318546f h1:hyFvo5hSFw2K417YvDr/vAKlgCG69uTuhZW/5LNdL0U=
github.com/minio/mc v0.0.0-20210626002108-cebf3318546f/go.mod h1:tuaonkPjVApCXkbtKENHBtsqUf7YTV33qmFrC+Pgp5g=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
@@ -887,16 +888,18 @@ github.com/minio/md5-simd v1.1.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U=
github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v7 v7.0.11-0.20210302210017-6ae69c73ce78/go.mod h1:mTh2uJuAbEqdhMVl6CMIIZLUeiMiWtJR4JB8/5g2skw=
github.com/minio/minio-go/v7 v7.0.11-0.20210607181445-e162fdb8e584/go.mod h1:WoyW+ySKAKjY98B9+7ZbI8z8S3jaxaisdcvj9TGlazA=
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e h1:aVnxKPpUI1gVeEf9vC+QEt8OxMXiiNMeUWcrBM62oDU=
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
github.com/minio/operator v0.0.0-20210616045941-65f31f5f78ae h1:GONmqbjCi/KTEc1CGujnS/m1qeJeghcQ8dUBLh19qQo=
github.com/minio/operator v0.0.0-20210616045941-65f31f5f78ae/go.mod h1:8/mIXK+CFdL6VqyxRn1SwD+PEX0jsN8uqjoadaw/Np0=
github.com/minio/operator/logsearchapi v0.0.0-20210604224119-7e256f98cf90 h1:Qu6j6oE7+QNuq7Kr2DLyVYq3fqMdqFd/T8NAeNp47og=
github.com/minio/operator/logsearchapi v0.0.0-20210604224119-7e256f98cf90/go.mod h1:R+38Pf3wfm+JMiyLPb/r8OMrBm0vK2hZgUT4y4aYoSY=
github.com/minio/minio-go/v7 v7.0.14 h1:T7cw8P586gVwEEd0y21kTYtloD576XZgP62N8pE130s=
github.com/minio/minio-go/v7 v7.0.14/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
github.com/minio/operator v0.0.0-20211011212245-31460bbbc4b7 h1:dkfuMNslMjGoJ4ArAMSoQhidYNdm3SgzLBP+f96O3/E=
github.com/minio/operator v0.0.0-20211011212245-31460bbbc4b7/go.mod h1:lDpuz8nwsfhKlfiBaA3Z8AW019fWEAjO2gltfLbdorE=
github.com/minio/operator/logsearchapi v0.0.0-20211011212245-31460bbbc4b7 h1:vFtQqCt67ETp0JAkOKRWTKkgwFv14Vc1jJSxmQ8wJE0=
github.com/minio/operator/logsearchapi v0.0.0-20211011212245-31460bbbc4b7/go.mod h1:R+38Pf3wfm+JMiyLPb/r8OMrBm0vK2hZgUT4y4aYoSY=
github.com/minio/pkg v1.0.3/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
github.com/minio/pkg v1.0.4/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
github.com/minio/pkg v1.0.8 h1:lWQwHSeYlvnRoPpO+wS0I4mL6c00ABxBgbGjSmjwOi4=
github.com/minio/pkg v1.0.8/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
github.com/minio/pkg v1.0.11/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
github.com/minio/pkg v1.1.5 h1:phwKkJBQdVLyxOXC3RChPVGLtebplzQJ5jJ3l/HBvnk=
github.com/minio/pkg v1.1.5/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
github.com/minio/selfupdate v0.3.1/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
@@ -954,8 +957,9 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -969,8 +973,9 @@ github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54=
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -979,8 +984,9 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
@@ -1025,8 +1031,6 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.44.1/go.mod h1:3WYi4xqXxGGXWDdQIITnLNmuDzO5n6wYva9spVhR4fg=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.46.0/go.mod h1:3WYi4xqXxGGXWDdQIITnLNmuDzO5n6wYva9spVhR4fg=
github.com/prometheus-operator/prometheus-operator/pkg/client v0.46.0/go.mod h1:k4BrWlVQQsvBiTcDnKEMgyh/euRxyxgrHdur/ZX/sdA=
@@ -1062,8 +1066,9 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
@@ -1105,6 +1110,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada h1:WokF3GuxBeL+n4Lk4Fa8v9mbdjlrl7bHuneF4N1bk2I=
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/gopsutil/v3 v3.21.4/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/shirou/gopsutil/v3 v3.21.5/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/shirou/gopsutil/v3 v3.21.6 h1:vU7jrp1Ic/2sHB7w6UNs7MIkn7ebVtTb5D9j45o9VYE=
github.com/shirou/gopsutil/v3 v3.21.6/go.mod h1:JfVbDpIBLVzT8oKbvMg9P3wEIMDDpVn+LwHTKj0ST88=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
@@ -1208,10 +1214,12 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/unrolled/secure v1.0.7 h1:BcQHp3iKZyZCKj5gRqwQG+5urnGBF00wGgoPPwtheVQ=
github.com/unrolled/secure v1.0.7/go.mod h1:uGc1OcRF8gCVBA+ANksKmvM85Hka6SZtQIbrKc3sHS4=
github.com/unrolled/secure v1.0.9 h1:BWRuEb1vDrBFFDdbCnKkof3gZ35I/bnHGyt0LB0TNyQ=
github.com/unrolled/secure v1.0.9/go.mod h1:fO+mEan+FLB0CdEnHf6Q4ZZVNqG+5fuLFnP8p0BXDPI=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
@@ -1391,6 +1399,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@@ -1423,6 +1432,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1490,14 +1500,16 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe h1:WdX7u8s3yOigWAhHEaDl8r9G+4XwFQEQFtBMYyN+kXQ=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
@@ -1599,8 +1611,10 @@ golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -1633,6 +1647,7 @@ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1673,6 +1688,7 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
@@ -1715,7 +1731,6 @@ gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

5
iconos/Lambda.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="227.615" height="256" viewBox="0 0 227.615 256">
<g id="lambda-icn" transform="translate(-89.849 -94.42)">
<path id="Trazado_442" data-name="Trazado 442" d="M71.316,41.17a15.363,15.363,0,0,0,0,30.727c23.352,0,32.017,14.872,40.928,34.353l1.475,3.134c1.229,2.643,3.872,8.542,7.436,16.408L37.271,274.264A15.363,15.363,0,0,0,64,289.382l72.823-128.623c19.481,44,44,99.494,44.431,100.415A58.2,58.2,0,0,0,252.3,294.544a15.375,15.375,0,0,0-9.1-29.375,27.531,27.531,0,0,1-33.861-16.593c-2.458-5.531-59.856-135.751-67.6-152.282l-1.352-2.95C132.462,76.506,116.3,41.17,71.316,41.17Z" transform="translate(54.335 53.25)" fill="#020202"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 692 B

7
iconos/Tiers.svg Normal file
View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="236.312" height="256" viewBox="0 0 236.312 256">
<g id="tiers-icn" transform="translate(-34.003 -3)">
<g id="tiers" transform="translate(34.003 3)">
<path id="Trazado_441" data-name="Trazado 441" d="M122.387,3a9.847,9.847,0,0,0-5.154,1.308L8.925,66.851a9.847,9.847,0,0,0,0,17.039l33.4,19.289-33.4,19.289a9.847,9.847,0,0,0,0,17.058l33.4,19.27-33.4,19.289a9.847,9.847,0,0,0,0,17.058l108.308,62.54a9.847,9.847,0,0,0,9.846,0l108.308-62.54a9.847,9.847,0,0,0,0-17.058l-33.4-19.289,33.4-19.27a9.847,9.847,0,0,0,0-17.058l-33.4-19.289,33.4-19.289a9.847,9.847,0,0,0,0-17.039L127.079,4.311A9.847,9.847,0,0,0,122.387,3ZM62.041,114.563l55.192,31.866a9.847,9.847,0,0,0,9.846,0l55.192-31.866,28.5,16.443L122.156,182.16,33.54,131.006Zm-.02,55.617,55.212,31.866a9.847,9.847,0,0,0,9.846,0l55.212-31.866,28.481,16.443-88.615,51.155L33.54,186.622Z" transform="translate(-4 -3)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 942 B

340
integration/buckets_test.go Normal file
View File

@@ -0,0 +1,340 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package integration
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"testing"
"time"
"github.com/go-openapi/loads"
"github.com/minio/console/restapi"
"github.com/minio/console/restapi/operations"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
)
var token string
func initConsoleServer() (*restapi.Server, error) {
//os.Setenv("CONSOLE_MINIO_SERVER", "localhost:9000")
swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
if err != nil {
return nil, err
}
noLog := func(string, ...interface{}) {
// nothing to log
}
// Initialize MinIO loggers
restapi.LogInfo = noLog
restapi.LogError = noLog
api := operations.NewConsoleAPI(swaggerSpec)
api.Logger = noLog
server := restapi.NewServer(api)
// register all APIs
server.ConfigureAPI()
//restapi.GlobalRootCAs, restapi.GlobalPublicCerts, restapi.GlobalTLSCertsManager = globalRootCAs, globalPublicCerts, globalTLSCerts
consolePort, _ := strconv.Atoi("9090")
server.Host = "0.0.0.0"
server.Port = consolePort
restapi.Port = "9090"
restapi.Hostname = "0.0.0.0"
return server, nil
}
func TestMain(m *testing.M) {
// start console server
go func() {
fmt.Println("start server")
srv, err := initConsoleServer()
if err != nil {
log.Println(err)
log.Println("init fail")
return
}
srv.Serve()
}()
fmt.Println("sleeping")
time.Sleep(2 * time.Second)
client := &http.Client{
Timeout: 2 * time.Second,
}
// get login credentials
requestData := map[string]string{
"accessKey": "minioadmin",
"secretKey": "minioadmin",
}
requestDataJSON, _ := json.Marshal(requestData)
requestDataBody := bytes.NewReader(requestDataJSON)
request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/login", requestDataBody)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Content-Type", "application/json")
response, err := client.Do(request)
if err != nil {
log.Println(err)
return
}
if response != nil {
bodyBytes, _ := ioutil.ReadAll(response.Body)
loginResponse := models.LoginResponse{}
err = json.Unmarshal(bodyBytes, &loginResponse)
if err != nil {
log.Println(err)
}
token = loginResponse.SessionID
}
code := m.Run()
requestDataAdd := map[string]interface{}{
"name": "test1",
}
requestDataJSON, _ = json.Marshal(requestDataAdd)
requestDataBody = bytes.NewReader(requestDataJSON)
// get list of buckets
request, err = http.NewRequest("DELETE", "http://localhost:9090/api/v1/buckets/test1", requestDataBody)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
request.Header.Add("Content-Type", "application/json")
response, err = client.Do(request)
if err != nil {
log.Println(err)
return
}
if response != nil {
fmt.Println("DELETE StatusCode:", response.StatusCode)
}
os.Exit(code)
}
func TestAddBucket(t *testing.T) {
assert := assert.New(t)
client := &http.Client{
Timeout: 2 * time.Second,
}
requestDataAdd := map[string]interface{}{
"name": "test1",
"versioning": false,
"locking": false,
}
requestDataJSON, _ := json.Marshal(requestDataAdd)
requestDataBody := bytes.NewReader(requestDataJSON)
// get list of buckets
request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/buckets", requestDataBody)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
request.Header.Add("Content-Type", "application/json")
response, err := client.Do(request)
assert.Nil(err)
if err != nil {
log.Println(err)
return
}
if response != nil {
assert.Equal(201, response.StatusCode, "Status Code is incorrect")
}
}
func TestBucketVersioning(t *testing.T) {
assert := assert.New(t)
client := &http.Client{
Timeout: 2 * time.Second,
}
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/session", nil)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
response, err := client.Do(request)
assert.Nil(err)
if err != nil {
log.Println(err)
return
}
var distributedSystem bool
if response != nil {
bodyBytes, _ := ioutil.ReadAll(response.Body)
sessionResponse := models.SessionResponse{}
err = json.Unmarshal(bodyBytes, &sessionResponse)
if err != nil {
log.Println(err)
}
distributedSystem = sessionResponse.DistributedMode
}
requestDataVersioning := map[string]interface{}{
"name": "test2",
"versioning": true,
"locking": false,
}
requestDataJSON, _ := json.Marshal(requestDataVersioning)
requestDataBody := bytes.NewReader(requestDataJSON)
request, err = http.NewRequest("POST", "http://localhost:9090/api/v1/buckets", requestDataBody)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
request.Header.Add("Content-Type", "application/json")
response, err = client.Do(request)
assert.Nil(err)
if err != nil {
log.Println(err)
return
}
fmt.Println("Versioned bucket creation test status:", response.Status)
if distributedSystem {
assert.Equal(201, response.StatusCode, "Versioning test Status Code is incorrect - bucket failed to create")
} else {
assert.NotEqual(201, response.StatusCode, "Versioning test Status Code is incorrect - versioned bucket created on non-distributed system")
}
request, err = http.NewRequest("DELETE", "http://localhost:9090/api/v1/buckets/test2", requestDataBody)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
request.Header.Add("Content-Type", "application/json")
response, err = client.Do(request)
if err != nil {
log.Println(err)
return
}
if response != nil {
fmt.Println("DELETE StatusCode:", response.StatusCode)
}
}
func TestBucketsGet(t *testing.T) {
assert := assert.New(t)
client := &http.Client{
Timeout: 2 * time.Second,
}
// get list of buckets
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/buckets", nil)
if err != nil {
log.Println(err)
return
}
request.Header.Add("Cookie", fmt.Sprintf("token=%s", token))
response, err := client.Do(request)
assert.Nil(err)
if err != nil {
log.Println(err)
return
}
if response != nil {
assert.Equal(200, response.StatusCode, "Status Code is incorrect")
bodyBytes, _ := ioutil.ReadAll(response.Body)
listBuckets := models.ListBucketsResponse{}
err = json.Unmarshal(bodyBytes, &listBuckets)
if err != nil {
log.Println(err)
assert.Nil(err)
}
assert.Greater(len(listBuckets.Buckets), 0, "No bucket was returned")
assert.Greater(listBuckets.Total, int64(0), "Total buckets is 0")
}
}

71
integration/login_test.go Normal file
View File

@@ -0,0 +1,71 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package integration
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"testing"
"time"
"github.com/minio/console/models"
"github.com/stretchr/testify/assert"
)
func TestLoginStrategy(t *testing.T) {
assert := assert.New(t)
// image for now:
// minio: 9000
// console: 9090
client := &http.Client{
Timeout: 2 * time.Second,
}
// copy query params
request, err := http.NewRequest("GET", "http://localhost:9090/api/v1/login", nil)
if err != nil {
log.Println(err)
return
}
response, err := client.Do(request)
assert.Nil(err)
if err != nil {
log.Println(err)
return
}
if response != nil {
bodyBytes, _ := ioutil.ReadAll(response.Body)
loginDetails := models.LoginDetails{}
err = json.Unmarshal(bodyBytes, &loginDetails)
if err != nil {
log.Println(err)
}
assert.Nil(err)
assert.Equal(models.LoginDetailsLoginStrategyForm, loginDetails.LoginStrategy, "Login Details don't match")
}
}

View File

@@ -1,12 +0,0 @@
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: console-sa-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: console-sa-role
subjects:
- kind: ServiceAccount
name: console-sa
namespace: default

View File

@@ -1,222 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: console-sa-role
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- watch
- create
- list
- patch
- update
- deletecollection
- apiGroups:
- ""
resources:
- namespaces
- pods
- services
- events
- resourcequotas
- nodes
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- deletecollection
- list
- get
- watch
- update
- apiGroups:
- "storage.k8s.io"
resources:
- storageclasses
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- apps
resources:
- statefulsets
- deployments
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- batch
resources:
- jobs
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- "certificates.k8s.io"
resources:
- "certificatesigningrequests"
- "certificatesigningrequests/approval"
- "certificatesigningrequests/status"
verbs:
- update
- create
- get
- apiGroups:
- minio.min.io
resources:
- "*"
verbs:
- "*"
- apiGroups:
- min.io
resources:
- "*"
verbs:
- "*"
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- watch
- create
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- events
verbs:
- create
- list
- watch
- update
- patch
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshots
verbs:
- get
- list
- apiGroups:
- snapshot.storage.k8s.io
resources:
- volumesnapshotcontents
verbs:
- get
- list
- apiGroups:
- storage.k8s.io
resources:
- csinodes
verbs:
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- volumeattachments
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- volumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- direct.csi.min.io
resources:
- directcsidrives
- directcsivolumes
verbs:
- get
- list
- watch
- create
- update
- delete
- apiGroups:
- ""
resources:
- pod
verbs:
- get
- list
- watch

View File

@@ -1,7 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: console-env
data:
CONSOLE_PORT: "9090"
CONSOLE_TLS_PORT: "9443"

View File

@@ -1,26 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: console
spec:
replicas: 1
selector:
matchLabels:
app: console
template:
metadata:
labels:
app: console
spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.8.0
imagePullPolicy: "IfNotPresent"
args:
- server
ports:
- containerPort: 9090
name: http
- containerPort: 9433
name: https

View File

@@ -1,5 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: console-sa
namespace: default

View File

@@ -1,14 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: console
labels:
name: console
spec:
ports:
- port: 9090
name: http
- port: 9443
name: https
selector:
app: console

View File

@@ -1,11 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# beginning of customizations
resources:
- console-service-account.yaml
- console-cluster-role.yaml
- console-cluster-role-binding.yaml
- console-configmap.yaml
- console-service.yaml
- console-deployment.yaml
- https://github.com/minio/operator/?ref=v3.0.10

View File

@@ -19,7 +19,6 @@ rules:
- ""
resources:
- namespaces
- pods
- services
- events
- resourcequotas
@@ -30,6 +29,18 @@ rules:
- create
- list
- patch
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- watch
- create
- list
- patch
- delete
- deletecollection
- apiGroups:
- ""
resources:

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.8.0
image: minio/console:v0.11.0
imagePullPolicy: "IfNotPresent"
env:
- name: CONSOLE_OPERATOR_MODE

70
models/access_rule.go Normal file
View File

@@ -0,0 +1,70 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// AccessRule access rule
//
// swagger:model accessRule
type AccessRule struct {
// access
Access string `json:"access,omitempty"`
// prefix
Prefix string `json:"prefix,omitempty"`
}
// Validate validates this access rule
func (m *AccessRule) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this access rule based on context it is used
func (m *AccessRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *AccessRule) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AccessRule) UnmarshalBinary(b []byte) error {
var res AccessRule
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -44,6 +44,10 @@ type AddUserRequest struct {
// Required: true
Groups []string `json:"groups"`
// policies
// Required: true
Policies []string `json:"policies"`
// secret key
// Required: true
SecretKey *string `json:"secretKey"`
@@ -61,6 +65,10 @@ func (m *AddUserRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validatePolicies(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretKey(formats); err != nil {
res = append(res, err)
}
@@ -89,6 +97,15 @@ func (m *AddUserRequest) validateGroups(formats strfmt.Registry) error {
return nil
}
func (m *AddUserRequest) validatePolicies(formats strfmt.Registry) error {
if err := validate.Required("policies", "body", m.Policies); err != nil {
return err
}
return nil
}
func (m *AddUserRequest) validateSecretKey(formats strfmt.Registry) error {
if err := validate.Required("secretKey", "body", m.SecretKey); err != nil {

View File

@@ -42,6 +42,9 @@ type AdminInfoResponse struct {
// objects
Objects int64 `json:"objects,omitempty"`
// servers
Servers []*ServerProperties `json:"servers"`
// usage
Usage int64 `json:"usage,omitempty"`
@@ -53,6 +56,10 @@ type AdminInfoResponse struct {
func (m *AdminInfoResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateServers(formats); err != nil {
res = append(res, err)
}
if err := m.validateWidgets(formats); err != nil {
res = append(res, err)
}
@@ -63,6 +70,30 @@ func (m *AdminInfoResponse) Validate(formats strfmt.Registry) error {
return nil
}
func (m *AdminInfoResponse) validateServers(formats strfmt.Registry) error {
if swag.IsZero(m.Servers) { // not required
return nil
}
for i := 0; i < len(m.Servers); i++ {
if swag.IsZero(m.Servers[i]) { // not required
continue
}
if m.Servers[i] != nil {
if err := m.Servers[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("servers" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *AdminInfoResponse) validateWidgets(formats strfmt.Registry) error {
if swag.IsZero(m.Widgets) { // not required
return nil
@@ -91,6 +122,10 @@ func (m *AdminInfoResponse) validateWidgets(formats strfmt.Registry) error {
func (m *AdminInfoResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateServers(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateWidgets(ctx, formats); err != nil {
res = append(res, err)
}
@@ -101,6 +136,24 @@ func (m *AdminInfoResponse) ContextValidate(ctx context.Context, formats strfmt.
return nil
}
func (m *AdminInfoResponse) contextValidateServers(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Servers); i++ {
if m.Servers[i] != nil {
if err := m.Servers[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("servers" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *AdminInfoResponse) contextValidateWidgets(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Widgets); i++ {

View File

@@ -0,0 +1,313 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AzureConfiguration azure configuration
//
// swagger:model azureConfiguration
type AzureConfiguration struct {
// keyvault
// Required: true
Keyvault *AzureConfigurationKeyvault `json:"keyvault"`
}
// Validate validates this azure configuration
func (m *AzureConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateKeyvault(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AzureConfiguration) validateKeyvault(formats strfmt.Registry) error {
if err := validate.Required("keyvault", "body", m.Keyvault); err != nil {
return err
}
if m.Keyvault != nil {
if err := m.Keyvault.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keyvault")
}
return err
}
}
return nil
}
// ContextValidate validate this azure configuration based on the context it is used
func (m *AzureConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateKeyvault(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AzureConfiguration) contextValidateKeyvault(ctx context.Context, formats strfmt.Registry) error {
if m.Keyvault != nil {
if err := m.Keyvault.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keyvault")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *AzureConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AzureConfiguration) UnmarshalBinary(b []byte) error {
var res AzureConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// AzureConfigurationKeyvault azure configuration keyvault
//
// swagger:model AzureConfigurationKeyvault
type AzureConfigurationKeyvault struct {
// credentials
Credentials *AzureConfigurationKeyvaultCredentials `json:"credentials,omitempty"`
// endpoint
// Required: true
Endpoint *string `json:"endpoint"`
}
// Validate validates this azure configuration keyvault
func (m *AzureConfigurationKeyvault) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCredentials(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndpoint(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AzureConfigurationKeyvault) validateCredentials(formats strfmt.Registry) error {
if swag.IsZero(m.Credentials) { // not required
return nil
}
if m.Credentials != nil {
if err := m.Credentials.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keyvault" + "." + "credentials")
}
return err
}
}
return nil
}
func (m *AzureConfigurationKeyvault) validateEndpoint(formats strfmt.Registry) error {
if err := validate.Required("keyvault"+"."+"endpoint", "body", m.Endpoint); err != nil {
return err
}
return nil
}
// ContextValidate validate this azure configuration keyvault based on the context it is used
func (m *AzureConfigurationKeyvault) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateCredentials(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AzureConfigurationKeyvault) contextValidateCredentials(ctx context.Context, formats strfmt.Registry) error {
if m.Credentials != nil {
if err := m.Credentials.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keyvault" + "." + "credentials")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *AzureConfigurationKeyvault) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AzureConfigurationKeyvault) UnmarshalBinary(b []byte) error {
var res AzureConfigurationKeyvault
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// AzureConfigurationKeyvaultCredentials azure configuration keyvault credentials
//
// swagger:model AzureConfigurationKeyvaultCredentials
type AzureConfigurationKeyvaultCredentials struct {
// client id
// Required: true
ClientID *string `json:"client_id"`
// client secret
// Required: true
ClientSecret *string `json:"client_secret"`
// tenant id
// Required: true
TenantID *string `json:"tenant_id"`
}
// Validate validates this azure configuration keyvault credentials
func (m *AzureConfigurationKeyvaultCredentials) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateClientID(formats); err != nil {
res = append(res, err)
}
if err := m.validateClientSecret(formats); err != nil {
res = append(res, err)
}
if err := m.validateTenantID(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AzureConfigurationKeyvaultCredentials) validateClientID(formats strfmt.Registry) error {
if err := validate.Required("keyvault"+"."+"credentials"+"."+"client_id", "body", m.ClientID); err != nil {
return err
}
return nil
}
func (m *AzureConfigurationKeyvaultCredentials) validateClientSecret(formats strfmt.Registry) error {
if err := validate.Required("keyvault"+"."+"credentials"+"."+"client_secret", "body", m.ClientSecret); err != nil {
return err
}
return nil
}
func (m *AzureConfigurationKeyvaultCredentials) validateTenantID(formats strfmt.Registry) error {
if err := validate.Required("keyvault"+"."+"credentials"+"."+"tenant_id", "body", m.TenantID); err != nil {
return err
}
return nil
}
// ContextValidate validates this azure configuration keyvault credentials based on context it is used
func (m *AzureConfigurationKeyvaultCredentials) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *AzureConfigurationKeyvaultCredentials) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AzureConfigurationKeyvaultCredentials) UnmarshalBinary(b []byte) error {
var res AzureConfigurationKeyvaultCredentials
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -24,6 +24,7 @@ package models
import (
"context"
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
@@ -42,11 +43,20 @@ type Bucket struct {
// creation date
CreationDate string `json:"creation_date,omitempty"`
// details
Details *BucketDetails `json:"details,omitempty"`
// name
// Required: true
// Min Length: 3
Name *string `json:"name"`
// objects
Objects int64 `json:"objects,omitempty"`
// rw access
RwAccess *BucketRwAccess `json:"rw_access,omitempty"`
// size
Size int64 `json:"size,omitempty"`
}
@@ -59,10 +69,18 @@ func (m *Bucket) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateDetails(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validateRwAccess(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -86,6 +104,23 @@ func (m *Bucket) validateAccess(formats strfmt.Registry) error {
return nil
}
func (m *Bucket) validateDetails(formats strfmt.Registry) error {
if swag.IsZero(m.Details) { // not required
return nil
}
if m.Details != nil {
if err := m.Details.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("details")
}
return err
}
}
return nil
}
func (m *Bucket) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
@@ -99,6 +134,23 @@ func (m *Bucket) validateName(formats strfmt.Registry) error {
return nil
}
func (m *Bucket) validateRwAccess(formats strfmt.Registry) error {
if swag.IsZero(m.RwAccess) { // not required
return nil
}
if m.RwAccess != nil {
if err := m.RwAccess.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("rw_access")
}
return err
}
}
return nil
}
// ContextValidate validate this bucket based on the context it is used
func (m *Bucket) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
@@ -107,6 +159,14 @@ func (m *Bucket) ContextValidate(ctx context.Context, formats strfmt.Registry) e
res = append(res, err)
}
if err := m.contextValidateDetails(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateRwAccess(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -127,6 +187,34 @@ func (m *Bucket) contextValidateAccess(ctx context.Context, formats strfmt.Regis
return nil
}
func (m *Bucket) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error {
if m.Details != nil {
if err := m.Details.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("details")
}
return err
}
}
return nil
}
func (m *Bucket) contextValidateRwAccess(ctx context.Context, formats strfmt.Registry) error {
if m.RwAccess != nil {
if err := m.RwAccess.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("rw_access")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *Bucket) MarshalBinary() ([]byte, error) {
if m == nil {
@@ -144,3 +232,236 @@ func (m *Bucket) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// BucketDetails bucket details
//
// swagger:model BucketDetails
type BucketDetails struct {
// locking
Locking bool `json:"locking,omitempty"`
// quota
Quota *BucketDetailsQuota `json:"quota,omitempty"`
// replication
Replication bool `json:"replication,omitempty"`
// tags
Tags map[string]string `json:"tags,omitempty"`
// versioning
Versioning bool `json:"versioning,omitempty"`
// versioning suspended
VersioningSuspended bool `json:"versioningSuspended,omitempty"`
}
// Validate validates this bucket details
func (m *BucketDetails) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateQuota(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *BucketDetails) validateQuota(formats strfmt.Registry) error {
if swag.IsZero(m.Quota) { // not required
return nil
}
if m.Quota != nil {
if err := m.Quota.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("details" + "." + "quota")
}
return err
}
}
return nil
}
// ContextValidate validate this bucket details based on the context it is used
func (m *BucketDetails) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateQuota(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *BucketDetails) contextValidateQuota(ctx context.Context, formats strfmt.Registry) error {
if m.Quota != nil {
if err := m.Quota.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("details" + "." + "quota")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *BucketDetails) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketDetails) UnmarshalBinary(b []byte) error {
var res BucketDetails
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// BucketDetailsQuota bucket details quota
//
// swagger:model BucketDetailsQuota
type BucketDetailsQuota struct {
// quota
Quota int64 `json:"quota,omitempty"`
// type
// Enum: [fifo hard]
Type string `json:"type,omitempty"`
}
// Validate validates this bucket details quota
func (m *BucketDetailsQuota) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateType(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var bucketDetailsQuotaTypeTypePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["fifo","hard"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
bucketDetailsQuotaTypeTypePropEnum = append(bucketDetailsQuotaTypeTypePropEnum, v)
}
}
const (
// BucketDetailsQuotaTypeFifo captures enum value "fifo"
BucketDetailsQuotaTypeFifo string = "fifo"
// BucketDetailsQuotaTypeHard captures enum value "hard"
BucketDetailsQuotaTypeHard string = "hard"
)
// prop value enum
func (m *BucketDetailsQuota) validateTypeEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, bucketDetailsQuotaTypeTypePropEnum, true); err != nil {
return err
}
return nil
}
func (m *BucketDetailsQuota) validateType(formats strfmt.Registry) error {
if swag.IsZero(m.Type) { // not required
return nil
}
// value enum
if err := m.validateTypeEnum("details"+"."+"quota"+"."+"type", "body", m.Type); err != nil {
return err
}
return nil
}
// ContextValidate validates this bucket details quota based on context it is used
func (m *BucketDetailsQuota) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketDetailsQuota) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketDetailsQuota) UnmarshalBinary(b []byte) error {
var res BucketDetailsQuota
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// BucketRwAccess bucket rw access
//
// swagger:model BucketRwAccess
type BucketRwAccess struct {
// read
Read bool `json:"read,omitempty"`
// write
Write bool `json:"write,omitempty"`
}
// Validate validates this bucket rw access
func (m *BucketRwAccess) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this bucket rw access based on context it is used
func (m *BucketRwAccess) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketRwAccess) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketRwAccess) UnmarshalBinary(b []byte) error {
var res BucketRwAccess
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -55,6 +55,9 @@ type BucketObject struct {
// legal hold status
LegalHoldStatus string `json:"legal_hold_status,omitempty"`
// metadata
Metadata map[string]string `json:"metadata,omitempty"`
// name
Name string `json:"name,omitempty"`
@@ -70,6 +73,9 @@ type BucketObject struct {
// tags
Tags map[string]string `json:"tags,omitempty"`
// user metadata
UserMetadata map[string]string `json:"user_metadata,omitempty"`
// user tags
UserTags map[string]string `json:"user_tags,omitempty"`

View File

@@ -1,134 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ConsoleConfiguration console configuration
//
// swagger:model consoleConfiguration
type ConsoleConfiguration struct {
MetadataFields
// image
Image string `json:"image,omitempty"`
}
// UnmarshalJSON unmarshals this object from a JSON structure
func (m *ConsoleConfiguration) UnmarshalJSON(raw []byte) error {
// AO0
var aO0 MetadataFields
if err := swag.ReadJSON(raw, &aO0); err != nil {
return err
}
m.MetadataFields = aO0
// AO1
var dataAO1 struct {
Image string `json:"image,omitempty"`
}
if err := swag.ReadJSON(raw, &dataAO1); err != nil {
return err
}
m.Image = dataAO1.Image
return nil
}
// MarshalJSON marshals this object to a JSON structure
func (m ConsoleConfiguration) MarshalJSON() ([]byte, error) {
_parts := make([][]byte, 0, 2)
aO0, err := swag.WriteJSON(m.MetadataFields)
if err != nil {
return nil, err
}
_parts = append(_parts, aO0)
var dataAO1 struct {
Image string `json:"image,omitempty"`
}
dataAO1.Image = m.Image
jsonDataAO1, errAO1 := swag.WriteJSON(dataAO1)
if errAO1 != nil {
return nil, errAO1
}
_parts = append(_parts, jsonDataAO1)
return swag.ConcatJSON(_parts...), nil
}
// Validate validates this console configuration
func (m *ConsoleConfiguration) Validate(formats strfmt.Registry) error {
var res []error
// validation for a type composition with MetadataFields
if err := m.MetadataFields.Validate(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// ContextValidate validate this console configuration based on the context it is used
func (m *ConsoleConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
// validation for a type composition with MetadataFields
if err := m.MetadataFields.ContextValidate(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// MarshalBinary interface implementation
func (m *ConsoleConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ConsoleConfiguration) UnmarshalBinary(b []byte) error {
var res ConsoleConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -43,12 +43,6 @@ type CreateTenantRequest struct {
// annotations
Annotations map[string]string `json:"annotations,omitempty"`
// console
Console *ConsoleConfiguration `json:"console,omitempty"`
// console image
ConsoleImage string `json:"console_image,omitempty"`
// enable console
EnableConsole *bool `json:"enable_console,omitempty"`
@@ -118,10 +112,6 @@ type CreateTenantRequest struct {
func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if err := m.validateEncryption(formats); err != nil {
res = append(res, err)
}
@@ -164,23 +154,6 @@ func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
return nil
}
func (m *CreateTenantRequest) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
if m.Console != nil {
if err := m.Console.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateEncryption(formats strfmt.Registry) error {
if swag.IsZero(m.Encryption) { // not required
return nil
@@ -334,10 +307,6 @@ func (m *CreateTenantRequest) validateTLS(formats strfmt.Registry) error {
func (m *CreateTenantRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateConsole(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateEncryption(ctx, formats); err != nil {
res = append(res, err)
}
@@ -372,20 +341,6 @@ func (m *CreateTenantRequest) ContextValidate(ctx context.Context, formats strfm
return nil
}
func (m *CreateTenantRequest) contextValidateConsole(ctx context.Context, formats strfmt.Registry) error {
if m.Console != nil {
if err := m.Console.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) contextValidateEncryption(ctx context.Context, formats strfmt.Registry) error {
if m.Encryption != nil {

View File

@@ -38,6 +38,9 @@ type CreateTenantResponse struct {
// console
Console []*TenantResponseItem `json:"console"`
// external ID p
ExternalIDP bool `json:"externalIDP,omitempty"`
}
// Validate validates this create tenant response

View File

@@ -39,6 +39,9 @@ type EncryptionConfiguration struct {
// aws
Aws *AwsConfiguration `json:"aws,omitempty"`
// azure
Azure *AzureConfiguration `json:"azure,omitempty"`
// client
Client *KeyPairConfiguration `json:"client,omitempty"`
@@ -54,6 +57,9 @@ type EncryptionConfiguration struct {
// replicas
Replicas string `json:"replicas,omitempty"`
// security context
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
// server
Server *KeyPairConfiguration `json:"server,omitempty"`
@@ -74,6 +80,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
var dataAO1 struct {
Aws *AwsConfiguration `json:"aws,omitempty"`
Azure *AzureConfiguration `json:"azure,omitempty"`
Client *KeyPairConfiguration `json:"client,omitempty"`
Gcp *GcpConfiguration `json:"gcp,omitempty"`
@@ -84,6 +92,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
Replicas string `json:"replicas,omitempty"`
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
Server *KeyPairConfiguration `json:"server,omitempty"`
Vault *VaultConfiguration `json:"vault,omitempty"`
@@ -94,6 +104,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
m.Aws = dataAO1.Aws
m.Azure = dataAO1.Azure
m.Client = dataAO1.Client
m.Gcp = dataAO1.Gcp
@@ -104,6 +116,8 @@ func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
m.Replicas = dataAO1.Replicas
m.SecurityContext = dataAO1.SecurityContext
m.Server = dataAO1.Server
m.Vault = dataAO1.Vault
@@ -123,6 +137,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
var dataAO1 struct {
Aws *AwsConfiguration `json:"aws,omitempty"`
Azure *AzureConfiguration `json:"azure,omitempty"`
Client *KeyPairConfiguration `json:"client,omitempty"`
Gcp *GcpConfiguration `json:"gcp,omitempty"`
@@ -133,6 +149,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
Replicas string `json:"replicas,omitempty"`
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
Server *KeyPairConfiguration `json:"server,omitempty"`
Vault *VaultConfiguration `json:"vault,omitempty"`
@@ -140,6 +158,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
dataAO1.Aws = m.Aws
dataAO1.Azure = m.Azure
dataAO1.Client = m.Client
dataAO1.Gcp = m.Gcp
@@ -150,6 +170,8 @@ func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
dataAO1.Replicas = m.Replicas
dataAO1.SecurityContext = m.SecurityContext
dataAO1.Server = m.Server
dataAO1.Vault = m.Vault
@@ -175,6 +197,10 @@ func (m *EncryptionConfiguration) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateAzure(formats); err != nil {
res = append(res, err)
}
if err := m.validateClient(formats); err != nil {
res = append(res, err)
}
@@ -187,6 +213,10 @@ func (m *EncryptionConfiguration) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateSecurityContext(formats); err != nil {
res = append(res, err)
}
if err := m.validateServer(formats); err != nil {
res = append(res, err)
}
@@ -219,6 +249,24 @@ func (m *EncryptionConfiguration) validateAws(formats strfmt.Registry) error {
return nil
}
func (m *EncryptionConfiguration) validateAzure(formats strfmt.Registry) error {
if swag.IsZero(m.Azure) { // not required
return nil
}
if m.Azure != nil {
if err := m.Azure.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("azure")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateClient(formats strfmt.Registry) error {
if swag.IsZero(m.Client) { // not required
@@ -273,6 +321,24 @@ func (m *EncryptionConfiguration) validateGemalto(formats strfmt.Registry) error
return nil
}
func (m *EncryptionConfiguration) validateSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.SecurityContext) { // not required
return nil
}
if m.SecurityContext != nil {
if err := m.SecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateServer(formats strfmt.Registry) error {
if swag.IsZero(m.Server) { // not required
@@ -322,6 +388,10 @@ func (m *EncryptionConfiguration) ContextValidate(ctx context.Context, formats s
res = append(res, err)
}
if err := m.contextValidateAzure(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateClient(ctx, formats); err != nil {
res = append(res, err)
}
@@ -334,6 +404,10 @@ func (m *EncryptionConfiguration) ContextValidate(ctx context.Context, formats s
res = append(res, err)
}
if err := m.contextValidateSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateServer(ctx, formats); err != nil {
res = append(res, err)
}
@@ -362,6 +436,20 @@ func (m *EncryptionConfiguration) contextValidateAws(ctx context.Context, format
return nil
}
func (m *EncryptionConfiguration) contextValidateAzure(ctx context.Context, formats strfmt.Registry) error {
if m.Azure != nil {
if err := m.Azure.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("azure")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) contextValidateClient(ctx context.Context, formats strfmt.Registry) error {
if m.Client != nil {
@@ -404,6 +492,20 @@ func (m *EncryptionConfiguration) contextValidateGemalto(ctx context.Context, fo
return nil
}
func (m *EncryptionConfiguration) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.SecurityContext != nil {
if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) contextValidateServer(ctx context.Context, formats strfmt.Registry) error {
if m.Server != nil {

View File

@@ -39,6 +39,10 @@ type Error struct {
// code
Code int32 `json:"code,omitempty"`
// detailed message
// Required: true
DetailedMessage *string `json:"detailedMessage"`
// message
// Required: true
Message *string `json:"message"`
@@ -48,6 +52,10 @@ type Error struct {
func (m *Error) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDetailedMessage(formats); err != nil {
res = append(res, err)
}
if err := m.validateMessage(formats); err != nil {
res = append(res, err)
}
@@ -58,6 +66,15 @@ func (m *Error) Validate(formats strfmt.Registry) error {
return nil
}
func (m *Error) validateDetailedMessage(formats strfmt.Registry) error {
if err := validate.Required("detailedMessage", "body", m.DetailedMessage); err != nil {
return err
}
return nil
}
func (m *Error) validateMessage(formats strfmt.Registry) error {
if err := validate.Required("message", "body", m.Message); err != nil {

View File

@@ -227,9 +227,18 @@ type IdpConfigurationActiveDirectory struct {
// group search filter
GroupSearchFilter string `json:"group_search_filter,omitempty"`
// lookup bind dn
LookupBindDn string `json:"lookup_bind_dn,omitempty"`
// lookup bind password
LookupBindPassword string `json:"lookup_bind_password,omitempty"`
// server insecure
ServerInsecure bool `json:"server_insecure,omitempty"`
// server start tls
ServerStartTLS bool `json:"server_start_tls,omitempty"`
// skip tls verification
SkipTLSVerification bool `json:"skip_tls_verification,omitempty"`
@@ -237,13 +246,20 @@ type IdpConfigurationActiveDirectory struct {
// Required: true
URL *string `json:"url"`
// user search filter
// Required: true
UserSearchFilter *string `json:"user_search_filter"`
// user dn search base dn
UserDnSearchBaseDn string `json:"user_dn_search_base_dn,omitempty"`
// user dn search filter
UserDnSearchFilter string `json:"user_dn_search_filter,omitempty"`
// user dns
UserDNS []string `json:"user_dns"`
// username format
// Required: true
UsernameFormat *string `json:"username_format"`
UsernameFormat string `json:"username_format,omitempty"`
// username search filter
UsernameSearchFilter string `json:"username_search_filter,omitempty"`
}
// Validate validates this idp configuration active directory
@@ -254,14 +270,6 @@ func (m *IdpConfigurationActiveDirectory) Validate(formats strfmt.Registry) erro
res = append(res, err)
}
if err := m.validateUserSearchFilter(formats); err != nil {
res = append(res, err)
}
if err := m.validateUsernameFormat(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -277,24 +285,6 @@ func (m *IdpConfigurationActiveDirectory) validateURL(formats strfmt.Registry) e
return nil
}
func (m *IdpConfigurationActiveDirectory) validateUserSearchFilter(formats strfmt.Registry) error {
if err := validate.Required("active_directory"+"."+"user_search_filter", "body", m.UserSearchFilter); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationActiveDirectory) validateUsernameFormat(formats strfmt.Registry) error {
if err := validate.Required("active_directory"+"."+"username_format", "body", m.UsernameFormat); err != nil {
return err
}
return nil
}
// ContextValidate validates this idp configuration active directory based on context it is used
func (m *IdpConfigurationActiveDirectory) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
@@ -396,41 +386,64 @@ func (m *IdpConfigurationKeysItems0) UnmarshalBinary(b []byte) error {
// swagger:model IdpConfigurationOidc
type IdpConfigurationOidc struct {
// callback url
CallbackURL string `json:"callback_url,omitempty"`
// claim name
// Required: true
ClaimName *string `json:"claim_name"`
// client id
// Required: true
ClientID *string `json:"client_id"`
// configuration url
// Required: true
ConfigurationURL *string `json:"configuration_url"`
// scopes
Scopes string `json:"scopes,omitempty"`
// secret id
// Required: true
SecretID *string `json:"secret_id"`
// url
// Required: true
URL *string `json:"url"`
}
// Validate validates this idp configuration oidc
func (m *IdpConfigurationOidc) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateClaimName(formats); err != nil {
res = append(res, err)
}
if err := m.validateClientID(formats); err != nil {
res = append(res, err)
}
if err := m.validateConfigurationURL(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretID(formats); err != nil {
res = append(res, err)
}
if err := m.validateURL(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *IdpConfigurationOidc) validateClaimName(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"claim_name", "body", m.ClaimName); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationOidc) validateClientID(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"client_id", "body", m.ClientID); err != nil {
@@ -440,18 +453,18 @@ func (m *IdpConfigurationOidc) validateClientID(formats strfmt.Registry) error {
return nil
}
func (m *IdpConfigurationOidc) validateSecretID(formats strfmt.Registry) error {
func (m *IdpConfigurationOidc) validateConfigurationURL(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"secret_id", "body", m.SecretID); err != nil {
if err := validate.Required("oidc"+"."+"configuration_url", "body", m.ConfigurationURL); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationOidc) validateURL(formats strfmt.Registry) error {
func (m *IdpConfigurationOidc) validateSecretID(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"url", "body", m.URL); err != nil {
if err := validate.Required("oidc"+"."+"secret_id", "body", m.SecretID); err != nil {
return err
}

View File

@@ -0,0 +1,132 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ListAccessRulesResponse list access rules response
//
// swagger:model listAccessRulesResponse
type ListAccessRulesResponse struct {
// list of policies
AccessRules []*AccessRule `json:"accessRules"`
// total number of policies
Total int64 `json:"total,omitempty"`
}
// Validate validates this list access rules response
func (m *ListAccessRulesResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAccessRules(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ListAccessRulesResponse) validateAccessRules(formats strfmt.Registry) error {
if swag.IsZero(m.AccessRules) { // not required
return nil
}
for i := 0; i < len(m.AccessRules); i++ {
if swag.IsZero(m.AccessRules[i]) { // not required
continue
}
if m.AccessRules[i] != nil {
if err := m.AccessRules[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("accessRules" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// ContextValidate validate this list access rules response based on the context it is used
func (m *ListAccessRulesResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateAccessRules(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ListAccessRulesResponse) contextValidateAccessRules(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.AccessRules); i++ {
if m.AccessRules[i] != nil {
if err := m.AccessRules[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("accessRules" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ListAccessRulesResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ListAccessRulesResponse) UnmarshalBinary(b []byte) error {
var res ListAccessRulesResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -39,7 +39,7 @@ type ListBucketsResponse struct {
// list of resulting buckets
Buckets []*Bucket `json:"buckets"`
// number of buckets accessible to tenant user
// number of buckets accessible to the user
Total int64 `json:"total,omitempty"`
}

View File

@@ -25,6 +25,7 @@ package models
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
@@ -40,6 +41,15 @@ type LogSearchConfiguration struct {
// postgres image
PostgresImage string `json:"postgres_image,omitempty"`
// postgres init image
PostgresInitImage string `json:"postgres_init_image,omitempty"`
// postgres security context
PostgresSecurityContext *SecurityContext `json:"postgres_securityContext,omitempty"`
// security context
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
// storage class
StorageClass string `json:"storageClass,omitempty"`
@@ -49,11 +59,99 @@ type LogSearchConfiguration struct {
// Validate validates this log search configuration
func (m *LogSearchConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePostgresSecurityContext(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecurityContext(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// ContextValidate validates this log search configuration based on context it is used
func (m *LogSearchConfiguration) validatePostgresSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.PostgresSecurityContext) { // not required
return nil
}
if m.PostgresSecurityContext != nil {
if err := m.PostgresSecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("postgres_securityContext")
}
return err
}
}
return nil
}
func (m *LogSearchConfiguration) validateSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.SecurityContext) { // not required
return nil
}
if m.SecurityContext != nil {
if err := m.SecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
// ContextValidate validate this log search configuration based on the context it is used
func (m *LogSearchConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidatePostgresSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *LogSearchConfiguration) contextValidatePostgresSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.PostgresSecurityContext != nil {
if err := m.PostgresSecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("postgres_securityContext")
}
return err
}
}
return nil
}
func (m *LogSearchConfiguration) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.SecurityContext != nil {
if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}

View File

@@ -48,6 +48,9 @@ type Pool struct {
// resources
Resources *PoolResources `json:"resources,omitempty"`
// security context
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
// servers
// Required: true
Servers *int64 `json:"servers"`
@@ -76,6 +79,10 @@ func (m *Pool) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateSecurityContext(formats); err != nil {
res = append(res, err)
}
if err := m.validateServers(formats); err != nil {
res = append(res, err)
}
@@ -132,6 +139,23 @@ func (m *Pool) validateResources(formats strfmt.Registry) error {
return nil
}
func (m *Pool) validateSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.SecurityContext) { // not required
return nil
}
if m.SecurityContext != nil {
if err := m.SecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
func (m *Pool) validateServers(formats strfmt.Registry) error {
if err := validate.Required("servers", "body", m.Servers); err != nil {
@@ -195,6 +219,10 @@ func (m *Pool) ContextValidate(ctx context.Context, formats strfmt.Registry) err
res = append(res, err)
}
if err := m.contextValidateSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateTolerations(ctx, formats); err != nil {
res = append(res, err)
}
@@ -237,6 +265,20 @@ func (m *Pool) contextValidateResources(ctx context.Context, formats strfmt.Regi
return nil
}
func (m *Pool) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.SecurityContext != nil {
if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
func (m *Pool) contextValidateTolerations(ctx context.Context, formats strfmt.Registry) error {
if err := m.Tolerations.ContextValidate(ctx, formats); err != nil {

View File

@@ -0,0 +1,70 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// PrefixAccessPair prefix access pair
//
// swagger:model prefixAccessPair
type PrefixAccessPair struct {
// access
Access string `json:"access,omitempty"`
// prefix
Prefix string `json:"prefix,omitempty"`
}
// Validate validates this prefix access pair
func (m *PrefixAccessPair) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this prefix access pair based on context it is used
func (m *PrefixAccessPair) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *PrefixAccessPair) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PrefixAccessPair) UnmarshalBinary(b []byte) error {
var res PrefixAccessPair
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

67
models/prefix_wrapper.go Normal file
View File

@@ -0,0 +1,67 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// PrefixWrapper prefix wrapper
//
// swagger:model prefixWrapper
type PrefixWrapper struct {
// prefix
Prefix string `json:"prefix,omitempty"`
}
// Validate validates this prefix wrapper
func (m *PrefixWrapper) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this prefix wrapper based on context it is used
func (m *PrefixWrapper) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *PrefixWrapper) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PrefixWrapper) UnmarshalBinary(b []byte) error {
var res PrefixWrapper
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -45,9 +45,6 @@ type Principal struct {
// account access key
AccountAccessKey string `json:"accountAccessKey,omitempty"`
// actions
Actions []string `json:"actions"`
}
// Validate validates this principal

View File

@@ -25,6 +25,7 @@ package models
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
@@ -37,6 +38,15 @@ type PrometheusConfiguration struct {
// image
Image string `json:"image,omitempty"`
// init image
InitImage string `json:"init_image,omitempty"`
// security context
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
// sidecar image
SidecarImage string `json:"sidecar_image,omitempty"`
// storage class
StorageClass string `json:"storageClass,omitempty"`
@@ -46,11 +56,60 @@ type PrometheusConfiguration struct {
// Validate validates this prometheus configuration
func (m *PrometheusConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateSecurityContext(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// ContextValidate validates this prometheus configuration based on context it is used
func (m *PrometheusConfiguration) validateSecurityContext(formats strfmt.Registry) error {
if swag.IsZero(m.SecurityContext) { // not required
return nil
}
if m.SecurityContext != nil {
if err := m.SecurityContext.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}
// ContextValidate validate this prometheus configuration based on the context it is used
func (m *PrometheusConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateSecurityContext(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PrometheusConfiguration) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error {
if m.SecurityContext != nil {
if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("securityContext")
}
return err
}
}
return nil
}

139
models/security_context.go Normal file
View File

@@ -0,0 +1,139 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SecurityContext security context
//
// swagger:model securityContext
type SecurityContext struct {
// fs group
// Required: true
FsGroup *string `json:"fsGroup"`
// run as group
// Required: true
RunAsGroup *string `json:"runAsGroup"`
// run as non root
// Required: true
RunAsNonRoot *bool `json:"runAsNonRoot"`
// run as user
// Required: true
RunAsUser *string `json:"runAsUser"`
}
// Validate validates this security context
func (m *SecurityContext) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateFsGroup(formats); err != nil {
res = append(res, err)
}
if err := m.validateRunAsGroup(formats); err != nil {
res = append(res, err)
}
if err := m.validateRunAsNonRoot(formats); err != nil {
res = append(res, err)
}
if err := m.validateRunAsUser(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *SecurityContext) validateFsGroup(formats strfmt.Registry) error {
if err := validate.Required("fsGroup", "body", m.FsGroup); err != nil {
return err
}
return nil
}
func (m *SecurityContext) validateRunAsGroup(formats strfmt.Registry) error {
if err := validate.Required("runAsGroup", "body", m.RunAsGroup); err != nil {
return err
}
return nil
}
func (m *SecurityContext) validateRunAsNonRoot(formats strfmt.Registry) error {
if err := validate.Required("runAsNonRoot", "body", m.RunAsNonRoot); err != nil {
return err
}
return nil
}
func (m *SecurityContext) validateRunAsUser(formats strfmt.Registry) error {
if err := validate.Required("runAsUser", "body", m.RunAsUser); err != nil {
return err
}
return nil
}
// ContextValidate validates this security context based on context it is used
func (m *SecurityContext) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *SecurityContext) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SecurityContext) UnmarshalBinary(b []byte) error {
var res SecurityContext
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

94
models/server_drives.go Normal file
View File

@@ -0,0 +1,94 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ServerDrives server drives
//
// swagger:model serverDrives
type ServerDrives struct {
// available space
AvailableSpace int64 `json:"availableSpace,omitempty"`
// drive path
DrivePath string `json:"drivePath,omitempty"`
// endpoint
Endpoint string `json:"endpoint,omitempty"`
// healing
Healing bool `json:"healing,omitempty"`
// model
Model string `json:"model,omitempty"`
// root disk
RootDisk bool `json:"rootDisk,omitempty"`
// state
State string `json:"state,omitempty"`
// total space
TotalSpace int64 `json:"totalSpace,omitempty"`
// used space
UsedSpace int64 `json:"usedSpace,omitempty"`
// uuid
UUID string `json:"uuid,omitempty"`
}
// Validate validates this server drives
func (m *ServerDrives) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this server drives based on context it is used
func (m *ServerDrives) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ServerDrives) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ServerDrives) UnmarshalBinary(b []byte) error {
var res ServerDrives
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

150
models/server_properties.go Normal file
View File

@@ -0,0 +1,150 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ServerProperties server properties
//
// swagger:model serverProperties
type ServerProperties struct {
// commit ID
CommitID string `json:"commitID,omitempty"`
// drives
Drives []*ServerDrives `json:"drives"`
// endpoint
Endpoint string `json:"endpoint,omitempty"`
// network
Network map[string]string `json:"network,omitempty"`
// pool number
PoolNumber int64 `json:"poolNumber,omitempty"`
// state
State string `json:"state,omitempty"`
// uptime
Uptime int64 `json:"uptime,omitempty"`
// version
Version string `json:"version,omitempty"`
}
// Validate validates this server properties
func (m *ServerProperties) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDrives(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ServerProperties) validateDrives(formats strfmt.Registry) error {
if swag.IsZero(m.Drives) { // not required
return nil
}
for i := 0; i < len(m.Drives); i++ {
if swag.IsZero(m.Drives[i]) { // not required
continue
}
if m.Drives[i] != nil {
if err := m.Drives[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("drives" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// ContextValidate validate this server properties based on the context it is used
func (m *ServerProperties) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateDrives(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ServerProperties) contextValidateDrives(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Drives); i++ {
if m.Drives[i] != nil {
if err := m.Drives[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("drives" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ServerProperties) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ServerProperties) UnmarshalBinary(b []byte) error {
var res ServerProperties
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,73 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ServiceAccountRequestCreds service account request creds
//
// swagger:model serviceAccountRequestCreds
type ServiceAccountRequestCreds struct {
// access key
AccessKey string `json:"accessKey,omitempty"`
// policy to be applied to the Service Account if any
Policy string `json:"policy,omitempty"`
// secret key
SecretKey string `json:"secretKey,omitempty"`
}
// Validate validates this service account request creds
func (m *ServiceAccountRequestCreds) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this service account request creds based on context it is used
func (m *ServiceAccountRequestCreds) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ServiceAccountRequestCreds) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ServiceAccountRequestCreds) UnmarshalBinary(b []byte) error {
var res ServiceAccountRequestCreds
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -31,20 +31,23 @@ import (
"github.com/go-openapi/swag"
)
// SetPolicyMultipleRequest set policy multiple request
// SetPolicyMultipleNameRequest set policy multiple name request
//
// swagger:model setPolicyMultipleRequest
type SetPolicyMultipleRequest struct {
// swagger:model setPolicyMultipleNameRequest
type SetPolicyMultipleNameRequest struct {
// groups
Groups []IamEntity `json:"groups"`
// name
Name []string `json:"name"`
// users
Users []IamEntity `json:"users"`
}
// Validate validates this set policy multiple request
func (m *SetPolicyMultipleRequest) Validate(formats strfmt.Registry) error {
// Validate validates this set policy multiple name request
func (m *SetPolicyMultipleNameRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateGroups(formats); err != nil {
@@ -61,7 +64,7 @@ func (m *SetPolicyMultipleRequest) Validate(formats strfmt.Registry) error {
return nil
}
func (m *SetPolicyMultipleRequest) validateGroups(formats strfmt.Registry) error {
func (m *SetPolicyMultipleNameRequest) validateGroups(formats strfmt.Registry) error {
if swag.IsZero(m.Groups) { // not required
return nil
}
@@ -80,7 +83,7 @@ func (m *SetPolicyMultipleRequest) validateGroups(formats strfmt.Registry) error
return nil
}
func (m *SetPolicyMultipleRequest) validateUsers(formats strfmt.Registry) error {
func (m *SetPolicyMultipleNameRequest) validateUsers(formats strfmt.Registry) error {
if swag.IsZero(m.Users) { // not required
return nil
}
@@ -99,8 +102,8 @@ func (m *SetPolicyMultipleRequest) validateUsers(formats strfmt.Registry) error
return nil
}
// ContextValidate validate this set policy multiple request based on the context it is used
func (m *SetPolicyMultipleRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
// ContextValidate validate this set policy multiple name request based on the context it is used
func (m *SetPolicyMultipleNameRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateGroups(ctx, formats); err != nil {
@@ -117,7 +120,7 @@ func (m *SetPolicyMultipleRequest) ContextValidate(ctx context.Context, formats
return nil
}
func (m *SetPolicyMultipleRequest) contextValidateGroups(ctx context.Context, formats strfmt.Registry) error {
func (m *SetPolicyMultipleNameRequest) contextValidateGroups(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Groups); i++ {
@@ -133,7 +136,7 @@ func (m *SetPolicyMultipleRequest) contextValidateGroups(ctx context.Context, fo
return nil
}
func (m *SetPolicyMultipleRequest) contextValidateUsers(ctx context.Context, formats strfmt.Registry) error {
func (m *SetPolicyMultipleNameRequest) contextValidateUsers(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Users); i++ {
@@ -150,7 +153,7 @@ func (m *SetPolicyMultipleRequest) contextValidateUsers(ctx context.Context, for
}
// MarshalBinary interface implementation
func (m *SetPolicyMultipleRequest) MarshalBinary() ([]byte, error) {
func (m *SetPolicyMultipleNameRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
@@ -158,8 +161,8 @@ func (m *SetPolicyMultipleRequest) MarshalBinary() ([]byte, error) {
}
// UnmarshalBinary interface implementation
func (m *SetPolicyMultipleRequest) UnmarshalBinary(b []byte) error {
var res SetPolicyMultipleRequest
func (m *SetPolicyMultipleNameRequest) UnmarshalBinary(b []byte) error {
var res SetPolicyMultipleNameRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}

View File

@@ -0,0 +1,158 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SetPolicyNameRequest set policy name request
//
// swagger:model setPolicyNameRequest
type SetPolicyNameRequest struct {
// entity name
// Required: true
EntityName *string `json:"entityName"`
// entity type
// Required: true
EntityType *PolicyEntity `json:"entityType"`
// name
// Required: true
Name []string `json:"name"`
}
// Validate validates this set policy name request
func (m *SetPolicyNameRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEntityName(formats); err != nil {
res = append(res, err)
}
if err := m.validateEntityType(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *SetPolicyNameRequest) validateEntityName(formats strfmt.Registry) error {
if err := validate.Required("entityName", "body", m.EntityName); err != nil {
return err
}
return nil
}
func (m *SetPolicyNameRequest) validateEntityType(formats strfmt.Registry) error {
if err := validate.Required("entityType", "body", m.EntityType); err != nil {
return err
}
if err := validate.Required("entityType", "body", m.EntityType); err != nil {
return err
}
if m.EntityType != nil {
if err := m.EntityType.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("entityType")
}
return err
}
}
return nil
}
func (m *SetPolicyNameRequest) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
// ContextValidate validate this set policy name request based on the context it is used
func (m *SetPolicyNameRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateEntityType(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *SetPolicyNameRequest) contextValidateEntityType(ctx context.Context, formats strfmt.Registry) error {
if m.EntityType != nil {
if err := m.EntityType.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("entityType")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *SetPolicyNameRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SetPolicyNameRequest) UnmarshalBinary(b []byte) error {
var res SetPolicyNameRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -36,15 +36,6 @@ import (
// swagger:model tenant
type Tenant struct {
// console enabled
ConsoleEnabled bool `json:"consoleEnabled,omitempty"`
// console TLS
ConsoleTLS bool `json:"consoleTLS,omitempty"`
// console image
ConsoleImage string `json:"console_image,omitempty"`
// creation date
CreationDate string `json:"creation_date,omitempty"`
@@ -66,8 +57,8 @@ type Tenant struct {
// idp ad enabled
IdpAdEnabled bool `json:"idpAdEnabled,omitempty"`
// idp oic enabled
IdpOicEnabled bool `json:"idpOicEnabled,omitempty"`
// idp oidc enabled
IdpOidcEnabled bool `json:"idpOidcEnabled,omitempty"`
// image
Image string `json:"image,omitempty"`

View File

@@ -125,12 +125,6 @@ func (m *TenantSecurityResponse) UnmarshalBinary(b []byte) error {
// swagger:model TenantSecurityResponseCustomCertificates
type TenantSecurityResponseCustomCertificates struct {
// console
Console []*CertificateInfo `json:"console"`
// console c as
ConsoleCAs []*CertificateInfo `json:"consoleCAs"`
// minio
Minio []*CertificateInfo `json:"minio"`
@@ -142,14 +136,6 @@ type TenantSecurityResponseCustomCertificates struct {
func (m *TenantSecurityResponseCustomCertificates) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if err := m.validateConsoleCAs(formats); err != nil {
res = append(res, err)
}
if err := m.validateMinio(formats); err != nil {
res = append(res, err)
}
@@ -164,54 +150,6 @@ func (m *TenantSecurityResponseCustomCertificates) Validate(formats strfmt.Regis
return nil
}
func (m *TenantSecurityResponseCustomCertificates) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
for i := 0; i < len(m.Console); i++ {
if swag.IsZero(m.Console[i]) { // not required
continue
}
if m.Console[i] != nil {
if err := m.Console[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "console" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *TenantSecurityResponseCustomCertificates) validateConsoleCAs(formats strfmt.Registry) error {
if swag.IsZero(m.ConsoleCAs) { // not required
return nil
}
for i := 0; i < len(m.ConsoleCAs); i++ {
if swag.IsZero(m.ConsoleCAs[i]) { // not required
continue
}
if m.ConsoleCAs[i] != nil {
if err := m.ConsoleCAs[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "consoleCAs" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *TenantSecurityResponseCustomCertificates) validateMinio(formats strfmt.Registry) error {
if swag.IsZero(m.Minio) { // not required
return nil
@@ -264,14 +202,6 @@ func (m *TenantSecurityResponseCustomCertificates) validateMinioCAs(formats strf
func (m *TenantSecurityResponseCustomCertificates) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateConsole(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateConsoleCAs(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateMinio(ctx, formats); err != nil {
res = append(res, err)
}
@@ -286,42 +216,6 @@ func (m *TenantSecurityResponseCustomCertificates) ContextValidate(ctx context.C
return nil
}
func (m *TenantSecurityResponseCustomCertificates) contextValidateConsole(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Console); i++ {
if m.Console[i] != nil {
if err := m.Console[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "console" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *TenantSecurityResponseCustomCertificates) contextValidateConsoleCAs(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.ConsoleCAs); i++ {
if m.ConsoleCAs[i] != nil {
if err := m.ConsoleCAs[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "consoleCAs" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *TenantSecurityResponseCustomCertificates) contextValidateMinio(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Minio); i++ {

View File

@@ -39,12 +39,6 @@ type TLSConfiguration struct {
// ca certificates
CaCertificates []string `json:"ca_certificates"`
// console
Console *KeyPairConfiguration `json:"console,omitempty"`
// console ca certificates
ConsoleCaCertificates []string `json:"console_ca_certificates"`
// minio
Minio []*KeyPairConfiguration `json:"minio"`
}
@@ -53,10 +47,6 @@ type TLSConfiguration struct {
func (m *TLSConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if err := m.validateMinio(formats); err != nil {
res = append(res, err)
}
@@ -67,23 +57,6 @@ func (m *TLSConfiguration) Validate(formats strfmt.Registry) error {
return nil
}
func (m *TLSConfiguration) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
if m.Console != nil {
if err := m.Console.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
func (m *TLSConfiguration) validateMinio(formats strfmt.Registry) error {
if swag.IsZero(m.Minio) { // not required
return nil
@@ -112,10 +85,6 @@ func (m *TLSConfiguration) validateMinio(formats strfmt.Registry) error {
func (m *TLSConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateConsole(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateMinio(ctx, formats); err != nil {
res = append(res, err)
}
@@ -126,20 +95,6 @@ func (m *TLSConfiguration) ContextValidate(ctx context.Context, formats strfmt.R
return nil
}
func (m *TLSConfiguration) contextValidateConsole(ctx context.Context, formats strfmt.Registry) error {
if m.Console != nil {
if err := m.Console.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
func (m *TLSConfiguration) contextValidateMinio(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Minio); i++ {

View File

@@ -36,10 +36,6 @@ import (
// swagger:model updateTenantRequest
type UpdateTenantRequest struct {
// console image
// Pattern: ^((.*?)/(.*?):(.+))$
ConsoleImage string `json:"console_image,omitempty"`
// enable prometheus
EnablePrometheus bool `json:"enable_prometheus,omitempty"`
@@ -58,10 +54,6 @@ type UpdateTenantRequest struct {
func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsoleImage(formats); err != nil {
res = append(res, err)
}
if err := m.validateImage(formats); err != nil {
res = append(res, err)
}
@@ -76,18 +68,6 @@ func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
return nil
}
func (m *UpdateTenantRequest) validateConsoleImage(formats strfmt.Registry) error {
if swag.IsZero(m.ConsoleImage) { // not required
return nil
}
if err := validate.Pattern("console_image", "body", m.ConsoleImage, `^((.*?)/(.*?):(.+))$`); err != nil {
return err
}
return nil
}
func (m *UpdateTenantRequest) validateImage(formats strfmt.Registry) error {
if swag.IsZero(m.Image) { // not required
return nil

View File

@@ -125,12 +125,6 @@ func (m *UpdateTenantSecurityRequest) UnmarshalBinary(b []byte) error {
// swagger:model UpdateTenantSecurityRequestCustomCertificates
type UpdateTenantSecurityRequestCustomCertificates struct {
// console
Console []*KeyPairConfiguration `json:"console"`
// console c as
ConsoleCAs []string `json:"consoleCAs"`
// minio
Minio []*KeyPairConfiguration `json:"minio"`
@@ -145,10 +139,6 @@ type UpdateTenantSecurityRequestCustomCertificates struct {
func (m *UpdateTenantSecurityRequestCustomCertificates) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if err := m.validateMinio(formats); err != nil {
res = append(res, err)
}
@@ -159,30 +149,6 @@ func (m *UpdateTenantSecurityRequestCustomCertificates) Validate(formats strfmt.
return nil
}
func (m *UpdateTenantSecurityRequestCustomCertificates) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
for i := 0; i < len(m.Console); i++ {
if swag.IsZero(m.Console[i]) { // not required
continue
}
if m.Console[i] != nil {
if err := m.Console[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "console" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *UpdateTenantSecurityRequestCustomCertificates) validateMinio(formats strfmt.Registry) error {
if swag.IsZero(m.Minio) { // not required
return nil
@@ -211,10 +177,6 @@ func (m *UpdateTenantSecurityRequestCustomCertificates) validateMinio(formats st
func (m *UpdateTenantSecurityRequestCustomCertificates) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateConsole(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateMinio(ctx, formats); err != nil {
res = append(res, err)
}
@@ -225,24 +187,6 @@ func (m *UpdateTenantSecurityRequestCustomCertificates) ContextValidate(ctx cont
return nil
}
func (m *UpdateTenantSecurityRequestCustomCertificates) contextValidateConsole(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Console); i++ {
if m.Console[i] != nil {
if err := m.Console[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("customCertificates" + "." + "console" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *UpdateTenantSecurityRequestCustomCertificates) contextValidateMinio(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Minio); i++ {

View File

@@ -37,6 +37,9 @@ type User struct {
// access key
AccessKey string `json:"accessKey,omitempty"`
// has policy
HasPolicy bool `json:"hasPolicy,omitempty"`
// member of
MemberOf []string `json:"memberOf"`

6
node_modules/.yarn-integrity generated vendored
View File

@@ -1,10 +1,12 @@
{
"systemParams": "darwin-x64-93",
"systemParams": "linux-x64-93",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"linkedModules": [
"one-ui-common"
],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],

View File

@@ -56,12 +56,6 @@ var (
GlobalTLSCertsManager *xcerts.Manager
)
var consoleImage string
func init() {
consoleImage = env.Get(ConsoleOperatorConsoleImage, ConsoleImageDefaultVersion)
}
// getK8sSAToken assumes the plugin is running inside a k8s pod and extract the current service account from the
// /var/run/secrets/kubernetes.io/serviceaccount/token file
func getK8sSAToken() string {
@@ -71,6 +65,3 @@ func getK8sSAToken() string {
}
return string(dat)
}
func getConsoleImage() string {
return consoleImage
}

View File

@@ -65,7 +65,6 @@ func configureAPI(api *operations.OperatorAPI) http.Handler {
}
return &models.Principal{
STSAccessKeyID: claims.STSAccessKeyID,
Actions: claims.Actions,
STSSecretAccessKey: claims.STSSecretAccessKey,
STSSessionToken: claims.STSSessionToken,
AccountAccessKey: claims.AccountAccessKey,
@@ -93,7 +92,7 @@ func configureAPI(api *operations.OperatorAPI) http.Handler {
// Namespaces handlers
registerNamespaceHandlers(api)
// Subscription handlers
registerOperatorSubscriptionHandlers(api)
registerSubscriptionHandlers(api)
api.PreServerShutdown = func() {}

View File

@@ -18,37 +18,9 @@ package operatorapi
// list of all console environment constants
const (
// Constants for common configuration
ConsoleMinIOServer = "CONSOLE_MINIO_SERVER"
ConsoleMinIORegion = "CONSOLE_MINIO_REGION"
ConsoleHostname = "CONSOLE_HOSTNAME"
ConsolePort = "CONSOLE_PORT"
ConsoleTLSHostname = "CONSOLE_TLS_HOSTNAME"
ConsoleTLSPort = "CONSOLE_TLS_PORT"
ConsoleSubnetLicense = "CONSOLE_SUBNET_LICENSE"
// Constants for Secure middleware
ConsoleSecureAllowedHosts = "CONSOLE_SECURE_ALLOWED_HOSTS"
ConsoleSecureAllowedHostsAreRegex = "CONSOLE_SECURE_ALLOWED_HOSTS_ARE_REGEX"
ConsoleSecureFrameDeny = "CONSOLE_SECURE_FRAME_DENY"
ConsoleSecureContentTypeNoSniff = "CONSOLE_SECURE_CONTENT_TYPE_NO_SNIFF"
ConsoleSecureBrowserXSSFilter = "CONSOLE_SECURE_BROWSER_XSS_FILTER"
ConsoleSecureContentSecurityPolicy = "CONSOLE_SECURE_CONTENT_SECURITY_POLICY"
ConsoleSecureContentSecurityPolicyReportOnly = "CONSOLE_SECURE_CONTENT_SECURITY_POLICY_REPORT_ONLY"
ConsoleSecureHostsProxyHeaders = "CONSOLE_SECURE_HOSTS_PROXY_HEADERS"
ConsoleSecureSTSSeconds = "CONSOLE_SECURE_STS_SECONDS"
ConsoleSecureSTSIncludeSubdomains = "CONSOLE_SECURE_STS_INCLUDE_SUB_DOMAINS"
ConsoleSecureSTSPreload = "CONSOLE_SECURE_STS_PRELOAD"
ConsoleSecureTLSRedirect = "CONSOLE_SECURE_TLS_REDIRECT"
ConsoleSecureTLSHost = "CONSOLE_SECURE_TLS_HOST"
ConsoleSecureTLSTemporaryRedirect = "CONSOLE_SECURE_TLS_TEMPORARY_REDIRECT"
ConsoleSecureForceSTSHeader = "CONSOLE_SECURE_FORCE_STS_HEADER"
ConsoleSecurePublicKey = "CONSOLE_SECURE_PUBLIC_KEY"
ConsoleSecureReferrerPolicy = "CONSOLE_SECURE_REFERRER_POLICY"
ConsoleSecureFeaturePolicy = "CONSOLE_SECURE_FEATURE_POLICY"
ConsoleSecureExpectCTHeader = "CONSOLE_SECURE_EXPECT_CT_HEADER"
ConsoleOperatorSAToken = "CONSOLE_OPERATOR_SA_TOKEN"
ConsoleOperatorConsoleImage = "CONSOLE_OPERATOR_CONSOLE_IMAGE"
ConsoleSubnetLicense = "CONSOLE_SUBNET_LICENSE"
ConsoleOperatorSAToken = "CONSOLE_OPERATOR_SA_TOKEN"
MinIOSubnetLicense = "MINIO_SUBNET_LICENSE"
// Constants for prometheus annotations
prometheusPath = "prometheus.io/path"
@@ -58,8 +30,7 @@ const (
// Image versions
const (
KESImageVersion = "minio/kes:v0.13.4"
ConsoleImageDefaultVersion = "minio/console:v0.8.0"
KESImageVersion = "minio/kes:v0.16.1"
)
// K8s

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,10 @@ var (
errLicenseNotFound = errors.New("license not found")
errAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself")
errAccessDenied = errors.New("access denied")
errTooManyNodes = errors.New("cannot request more nodes than what is available in the cluster")
errTooFewNodes = errors.New("there are not enough nodes in the cluster to support this tenant")
errTooFewSchedulableNodes = errors.New("there is not enough schedulable nodes to satisfy this requirement")
errFewerThanFourNodes = errors.New("at least 4 nodes are required for a tenant")
)
// prepareError receives an error object and parse it against k8sErrors, returns the right error code paired with a generic error message
@@ -156,8 +160,20 @@ func prepareError(err ...error) *models.Error {
if errors.Is(err[0], errRemoteTierExists) {
errorMessage = err[0].Error()
}
if errors.Is(err[0], errTooFewNodes) {
errorCode = 507
errorMessage = errTooFewNodes.Error()
}
if errors.Is(err[0], errTooFewSchedulableNodes) {
errorCode = 507
errorMessage = errTooFewSchedulableNodes.Error()
}
if errors.Is(err[0], errFewerThanFourNodes) {
errorCode = 507
errorMessage = errFewerThanFourNodes.Error()
}
}
return &models.Error{Code: errorCode, Message: swag.String(errorMessage)}
return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err[0].Error())}
}
func getFrame(skipFrames int) runtime.Frame {

View File

@@ -37,6 +37,7 @@ type K8sClientI interface {
deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
updateSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.UpdateOptions) (*v1.Secret, error)
}
// Interface implementation
@@ -70,6 +71,10 @@ func (c *k8sClient) createSecret(ctx context.Context, namespace string, secret *
return c.client.CoreV1().Secrets(namespace).Create(ctx, secret, opts)
}
func (c *k8sClient) updateSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.UpdateOptions) (*v1.Secret, error) {
return c.client.CoreV1().Secrets(namespace).Update(ctx, secret, opts)
}
func (c *k8sClient) getNamespace(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Namespace, error) {
return c.client.CoreV1().Namespaces().Get(ctx, name, opts)
}

View File

@@ -117,6 +117,9 @@ func NewOperatorAPI(spec *loads.Document) *OperatorAPI {
OperatorAPIListPVCsHandler: operator_api.ListPVCsHandlerFunc(func(params operator_api.ListPVCsParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.ListPVCs has not yet been implemented")
}),
OperatorAPIListPVCsForTenantHandler: operator_api.ListPVCsForTenantHandlerFunc(func(params operator_api.ListPVCsForTenantParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.ListPVCsForTenant has not yet been implemented")
}),
OperatorAPIListTenantsHandler: operator_api.ListTenantsHandlerFunc(func(params operator_api.ListTenantsParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.ListTenants has not yet been implemented")
}),
@@ -262,6 +265,8 @@ type OperatorAPI struct {
OperatorAPIListNodeLabelsHandler operator_api.ListNodeLabelsHandler
// OperatorAPIListPVCsHandler sets the operation handler for the list p v cs operation
OperatorAPIListPVCsHandler operator_api.ListPVCsHandler
// OperatorAPIListPVCsForTenantHandler sets the operation handler for the list p v cs for tenant operation
OperatorAPIListPVCsForTenantHandler operator_api.ListPVCsForTenantHandler
// OperatorAPIListTenantsHandler sets the operation handler for the list tenants operation
OperatorAPIListTenantsHandler operator_api.ListTenantsHandler
// UserAPILoginHandler sets the operation handler for the login operation
@@ -437,6 +442,9 @@ func (o *OperatorAPI) Validate() error {
if o.OperatorAPIListPVCsHandler == nil {
unregistered = append(unregistered, "operator_api.ListPVCsHandler")
}
if o.OperatorAPIListPVCsForTenantHandler == nil {
unregistered = append(unregistered, "operator_api.ListPVCsForTenantHandler")
}
if o.OperatorAPIListTenantsHandler == nil {
unregistered = append(unregistered, "operator_api.ListTenantsHandler")
}
@@ -670,6 +678,10 @@ func (o *OperatorAPI) initHandlerCache() {
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants/{tenant}/pvcs"] = operator_api.NewListPVCsForTenant(o.context, o.OperatorAPIListPVCsForTenantHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants"] = operator_api.NewListTenants(o.context, o.OperatorAPIListTenantsHandler)
if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler)

View File

@@ -0,0 +1,88 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// ListPVCsForTenantHandlerFunc turns a function with the right signature into a list p v cs for tenant handler
type ListPVCsForTenantHandlerFunc func(ListPVCsForTenantParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn ListPVCsForTenantHandlerFunc) Handle(params ListPVCsForTenantParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// ListPVCsForTenantHandler interface for that can handle valid list p v cs for tenant params
type ListPVCsForTenantHandler interface {
Handle(ListPVCsForTenantParams, *models.Principal) middleware.Responder
}
// NewListPVCsForTenant creates a new http.Handler for the list p v cs for tenant operation
func NewListPVCsForTenant(ctx *middleware.Context, handler ListPVCsForTenantHandler) *ListPVCsForTenant {
return &ListPVCsForTenant{Context: ctx, Handler: handler}
}
/* ListPVCsForTenant swagger:route GET /namespaces/{namespace}/tenants/{tenant}/pvcs OperatorAPI listPVCsForTenant
List all PVCs from given Tenant
*/
type ListPVCsForTenant struct {
Context *middleware.Context
Handler ListPVCsForTenantHandler
}
func (o *ListPVCsForTenant) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewListPVCsForTenantParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -0,0 +1,112 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// NewListPVCsForTenantParams creates a new ListPVCsForTenantParams object
//
// There are no default values defined in the spec.
func NewListPVCsForTenantParams() ListPVCsForTenantParams {
return ListPVCsForTenantParams{}
}
// ListPVCsForTenantParams contains all the bound params for the list p v cs for tenant operation
// typically these are obtained from a http.Request
//
// swagger:parameters ListPVCsForTenant
type ListPVCsForTenantParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: path
*/
Namespace string
/*
Required: true
In: path
*/
Tenant string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewListPVCsForTenantParams() beforehand.
func (o *ListPVCsForTenantParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
res = append(res, err)
}
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindNamespace binds and validates parameter Namespace from path.
func (o *ListPVCsForTenantParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Namespace = raw
return nil
}
// bindTenant binds and validates parameter Tenant from path.
func (o *ListPVCsForTenantParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Tenant = raw
return nil
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// ListPVCsForTenantOKCode is the HTTP code returned for type ListPVCsForTenantOK
const ListPVCsForTenantOKCode int = 200
/*ListPVCsForTenantOK A successful response.
swagger:response listPVCsForTenantOK
*/
type ListPVCsForTenantOK struct {
/*
In: Body
*/
Payload *models.ListPVCsResponse `json:"body,omitempty"`
}
// NewListPVCsForTenantOK creates ListPVCsForTenantOK with default headers values
func NewListPVCsForTenantOK() *ListPVCsForTenantOK {
return &ListPVCsForTenantOK{}
}
// WithPayload adds the payload to the list p v cs for tenant o k response
func (o *ListPVCsForTenantOK) WithPayload(payload *models.ListPVCsResponse) *ListPVCsForTenantOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the list p v cs for tenant o k response
func (o *ListPVCsForTenantOK) SetPayload(payload *models.ListPVCsResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *ListPVCsForTenantOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*ListPVCsForTenantDefault Generic error response.
swagger:response listPVCsForTenantDefault
*/
type ListPVCsForTenantDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewListPVCsForTenantDefault creates ListPVCsForTenantDefault with default headers values
func NewListPVCsForTenantDefault(code int) *ListPVCsForTenantDefault {
if code <= 0 {
code = 500
}
return &ListPVCsForTenantDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the list p v cs for tenant default response
func (o *ListPVCsForTenantDefault) WithStatusCode(code int) *ListPVCsForTenantDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the list p v cs for tenant default response
func (o *ListPVCsForTenantDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the list p v cs for tenant default response
func (o *ListPVCsForTenantDefault) WithPayload(payload *models.Error) *ListPVCsForTenantDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the list p v cs for tenant default response
func (o *ListPVCsForTenantDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *ListPVCsForTenantDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -0,0 +1,124 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// ListPVCsForTenantURL generates an URL for the list p v cs for tenant operation
type ListPVCsForTenantURL struct {
Namespace string
Tenant string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *ListPVCsForTenantURL) WithBasePath(bp string) *ListPVCsForTenantURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *ListPVCsForTenantURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *ListPVCsForTenantURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/namespaces/{namespace}/tenants/{tenant}/pvcs"
namespace := o.Namespace
if namespace != "" {
_path = strings.Replace(_path, "{namespace}", namespace, -1)
} else {
return nil, errors.New("namespace is required on ListPVCsForTenantURL")
}
tenant := o.Tenant
if tenant != "" {
_path = strings.Replace(_path, "{tenant}", tenant, -1)
} else {
return nil, errors.New("tenant is required on ListPVCsForTenantURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *ListPVCsForTenantURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *ListPVCsForTenantURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *ListPVCsForTenantURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on ListPVCsForTenantURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on ListPVCsForTenantURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *ListPVCsForTenantURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -17,23 +17,17 @@
package operatorapi
import (
"bytes"
"context"
"net/http"
"time"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/minio/console/restapi"
iampolicy "github.com/minio/pkg/iam/policy"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
"github.com/minio/console/operatorapi/operations"
"github.com/minio/console/operatorapi/operations/user_api"
"github.com/minio/console/pkg/acl"
"github.com/minio/console/pkg/auth"
"github.com/minio/console/pkg/auth/idp/oauth2"
)
@@ -95,7 +89,7 @@ func login(credentials restapi.ConsoleCredentialsI) (*string, error) {
return nil, err
}
// if we made it here, the consoleCredentials work, generate a jwt with claims
token, err := auth.NewEncryptedTokenForClient(&tokens, credentials.GetAccountAccessKey(), credentials.GetActions())
token, err := auth.NewEncryptedTokenForClient(&tokens, credentials.GetAccountAccessKey())
if err != nil {
LogError("error authenticating user: %v", err)
return nil, errInvalidCredentials
@@ -103,67 +97,22 @@ func login(credentials restapi.ConsoleCredentialsI) (*string, error) {
return &token, nil
}
// getAccountPolicy will return the associated policy of the current account
func getAccountPolicy(ctx context.Context, client restapi.MinioAdmin) (*iampolicy.Policy, error) {
// Obtain the current policy assigned to this user
// necessary for generating the list of allowed endpoints
accountInfo, err := client.AccountInfo(ctx)
if err != nil {
return nil, err
}
return iampolicy.ParseConfig(bytes.NewReader(accountInfo.Policy))
}
// getConsoleCredentials will return consoleCredentials interface including the associated policy of the current account
func getConsoleCredentials(ctx context.Context, accessKey, secretKey string) (*restapi.ConsoleCredentials, error) {
func getConsoleCredentials(accessKey, secretKey string) (*restapi.ConsoleCredentials, error) {
creds, err := newConsoleCredentials(secretKey)
if err != nil {
return nil, err
}
// cCredentials will be sts credentials, account credentials will be need it in the scenario the user wish
// to change its password
cCredentials := &restapi.ConsoleCredentials{
return &restapi.ConsoleCredentials{
ConsoleCredentials: creds,
AccountAccessKey: accessKey,
}
tokens, err := cCredentials.Get()
if err != nil {
return nil, err
}
// initialize admin client
mAdminClient, err := restapi.NewMinioAdminClient(&models.Principal{
STSAccessKeyID: tokens.AccessKeyID,
STSSecretAccessKey: tokens.SecretAccessKey,
STSSessionToken: tokens.SessionToken,
})
if err != nil {
return nil, err
}
userAdminClient := restapi.AdminClient{Client: mAdminClient}
// Obtain the current policy assigned to this user
// necessary for generating the list of allowed endpoints
policy, err := getAccountPolicy(ctx, userAdminClient)
if err != nil {
return nil, err
}
// by default every user starts with an empty array of available actions
// therefore we would have access only to pages that doesn't require any privilege
// ie: service-account page
var actions []string
// if a policy is assigned to this user we parse the actions from there
if policy != nil {
actions = acl.GetActionsStringFromPolicy(policy)
}
cCredentials.Actions = actions
return cCredentials, nil
}, nil
}
// getLoginResponse performs login() and serializes it to the handler's output
func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, *models.Error) {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
// prepare console credentials
consolCreds, err := getConsoleCredentials(ctx, *lr.AccessKey, *lr.SecretKey)
consolCreds, err := getConsoleCredentials(*lr.AccessKey, *lr.SecretKey)
if err != nil {
return nil, prepareError(errInvalidCredentials, nil, err)
}
@@ -180,15 +129,13 @@ func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, *models.E
// getLoginDetailsResponse returns information regarding the Console authentication mechanism.
func getLoginDetailsResponse() (*models.LoginDetails, *models.Error) {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
loginStrategy := models.LoginDetailsLoginStrategyServiceDashAccount
redirectURL := ""
if oauth2.IsIdpEnabled() {
if oauth2.IsIDPEnabled() {
loginStrategy = models.LoginDetailsLoginStrategyRedirect
// initialize new oauth2 client
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil, restapi.GetConsoleSTSClient())
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, restapi.GetConsoleHTTPClient())
if err != nil {
return nil, prepareError(err)
}
@@ -210,7 +157,7 @@ func getLoginOauth2AuthResponse() (*models.LoginResponse, *models.Error) {
if err != nil {
return nil, prepareError(err)
}
consoleCredentials := restapi.ConsoleCredentials{ConsoleCredentials: creds, Actions: []string{}}
consoleCredentials := restapi.ConsoleCredentials{ConsoleCredentials: creds}
token, err := login(consoleCredentials)
if err != nil {
return nil, prepareError(errInvalidCredentials, nil, err)
@@ -236,7 +183,7 @@ func getLoginOperatorResponse(lmr *models.LoginOperatorRequest) (*models.LoginRe
if err != nil {
return nil, prepareError(err)
}
consoleCreds := restapi.ConsoleCredentials{ConsoleCredentials: creds, Actions: []string{}}
consoleCreds := restapi.ConsoleCredentials{ConsoleCredentials: creds}
token, err := login(consoleCreds)
if err != nil {
return nil, prepareError(errInvalidCredentials, nil, err)

View File

@@ -26,8 +26,6 @@ import (
"github.com/minio/console/cluster"
"errors"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
"github.com/minio/console/operatorapi/operations"
@@ -56,8 +54,9 @@ func registerNodesHandlers(api *operations.OperatorAPI) {
// getMaxAllocatableMemory get max allocatable memory given a desired number of nodes
func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
if numNodes == 0 {
return nil, errors.New("error NumNodes must be greated than 0")
// can't request less than 4 nodes
if numNodes < 4 {
return nil, errFewerThanFourNodes
}
// get all nodes from cluster
@@ -66,6 +65,34 @@ func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface,
return nil, err
}
// requesting more nodes than are schedulable in the cluster
schedulableNodes := len(nodes.Items)
nonMasterNodes := len(nodes.Items)
for _, node := range nodes.Items {
// check taints to check if node is schedulable
for _, taint := range node.Spec.Taints {
if taint.Effect == corev1.TaintEffectNoSchedule {
schedulableNodes--
}
// check if the node is a master
if taint.Key == "node-role.kubernetes.io/master" {
nonMasterNodes--
}
}
}
// requesting more nodes than schedulable and less than total number of workers
if int(numNodes) > schedulableNodes && int(numNodes) < nonMasterNodes {
return nil, errTooManyNodes
}
if nonMasterNodes < int(numNodes) {
return nil, errTooFewNodes
}
// not enough schedulable nodes
if schedulableNodes < int(numNodes) {
return nil, errTooFewSchedulableNodes
}
availableMemSizes := []int64{}
OUTER:
for _, n := range nodes.Items {

View File

@@ -42,7 +42,7 @@ func getSessionResponse(session *models.Principal) (*models.OperatorSessionRespo
return nil, prepareError(errorGenericInvalidSession)
}
sessionResp := &models.OperatorSessionResponse{
Pages: acl.GetAuthorizedEndpoints(session.Actions),
Pages: acl.GetAuthorizedEndpoints([]string{}),
Features: getListOfEnabledFeatures(),
Status: models.OperatorSessionResponseStatusOk,
Operator: true,

View File

@@ -20,13 +20,12 @@ package operatorapi
import (
"context"
"errors"
"fmt"
"time"
"github.com/minio/console/pkg/subnet"
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/minio/console/restapi"
@@ -38,10 +37,10 @@ import (
"github.com/minio/console/operatorapi/operations/operator_api"
)
func registerOperatorSubscriptionHandlers(api *operations.OperatorAPI) {
func registerSubscriptionHandlers(api *operations.OperatorAPI) {
// Activate license subscription for a particular tenant
api.OperatorAPISubscriptionActivateHandler = operator_api.SubscriptionActivateHandlerFunc(func(params operator_api.SubscriptionActivateParams, session *models.Principal) middleware.Responder {
err := getOperatorSubscriptionActivateResponse(session, params.Namespace, params.Tenant)
err := getSubscriptionActivateResponse(session, params.Namespace, params.Tenant)
if err != nil {
return operator_api.NewSubscriptionActivateDefault(int(err.Code)).WithPayload(err)
}
@@ -55,10 +54,33 @@ func registerOperatorSubscriptionHandlers(api *operations.OperatorAPI) {
}
return operator_api.NewSubscriptionRefreshOK().WithPayload(license)
})
// Validate subscription handler
api.OperatorAPISubscriptionValidateHandler = operator_api.SubscriptionValidateHandlerFunc(func(params operator_api.SubscriptionValidateParams, session *models.Principal) middleware.Responder {
license, err := getSubscriptionValidateResponse(session, params.Body)
if err != nil {
return operator_api.NewSubscriptionValidateDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewSubscriptionValidateOK().WithPayload(license)
})
// Get subscription information handler
api.OperatorAPISubscriptionInfoHandler = operator_api.SubscriptionInfoHandlerFunc(func(params operator_api.SubscriptionInfoParams, session *models.Principal) middleware.Responder {
license, err := getSubscriptionInfoResponse(session)
if err != nil {
return operator_api.NewSubscriptionInfoDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewSubscriptionInfoOK().WithPayload(license)
})
// Refresh license for k8s cluster
api.OperatorAPISubscriptionRefreshHandler = operator_api.SubscriptionRefreshHandlerFunc(func(params operator_api.SubscriptionRefreshParams, session *models.Principal) middleware.Responder {
license, err := getSubscriptionRefreshResponse(session)
if err != nil {
return operator_api.NewSubscriptionRefreshDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewSubscriptionRefreshOK().WithPayload(license)
})
}
// retrieveLicense returns license from K8S secrets (If console is deployed in operator mode) or from
// the configured CONSOLE_SUBNET_LICENSE environment variable
// retrieveLicense returns license from K8S secrets
func retrieveLicense(ctx context.Context, sessionToken string) (string, error) {
var license string
@@ -79,46 +101,6 @@ func retrieveLicense(ctx context.Context, sessionToken string) (string, error) {
return license, nil
}
func getOperatorSubscriptionActivateResponse(session *models.Principal, namespace, tenant string) *models.Error {
// 20 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
if err != nil {
return prepareError(restapi.ErrorGeneric, nil, err)
}
clientSet, err := cluster.K8sClient(session.STSSessionToken)
if err != nil {
return prepareError(restapi.ErrorGeneric, nil, err)
}
opClient := &operatorClient{
client: opClientClientSet,
}
minTenant, err := getTenant(ctx, opClient, namespace, tenant)
if err != nil {
return prepareError(err, restapi.ErrorGeneric)
}
// If console is not deployed for this tenant return an error
if minTenant.Spec.Console == nil {
return prepareError(restapi.ErrorGenericNotFound)
}
// configure kubernetes client
k8sClient := k8sClient{
client: clientSet,
}
// Get cluster subscription license
license, err := getSubscriptionLicense(ctx, &k8sClient, cluster.Namespace, OperatorSubnetLicenseSecretName)
if err != nil {
return prepareError(errInvalidCredentials, nil, err)
}
// add subscription license to existing console Tenant
if err = addSubscriptionLicenseToTenant(ctx, &k8sClient, license, namespace, tenant, minTenant.Spec.Console.ConsoleSecret.Name); err != nil {
return prepareError(err, restapi.ErrorGeneric)
}
return nil
}
// getSubscriptionLicense will retrieve stored license jwt from k8s secret
func getSubscriptionLicense(ctx context.Context, clientSet K8sClientI, namespace, secretName string) (string, error) {
// retrieve license stored in k8s
@@ -135,86 +117,66 @@ func getSubscriptionLicense(ctx context.Context, clientSet K8sClientI, namespace
}
// addSubscriptionLicenseToTenant replace existing console tenant secret and adds the subnet license key
func addSubscriptionLicenseToTenant(ctx context.Context, clientSet K8sClientI, license, namespace, tenantName, secretName string) error {
// Retrieve console secret for Tenant
consoleSecret, err := clientSet.getSecret(ctx, namespace, secretName, metav1.GetOptions{})
if err != nil {
return err
}
// Copy current console secret
dataNewSecret := consoleSecret.Data
// Add subnet license to the new console secret
dataNewSecret[ConsoleSubnetLicense] = []byte(license)
// Delete existing console secret
err = clientSet.deleteSecret(ctx, namespace, secretName, metav1.DeleteOptions{})
if err != nil {
return err
}
// Prepare the new Console Secret
imm := true
newConsoleSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Labels: map[string]string{
miniov2.TenantLabel: tenantName,
},
},
Immutable: &imm,
Data: dataNewSecret,
}
// Create new Console secret with the subnet License
_, err = clientSet.createSecret(ctx, namespace, newConsoleSecret, metav1.CreateOptions{})
if err != nil {
return err
}
// restart Console pods based on label:
// v1.min.io/console: TENANT-console
err = clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s%s", miniov2.ConsoleTenantLabel, tenantName, miniov2.ConsoleName),
})
if err != nil {
return err
}
return nil
}
// updateTenantLicenseAndRestartConsole
func updateTenantLicenseAndRestartConsole(ctx context.Context, clientSet K8sClientI, license, namespace, tenantName string) error {
consoleSelector := fmt.Sprintf("%s-console", tenantName)
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
// read current console configuration from k8s secrets
currentConsoleSecret, err := clientSet.getSecret(ctx, namespace, consoleSecretName, metav1.GetOptions{})
if err != nil || currentConsoleSecret == nil {
return err
}
secretData := currentConsoleSecret.Data
secretData[ConsoleSubnetLicense] = []byte(license)
// delete existing console configuration from k8s secrets
err = clientSet.deleteSecret(ctx, namespace, consoleSecretName, metav1.DeleteOptions{})
if err != nil {
// log the error if any and continue
LogError("unable to delete secret %s: %v", consoleSecretName, err)
}
// Save subnet license in k8s secrets
imm := true
consoleConfigSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: consoleSecretName,
},
Immutable: &imm,
Data: secretData,
}
_, err = clientSet.createSecret(ctx, namespace, consoleConfigSecret, metav1.CreateOptions{})
if err != nil {
return err
}
// restart Console pods based on label:
// v1.min.io/console: TENANT-console
err = clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s%s", miniov2.ConsoleTenantLabel, tenantName, miniov2.ConsoleName),
})
if err != nil {
return err
func addSubscriptionLicenseToTenant(ctx context.Context, clientSet K8sClientI, opClient OperatorClientI, license string, tenant *miniov2.Tenant) error {
// If Tenant has a configuration secret update the license there and MinIO pods doesn't need to get restarted
if tenant.HasConfigurationSecret() {
// Update the Tenant Configuration
tenantConfigurationSecret, err := clientSet.getSecret(ctx, tenant.Namespace, tenant.Spec.Configuration.Name, metav1.GetOptions{})
if err != nil {
return err
}
if _, ok := tenantConfigurationSecret.Data["config.env"]; ok {
updatedTenantConfiguration := map[string]string{}
tenantConfigurationMap := miniov2.ParseRawConfiguration(tenantConfigurationSecret.Data["config.env"])
for key, val := range tenantConfigurationMap {
updatedTenantConfiguration[key] = string(val)
}
updatedTenantConfiguration[MinIOSubnetLicense] = license
// removing accesskey & secretkey that are added automatically by parsing function
// and are not need it for the tenant itself
delete(updatedTenantConfiguration, "accesskey")
delete(updatedTenantConfiguration, "secretkey")
tenantConfigurationSecret.Data = map[string][]byte{
"config.env": []byte(GenerateTenantConfigurationFile(updatedTenantConfiguration)),
}
_, err = clientSet.updateSecret(ctx, tenant.Namespace, tenantConfigurationSecret, metav1.UpdateOptions{})
if err != nil {
return err
}
} else {
return errors.New("tenant configuration secret has wrong format")
}
} else {
// If configuration file is not present set the license to the container env
updatedTenant := tenant.DeepCopy()
// reset container env vars
updatedTenant.Spec.Env = []corev1.EnvVar{}
var licenseIsSet bool
for _, env := range tenant.GetEnvVars() {
// check if license already exists and override
if env.Name == MinIOSubnetLicense {
updatedTenant.Spec.Env = append(updatedTenant.Spec.Env, corev1.EnvVar{
Name: MinIOSubnetLicense,
Value: license,
})
licenseIsSet = true
} else {
// copy existing container env variables
updatedTenant.Spec.Env = append(updatedTenant.Spec.Env, env)
}
}
// if license didnt exists append it
if !licenseIsSet {
updatedTenant.Spec.Env = append(updatedTenant.Spec.Env, corev1.EnvVar{
Name: MinIOSubnetLicense,
Value: license,
})
}
// this will start MinIO pods rolling restart
_, err := opClient.TenantUpdate(ctx, updatedTenant, metav1.UpdateOptions{})
if err != nil {
return err
}
}
return nil
}
@@ -224,9 +186,9 @@ func getSubscriptionRefreshResponse(session *models.Principal) (*models.License,
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
client := &cluster.HTTPClient{
Client: restapi.GetConsoleSTSClient(),
Client: restapi.GetConsoleHTTPClient(),
}
licenseKey, err := retrieveLicense(context.Background(), session.STSSessionToken)
licenseKey, err := retrieveLicense(ctx, session.STSSessionToken)
if err != nil {
return nil, prepareError(errLicenseNotFound, nil, err)
}
@@ -251,17 +213,17 @@ func getSubscriptionRefreshResponse(session *models.Principal) (*models.License,
if err != nil {
return nil, prepareError(err)
}
opClient := &operatorClient{
opClient := operatorClient{
client: opClientClientSet,
}
tenants, err := listTenants(ctx, opClient, "", nil)
// iterate over all tenants and update licenses
tenants, err := opClient.TenantList(ctx, "", metav1.ListOptions{})
if err != nil {
return nil, prepareError(err)
}
// iterate over all tenants, update console configuration and restart console pods
for _, tenant := range tenants.Tenants {
if err := updateTenantLicenseAndRestartConsole(ctx, &k8sClient, licenseRaw, tenant.Namespace, tenant.Name); err != nil {
LogError("unable to updateTenantLicenseAndRestartConsole: %v", err)
for _, tenant := range tenants.Items {
if err = addSubscriptionLicenseToTenant(ctx, &k8sClient, &opClient, licenseRaw, &tenant); err != nil {
return nil, prepareError(err)
}
}
@@ -280,7 +242,7 @@ func RefreshLicense() error {
return err
}
client := &cluster.HTTPClient{
Client: restapi.GetConsoleSTSClient(),
Client: restapi.GetConsoleHTTPClient(),
}
// Attempt to refresh license
_, refreshedLicenseKey, err := subscriptionRefresh(client, licenseKey)
@@ -321,24 +283,31 @@ func subscriptionRefresh(httpClient *cluster.HTTPClient, license string) (*model
// saveSubscriptionLicense will create or replace an existing subnet license secret in the k8s cluster
func saveSubscriptionLicense(ctx context.Context, clientSet K8sClientI, license string) error {
// Delete subnet license secret if exists
err := clientSet.deleteSecret(ctx, cluster.Namespace, OperatorSubnetLicenseSecretName, metav1.DeleteOptions{})
licenseSecret, err := clientSet.getSecret(ctx, cluster.Namespace, OperatorSubnetLicenseSecretName, metav1.GetOptions{})
if err != nil {
// log the error if any and continue
LogError("unable to delete secret %s: %v", OperatorSubnetLicenseSecretName, err)
if k8serrors.IsNotFound(err) {
// Save subnet license in k8s secrets
licenseSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
},
Data: map[string][]byte{
ConsoleSubnetLicense: []byte(license),
},
}
_, err = clientSet.createSecret(ctx, cluster.Namespace, licenseSecret, metav1.CreateOptions{})
if err != nil {
return err
}
return nil
}
return err
}
// Save subnet license in k8s secrets
imm := true
licenseSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
},
Immutable: &imm,
Data: map[string][]byte{
ConsoleSubnetLicense: []byte(license),
},
// update existing license
licenseSecret.Data = map[string][]byte{
ConsoleSubnetLicense: []byte(license),
}
_, err = clientSet.createSecret(ctx, cluster.Namespace, licenseSecret, metav1.CreateOptions{})
_, err = clientSet.updateSecret(ctx, cluster.Namespace, licenseSecret, metav1.UpdateOptions{})
if err != nil {
return err
}
@@ -360,3 +329,88 @@ func subscriptionValidate(client cluster.HTTPClientI, license, email, password s
Organization: licenseInfo.Organization,
}, rawLicense, nil
}
// getSubscriptionValidateResponse
func getSubscriptionValidateResponse(session *models.Principal, params *models.SubscriptionValidateRequest) (*models.License, *models.Error) {
// 20 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
client := &cluster.HTTPClient{
Client: restapi.GetConsoleHTTPClient(),
}
// validate license key
licenseInfo, license, err := subscriptionValidate(client, params.License, params.Email, params.Password)
if err != nil {
return nil, prepareError(errInvalidLicense, nil, err)
}
// configure kubernetes client
clientSet, err := cluster.K8sClient(session.STSSessionToken)
k8sClient := k8sClient{
client: clientSet,
}
if err != nil {
return nil, prepareError(errorGeneric, nil, err)
}
// save license key to k8s
if err = saveSubscriptionLicense(ctx, &k8sClient, license); err != nil {
return nil, prepareError(errorGeneric, nil, err)
}
return licenseInfo, nil
}
func getSubscriptionActivateResponse(session *models.Principal, namespace, tenantName string) *models.Error {
// 20 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
if err != nil {
return prepareError(errorGeneric, nil, err)
}
clientSet, err := cluster.K8sClient(session.STSSessionToken)
if err != nil {
return prepareError(errorGeneric, nil, err)
}
opClient := operatorClient{
client: opClientClientSet,
}
tenant, err := getTenant(ctx, &opClient, namespace, tenantName)
if err != nil {
return prepareError(err, errorGeneric)
}
// configure kubernetes client
k8sClient := k8sClient{
client: clientSet,
}
// Get cluster subscription license
license, err := getSubscriptionLicense(ctx, &k8sClient, cluster.Namespace, OperatorSubnetLicenseSecretName)
if err != nil {
return prepareError(errInvalidCredentials, nil, err)
}
// add subscription license to existing console Tenant
if err = addSubscriptionLicenseToTenant(ctx, &k8sClient, &opClient, license, tenant); err != nil {
return prepareError(err, errorGeneric)
}
return nil
}
// getSubscriptionInfoResponse returns information about the current configured subnet license for Console
func getSubscriptionInfoResponse(session *models.Principal) (*models.License, *models.Error) {
// 20 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
var licenseInfo *models.License
client := &cluster.HTTPClient{
Client: restapi.GetConsoleHTTPClient(),
}
licenseKey, err := retrieveLicense(ctx, session.STSSessionToken)
if err != nil {
return nil, prepareError(errLicenseNotFound, nil, err)
}
// validate license key and obtain license info
licenseInfo, _, err = subscriptionValidate(client, licenseKey, "", "")
if err != nil {
return nil, prepareError(errLicenseNotFound, nil, err)
}
return licenseInfo, nil
}

View File

@@ -20,6 +20,8 @@ import (
"context"
"testing"
v2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
"errors"
corev1 "k8s.io/api/core/v1"
@@ -28,13 +30,17 @@ import (
func Test_addSubscriptionLicenseToTenant(t *testing.T) {
k8sClient := k8sClientMock{}
opClient := opClientMock{}
tenant := &v2.Tenant{
ObjectMeta: metav1.ObjectMeta{},
Spec: v2.TenantSpec{},
}
type args struct {
ctx context.Context
clientSet K8sClientI
license string
namespace string
tenantName string
secretName string
ctx context.Context
clientSet K8sClientI
opClient OperatorClientI
license string
tenant *v2.Tenant
}
tests := []struct {
name string
@@ -43,150 +49,158 @@ func Test_addSubscriptionLicenseToTenant(t *testing.T) {
mockFunc func()
}{
{
name: "error because subnet license doesnt exists",
name: "success updating subscription for tenant with configuration file",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
license: "",
namespace: "",
tenantName: "",
secretName: "subnet-license",
},
wantErr: true,
mockFunc: func() {
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
return nil, errors.New("something went wrong")
}
},
},
{
name: "error because existing license could not be deleted",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
license: "",
namespace: "",
tenantName: "",
secretName: OperatorSubnetLicenseSecretName,
},
wantErr: true,
mockFunc: func() {
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
imm := true
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
},
Immutable: &imm,
Data: map[string][]byte{
ConsoleSubnetLicense: []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I"),
},
}, nil
}
DeleteSecretMock = func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
return errors.New("something went wrong")
}
},
},
{
name: "error because unable to create new subnet license",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
license: "",
namespace: "",
tenantName: "",
secretName: OperatorSubnetLicenseSecretName,
},
wantErr: true,
mockFunc: func() {
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
imm := true
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
},
Immutable: &imm,
Data: map[string][]byte{
ConsoleSubnetLicense: []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I"),
},
}, nil
}
DeleteSecretMock = func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
return nil
}
CreateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.CreateOptions) (*corev1.Secret, error) {
return nil, errors.New("something went wrong")
}
},
},
{
name: "error because unable to delete pod collection",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
license: "",
namespace: "",
tenantName: "",
secretName: OperatorSubnetLicenseSecretName,
},
wantErr: true,
mockFunc: func() {
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
imm := true
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
},
Immutable: &imm,
Data: map[string][]byte{
ConsoleSubnetLicense: []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I"),
},
}, nil
}
DeleteSecretMock = func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
return nil
}
CreateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.CreateOptions) (*corev1.Secret, error) {
return nil, nil
}
DeletePodCollectionMock = func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
return errors.New("something went wrong")
}
},
},
{
name: "subscription updated successfully",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
license: "",
namespace: "",
tenantName: "",
secretName: OperatorSubnetLicenseSecretName,
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: false,
mockFunc: func() {
tenant.Spec.Configuration = &corev1.LocalObjectReference{
Name: "minio-configuration",
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
imm := true
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: OperatorSubnetLicenseSecretName,
Name: "minio-configuration",
},
Immutable: &imm,
Data: map[string][]byte{
ConsoleSubnetLicense: []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I"),
"config.env": []byte("export MINIO_SUBNET_LICENSE=\"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I\""),
},
}, nil
}
DeleteSecretMock = func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
return nil
}
CreateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.CreateOptions) (*corev1.Secret, error) {
UpdateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.UpdateOptions) (*corev1.Secret, error) {
return nil, nil
}
DeletePodCollectionMock = func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
return nil
},
},
{
name: "error updating subscription for tenant because cannot get configuration file",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: true,
mockFunc: func() {
tenant.Spec.Configuration = &corev1.LocalObjectReference{
Name: "minio-configuration",
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
return nil, errors.New("something wrong happened")
}
UpdateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.UpdateOptions) (*corev1.Secret, error) {
return nil, nil
}
},
},
{
name: "error updating subscription for tenant because configuration file has wrong format",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: true,
mockFunc: func() {
tenant.Spec.Configuration = &corev1.LocalObjectReference{
Name: "minio-configuration",
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "minio-configuration",
},
Data: map[string][]byte{
"aaaaa": []byte("export MINIO_SUBNET_LICENSE=\"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I\""),
},
}, nil
}
UpdateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.UpdateOptions) (*corev1.Secret, error) {
return nil, nil
}
},
},
{
name: "error updating subscription for tenant because cannot update configuration file",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: true,
mockFunc: func() {
tenant.Spec.Configuration = &corev1.LocalObjectReference{
Name: "minio-configuration",
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "minio-configuration",
},
Data: map[string][]byte{
"config.env": []byte("export MINIO_SUBNET_LICENSE=\"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsZW5pbitjMUBtaW5pby5pbyIsInRlYW1OYW1lIjoiY29uc29sZS1jdXN0b21lciIsImV4cCI6MS42Mzk5NTI2MTE2MDkxNDQ3MzJlOSwiaXNzIjoic3VibmV0QG1pbmlvLmlvIiwiY2FwYWNpdHkiOjI1LCJpYXQiOjEuNjA4NDE2NjExNjA5MTQ0NzMyZTksImFjY291bnRJZCI6MTc2LCJzZXJ2aWNlVHlwZSI6IlNUQU5EQVJEIn0.ndtf8V_FJTvhXeemVLlORyDev6RJaSPhZ2djkMVK9SvXD0srR_qlYJATPjC4NljkS71nXMGVDov5uCTuUL97x6FGQEKDruA-z24x_2Zr8kof4LfBb3HUHudCR8QvE--I\""),
},
}, nil
}
UpdateSecretMock = func(ctx context.Context, namespace string, secret *corev1.Secret, opts metav1.UpdateOptions) (*corev1.Secret, error) {
return nil, errors.New("something wrong happened")
}
},
},
{
name: "success updating subscription for tenant with env variable",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: false,
mockFunc: func() {
tenant.Spec.Env = []corev1.EnvVar{
{
Name: "MINIO_SUBNET_LICENSE",
Value: "",
ValueFrom: nil,
},
}
opClientTenantUpdateMock = func(ctx context.Context, tenant *v2.Tenant, opts metav1.UpdateOptions) (*v2.Tenant, error) {
return nil, nil
}
},
},
{
name: "error updating subscription for tenant with env variable because of update tenant error",
args: args{
ctx: context.Background(),
clientSet: k8sClient,
opClient: opClient,
license: "",
tenant: tenant,
},
wantErr: true,
mockFunc: func() {
tenant.Spec.Env = []corev1.EnvVar{
{
Name: "MINIO_SUBNET_LICENSE",
Value: "",
ValueFrom: nil,
},
}
opClientTenantUpdateMock = func(ctx context.Context, tenant *v2.Tenant, opts metav1.UpdateOptions) (*v2.Tenant, error) {
return nil, errors.New("something wrong happened")
}
},
},
@@ -196,7 +210,7 @@ func Test_addSubscriptionLicenseToTenant(t *testing.T) {
if tt.mockFunc != nil {
tt.mockFunc()
}
if err := addSubscriptionLicenseToTenant(tt.args.ctx, tt.args.clientSet, tt.args.license, tt.args.namespace, tt.args.tenantName, tt.args.secretName); (err != nil) != tt.wantErr {
if err := addSubscriptionLicenseToTenant(tt.args.ctx, tt.args.clientSet, tt.args.opClient, tt.args.license, tt.args.tenant); (err != nil) != tt.wantErr {
t.Errorf("addSubscriptionLicenseToTenant() error = %v, wantErr %v", err, tt.wantErr)
}
})

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,31 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// parseSecurityContext validate and return securityContext for pods
func parseSecurityContext(sc *models.SecurityContext) (*corev1.PodSecurityContext, error) {
if sc == nil {
return nil, errors.New("invalid security context")
}
runAsUser, err := strconv.ParseInt(*sc.RunAsUser, 10, 64)
if err != nil {
return nil, err
}
RunAsGroup, err := strconv.ParseInt(*sc.RunAsGroup, 10, 64)
if err != nil {
return nil, err
}
FsGroup, err := strconv.ParseInt(*sc.FsGroup, 10, 64)
if err != nil {
return nil, err
}
return &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &RunAsGroup,
RunAsNonRoot: sc.RunAsNonRoot,
FSGroup: &FsGroup,
}, nil
}
// tenantUpdateCertificates receives the keyPair certificates (public and private keys) for Minio and Console and will try
// to replace the existing kubernetes secrets with the new values, then will restart the affected pods so the new volumes can be mounted
func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params operator_api.TenantUpdateCertificateParams) error {
@@ -63,22 +88,6 @@ func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClient
return err
}
}
// check if Console is deployed with external certs and user provided new Console keypair
if tenant.ConsoleExternalCert() && tenant.HasConsoleEnabled() && body.Console != nil {
consoleCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
// update certificates
certificates := []*models.KeyPairConfiguration{body.Console}
if _, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, certificates, consoleCertSecretName, tenantName); err != nil {
return err
}
// restart Console pods
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", miniov2.ConsoleTenantLabel, fmt.Sprintf("%s-console", tenantName)),
})
if err != nil {
return err
}
}
return nil
}
@@ -251,7 +260,6 @@ func createOrReplaceSecrets(ctx context.Context, clientSet K8sClientI, ns string
// log the error if any and continue
LogError("deleting secret name %s failed: %v, continuing..", secret.Name, err)
}
imm := true
k8sSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secret.Name,
@@ -259,9 +267,8 @@ func createOrReplaceSecrets(ctx context.Context, clientSet K8sClientI, ns string
miniov2.TenantLabel: tenantName,
},
},
Type: corev1.SecretTypeOpaque,
Immutable: &imm,
Data: secret.Content,
Type: corev1.SecretTypeOpaque,
Data: secret.Content,
}
_, err = clientSet.createSecret(ctx, ns, k8sSecret, metav1.CreateOptions{})
if err != nil {
@@ -516,6 +523,21 @@ func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sCl
}
}
}
} else if encryptionCfg.Azure != nil {
// Initialize Azure
kesConfig.Keys.Azure = &kes.Azure{
KeyVault: &kes.AzureKeyVault{},
}
if encryptionCfg.Azure.Keyvault != nil {
kesConfig.Keys.Azure.KeyVault.Endpoint = *encryptionCfg.Azure.Keyvault.Endpoint
if encryptionCfg.Azure.Keyvault.Credentials != nil {
kesConfig.Keys.Azure.KeyVault.Credentials = &kes.AzureCredentials{
TenantID: *encryptionCfg.Azure.Keyvault.Credentials.TenantID,
ClientID: *encryptionCfg.Azure.Keyvault.Credentials.ClientID,
ClientSecret: *encryptionCfg.Azure.Keyvault.Credentials.ClientSecret,
}
}
}
}
imm := true
// if mTLSCertificates contains elements we create the kubernetes secret

View File

@@ -33,6 +33,7 @@ import (
var DeletePodCollectionMock func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
var DeleteSecretMock func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
var CreateSecretMock func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
var UpdateSecretMock func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.UpdateOptions) (*v1.Secret, error)
func (c k8sClientMock) deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
return DeletePodCollectionMock(ctx, namespace, opts, listOpts)
@@ -46,6 +47,10 @@ func (c k8sClientMock) createSecret(ctx context.Context, namespace string, secre
return CreateSecretMock(ctx, namespace, secret, opts)
}
func (c k8sClientMock) updateSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.UpdateOptions) (*v1.Secret, error) {
return UpdateSecretMock(ctx, namespace, secret, opts)
}
func Test_tenantUpdateCertificates(t *testing.T) {
k8sClient := k8sClientMock{}
opClient := opClientMock{}
@@ -228,70 +233,6 @@ func Test_tenantUpdateCertificates(t *testing.T) {
},
wantErr: true,
},
{
name: "error replacing external certs for console because of missing keypair",
args: args{
ctx: context.Background(),
opClient: opClient,
clientSet: k8sClient,
namespace: "",
params: operator_api.TenantUpdateCertificateParams{
Body: &models.TLSConfiguration{
Console: &models.KeyPairConfiguration{},
},
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
Console: &miniov2.ConsoleConfiguration{
ExternalCertSecret: &miniov2.LocalCertificateReference{
Name: "secret",
},
},
},
}, nil
},
},
wantErr: true,
},
{
name: "certificates replaced but error during deleting existing tenant pods",
args: args{
ctx: context.Background(),
opClient: opClient,
clientSet: k8sClient,
namespace: "",
params: operator_api.TenantUpdateCertificateParams{
Body: &models.TLSConfiguration{
Console: &models.KeyPairConfiguration{
Crt: &crt,
Key: &key,
},
},
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
Console: &miniov2.ConsoleConfiguration{
ExternalCertSecret: &miniov2.LocalCertificateReference{
Name: "secret",
},
},
},
}, nil
},
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
return nil
},
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
return &v1.Secret{}, nil
},
mockDeletePodCollection: func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
return errors.New("error deleting console pods")
},
},
wantErr: true,
},
}
for _, tt := range tests {
opClientTenantGetMock = tt.args.mockTenantGet

View File

@@ -468,9 +468,6 @@ func Test_TenantInfo(t *testing.T) {
Spec: miniov2.TenantSpec{
Pools: []miniov2.Pool{},
Image: "minio/minio:RELEASE.2020-06-14T18-32-17Z",
Console: &miniov2.ConsoleConfiguration{
Image: "minio/console:master",
},
},
Status: miniov2.TenantStatus{
CurrentState: "ready",
@@ -484,7 +481,6 @@ func Test_TenantInfo(t *testing.T) {
Namespace: "minio-ns",
Image: "minio/minio:RELEASE.2020-06-14T18-32-17Z",
EnablePrometheus: false,
ConsoleImage: "minio/console:master",
},
},
}
@@ -505,8 +501,7 @@ func Test_deleteTenantAction(t *testing.T) {
type args struct {
ctx context.Context
operatorClient OperatorClientI
nameSpace string
tenantName string
tenant *miniov2.Tenant
deletePvcs bool
objs []runtime.Object
mockTenantDelete func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error
@@ -521,9 +516,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "default",
tenantName: "minio-tenant",
deletePvcs: false,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Namespace: "minio-tenant",
},
},
deletePvcs: false,
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
return nil
},
@@ -535,9 +534,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "default",
tenantName: "minio-tenant",
deletePvcs: false,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Namespace: "minio-tenant",
},
},
deletePvcs: false,
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
return errors.New("something happened")
},
@@ -550,9 +553,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "minio-tenant",
tenantName: "tenant1",
deletePvcs: true,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant1",
Namespace: "minio-tenant",
},
},
deletePvcs: true,
objs: []runtime.Object{
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -577,9 +584,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "minio-tenant",
tenantName: "tenant1",
deletePvcs: false,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant1",
Namespace: "minio-tenant",
},
},
deletePvcs: false,
objs: []runtime.Object{
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -604,9 +615,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "minio-tenant",
tenantName: "tenant1",
deletePvcs: true,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant1",
Namespace: "minio-tenant",
},
},
deletePvcs: true,
objs: []runtime.Object{
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -631,9 +646,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "minio-tenant",
tenantName: "tenant1",
deletePvcs: true,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant1",
Namespace: "minio-tenant",
},
},
deletePvcs: true,
objs: []runtime.Object{
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -659,9 +678,13 @@ func Test_deleteTenantAction(t *testing.T) {
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "minio-tenant",
tenantName: "tenant1",
deletePvcs: false,
tenant: &miniov2.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "tenant1",
Namespace: "minio-tenant",
},
},
deletePvcs: false,
objs: []runtime.Object{
&corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
@@ -685,7 +708,7 @@ func Test_deleteTenantAction(t *testing.T) {
opClientTenantDeleteMock = tt.args.mockTenantDelete
kubeClient := fake.NewSimpleClientset(tt.args.objs...)
t.Run(tt.name, func(t *testing.T) {
if err := deleteTenantAction(tt.args.ctx, tt.args.operatorClient, kubeClient.CoreV1(), tt.args.nameSpace, tt.args.tenantName, tt.args.deletePvcs); (err != nil) != tt.wantErr {
if err := deleteTenantAction(tt.args.ctx, tt.args.operatorClient, kubeClient.CoreV1(), tt.args.tenant, tt.args.deletePvcs); (err != nil) != tt.wantErr {
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
}
})
@@ -1017,31 +1040,6 @@ func Test_UpdateTenantAction(t *testing.T) {
},
wantErr: false,
},
{
name: "Update minio console version no errors",
args: args{
ctx: context.Background(),
operatorClient: opClient,
httpCl: httpClientM,
nameSpace: "default",
tenantName: "minio-tenant",
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{}, nil
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{}, nil
},
mockHTTPClientGet: func(url string) (resp *http.Response, err error) {
return nil, errors.New("use default minio")
},
params: operator_api.UpdateTenantParams{
Body: &models.UpdateTenantRequest{
ConsoleImage: "minio/console:v0.8.0",
},
},
},
wantErr: false,
},
{
name: "Update minio image pull secrets no errors",
args: args{

View File

@@ -18,6 +18,7 @@ package operatorapi
import (
"context"
"fmt"
miniov1 "github.com/minio/operator/pkg/apis/minio.min.io/v1"
@@ -39,6 +40,16 @@ func registerVolumesHandlers(api *operations.OperatorAPI) {
return operator_api.NewListPVCsOK().WithPayload(payload)
})
api.OperatorAPIListPVCsForTenantHandler = operator_api.ListPVCsForTenantHandlerFunc(func(params operator_api.ListPVCsForTenantParams, session *models.Principal) middleware.Responder {
payload, err := getPVCsForTenantResponse(session, params)
if err != nil {
return operator_api.NewListPVCsForTenantDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewListPVCsForTenantOK().WithPayload(payload)
})
}
func getPVCsResponse(session *models.Principal) (*models.ListPVCsResponse, *models.Error) {
@@ -83,3 +94,46 @@ func getPVCsResponse(session *models.Principal) (*models.ListPVCsResponse, *mode
return &PVCsResponse, nil
}
func getPVCsForTenantResponse(session *models.Principal, params operator_api.ListPVCsForTenantParams) (*models.ListPVCsResponse, *models.Error) {
ctx := context.Background()
clientset, err := cluster.K8sClient(session.STSSessionToken)
if err != nil {
return nil, prepareError(err)
}
// Filter Tenant PVCs. They keep their v1 tenant annotation
listOpts := metav1.ListOptions{
LabelSelector: fmt.Sprintf("v1.min.io/tenant=%s", params.Tenant),
}
// List all PVCs
listAllPvcs, err2 := clientset.CoreV1().PersistentVolumeClaims(params.Namespace).List(ctx, listOpts)
if err2 != nil {
return nil, prepareError(err2)
}
var ListPVCs []*models.PvcsListResponse
for _, pvc := range listAllPvcs.Items {
pvcResponse := models.PvcsListResponse{
Name: pvc.Name,
Age: pvc.CreationTimestamp.String(),
Capacity: pvc.Status.Capacity.Storage().String(),
Namespace: pvc.Namespace,
Status: string(pvc.Status.Phase),
StorageClass: *pvc.Spec.StorageClassName,
Volume: pvc.Spec.VolumeName,
Tenant: pvc.Labels["v1.min.io/tenant"],
}
ListPVCs = append(ListPVCs, &pvcResponse)
}
PVCsResponse := models.ListPVCsResponse{
Pvcs: ListPVCs,
}
return &PVCsResponse, nil
}

View File

@@ -21,6 +21,7 @@ import (
"crypto/sha1"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"log"
@@ -85,11 +86,12 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
nsTenant := fmt.Sprintf("%s/%s", tenant.Namespace, tenant.Name)
tenantSchema := "http"
tenantPort := ":9090"
if tenant.AutoCert() || tenant.ConsoleExternalCert() {
tenantPort := fmt.Sprintf(":%d", v2.ConsolePort)
if tenant.AutoCert() || tenant.ExternalCert() {
tenantSchema = "https"
tenantPort = ":9443"
tenantPort = fmt.Sprintf(":%d", v2.ConsoleTLSPort)
}
tenantURL := fmt.Sprintf("%s://%s.%s.svc.%s%s", tenantSchema, tenant.ConsoleCIServiceName(), tenant.Namespace, v2.GetClusterDomain(), tenantPort)
// for development
//tenantURL = "http://localhost:9091"
@@ -111,7 +113,10 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
return
}
currentSecret, err := clientSet.CoreV1().Secrets(tenant.Namespace).Get(req.Context(), tenant.Spec.CredsSecret.Name, metav1.GetOptions{})
k8sClient := k8sClient{
client: clientSet,
}
tenantConfiguration, err := GetTenantConfiguration(req.Context(), &k8sClient, tenant)
if err != nil {
log.Println(err)
responseWriter.WriteHeader(500)
@@ -119,8 +124,8 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
}
data := map[string]string{
"accessKey": string(currentSecret.Data["accesskey"]),
"secretKey": string(currentSecret.Data["secretkey"]),
"accessKey": string(tenantConfiguration["accesskey"]),
"secretKey": string(tenantConfiguration["secretkey"]),
}
payload, _ := json.Marshal(data)
@@ -132,7 +137,7 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
}
loginReq.Header.Add("Content-Type", "application/json")
// FIXME: in the future we should use restapi.GetConsoleSTSClient()
// FIXME: in the future we should use restapi.GetConsoleHTTPClient()
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
@@ -145,6 +150,12 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
return
}
if loginResp.StatusCode < 200 && loginResp.StatusCode <= 299 {
log.Println(fmt.Printf("Status: %d. Couldn't complete login", loginResp.StatusCode))
responseWriter.WriteHeader(500)
return
}
for _, c := range loginResp.Cookies() {
if c.Name == "token" {
tenantCookie = c
@@ -162,6 +173,11 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
}
defer loginResp.Body.Close()
}
if tenantCookie == nil {
log.Println(errors.New("couldn't login to tenant and get cookie"))
responseWriter.WriteHeader(500)
return
}
targetURL, err := url2.Parse(tenantURL)
if err != nil {
@@ -183,7 +199,7 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
proxyCookieJar.SetCookies(targetURL, []*http.Cookie{proxiedCookie})
tr := &http.Transport{
// FIXME: use restapi.GetConsoleSTSClient()
// FIXME: use restapi.GetConsoleHTTPClient()
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr,
@@ -191,7 +207,8 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}}
// copy query params
targetURL.RawQuery = req.URL.Query().Encode()
proxRequest, err := http.NewRequest(req.Method, targetURL.String(), req.Body)
if err != nil {
log.Println(err)

65
operatorapi/utils.go Normal file
View File

@@ -0,0 +1,65 @@
// This file is part of MinIO Console Server
// Copyright (c) 2021 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package operatorapi
import (
"context"
"errors"
"fmt"
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func GetTenantConfiguration(ctx context.Context, clientSet K8sClientI, tenant *miniov2.Tenant) (map[string]string, error) {
if tenant == nil {
return nil, errors.New("tenant cannot be nil")
}
tenantConfiguration := map[string]string{}
for _, config := range tenant.GetEnvVars() {
tenantConfiguration[config.Name] = config.Value
}
// legacy support for tenants with tenant.spec.credsSecret
if tenant.HasCredsSecret() {
minioSecret, err := clientSet.getSecret(ctx, tenant.Namespace, tenant.Spec.CredsSecret.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
configFromCredsSecret := minioSecret.Data
for key, val := range configFromCredsSecret {
tenantConfiguration[key] = string(val)
}
}
if tenant.HasConfigurationSecret() {
minioConfigurationSecret, err := clientSet.getSecret(ctx, tenant.Namespace, tenant.Spec.Configuration.Name, metav1.GetOptions{})
if err == nil {
configFromFile := miniov2.ParseRawConfiguration(minioConfigurationSecret.Data["config.env"])
for key, val := range configFromFile {
tenantConfiguration[key] = string(val)
}
}
}
return tenantConfiguration, nil
}
func GenerateTenantConfigurationFile(configuration map[string]string) string {
var rawConfiguration string
for key, val := range configuration {
rawConfiguration += fmt.Sprintf("export %s=\"%s\"\n", key, val)
}
return rawConfiguration
}

View File

@@ -23,26 +23,33 @@ import (
// endpoints definition
var (
configuration = "/settings"
notificationEndpoints = "/notification-endpoints"
notificationEndpointsAddAny = "/notification-endpoints/add/:service"
notificationEndpointsAdd = "/notification-endpoints/add"
tiers = "/tiers"
tiersAddAny = "/tiers/add/:service"
tiersAdd = "/tiers/add"
users = "/users"
usersDetail = "/users/:userName+"
groups = "/groups"
iamPolicies = "/policies"
policiesDetail = "/policies/:policyName"
policiesDetail = "/policies/*"
dashboard = "/dashboard"
metrics = "/metrics"
profiling = "/profiling"
buckets = "/buckets"
bucketsDetail = "/buckets/:bucketName"
bucketsDetailSummary = "/buckets/:bucketName/summary"
bucketsDetailEvents = "/buckets/:bucketName/events"
bucketsDetailReplication = "/buckets/:bucketName/replication"
bucketsDetailLifecycle = "/buckets/:bucketName/lifecycle"
bucketsDetailAccess = "/buckets/:bucketName/access"
bucketsDetailAccessPolicies = "/buckets/:bucketName/access/policies"
bucketsDetailAccessUsers = "/buckets/:bucketName/access/users"
bucketsGeneral = "/buckets/*"
bucketsAdmin = "/buckets/:bucketName/admin/*"
bucketsAdminMain = "/buckets/:bucketName/admin"
bucketsBrowserMenu = "/buckets"
bucketsBrowserList = "/buckets/*"
bucketsBrowser = "/buckets/:bucketName/browse/*"
bucketsBrowserMain = "/buckets/:bucketName/browse"
serviceAccounts = "/account"
changePassword = "/account/change-password"
tenants = "/tenants"
tenantsAdd = "/tenants/add"
tenantsAddSub = "/tenants/add/*"
tenantsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName"
tenantHop = "/namespaces/:tenantNamespace/tenants/:tenantName/hop"
podsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName/pods/:podName"
@@ -50,6 +57,7 @@ var (
tenantsDetailMetrics = "/namespaces/:tenantNamespace/tenants/:tenantName/metrics"
tenantsDetailPods = "/namespaces/:tenantNamespace/tenants/:tenantName/pods"
tenantsDetailPools = "/namespaces/:tenantNamespace/tenants/:tenantName/pools"
tenantsDetailVolumes = "/namespaces/:tenantNamespace/tenants/:tenantName/volumes"
tenantsDetailLicense = "/namespaces/:tenantNamespace/tenants/:tenantName/license"
tenantsDetailSecurity = "/namespaces/:tenantNamespace/tenants/:tenantName/security"
storage = "/storage"
@@ -57,9 +65,6 @@ var (
storageDrives = "/storage/drives"
remoteBuckets = "/remote-buckets"
replication = "/replication"
objectBrowser = "/object-browser/:bucket/*"
objectBrowserBucket = "/object-browser/:bucket"
mainObjectBrowser = "/object-browser"
license = "/license"
watch = "/watch"
heal = "/heal"
@@ -289,6 +294,12 @@ var displayRules = map[string]func() bool{
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
var endpointRules = map[string]ConfigurationActionSet{
configuration: configurationActionSet,
notificationEndpoints: configurationActionSet,
notificationEndpointsAdd: configurationActionSet,
notificationEndpointsAddAny: configurationActionSet,
tiers: configurationActionSet,
tiersAdd: configurationActionSet,
tiersAddAny: configurationActionSet,
users: usersActionSet,
usersDetail: usersActionSet,
groups: groupsActionSet,
@@ -298,21 +309,17 @@ var endpointRules = map[string]ConfigurationActionSet{
metrics: dashboardActionSet,
profiling: profilingActionSet,
buckets: bucketsActionSet,
bucketsDetail: bucketsActionSet,
bucketsDetailSummary: bucketsActionSet,
bucketsDetailEvents: bucketsActionSet,
bucketsDetailReplication: bucketsActionSet,
bucketsDetailLifecycle: bucketsActionSet,
bucketsDetailAccess: bucketsActionSet,
bucketsDetailAccessPolicies: bucketsActionSet,
bucketsDetailAccessUsers: bucketsActionSet,
bucketsGeneral: bucketsActionSet,
bucketsAdmin: bucketsActionSet,
bucketsAdminMain: bucketsActionSet,
serviceAccounts: serviceAccountsActionSet,
changePassword: changePasswordActionSet,
remoteBuckets: remoteBucketsActionSet,
replication: replicationActionSet,
objectBrowser: objectBrowserActionSet,
mainObjectBrowser: objectBrowserActionSet,
objectBrowserBucket: objectBrowserActionSet,
bucketsBrowser: objectBrowserActionSet,
bucketsBrowserMenu: objectBrowserActionSet,
bucketsBrowserList: objectBrowserActionSet,
bucketsBrowserMain: objectBrowserActionSet,
license: licenseActionSet,
watch: watchActionSet,
heal: healActionSet,
@@ -324,12 +331,15 @@ var endpointRules = map[string]ConfigurationActionSet{
// operatorRules contains the mapping between endpoints and ActionSets for operator only mode
var operatorRules = map[string]ConfigurationActionSet{
tenants: tenantsActionSet,
tenantsAdd: tenantsActionSet,
tenantsAddSub: tenantsActionSet,
tenantsDetail: tenantsActionSet,
tenantHop: tenantsActionSet,
tenantsDetailSummary: tenantsActionSet,
tenantsDetailMetrics: tenantsActionSet,
tenantsDetailPods: tenantsActionSet,
tenantsDetailPools: tenantsActionSet,
tenantsDetailVolumes: tenantsActionSet,
tenantsDetailLicense: tenantsActionSet,
tenantsDetailSecurity: tenantsActionSet,
podsDetail: tenantsActionSet,
@@ -396,7 +406,6 @@ func GetAuthorizedEndpoints(actions []string) []string {
if operatorOnly {
rangeTake = operatorRules
}
// Prepare new ActionSet structure that will hold all the user actions
userAllowedAction := actionsStringToActionSet(actions)
var allowedEndpoints []string

View File

@@ -19,8 +19,6 @@ package acl
import (
"reflect"
"testing"
iampolicy "github.com/minio/pkg/iam/policy"
)
type args struct {
@@ -50,7 +48,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
args: args{
[]string{"admin:ServerInfo"},
},
want: 8,
want: 9,
},
{
name: "policies endpoint",
@@ -63,7 +61,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"admin:ListUserPolicies",
},
},
want: 8,
want: 9,
},
{
name: "all admin endpoints",
@@ -72,7 +70,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"admin:*",
},
},
want: 22,
want: 29,
},
{
name: "all s3 endpoints",
@@ -81,7 +79,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"s3:*",
},
},
want: 15,
want: 9,
},
{
name: "all admin and s3 endpoints",
@@ -98,7 +96,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
args: args{
[]string{},
},
want: 6,
want: 7,
},
}
@@ -111,80 +109,10 @@ func TestOperatorOnlyEndpoints(t *testing.T) {
tests := []endpoint{
{
name: "Operator Only - all admin endpoints",
args: args{
[]string{
"admin:*",
},
},
want: 14,
},
{
name: "Operator Only - all s3 endpoints",
args: args{
[]string{
"s3:*",
},
},
want: 14,
},
{
name: "Operator Only - all admin and s3 endpoints",
args: args{
[]string{
"admin:*",
"s3:*",
},
},
want: 14,
},
{
name: "Operator Only - default endpoints",
args: args{
[]string{},
},
want: 14,
args: args{},
want: 17,
},
}
validateEndpoints(t, tests)
}
func TestGetActionsStringFromPolicy(t *testing.T) {
type args struct {
policy *iampolicy.Policy
}
tests := []struct {
name string
args args
want int
}{
{
name: "parse ReadOnly policy",
args: args{
policy: &iampolicy.ReadOnly,
},
want: 2,
},
{
name: "parse WriteOnly policy",
args: args{
policy: &iampolicy.WriteOnly,
},
want: 1,
},
{
name: "parse AdminDiagnostics policy",
args: args{
policy: &iampolicy.AdminDiagnostics,
},
want: 8,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetActionsStringFromPolicy(tt.args.policy); !reflect.DeepEqual(len(got), tt.want) {
t.Errorf("GetActionsStringFromPolicy() = %v, want %v", len(got), tt.want)
}
})
}
}

View File

@@ -29,49 +29,53 @@ func GetSTSEndpoint() string {
return strings.TrimSpace(env.Get(ConsoleMinIOServer, "http://localhost:9000"))
}
func GetIdpURL() string {
return env.Get(ConsoleIdpURL, "")
func GetIDPURL() string {
return env.Get(ConsoleIDPURL, "")
}
func GetIdpClientID() string {
return env.Get(ConsoleIdpClientID, "")
func GetIDPClientID() string {
return env.Get(ConsoleIDPClientID, "")
}
func GetIdpSecret() string {
return env.Get(ConsoleIdpSecret, "")
func GetIDPUserInfo() bool {
return env.Get(ConsoleIDPUserInfo, "") == "on"
}
func GetIDPSecret() string {
return env.Get(ConsoleIDPSecret, "")
}
// Public endpoint used by the identity oidcProvider when redirecting the user after identity verification
func GetIdpCallbackURL() string {
return env.Get(ConsoleIdpCallbackURL, "")
func GetIDPCallbackURL() string {
return env.Get(ConsoleIDPCallbackURL, "")
}
func IsIdpEnabled() bool {
return GetIdpURL() != "" &&
GetIdpClientID() != "" &&
GetIdpCallbackURL() != ""
func IsIDPEnabled() bool {
return GetIDPURL() != "" &&
GetIDPClientID() != "" &&
GetIDPCallbackURL() != ""
}
var defaultPassphraseForIdpHmac = utils.RandomCharString(64)
var defaultPassphraseForIDPHmac = utils.RandomCharString(64)
// GetPassphraseForIdpHmac returns passphrase for the pbkdf2 function used to sign the oauth2 state parameter
func getPassphraseForIdpHmac() string {
return env.Get(ConsoleIdpHmacPassphrase, defaultPassphraseForIdpHmac)
// GetPassphraseForIDPHmac returns passphrase for the pbkdf2 function used to sign the oauth2 state parameter
func getPassphraseForIDPHmac() string {
return env.Get(ConsoleIDPHmacPassphrase, defaultPassphraseForIDPHmac)
}
var defaultSaltForIdpHmac = utils.RandomCharString(64)
var defaultSaltForIDPHmac = utils.RandomCharString(64)
// GetSaltForIdpHmac returns salt for the pbkdf2 function used to sign the oauth2 state parameter
func getSaltForIdpHmac() string {
return env.Get(ConsoleIdpHmacSalt, defaultSaltForIdpHmac)
// GetSaltForIDPHmac returns salt for the pbkdf2 function used to sign the oauth2 state parameter
func getSaltForIDPHmac() string {
return env.Get(ConsoleIDPHmacSalt, defaultSaltForIDPHmac)
}
// getIdpScopes return default scopes during the IDP login request
func getIdpScopes() string {
// getIDPScopes return default scopes during the IDP login request
func getIDPScopes() string {
return env.Get(ConsoleIDPScopes, "openid,profile,email")
}
// getIdpTokenExpiration return default token expiration for access token (in seconds)
func getIdpTokenExpiration() string {
// getIDPTokenExpiration return default token expiration for access token (in seconds)
func getIDPTokenExpiration() string {
return env.Get(ConsoleIDPTokenExpiration, "3600")
}

View File

@@ -16,15 +16,16 @@
package oauth2
// Environment constants for console IDP/SSO configuration
const (
// const for idp configuration
ConsoleMinIOServer = "CONSOLE_MINIO_SERVER"
ConsoleIdpURL = "CONSOLE_IDP_URL"
ConsoleIdpClientID = "CONSOLE_IDP_CLIENT_ID"
ConsoleIdpSecret = "CONSOLE_IDP_SECRET"
ConsoleIdpCallbackURL = "CONSOLE_IDP_CALLBACK"
ConsoleIdpHmacPassphrase = "CONSOLE_IDP_HMAC_PASSPHRASE"
ConsoleIdpHmacSalt = "CONSOLE_IDP_HMAC_SALT"
ConsoleIDPURL = "CONSOLE_IDP_URL"
ConsoleIDPClientID = "CONSOLE_IDP_CLIENT_ID"
ConsoleIDPSecret = "CONSOLE_IDP_SECRET"
ConsoleIDPCallbackURL = "CONSOLE_IDP_CALLBACK"
ConsoleIDPHmacPassphrase = "CONSOLE_IDP_HMAC_PASSPHRASE"
ConsoleIDPHmacSalt = "CONSOLE_IDP_HMAC_SALT"
ConsoleIDPScopes = "CONSOLE_IDP_SCOPES"
ConsoleIDPUserInfo = "CONSOLE_IDP_USERINFO"
ConsoleIDPTokenExpiration = "CONSOLE_IDP_TOKEN_EXPIRATION"
)

View File

@@ -20,6 +20,7 @@ import (
"context"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -30,7 +31,6 @@ import (
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/coreos/go-oidc"
"github.com/minio/console/pkg/auth/utils"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/oauth2"
@@ -49,6 +49,24 @@ type Config struct {
xoauth2.Config
}
// DiscoveryDoc - parses the output from openid-configuration
// for example https://accounts.google.com/.well-known/openid-configuration
type DiscoveryDoc struct {
Issuer string `json:"issuer,omitempty"`
AuthEndpoint string `json:"authorization_endpoint,omitempty"`
TokenEndpoint string `json:"token_endpoint,omitempty"`
UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
JwksURI string `json:"jwks_uri,omitempty"`
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
TokenEndpointAuthMethods []string `json:"token_endpoint_auth_methods_supported,omitempty"`
ClaimsSupported []string `json:"claims_supported,omitempty"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
}
func (ac Config) Exchange(ctx context.Context, code string, opts ...xoauth2.AuthCodeOption) (*xoauth2.Token, error) {
return ac.Exchange(ctx, code, opts...)
}
@@ -88,51 +106,51 @@ type Provider struct {
// often available via site-specific packages, such as
// google.Endpoint or github.Endpoint.
// - Scopes specifies optional requested permissions.
ClientID string
ClientID string
// if enabled means that we need extrace access_token as well
UserInfo bool
oauth2Config Configuration
oidcProvider *oidc.Provider
provHTTPClient *http.Client
}
// derivedKey is the key used to compute the HMAC for signing the oauth state parameter
// its derived using pbkdf on CONSOLE_IDP_HMAC_PASSPHRASE with CONSOLE_IDP_HMAC_SALT
var derivedKey = func() []byte {
return pbkdf2.Key([]byte(getPassphraseForIdpHmac()), []byte(getSaltForIdpHmac()), 4096, 32, sha1.New)
return pbkdf2.Key([]byte(getPassphraseForIDPHmac()), []byte(getSaltForIDPHmac()), 4096, 32, sha1.New)
}
// NewOauth2ProviderClient instantiates a new oauth2 client using the configured credentials
// it returns a *Provider object that contains the necessary configuration to initiate an
// oauth2 authentication flow
func NewOauth2ProviderClient(ctx context.Context, scopes []string, httpClient *http.Client) (*Provider, error) {
customCtx := oidc.ClientContext(ctx, httpClient)
provider, err := oidc.NewProvider(customCtx, GetIdpURL())
func NewOauth2ProviderClient(scopes []string, httpClient *http.Client) (*Provider, error) {
ddoc, err := parseDiscoveryDoc(GetIDPURL(), httpClient)
if err != nil {
return nil, err
}
// if google, change scopes
u, err := url.Parse(GetIdpURL())
if err != nil {
return nil, err
}
// below verification should not be necessary if the user configure exactly the
// scopes he need, will be removed on a future release
if u.Host == "google.com" {
scopes = []string{oidc.ScopeOpenID}
}
// If provided scopes are empty we use a default list or the user configured list
if len(scopes) == 0 {
scopes = strings.Split(getIdpScopes(), ",")
scopes = strings.Split(getIDPScopes(), ",")
}
// add "openid" scope always.
scopes = append(scopes, "openid")
client := new(Provider)
client.oauth2Config = &xoauth2.Config{
ClientID: GetIdpClientID(),
ClientSecret: GetIdpSecret(),
RedirectURL: GetIdpCallbackURL(),
Endpoint: provider.Endpoint(),
Scopes: scopes,
ClientID: GetIDPClientID(),
ClientSecret: GetIDPSecret(),
RedirectURL: GetIDPCallbackURL(),
Endpoint: oauth2.Endpoint{
AuthURL: ddoc.AuthEndpoint,
TokenURL: ddoc.TokenEndpoint,
},
Scopes: scopes,
}
client.oidcProvider = provider
client.ClientID = GetIdpClientID()
client.ClientID = GetIDPClientID()
client.UserInfo = GetIDPUserInfo()
client.provHTTPClient = httpClient
return client, nil
@@ -184,18 +202,26 @@ func (client *Provider) VerifyIdentity(ctx context.Context, code, state string)
// check if user configured a hardcoded expiration for console via env variables
// and override the incoming expiration
userConfiguredExpiration := getIdpTokenExpiration()
userConfiguredExpiration := getIDPTokenExpiration()
if userConfiguredExpiration != "" {
expiration, _ = strconv.Atoi(userConfiguredExpiration)
}
idToken := oauth2Token.Extra("id_token")
if idToken == nil {
return nil, errors.New("returned token is missing id_token claim")
return nil, errors.New("missing id_token")
}
return &credentials.WebIdentityToken{
token := &credentials.WebIdentityToken{
Token: idToken.(string),
Expiry: expiration,
}, nil
}
if client.UserInfo { // look for access_token only if userinfo is requested.
accessToken := oauth2Token.Extra("access_token")
if accessToken == nil {
return nil, errors.New("missing access_token")
}
token.AccessToken = accessToken.(string)
}
return token, nil
}
stsEndpoint := GetSTSEndpoint()
sts := credentials.New(&credentials.STSWebIdentity{
@@ -235,6 +261,32 @@ func validateOauth2State(state string) error {
return nil
}
// parseDiscoveryDoc parses a discovery doc from an OAuth provider
// into a DiscoveryDoc struct that have the correct endpoints
func parseDiscoveryDoc(ustr string, httpClient *http.Client) (DiscoveryDoc, error) {
d := DiscoveryDoc{}
req, err := http.NewRequest(http.MethodGet, ustr, nil)
if err != nil {
return d, err
}
clnt := http.Client{
Transport: httpClient.Transport,
}
resp, err := clnt.Do(req)
if err != nil {
return d, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return d, err
}
dec := json.NewDecoder(resp.Body)
if err = dec.Decode(&d); err != nil {
return d, err
}
return d, nil
}
// GetRandomStateWithHMAC computes message + hmac(message, pbkdf2(key, salt)) to be used as state during the oauth authorization
func GetRandomStateWithHMAC(length int) string {
state := utils.RandomCharString(length)

View File

@@ -21,7 +21,6 @@ import (
"net/http"
"testing"
"github.com/coreos/go-oidc"
"github.com/stretchr/testify/assert"
"golang.org/x/oauth2"
)
@@ -58,7 +57,6 @@ func TestGenerateLoginURL(t *testing.T) {
funcAssert := assert.New(t)
oauth2Provider := Provider{
oauth2Config: Oauth2configMock{},
oidcProvider: &oidc.Provider{},
}
// Test-1 : GenerateLoginURL() generates URL correctly with provided state
oauth2ConfigAuthCodeURLMock = func(state string, opts ...oauth2.AuthCodeOption) string {

View File

@@ -62,11 +62,10 @@ func IsSessionTokenValid(token string) bool {
// TokenClaims claims struct for decrypted credentials
type TokenClaims struct {
STSAccessKeyID string `json:"stsAccessKeyID,omitempty"`
STSSecretAccessKey string `json:"stsSecretAccessKey,omitempty"`
STSSessionToken string `json:"stsSessionToken,omitempty"`
AccountAccessKey string `json:"accountAccessKey,omitempty"`
Actions []string `json:"actions,omitempty"`
STSAccessKeyID string `json:"stsAccessKeyID,omitempty"`
STSSecretAccessKey string `json:"stsSecretAccessKey,omitempty"`
STSSessionToken string `json:"stsSessionToken,omitempty"`
AccountAccessKey string `json:"accountAccessKey,omitempty"`
}
// SessionTokenAuthenticate takes a session token, decode it, extract claims and validate the signature
@@ -79,7 +78,6 @@ type TokenClaims struct {
// STSSecretAccessKey
// STSSessionToken
// AccountAccessKey
// Actions
// }
func SessionTokenAuthenticate(token string) (*TokenClaims, error) {
if token == "" {
@@ -98,14 +96,13 @@ func SessionTokenAuthenticate(token string) (*TokenClaims, error) {
// NewEncryptedTokenForClient generates a new session token with claims based on the provided STS credentials, first
// encrypts the claims and the sign them
func NewEncryptedTokenForClient(credentials *credentials.Value, accountAccessKey string, actions []string) (string, error) {
func NewEncryptedTokenForClient(credentials *credentials.Value, accountAccessKey string) (string, error) {
if credentials != nil {
encryptedClaims, err := encryptClaims(&TokenClaims{
STSAccessKeyID: credentials.AccessKeyID,
STSSecretAccessKey: credentials.SecretAccessKey,
STSSessionToken: credentials.SessionToken,
AccountAccessKey: accountAccessKey,
Actions: actions,
})
if err != nil {
return "", err
@@ -311,7 +308,6 @@ func GetClaimsFromTokenInRequest(req *http.Request) (*models.Principal, error) {
}
return &models.Principal{
STSAccessKeyID: claims.STSAccessKeyID,
Actions: claims.Actions,
STSSecretAccessKey: claims.STSSecretAccessKey,
STSSessionToken: claims.STSSessionToken,
AccountAccessKey: claims.AccountAccessKey,

View File

@@ -36,14 +36,14 @@ func TestNewJWTWithClaimsForClient(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : NewEncryptedTokenForClient() is generated correctly without errors
function := "NewEncryptedTokenForClient()"
token, err := NewEncryptedTokenForClient(creds, "", []string{""})
token, err := NewEncryptedTokenForClient(creds, "")
if err != nil || token == "" {
t.Errorf("Failed on %s:, error occurred: %s", function, err)
}
// saving token for future tests
goodToken = token
// Test-2 : NewEncryptedTokenForClient() throws error because of empty credentials
if _, err = NewEncryptedTokenForClient(nil, "", []string{""}); err != nil {
if _, err = NewEncryptedTokenForClient(nil, ""); err != nil {
funcAssert.Equal("provided credentials are empty", err.Error())
}
}

View File

@@ -130,12 +130,28 @@ type Gcp struct {
SecretManager *GcpSecretManager `yaml:"secretmanager,omitempty"`
}
type AzureCredentials struct {
TenantID string `yaml:"tenant_id"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
}
type AzureKeyVault struct {
Endpoint string `yaml:"endpoint,omitempty"`
Credentials *AzureCredentials `yaml:"credentials,omitempty"`
}
type Azure struct {
KeyVault *AzureKeyVault `yaml:"keyvault,omitempty"`
}
type Keys struct {
Fs *Fs `yaml:"fs,omitempty"`
Vault *Vault `yaml:"vault,omitempty"`
Aws *Aws `yaml:"aws,omitempty"`
Gemalto *Gemalto `yaml:"gemalto,omitempty"`
Gcp *Gcp `yaml:"gcp,omitempty"`
Azure *Azure `yaml:"azure,omitempty"`
}
type ServerConfig struct {

View File

@@ -150,6 +150,9 @@ func getLicenseFromCredentials(client cluster.HTTPClientI, username, password st
if err != nil {
return "", err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return "", fmt.Errorf("subnet served returned status %d code", resp.StatusCode)
}
userLicense := &subnetLicenseResponse{}
// Parse subnet license response
err = json.Unmarshal(bodyBytes, userLicense)

View File

@@ -144,11 +144,17 @@ func Test_getLicenseFromCredentials(t *testing.T) {
mockFunc: func() {
HTTPPostMock = func(url, contentType string, body io.Reader) (resp *http.Response, err error) {
// returning test jwt token
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"has_memberships\":true,\"token_info\":{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik4wRXdOa1V5UXpORU1UUkNOekU0UmpSR1JVWkJSa1UxUmtZNE9EY3lOekZHTXpjNU1qZ3hNZyJ9.eyJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vY2xhaW1zL2dyb3VwcyI6W10sImh0dHBzOi8vaWQuc3VibmV0Lm1pbi5pby9jbGFpbXMvcm9sZXMiOltdLCJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vY2xhaW1zL2VtYWlsIjoibGVuaW4rYzFAbWluaW8uaW8iLCJpc3MiOiJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vIiwic3ViIjoiYXV0aDB8NWZjZWFlYTMyNTNhZjEwMDc3NDZkMDM0IiwiYXVkIjoiaHR0cHM6Ly9zdWJuZXQubWluLmlvL2FwaSIsImlhdCI6MTYwODQxNjE5NiwiZXhwIjoxNjExMDA4MTk2LCJhenAiOiI1WTA0eVZlejNiOFgxUFVzRHVqSmxuZXVuY3ExVjZxaiIsInNjb3BlIjoib2ZmbGluZV9hY2Nlc3MiLCJndHkiOiJwYXNzd29yZCJ9.GC8DRLT0jUEteuBZBmyMXMswLSblCr_89Gu5NcVRUzKSYAaZ5VFW4UFgo1BpiC0sePuWJ0Vykitphx7znTfZfj5B3mZbOw3ejG6kxz7nm9DuYMmySJFYnwroZ9EP02vkW7-n_-YvEg8le1wXfkJ3lTUzO3aWddS4rfQRsZ2YJJUj61GiNyEK_QNP4PrYOuzLyD1wV75NejFqfcFoj7nRkT1K2BM0-89-_f2AFDGTjov6Ig6s1s-zLC9wxcYSmubNwpCJytZmQgPqIepOr065Y6OB4n0n0B5sXguuGuzb8VAkECrHhHPz8ta926fc0jC4XxVCNKdbV1_qC3-1yY7AJA\",\"expires_in\":2592000.0,\"token_type\":\"Bearer\"}}")))}, nil
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"has_memberships\":true,\"token_info\":{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik4wRXdOa1V5UXpORU1UUkNOekU0UmpSR1JVWkJSa1UxUmtZNE9EY3lOekZHTXpjNU1qZ3hNZyJ9.eyJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vY2xhaW1zL2dyb3VwcyI6W10sImh0dHBzOi8vaWQuc3VibmV0Lm1pbi5pby9jbGFpbXMvcm9sZXMiOltdLCJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vY2xhaW1zL2VtYWlsIjoibGVuaW4rYzFAbWluaW8uaW8iLCJpc3MiOiJodHRwczovL2lkLnN1Ym5ldC5taW4uaW8vIiwic3ViIjoiYXV0aDB8NWZjZWFlYTMyNTNhZjEwMDc3NDZkMDM0IiwiYXVkIjoiaHR0cHM6Ly9zdWJuZXQubWluLmlvL2FwaSIsImlhdCI6MTYwODQxNjE5NiwiZXhwIjoxNjExMDA4MTk2LCJhenAiOiI1WTA0eVZlejNiOFgxUFVzRHVqSmxuZXVuY3ExVjZxaiIsInNjb3BlIjoib2ZmbGluZV9hY2Nlc3MiLCJndHkiOiJwYXNzd29yZCJ9.GC8DRLT0jUEteuBZBmyMXMswLSblCr_89Gu5NcVRUzKSYAaZ5VFW4UFgo1BpiC0sePuWJ0Vykitphx7znTfZfj5B3mZbOw3ejG6kxz7nm9DuYMmySJFYnwroZ9EP02vkW7-n_-YvEg8le1wXfkJ3lTUzO3aWddS4rfQRsZ2YJJUj61GiNyEK_QNP4PrYOuzLyD1wV75NejFqfcFoj7nRkT1K2BM0-89-_f2AFDGTjov6Ig6s1s-zLC9wxcYSmubNwpCJytZmQgPqIepOr065Y6OB4n0n0B5sXguuGuzb8VAkECrHhHPz8ta926fc0jC4XxVCNKdbV1_qC3-1yY7AJA\",\"expires_in\":2592000.0,\"token_type\":\"Bearer\"}}"))),
}, nil
}
HTTPDoMock = func(req *http.Request) (*http.Response, error) {
// returning test jwt license
return &http.Response{Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"license\":\"" + license + "\",\"metadata\":{\"email\":\"lenin+c1@minio.io\",\"issuer\":\"subnet@minio.io\",\"accountId\":176,\"teamName\":\"console-customer\",\"serviceType\":\"STANDARD\",\"capacity\":25,\"requestedAt\":\"2020-12-19T22:23:31.609144732Z\",\"expiresAt\":\"2021-12-19T22:23:31.609144732Z\"}}")))}, nil
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"license\":\"" + license + "\",\"metadata\":{\"email\":\"lenin+c1@minio.io\",\"issuer\":\"subnet@minio.io\",\"accountId\":176,\"teamName\":\"console-customer\",\"serviceType\":\"STANDARD\",\"capacity\":25,\"requestedAt\":\"2020-12-19T22:23:31.609144732Z\",\"expiresAt\":\"2021-12-19T22:23:31.609144732Z\"}}"))),
}, nil
}
},
},

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="49.035" height="47.998" viewBox="0 0 49.035 47.998"><defs><style>.a{fill:#d0d2d4;}.b{fill:#0e2d90;}.c{fill:#adb9de;}</style></defs><path d="M89.091,200.387,75.719,187.176H40.056v13.211Z" transform="translate(-40.056 -152.389)"/><path class="a" d="M201.19,90.4V42.416H187.662V77.244Z" transform="translate(-152.155 -42.401)"/><path class="b" d="M57.736,114.687v.1H40.056V128H71.42Z" transform="translate(-40.056 -97.312)"/><path class="c" d="M127.346,73.042h.008V42.354H113.662V59.728Z" transform="translate(-96.074 -42.354)"/><path d="M53.434,56.086,40.056,43.069V56.276H53.434Z" transform="translate(-40.056 -42.897)"/><path class="a" d="M53.434,55.543V42.354H40.056v.172Z" transform="translate(-40.056 -42.354)"/></svg>

After

Width:  |  Height:  |  Size: 768 B

View File

@@ -1,25 +1,23 @@
{
"files": {
"main.css": "/static/css/main.8cfac526.chunk.css",
"main.js": "/static/js/main.926c7b22.chunk.js",
"main.js.map": "/static/js/main.926c7b22.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.43a31377.js",
"runtime-main.js.map": "/static/js/runtime-main.43a31377.js.map",
"static/css/2.60e04a19.chunk.css": "/static/css/2.60e04a19.chunk.css",
"static/js/2.1bafa615.chunk.js": "/static/js/2.1bafa615.chunk.js",
"static/js/2.1bafa615.chunk.js.map": "/static/js/2.1bafa615.chunk.js.map",
"index.html": "/index.html",
"static/css/2.60e04a19.chunk.css.map": "/static/css/2.60e04a19.chunk.css.map",
"static/css/main.8cfac526.chunk.css.map": "/static/css/main.8cfac526.chunk.css.map",
"static/js/2.1bafa615.chunk.js.LICENSE.txt": "/static/js/2.1bafa615.chunk.js.LICENSE.txt",
"static/media/minio_console_logo.0837460e.svg": "/static/media/minio_console_logo.0837460e.svg",
"static/media/minio_operator_logo.1312b7c9.svg": "/static/media/minio_operator_logo.1312b7c9.svg"
"main.css": "./static/css/main.e33a67ba.chunk.css",
"main.js": "./static/js/main.0d2bb0ae.chunk.js",
"main.js.map": "./static/js/main.0d2bb0ae.chunk.js.map",
"runtime-main.js": "./static/js/runtime-main.30f8243a.js",
"runtime-main.js.map": "./static/js/runtime-main.30f8243a.js.map",
"static/css/2.5c96c0d7.chunk.css": "./static/css/2.5c96c0d7.chunk.css",
"static/js/2.edb168ed.chunk.js": "./static/js/2.edb168ed.chunk.js",
"static/js/2.edb168ed.chunk.js.map": "./static/js/2.edb168ed.chunk.js.map",
"index.html": "./index.html",
"static/css/2.5c96c0d7.chunk.css.map": "./static/css/2.5c96c0d7.chunk.css.map",
"static/css/main.e33a67ba.chunk.css.map": "./static/css/main.e33a67ba.chunk.css.map",
"static/js/2.edb168ed.chunk.js.LICENSE.txt": "./static/js/2.edb168ed.chunk.js.LICENSE.txt"
},
"entrypoints": [
"static/js/runtime-main.43a31377.js",
"static/css/2.60e04a19.chunk.css",
"static/js/2.1bafa615.chunk.js",
"static/css/main.8cfac526.chunk.css",
"static/js/main.926c7b22.chunk.js"
"static/js/runtime-main.30f8243a.js",
"static/css/2.5c96c0d7.chunk.css",
"static/js/2.edb168ed.chunk.js",
"static/css/main.e33a67ba.chunk.css",
"static/js/main.0d2bb0ae.chunk.js"
]
}

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 304 182" style="enable-background:new 0 0 304 182;" xml:space="preserve">
<style type="text/css">
.st0{fill:#252F3E;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FF9900;}
</style>
<g>
<path class="st0" d="M86.4,66.4c0,3.7,0.4,6.7,1.1,8.9c0.8,2.2,1.8,4.6,3.2,7.2c0.5,0.8,0.7,1.6,0.7,2.3c0,1-0.6,2-1.9,3l-6.3,4.2
c-0.9,0.6-1.8,0.9-2.6,0.9c-1,0-2-0.5-3-1.4C76.2,90,75,88.4,74,86.8c-1-1.7-2-3.6-3.1-5.9c-7.8,9.2-17.6,13.8-29.4,13.8
c-8.4,0-15.1-2.4-20-7.2c-4.9-4.8-7.4-11.2-7.4-19.2c0-8.5,3-15.4,9.1-20.6c6.1-5.2,14.2-7.8,24.5-7.8c3.4,0,6.9,0.3,10.6,0.8
c3.7,0.5,7.5,1.3,11.5,2.2v-7.3c0-7.6-1.6-12.9-4.7-16c-3.2-3.1-8.6-4.6-16.3-4.6c-3.5,0-7.1,0.4-10.8,1.3c-3.7,0.9-7.3,2-10.8,3.4
c-1.6,0.7-2.8,1.1-3.5,1.3c-0.7,0.2-1.2,0.3-1.6,0.3c-1.4,0-2.1-1-2.1-3.1v-4.9c0-1.6,0.2-2.8,0.7-3.5c0.5-0.7,1.4-1.4,2.8-2.1
c3.5-1.8,7.7-3.3,12.6-4.5c4.9-1.3,10.1-1.9,15.6-1.9c11.9,0,20.6,2.7,26.2,8.1c5.5,5.4,8.3,13.6,8.3,24.6V66.4z M45.8,81.6
c3.3,0,6.7-0.6,10.3-1.8c3.6-1.2,6.8-3.4,9.5-6.4c1.6-1.9,2.8-4,3.4-6.4c0.6-2.4,1-5.3,1-8.7v-4.2c-2.9-0.7-6-1.3-9.2-1.7
c-3.2-0.4-6.3-0.6-9.4-0.6c-6.7,0-11.6,1.3-14.9,4c-3.3,2.7-4.9,6.5-4.9,11.5c0,4.7,1.2,8.2,3.7,10.6
C37.7,80.4,41.2,81.6,45.8,81.6z M126.1,92.4c-1.8,0-3-0.3-3.8-1c-0.8-0.6-1.5-2-2.1-3.9L96.7,10.2c-0.6-2-0.9-3.3-0.9-4
c0-1.6,0.8-2.5,2.4-2.5h9.8c1.9,0,3.2,0.3,3.9,1c0.8,0.6,1.4,2,2,3.9l16.8,66.2l15.6-66.2c0.5-2,1.1-3.3,1.9-3.9c0.8-0.6,2.2-1,4-1
h8c1.9,0,3.2,0.3,4,1c0.8,0.6,1.5,2,1.9,3.9l15.8,67l17.3-67c0.6-2,1.3-3.3,2-3.9c0.8-0.6,2.1-1,3.9-1h9.3c1.6,0,2.5,0.8,2.5,2.5
c0,0.5-0.1,1-0.2,1.6c-0.1,0.6-0.3,1.4-0.7,2.5l-24.1,77.3c-0.6,2-1.3,3.3-2.1,3.9c-0.8,0.6-2.1,1-3.8,1h-8.6c-1.9,0-3.2-0.3-4-1
c-0.8-0.7-1.5-2-1.9-4L156,23l-15.4,64.4c-0.5,2-1.1,3.3-1.9,4c-0.8,0.7-2.2,1-4,1H126.1z M254.6,95.1c-5.2,0-10.4-0.6-15.4-1.8
c-5-1.2-8.9-2.5-11.5-4c-1.6-0.9-2.7-1.9-3.1-2.8c-0.4-0.9-0.6-1.9-0.6-2.8v-5.1c0-2.1,0.8-3.1,2.3-3.1c0.6,0,1.2,0.1,1.8,0.3
c0.6,0.2,1.5,0.6,2.5,1c3.4,1.5,7.1,2.7,11,3.5c4,0.8,7.9,1.2,11.9,1.2c6.3,0,11.2-1.1,14.6-3.3c3.4-2.2,5.2-5.4,5.2-9.5
c0-2.8-0.9-5.1-2.7-7c-1.8-1.9-5.2-3.6-10.1-5.2L246,52c-7.3-2.3-12.7-5.7-16-10.2c-3.3-4.4-5-9.3-5-14.5c0-4.2,0.9-7.9,2.7-11.1
c1.8-3.2,4.2-6,7.2-8.2c3-2.3,6.4-4,10.4-5.2c4-1.2,8.2-1.7,12.6-1.7c2.2,0,4.5,0.1,6.7,0.4c2.3,0.3,4.4,0.7,6.5,1.1
c2,0.5,3.9,1,5.7,1.6c1.8,0.6,3.2,1.2,4.2,1.8c1.4,0.8,2.4,1.6,3,2.5c0.6,0.8,0.9,1.9,0.9,3.3v4.7c0,2.1-0.8,3.2-2.3,3.2
c-0.8,0-2.1-0.4-3.8-1.2c-5.7-2.6-12.1-3.9-19.2-3.9c-5.7,0-10.2,0.9-13.3,2.8c-3.1,1.9-4.7,4.8-4.7,8.9c0,2.8,1,5.2,3,7.1
c2,1.9,5.7,3.8,11,5.5l14.2,4.5c7.2,2.3,12.4,5.5,15.5,9.6c3.1,4.1,4.6,8.8,4.6,14c0,4.3-0.9,8.2-2.6,11.6
c-1.8,3.4-4.2,6.4-7.3,8.8c-3.1,2.5-6.8,4.3-11.1,5.6C264.4,94.4,259.7,95.1,254.6,95.1z"/>
<g>
<path class="st1" d="M273.5,143.7c-32.9,24.3-80.7,37.2-121.8,37.2c-57.6,0-109.5-21.3-148.7-56.7c-3.1-2.8-0.3-6.6,3.4-4.4
c42.4,24.6,94.7,39.5,148.8,39.5c36.5,0,76.6-7.6,113.5-23.2C274.2,133.6,278.9,139.7,273.5,143.7z"/>
<path class="st1" d="M287.2,128.1c-4.2-5.4-27.8-2.6-38.5-1.3c-3.2,0.4-3.7-2.4-0.8-4.5c18.8-13.2,49.7-9.4,53.3-5
c3.6,4.5-1,35.4-18.6,50.2c-2.7,2.3-5.3,1.1-4.1-1.9C282.5,155.7,291.4,133.4,287.2,128.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="77.43" viewBox="0 0 19.68 15.24"><path d="M9.105 14.43l4.642-.82.043-.01-2.387-2.84a403.945 403.945 0 0 1-2.387-2.853c0-.014 2.465-6.802 2.479-6.826.004-.008 1.682 2.888 4.066 7.02l4.09 7.09.031.054-7.587-.001-7.587-.001 4.597-.812zM0 13.566c0-.004 1.125-1.957 2.5-4.34L5 4.893l2.913-2.445C9.515 1.104 10.83.002 10.836 0a.512.512 0 0 1-.047.118L7.625 6.903l-3.107 6.663-2.259.003c-1.242.002-2.259 0-2.259-.004z" fill="#0089d6"/></svg>

After

Width:  |  Height:  |  Size: 494 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="42.034" height="45.939" viewBox="0 0 42.034 45.939"><defs><style>.a{fill:#00a9e5;}.b{fill:#353535;}.c{fill:#00bfb3;}.d{fill:#019b8f;}.e{fill:#f9b110;}.f{fill:#fed10a;}</style></defs><path class="a" d="M132.9,115.5h-12c.057.287.172.574.23.8a21.107,21.107,0,0,1,.747,4.307c.057.574.057,1.206.057,1.78s0,1.206-.057,1.78a21.106,21.106,0,0,1-.747,4.307c-.057.287-.172.574-.23.8h12a6.891,6.891,0,0,0,0-13.782Z" transform="translate(-101.318 -99.421)"/><path class="b" d="M107.358,124.171c.057-.574.057-1.206.057-1.78s0-1.206-.057-1.78a21.106,21.106,0,0,0-.747-4.307c-.057-.287-.172-.574-.23-.8H87.834a23.487,23.487,0,0,0,0,13.782h18.548c.057-.287.172-.574.23-.8A21.107,21.107,0,0,0,107.358,124.171Z" transform="translate(-86.8 -99.421)"/><path class="c" d="M128.072,143.5h-14.93a23.6,23.6,0,0,1-1.55,2.929,22.29,22.29,0,0,1-3.043,3.9c-.4.4-.8.747-1.206,1.148a22.846,22.846,0,0,1-2.642,2.01,22.725,22.725,0,0,0,12.633,3.79,23.018,23.018,0,0,0,19.122-10.221A11.712,11.712,0,0,0,128.072,143.5Z" transform="translate(-94.421 -111.343)"/><path class="d" d="M105.375,146.429a23.6,23.6,0,0,0,1.55-2.929H90.1a22.705,22.705,0,0,0,8.441,9.992,29.127,29.127,0,0,0,2.641-2.01c.4-.345.8-.747,1.206-1.148a22.635,22.635,0,0,0,2.986-3.9Z" transform="translate(-88.205 -111.343)"/><path class="e" d="M102.289,97.258c-.4-.4-.8-.747-1.206-1.148a22.847,22.847,0,0,0-2.641-2.01A23.475,23.475,0,0,0,90,104.092h16.825a23.6,23.6,0,0,0-1.55-2.929A18.059,18.059,0,0,0,102.289,97.258Z" transform="translate(-88.162 -90.31)"/><path class="f" d="M117.333,87.5A22.725,22.725,0,0,0,104.7,91.29a29.13,29.13,0,0,1,2.642,2.01c.4.345.8.747,1.206,1.148a22.29,22.29,0,0,1,3.043,3.9,23.605,23.605,0,0,1,1.55,2.929h14.93a11.712,11.712,0,0,0,8.384-3.56A23.018,23.018,0,0,0,117.333,87.5Z" transform="translate(-94.421 -87.5)"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M40.728 20.488l2.05.035 5.57-5.57.27-2.36C44.2 8.657 38.367 6.26 31.993 6.26c-11.54 0-21.28 7.852-24.163 18.488.608-.424 1.908-.106 1.908-.106l11.13-1.83s.572-.947.862-.9A13.88 13.88 0 0 1 32 17.375c3.3.007 6.34 1.173 8.728 3.102z" fill="#ea4335"/><path d="M56.17 24.77c-1.293-4.77-3.958-8.982-7.555-12.177l-7.887 7.887c3.16 2.55 5.187 6.452 5.187 10.82v1.392c3.837 0 6.954 3.124 6.954 6.954 0 3.837-3.124 6.954-6.954 6.954H32.007L30.615 48v8.346l1.392 1.385h13.908A18.11 18.11 0 0 0 64 39.647c-.007-6.155-3.1-11.6-7.83-14.876z" fill="#4285f4"/><path d="M18.085 57.74h13.9V46.6h-13.9a6.89 6.89 0 0 1-2.862-.622l-2.007.615-5.57 5.57-.488 1.88a18 18 0 0 0 10.926 3.689z" fill="#34a853"/><path d="M18.085 21.57A18.11 18.11 0 0 0 0 39.654c0 5.873 2.813 11.095 7.166 14.403l8.064-8.064a6.96 6.96 0 0 1-4.099-6.339c0-3.837 3.124-6.954 6.954-6.954 2.82 0 5.244 1.7 6.34 4.1l8.064-8.064c-3.307-4.353-8.53-7.166-14.403-7.166z" fill="#fbbc05"/></svg>

After

Width:  |  Height:  |  Size: 1012 B

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="28.141" height="23.33" viewBox="0 0 28.141 23.33">
<g id="object-browser-folder-icn" transform="translate(3875.698 1391.955)">
<g id="Grupo_1541" data-name="Grupo 1541" transform="translate(-3866.02 -1382.94)">
<circle id="Elipse_57" data-name="Elipse 57" cx="1.268" cy="1.268" r="1.268" transform="translate(4.275 5.49) rotate(-10.901)"/>
<rect id="Rectángulo_805" data-name="Rectángulo 805" width="2.707" height="2.295" rx="1.148" transform="translate(1.601 2.812)"/>
<path id="Trazado_365" data-name="Trazado 365" d="M-3848.674-1356.694a.267.267,0,0,0-.463,0l-1,1.735a.267.267,0,0,0,.231.4h2a.267.267,0,0,0,.232-.4Z" transform="translate(3851.773 1363.331)"/>
<path id="Trazado_366" data-name="Trazado 366" d="M-3845.066-1368.444a16.588,16.588,0,0,0-.021-1.927,1.119,1.119,0,0,0-.717-1.042,1.734,1.734,0,0,0-.2-.058,4.224,4.224,0,0,0-.807-.073c-.472-.014-.943.015-1.415.013-.945,0-1.889.013-2.834.017h-2.037a.694.694,0,0,0-.693.693v8.874a.694.694,0,0,0,.693.693h7.34a.694.694,0,0,0,.693-.693v-4.421C-3845.065-1367.059-3845.083-1367.754-3845.066-1368.444Zm-.842,5.871a.6.6,0,0,1-.6.6h-5.967a.6.6,0,0,1-.6-.6v-7.621a.6.6,0,0,1,.6-.6h4v1.024a1.52,1.52,0,0,0,1.518,1.518h1.043Zm0-6.34h-1.043a.857.857,0,0,1-.856-.856v-1.024h1.3a.6.6,0,0,1,.6.6Z" transform="translate(3853.792 1371.548)"/>
</g>
<path id="Trazado_367" data-name="Trazado 367" d="M-3864.516-1389.746c.726,0,1.5,2.076,2.283,2.076h9.68a1.041,1.041,0,0,1,1.038,1.038v.519h-19.748v-2.595h-.026a1.041,1.041,0,0,1,1.038-1.038h5.735m13.674,4.9a1.079,1.079,0,0,1,1.076,1.076l-1.1,11.862a1.079,1.079,0,0,1-1.076,1.076h-19.393a1.079,1.079,0,0,1-1.076-1.076l-1.076-11.862a1.079,1.079,0,0,1,1.076-1.076h21.571m-13.674-7.108h-5.735a3.25,3.25,0,0,0-3.247,3.247,2.22,2.22,0,0,0,.026.339v1.487a3.291,3.291,0,0,0-2.227,3.11c0,.067,0,.133.009.2l1.069,11.788a3.288,3.288,0,0,0,3.282,3.158h19.393a3.288,3.288,0,0,0,3.282-3.155l1.1-11.786c.006-.068.009-.136.009-.2a3.288,3.288,0,0,0-1.749-2.9,3.251,3.251,0,0,0-3.247-3.2h-8.959l-.124-.167a3.694,3.694,0,0,0-2.88-1.909Z" transform="translate(0 0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,6 @@
<svg id="object-browser-icn" xmlns="http://www.w3.org/2000/svg" width="11.502" height="13.542" viewBox="0 0 11.502 13.542">
<circle id="Elipse_55" data-name="Elipse 55" cx="1.667" cy="1.667" r="1.667" transform="translate(5.623 7.221) rotate(-10.901)"/>
<rect id="Rectángulo_797" data-name="Rectángulo 797" width="3.561" height="3.019" rx="1.51" transform="translate(2.105 3.699)"/>
<path id="Trazado_322" data-name="Trazado 322" d="M-4332.738-1202.411a.352.352,0,0,0-.609,0l-1.317,2.282a.352.352,0,0,0,.3.527h2.635a.352.352,0,0,0,.3-.527Z" transform="translate(4336.814 1211.141)"/>
<path id="Trazado_323" data-name="Trazado 323" d="M-4328.313-1219.174a22.083,22.083,0,0,0-.027-2.536,1.472,1.472,0,0,0-.943-1.371,2.294,2.294,0,0,0-.266-.077,5.586,5.586,0,0,0-1.063-.095c-.62-.018-1.24.019-1.86.017-1.243-.005-2.486.017-3.729.022h-2.68a.913.913,0,0,0-.912.912v11.674a.913.913,0,0,0,.912.912h9.656a.912.912,0,0,0,.912-.912v-5.816C-4328.312-1217.353-4328.335-1218.266-4328.313-1219.174Zm-1.107,7.722a.788.788,0,0,1-.787.788h-7.849a.787.787,0,0,1-.787-.788v-10.025a.787.787,0,0,1,.787-.788h5.266v1.347a2,2,0,0,0,2,2h1.373Zm0-8.339h-1.373a1.128,1.128,0,0,1-1.126-1.127v-1.347h1.712a.788.788,0,0,1,.787.788Z" transform="translate(4339.792 1223.257)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="9.836" height="12.646" viewBox="0 0 9.836 12.646">
<g id="trash-icn" transform="translate(2222 1227)">
<path id="Trazado_359" data-name="Trazado 359" d="M-2212.473-1226.3h-2.5v-.395a.308.308,0,0,0-.308-.308h-3.6a.308.308,0,0,0-.308.308v.395h-2.5a.309.309,0,0,0-.309.309v.787a.309.309,0,0,0,.309.309h9.218a.309.309,0,0,0,.309-.309v-.787A.309.309,0,0,0-2212.473-1226.3Z"/>
<path id="Trazado_360" data-name="Trazado 360" d="M-2221-1214.585a1.425,1.425,0,0,0,1.42,1.421h5.59a1.425,1.425,0,0,0,1.42-1.421V-1223H-2221Z" transform="translate(-0.297 -1.19)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 623 B

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