From 06f333395e54207fe65816b1b129a2aac44a028b Mon Sep 17 00:00:00 2001 From: Cesar N Date: Wed, 4 Nov 2020 21:45:48 -0800 Subject: [PATCH] Move trace and logs UI to Operator Console (#375) Co-authored-by: Daniel Valdivia --- go.mod | 2 +- go.sum | 11 +- models/create_tenant_request.go | 3 - pkg/acl/endpoints.go | 24 ---- pkg/acl/endpoints_test.go | 4 +- portal-ui/src/screens/Console/Console.tsx | 10 -- portal-ui/src/screens/Console/Menu/Menu.tsx | 18 --- .../{ => Tenants/TenantDetails}/Logs/Logs.tsx | 72 +++++----- .../TenantDetails}/Logs/actions.ts | 0 .../TenantDetails}/Logs/reducers.ts | 0 .../{ => Tenants/TenantDetails}/Logs/types.ts | 0 .../Tenants/TenantDetails/TenantDetails.tsx | 80 ++++++----- .../TenantDetails}/Trace/Trace.tsx | 131 +++++++++--------- .../TenantDetails}/Trace/actions.ts | 0 .../TenantDetails}/Trace/reducers.ts | 0 .../TenantDetails}/Trace/types.ts | 0 portal-ui/src/store.ts | 4 +- restapi/admin_console.go | 24 ++++ restapi/admin_tenants.go | 18 ++- restapi/admin_tenants_helper.go | 4 +- restapi/embedded_spec.go | 6 - restapi/ws_handle.go | 65 ++++++++- swagger.yml | 2 - 23 files changed, 256 insertions(+), 222 deletions(-) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Logs/Logs.tsx (88%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Logs/actions.ts (100%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Logs/reducers.ts (100%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Logs/types.ts (100%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Trace/Trace.tsx (57%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Trace/actions.ts (100%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Trace/reducers.ts (100%) rename portal-ui/src/screens/Console/{ => Tenants/TenantDetails}/Trace/types.ts (100%) diff --git a/go.mod b/go.mod index 98ac601b8..1287d4c46 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/minio/mc v0.0.0-20201001165056-7f2df96e4821 github.com/minio/minio v0.0.0-20200927172404-27d9bd04e544 github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089 - github.com/minio/operator v0.0.0-20200930213302-ab2bbdfae96c + github.com/minio/operator v0.0.0-20201022162018-527e5c32132b github.com/mitchellh/go-homedir v1.1.0 github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/secure-io/sio-go v0.3.1 diff --git a/go.sum b/go.sum index 3c7910dfc..4e4142a2d 100644 --- a/go.sum +++ b/go.sum @@ -60,10 +60,12 @@ github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESN github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI= github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= @@ -72,11 +74,13 @@ github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMl github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.1 h1:xjPqigMQe2+0DAJ5A6MLUPp5D2r2Io8qHCuCMMI/yJU= github.com/Azure/go-autorest/autorest/adal v0.9.1/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= @@ -86,8 +90,10 @@ github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocm github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= +github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -540,6 +546,7 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/googleapis/gnostic v0.2.2 h1:DcFegQ7+ECdmkJMfVwWlC+89I4esJ7p8nkGt9ainGDk= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= +github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -798,8 +805,8 @@ github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6J github.com/minio/minio-go/v7 v7.0.5-0.20200811211821-14ed05478889/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk= github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089 h1:9DDs/Gc3fNHOQxQmwIFWs7YDLMTBh59r2XQ6RqEUA1I= github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk= -github.com/minio/operator v0.0.0-20200930213302-ab2bbdfae96c h1:OIKdzEJDFmUokbJ1rIdlr3kcfsBfXelYgSCTN/+Ppec= -github.com/minio/operator v0.0.0-20200930213302-ab2bbdfae96c/go.mod h1:6lavbNo2YuJWeQR5bZYsEWdbpRCO2KrTyfQ0PtC/AN4= +github.com/minio/operator v0.0.0-20201022162018-527e5c32132b h1:ggfD6V3nodTzhHJHCYIT1F897gscrz+hHsan0a2Wtqw= +github.com/minio/operator v0.0.0-20201022162018-527e5c32132b/go.mod h1:At+++4/6W5BEXK11tN5DKIvkJKhYBZybbb5zmxb0LQI= 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 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= diff --git a/models/create_tenant_request.go b/models/create_tenant_request.go index 2a1ac8022..5fd5c013c 100644 --- a/models/create_tenant_request.go +++ b/models/create_tenant_request.go @@ -93,9 +93,6 @@ type CreateTenantRequest struct { // secret key SecretKey string `json:"secret_key,omitempty"` - // service name - ServiceName string `json:"service_name,omitempty"` - // tls TLS *TLSConfiguration `json:"tls,omitempty"` diff --git a/pkg/acl/endpoints.go b/pkg/acl/endpoints.go index 506d99b91..98d920e2c 100644 --- a/pkg/acl/endpoints.go +++ b/pkg/acl/endpoints.go @@ -28,8 +28,6 @@ var ( iamPolicies = "/policies" dashboard = "/dashboard" profiling = "/profiling" - trace = "/trace" - logs = "/logs" watch = "/watch" notifications = "/notification-endpoints" buckets = "/buckets" @@ -61,16 +59,6 @@ var configurationActionSet = ConfigurationActionSet{ ), } -// logsActionSet contains the list of admin actions required for this endpoint to work -var logsActionSet = ConfigurationActionSet{ - actionTypes: iampolicy.NewActionSet( - iampolicy.AllAdminActions, - ), - actions: iampolicy.NewActionSet( - iampolicy.ConsoleLogAdminAction, - ), -} - // dashboardActionSet contains the list of admin actions required for this endpoint to work var dashboardActionSet = ConfigurationActionSet{ actionTypes: iampolicy.NewActionSet( @@ -119,16 +107,6 @@ var profilingActionSet = ConfigurationActionSet{ ), } -// traceActionSet contains the list of admin actions required for this endpoint to work -var traceActionSet = ConfigurationActionSet{ - actionTypes: iampolicy.NewActionSet( - iampolicy.AllAdminActions, - ), - actions: iampolicy.NewActionSet( - iampolicy.TraceAdminAction, - ), -} - // usersActionSet contains the list of admin actions required for this endpoint to work var usersActionSet = ConfigurationActionSet{ actionTypes: iampolicy.NewActionSet( @@ -252,8 +230,6 @@ var endpointRules = map[string]ConfigurationActionSet{ iamPolicies: iamPoliciesActionSet, dashboard: dashboardActionSet, profiling: profilingActionSet, - trace: traceActionSet, - logs: logsActionSet, watch: watchActionSet, notifications: notificationsActionSet, buckets: bucketsActionSet, diff --git a/pkg/acl/endpoints_test.go b/pkg/acl/endpoints_test.go index bba56bbca..e5a2a63ca 100644 --- a/pkg/acl/endpoints_test.go +++ b/pkg/acl/endpoints_test.go @@ -72,7 +72,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) { "admin:*", }, }, - want: 17, + want: 15, }, { name: "all s3 endpoints", @@ -91,7 +91,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) { "s3:*", }, }, - want: 20, + want: 18, }, { name: "no endpoints", diff --git a/portal-ui/src/screens/Console/Console.tsx b/portal-ui/src/screens/Console/Console.tsx index 35fe69904..88a55ef46 100644 --- a/portal-ui/src/screens/Console/Console.tsx +++ b/portal-ui/src/screens/Console/Console.tsx @@ -42,8 +42,6 @@ import ListNotificationEndpoints from "./NotificationEndopoints/ListNotification import ConfigurationsList from "./Configurations/ConfigurationPanels/ConfigurationsList"; import { Button, LinearProgress } from "@material-ui/core"; import WebhookPanel from "./Configurations/ConfigurationPanels/WebhookPanel"; -import Trace from "./Trace/Trace"; -import Logs from "./Logs/Logs"; import Heal from "./Heal/Heal"; import Watch from "./Watch/Watch"; import ListTenants from "./Tenants/ListTenants/ListTenants"; @@ -256,14 +254,6 @@ const Console = ({ component: Policies, path: "/policies", }, - { - component: Trace, - path: "/trace", - }, - { - component: Logs, - path: "/logs", - }, { component: Heal, path: "/heal", diff --git a/portal-ui/src/screens/Console/Menu/Menu.tsx b/portal-ui/src/screens/Console/Menu/Menu.tsx index 385d1f4be..0cb5d099c 100644 --- a/portal-ui/src/screens/Console/Menu/Menu.tsx +++ b/portal-ui/src/screens/Console/Menu/Menu.tsx @@ -43,13 +43,11 @@ import { LambdaNotificationsIcon, MirroringIcon, ServiceAccountsIcon, - TraceIcon, UsersIcon, WarpIcon, } from "../../../icons"; import { clearSession } from "../../../common/utils"; import HealIcon from "../../../icons/HealIcon"; -import ConsoleIcon from "../../../icons/ConsoleIcon"; import LicenseIcon from "../../../icons/LicenseIcon"; import LogoutIcon from "../../../icons/LogoutIcon"; @@ -242,14 +240,6 @@ const Menu = ({ userLoggedIn, classes, pages }: IMenuProps) => { name: "IAM Policies", icon: , }, - { - group: "Tools", - type: "item", - component: NavLink, - to: "/logs", - name: "Logs", - icon: , - }, { group: "Tools", type: "item", @@ -258,14 +248,6 @@ const Menu = ({ userLoggedIn, classes, pages }: IMenuProps) => { name: "Watch", icon: , }, - { - group: "Tools", - type: "item", - component: NavLink, - to: "/trace", - name: "Trace", - icon: , - }, { group: "Tools", type: "item", diff --git a/portal-ui/src/screens/Console/Logs/Logs.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/Logs.tsx similarity index 88% rename from portal-ui/src/screens/Console/Logs/Logs.tsx rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/Logs.tsx index 2752d5956..909de931f 100644 --- a/portal-ui/src/screens/Console/Logs/Logs.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/Logs.tsx @@ -15,20 +15,19 @@ // along with this program. If not, see . import React, { useState, useEffect } from "react"; import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket"; -import { AppState } from "../../../store"; +import { AppState } from "../../../../../store"; import { connect } from "react-redux"; import { logMessageReceived, logResetMessages } from "./actions"; import { LogMessage } from "./types"; import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import { timeFromDate } from "../../../common/utils"; -import { wsProtocol } from "../../../utils/wsUtils"; +import { timeFromDate } from "../../../../../common/utils"; +import { wsProtocol } from "../../../../../utils/wsUtils"; import { actionsTray, containerForHeader, searchField, -} from "../Common/FormComponents/common/styleLibrary"; +} from "../../../Common/FormComponents/common/styleLibrary"; import { Grid } from "@material-ui/core"; -import PageHeader from "../Common/PageHeader/PageHeader"; import TextField from "@material-ui/core/TextField"; import InputAdornment from "@material-ui/core/InputAdornment"; import SearchIcon from "@material-ui/icons/Search"; @@ -73,6 +72,8 @@ interface ILogs { logMessageReceived: typeof logMessageReceived; logResetMessages: typeof logResetMessages; messages: LogMessage[]; + namespace: string; + tenant: string; } const Logs = ({ @@ -80,6 +81,8 @@ const Logs = ({ logMessageReceived, logResetMessages, messages, + namespace, + tenant, }: ILogs) => { const [highlight, setHighlight] = useState(""); @@ -92,7 +95,7 @@ const Logs = ({ const wsProt = wsProtocol(url.protocol); const c = new W3CWebSocket( - `${wsProt}://${url.hostname}:${port}/ws/console` + `${wsProt}://${url.hostname}:${port}/ws/console/${namespace}/${tenant}` ); let interval: any | null = null; @@ -321,38 +324,33 @@ const Logs = ({ }); return ( - - - - - - { - setHighlight(val.target.value); - }} - InputProps={{ - disableUnderline: true, - startAdornment: ( - - - - ), - }} - /> - - -
-
- -
{renderLines}
-
-
+ + + { + setHighlight(val.target.value); + }} + InputProps={{ + disableUnderline: true, + startAdornment: ( + + + + ), + }} + /> -
+ +
+
+ +
{renderLines}
+
+ ); }; diff --git a/portal-ui/src/screens/Console/Logs/actions.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/actions.ts similarity index 100% rename from portal-ui/src/screens/Console/Logs/actions.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/actions.ts diff --git a/portal-ui/src/screens/Console/Logs/reducers.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/reducers.ts similarity index 100% rename from portal-ui/src/screens/Console/Logs/reducers.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/reducers.ts diff --git a/portal-ui/src/screens/Console/Logs/types.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/types.ts similarity index 100% rename from portal-ui/src/screens/Console/Logs/types.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Logs/types.ts diff --git a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx index 5d6a8cd72..f54494e06 100644 --- a/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/TenantDetails.tsx @@ -32,6 +32,8 @@ import AddBucket from "../../Buckets/ListBuckets/AddBucket"; import ReplicationSetup from "./ReplicationSetup"; import api from "../../../../common/api"; import { ITenant, IZone } from "../ListTenants/types"; +import Logs from "./Logs/Logs"; +import Trace from "./Trace/Trace"; interface ITenantDetailsProps { classes: any; @@ -237,6 +239,8 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => { aria-label="tenant-tabs" > + + @@ -255,42 +259,50 @@ const TenantDetails = ({ classes, match }: ITenantDetailsProps) => {
- { - console.log(element); + {selectedTab === 0 && ( + { + console.log(element); + }, + sendOnlyId: true, }, - sendOnlyId: true, - }, - ]} - columns={[ - { label: "Name", elementKey: "name" }, - { label: "Capacity", elementKey: "capacity" }, - { label: "# of Instances", elementKey: "servers" }, - { label: "# of Drives", elementKey: "volumes" }, - ]} - isLoading={false} - records={zones} - entityName="Zones" - idField="name" - paginatorConfig={{ - rowsPerPageOptions: [5, 10, 25], - colSpan: 3, - count: zoneCount, - rowsPerPage: 10, - page: 0, - SelectProps: { - inputProps: { "aria-label": "rows per page" }, - native: true, - }, - ActionsComponent: MinTablePaginationActions, - onChangePage: () => {}, - onChangeRowsPerPage: () => {}, - }} - /> + ]} + columns={[ + { label: "Name", elementKey: "name" }, + { label: "Capacity", elementKey: "capacity" }, + { label: "# of Instances", elementKey: "servers" }, + { label: "# of Drives", elementKey: "volumes" }, + ]} + isLoading={false} + records={zones} + entityName="Zones" + idField="name" + paginatorConfig={{ + rowsPerPageOptions: [5, 10, 25], + colSpan: 3, + count: zoneCount, + rowsPerPage: 10, + page: 0, + SelectProps: { + inputProps: { "aria-label": "rows per page" }, + native: true, + }, + ActionsComponent: MinTablePaginationActions, + onChangePage: () => {}, + onChangeRowsPerPage: () => {}, + }} + /> + )} + {selectedTab === 1 && tenant !== null && ( + + )} + {selectedTab === 2 && tenant !== null && ( + + )} ); diff --git a/portal-ui/src/screens/Console/Trace/Trace.tsx b/portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/Trace.tsx similarity index 57% rename from portal-ui/src/screens/Console/Trace/Trace.tsx rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/Trace.tsx index 42d238021..b75cdf46e 100644 --- a/portal-ui/src/screens/Console/Trace/Trace.tsx +++ b/portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/Trace.tsx @@ -16,17 +16,17 @@ import React, { useEffect } from "react"; import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket"; -import { AppState } from "../../../store"; +import { AppState } from "../../../../../store"; import { connect } from "react-redux"; import { traceMessageReceived, traceResetMessages } from "./actions"; import { TraceMessage } from "./types"; import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; -import { niceBytes, timeFromDate } from "../../../common/utils"; -import { wsProtocol } from "../../../utils/wsUtils"; -import { containerForHeader } from "../Common/FormComponents/common/styleLibrary"; -import PageHeader from "../Common/PageHeader/PageHeader"; +import { niceBytes, timeFromDate } from "../../../../../common/utils"; +import { wsProtocol } from "../../../../../utils/wsUtils"; +import { containerForHeader } from "../../../Common/FormComponents/common/styleLibrary"; +import PageHeader from "../../../Common/PageHeader/PageHeader"; import { Grid } from "@material-ui/core"; -import TableWrapper from "../Common/TableWrapper/TableWrapper"; +import TableWrapper from "../../../Common/TableWrapper/TableWrapper"; const styles = (theme: Theme) => createStyles({ @@ -59,6 +59,8 @@ interface ITrace { traceMessageReceived: typeof traceMessageReceived; traceResetMessages: typeof traceResetMessages; messages: TraceMessage[]; + namespace: string; + tenant: string; } const Trace = ({ @@ -66,6 +68,8 @@ const Trace = ({ traceMessageReceived, traceResetMessages, messages, + namespace, + tenant, }: ITrace) => { useEffect(() => { traceResetMessages(); @@ -74,7 +78,9 @@ const Trace = ({ const port = isDev ? "9090" : url.port; const wsProt = wsProtocol(url.protocol); - const c = new W3CWebSocket(`${wsProt}://${url.hostname}:${port}/ws/trace`); + const c = new W3CWebSocket( + `${wsProt}://${url.hostname}:${port}/ws/trace/${namespace}/${tenant}` + ); let interval: any | null = null; if (c !== null) { @@ -104,64 +110,59 @@ const Trace = ({ }, [traceMessageReceived, traceResetMessages]); return ( - - - - - { - const timeParse = new Date(time); - return timeFromDate(timeParse); - }, - globalClass: classes.timeItem, - }, - { label: "Name", elementKey: "api" }, - { - label: "Status", - elementKey: "", - renderFunction: (fullElement: TraceMessage) => - `${fullElement.statusCode} ${fullElement.statusMsg}`, - renderFullObject: true, - }, - { - label: "Location", - elementKey: "configuration_id", - renderFunction: (fullElement: TraceMessage) => - `${fullElement.host} ${fullElement.client}`, - renderFullObject: true, - }, - { - label: "Load Time", - elementKey: "callStats.duration", - globalClass: classes.timeItem, - }, - { - label: "Upload", - elementKey: "callStats.rx", - renderFunction: niceBytes, - globalClass: classes.sizeItem, - }, - { - label: "Download", - elementKey: "callStats.tx", - renderFunction: niceBytes, - globalClass: classes.sizeItem, - }, - ]} - isLoading={false} - records={messages} - entityName="Traces" - idField="api" - customEmptyMessage="There are no traced Elements yet" - /> - - - + + { + const timeParse = new Date(time); + return timeFromDate(timeParse); + }, + globalClass: classes.timeItem, + }, + { label: "Name", elementKey: "api" }, + { + label: "Status", + elementKey: "", + renderFunction: (fullElement: TraceMessage) => + `${fullElement.statusCode} ${fullElement.statusMsg}`, + renderFullObject: true, + }, + { + label: "Location", + elementKey: "configuration_id", + renderFunction: (fullElement: TraceMessage) => + `${fullElement.host} ${fullElement.client}`, + renderFullObject: true, + }, + { + label: "Load Time", + elementKey: "callStats.duration", + globalClass: classes.timeItem, + }, + { + label: "Upload", + elementKey: "callStats.rx", + renderFunction: niceBytes, + globalClass: classes.sizeItem, + }, + { + label: "Download", + elementKey: "callStats.tx", + renderFunction: niceBytes, + globalClass: classes.sizeItem, + }, + ]} + isLoading={false} + records={messages} + entityName="Traces" + idField="api" + customEmptyMessage="There are no traced Elements yet" + /> + ); }; diff --git a/portal-ui/src/screens/Console/Trace/actions.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/actions.ts similarity index 100% rename from portal-ui/src/screens/Console/Trace/actions.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/actions.ts diff --git a/portal-ui/src/screens/Console/Trace/reducers.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/reducers.ts similarity index 100% rename from portal-ui/src/screens/Console/Trace/reducers.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/reducers.ts diff --git a/portal-ui/src/screens/Console/Trace/types.ts b/portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/types.ts similarity index 100% rename from portal-ui/src/screens/Console/Trace/types.ts rename to portal-ui/src/screens/Console/Tenants/TenantDetails/Trace/types.ts diff --git a/portal-ui/src/store.ts b/portal-ui/src/store.ts index 6def23a18..c9598ee94 100644 --- a/portal-ui/src/store.ts +++ b/portal-ui/src/store.ts @@ -17,8 +17,8 @@ import { applyMiddleware, combineReducers, compose, createStore } from "redux"; import thunk from "redux-thunk"; import { systemReducer } from "./reducer"; -import { traceReducer } from "./screens/Console/Trace/reducers"; -import { logReducer } from "./screens/Console/Logs/reducers"; +import { traceReducer } from "./screens/Console/Tenants/TenantDetails/Trace/reducers"; +import { logReducer } from "./screens/Console/Tenants/TenantDetails/Logs/reducers"; import { watchReducer } from "./screens/Console/Watch/reducers"; import { consoleReducer } from "./screens/Console/reducer"; import { bucketsReducer } from "./screens/Console/Buckets/reducers"; diff --git a/restapi/admin_console.go b/restapi/admin_console.go index 3420846f8..1c2445ba2 100644 --- a/restapi/admin_console.go +++ b/restapi/admin_console.go @@ -21,6 +21,8 @@ import ( "encoding/json" "fmt" "log" + "net/http" + "regexp" "strings" "time" @@ -93,3 +95,25 @@ func getLogTime(lt string) string { } return tm.Format(logTimeFormat) } + +// getConsoleLogOptionsFromReq return tenant name from url +// path come as : `/console//` +func getConsoleLogOptionsFromReq(req *http.Request) (namespace, tenant string) { + re := regexp.MustCompile(`(/console/)(.*?)/(.*?)(\?.*?$|$)`) + matches := re.FindAllSubmatch([]byte(req.URL.Path), -1) + // len matches is always 4 + namespace = strings.TrimSpace(string(matches[0][2])) + tenant = strings.TrimSpace(string(matches[0][3])) + return namespace, tenant +} + +// getTraceOptionsFromReq return tenant name from url +// path come as : `/trace//` +func getTraceOptionsFromReq(req *http.Request) (namespace, tenant string) { + re := regexp.MustCompile(`(/trace/)(.*?)/(.*?)(\?.*?$|$)`) + matches := re.FindAllSubmatch([]byte(req.URL.Path), -1) + // len matches is always 4 + namespace = strings.TrimSpace(string(matches[0][2])) + tenant = strings.TrimSpace(string(matches[0][3])) + return namespace, tenant +} diff --git a/restapi/admin_tenants.go b/restapi/admin_tenants.go index f3fa5ff41..167a11857 100644 --- a/restapi/admin_tenants.go +++ b/restapi/admin_tenants.go @@ -576,14 +576,16 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create if tenantReq.EnableTLS != nil && *tenantReq.EnableTLS { // If user request autoCert, Operator will generate certificate keypair for MinIO (server), Console (server) and KES (server and app mTLS) isEncryptionEnabled = true - minInst.Spec.RequestAutoCert = *tenantReq.EnableTLS + minInst.Spec.RequestAutoCert = tenantReq.EnableTLS } - if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && len(tenantReq.TLS.Minio) > 0 { + if (minInst.Spec.RequestAutoCert == nil || (minInst.Spec.RequestAutoCert != nil && !*minInst.Spec.RequestAutoCert)) && + tenantReq.TLS != nil && + len(tenantReq.TLS.Minio) > 0 { // User provided TLS certificates for MinIO isEncryptionEnabled = true // disable autoCert - minInst.Spec.RequestAutoCert = false + minInst.Spec.RequestAutoCert = swag.Bool(false) // Certificates used by the MinIO instance externalCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName) externalCertSecret, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, tenantReq.TLS.Minio, externalCertSecretName, tenantName) @@ -600,7 +602,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create Value: "on", }) // KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled - if !minInst.Spec.RequestAutoCert { + if minInst.Spec.RequestAutoCert == nil || (minInst.Spec.RequestAutoCert != nil && !*minInst.Spec.RequestAutoCert) { tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName) certificates := []*models.KeyPairConfiguration{tenantReq.Encryption.Client} certificateSecrets, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, certificates, tenantExternalClientCertSecretName, tenantName) @@ -664,7 +666,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create instanceSecret.Data["CONSOLE_IDP_SECRET"] = []byte(secretID) consoleScheme := "http" consolePort := 9090 - if minInst.Spec.RequestAutoCert { + if minInst.Spec.RequestAutoCert != nil && *minInst.Spec.RequestAutoCert { consoleScheme = "https" consolePort = 9443 } @@ -690,7 +692,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create }, }, } - if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Console != nil { + if (minInst.Spec.RequestAutoCert == nil || (minInst.Spec.RequestAutoCert != nil && !*minInst.Spec.RequestAutoCert)) && tenantReq.TLS != nil && tenantReq.TLS.Console != nil { // Certificates used by the console instance externalCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName) certificates := []*models.KeyPairConfiguration{tenantReq.TLS.Console} @@ -711,10 +713,6 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create } } - // set the service name if provided - if tenantReq.ServiceName != "" { - minInst.Spec.ServiceName = tenantReq.ServiceName - } // add annotations var annotations map[string]string diff --git a/restapi/admin_tenants_helper.go b/restapi/admin_tenants_helper.go index 1ee03cc4c..beb723d2b 100644 --- a/restapi/admin_tenants_helper.go +++ b/restapi/admin_tenants_helper.go @@ -185,7 +185,7 @@ func getTenantUpdateEncryptionResponse(session *models.Principal, params admin_a // getKESConfiguration will generate the KES server certificate secrets, the tenant client secrets for mTLS authentication between MinIO and KES and the // kes-configuration.yaml file used by the KES service (how to connect to the external KMS, eg: Vault, AWS, Gemalto, etc) -func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) { +func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert *bool) (kesConfiguration *operator.KESConfig, err error) { // Secrets used by the KES service // // kesExternalCertSecretName is the name of the secret that will store the certificates for TLS in the KES server, eg: server.key and server.crt @@ -204,7 +204,7 @@ func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, e kesConfiguration.Image = encryptionCfg.Image } // Generate server certificates for KES only if autoCert is disabled - if !autoCert { + if autoCert == nil || (autoCert != nil && !*autoCert) { certificates := []*models.KeyPairConfiguration{encryptionCfg.Server} certificateSecrets, err := createOrReplaceExternalCertSecrets(ctx, clientSet, ns, certificates, kesExternalCertSecretName, tenantName) if err != nil { diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 402ce684b..b63f2dede 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -3264,9 +3264,6 @@ func init() { "secret_key": { "type": "string" }, - "service_name": { - "type": "string" - }, "tls": { "type": "object", "$ref": "#/definitions/tlsConfiguration" @@ -8656,9 +8653,6 @@ func init() { "secret_key": { "type": "string" }, - "service_name": { - "type": "string" - }, "tls": { "type": "object", "$ref": "#/definitions/tlsConfiguration" diff --git a/restapi/ws_handle.go b/restapi/ws_handle.go index 41749310f..325435711 100644 --- a/restapi/ws_handle.go +++ b/restapi/ws_handle.go @@ -22,9 +22,11 @@ import ( "net" "net/http" "strings" + "time" "github.com/go-openapi/errors" "github.com/gorilla/websocket" + "github.com/minio/console/cluster" "github.com/minio/console/models" "github.com/minio/console/pkg/auth" ) @@ -118,15 +120,19 @@ func serveWS(w http.ResponseWriter, req *http.Request) { wsPath := strings.TrimPrefix(req.URL.Path, wsBasePath) switch { - case wsPath == "/trace": - wsAdminClient, err := newWebSocketAdminClient(conn, session) + case strings.HasPrefix(wsPath, `/trace`): + // Trace api only for operator Console + namespace, tenant := getTraceOptionsFromReq(req) + wsAdminClient, err := newWebSocketTenantAdminClient(conn, session, namespace, tenant) if err != nil { closeWsConn(conn) return } go wsAdminClient.trace() - case wsPath == "/console": - wsAdminClient, err := newWebSocketAdminClient(conn, session) + case strings.HasPrefix(wsPath, `/console`): + // Trace api only for operator Console + namespace, tenant := getConsoleLogOptionsFromReq(req) + wsAdminClient, err := newWebSocketTenantAdminClient(conn, session, namespace, tenant) if err != nil { closeWsConn(conn) return @@ -159,6 +165,57 @@ func serveWS(w http.ResponseWriter, req *http.Request) { } } +// newWebSocketTenantAdminClient creates a ws Client with a k8s tenant client +// this is to be used for a kubernetes environment and for a particular tenant +// in a defined namespace +func newWebSocketTenantAdminClient(conn *websocket.Conn, session *models.Principal, namespace, tenant string) (*wsAdminClient, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + opClientClientSet, err := cluster.OperatorClient(session.SessionToken) + if err != nil { + return nil, err + } + clientSet, err := cluster.K8sClient(session.SessionToken) + if err != nil { + return nil, err + } + + opClient := &operatorClient{ + client: opClientClientSet, + } + k8sClient := &k8sClient{ + client: clientSet, + } + + minTenant, err := getTenant(ctx, opClient, namespace, tenant) + if err != nil { + return nil, err + } + minTenant.EnsureDefaults() + + svcURL := GetTenantServiceURL(minTenant) + + mAdmin, err := getTenantAdminClient( + ctx, + k8sClient, + minTenant, + svcURL, + true) + if err != nil { + return nil, err + } + // create a websocket connection interface implementation + // defining the connection to be used + wsConnection := wsConn{conn: conn} + // create a minioClient interface implementation + // defining the client to be used + adminClient := adminClient{client: mAdmin} + // create websocket client and handle request + wsAdminClient := &wsAdminClient{conn: wsConnection, client: adminClient} + return wsAdminClient, nil +} + // newWebSocketAdminClient returns a wsAdminClient authenticated as an admin user func newWebSocketAdminClient(conn *websocket.Conn, autClaims *models.Principal) (*wsAdminClient, error) { // Only start Websocket Interaction after user has been diff --git a/swagger.yml b/swagger.yml index 1bd125ee2..0cbcea648 100644 --- a/swagger.yml +++ b/swagger.yml @@ -2697,8 +2697,6 @@ definitions: type: string console_image: type: string - service_name: - type: string zones: type: array items: