Support for Hop into tenants (#878)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -64,7 +64,6 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
//STSSessionToken := currToken.Value
|
||||
STSSessionToken := claims.STSSessionToken
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(STSSessionToken)
|
||||
@@ -98,7 +97,6 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
|
||||
|
||||
h := sha1.New()
|
||||
h.Write([]byte(nsTenant))
|
||||
log.Printf("Proxying request for %s/%s", namespace, tenantName)
|
||||
tenantCookieName := fmt.Sprintf("token-%x", string(h.Sum(nil)))
|
||||
tenantCookie, err := req.Cookie(tenantCookieName)
|
||||
if err != nil {
|
||||
@@ -113,7 +111,7 @@ func serveProxy(responseWriter http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
currentSecret, err := clientSet.CoreV1().Secrets(namespace).Get(req.Context(), tenant.Spec.CredsSecret.Name, metav1.GetOptions{})
|
||||
currentSecret, err := clientSet.CoreV1().Secrets(tenant.Namespace).Get(req.Context(), tenant.Spec.CredsSecret.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
responseWriter.WriteHeader(500)
|
||||
|
||||
@@ -44,6 +44,7 @@ var (
|
||||
changePassword = "/account/change-password"
|
||||
tenants = "/tenants"
|
||||
tenantsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName"
|
||||
tenantHop = "/namespaces/:tenantNamespace/tenants/:tenantName/hop"
|
||||
podsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName/pods/:podName"
|
||||
tenantsDetailSummary = "/namespaces/:tenantNamespace/tenants/:tenantName/summary"
|
||||
tenantsDetailMetrics = "/namespaces/:tenantNamespace/tenants/:tenantName/metrics"
|
||||
@@ -324,6 +325,7 @@ var endpointRules = map[string]ConfigurationActionSet{
|
||||
var operatorRules = map[string]ConfigurationActionSet{
|
||||
tenants: tenantsActionSet,
|
||||
tenantsDetail: tenantsActionSet,
|
||||
tenantHop: tenantsActionSet,
|
||||
tenantsDetailSummary: tenantsActionSet,
|
||||
tenantsDetailMetrics: tenantsActionSet,
|
||||
tenantsDetailPods: tenantsActionSet,
|
||||
|
||||
@@ -116,7 +116,7 @@ func TestOperatorOnlyEndpoints(t *testing.T) {
|
||||
"admin:*",
|
||||
},
|
||||
},
|
||||
want: 13,
|
||||
want: 14,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - all s3 endpoints",
|
||||
@@ -125,7 +125,7 @@ func TestOperatorOnlyEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 13,
|
||||
want: 14,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - all admin and s3 endpoints",
|
||||
@@ -135,14 +135,14 @@ func TestOperatorOnlyEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 13,
|
||||
want: 14,
|
||||
},
|
||||
{
|
||||
name: "Operator Only - default endpoints",
|
||||
args: args{
|
||||
[]string{},
|
||||
},
|
||||
want: 13,
|
||||
want: 14,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
"main.js.map": "/static/js/main.439bfd00.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.c5a51b70.chunk.css": "/static/css/2.c5a51b70.chunk.css",
|
||||
"static/js/2.55ef6ad7.chunk.js": "/static/js/2.55ef6ad7.chunk.js",
|
||||
"static/js/2.55ef6ad7.chunk.js.map": "/static/js/2.55ef6ad7.chunk.js.map",
|
||||
"static/css/2.20c81d8d.chunk.css": "/static/css/2.20c81d8d.chunk.css",
|
||||
"static/js/2.02087608.chunk.js": "/static/js/2.02087608.chunk.js",
|
||||
"static/js/2.02087608.chunk.js.map": "/static/js/2.02087608.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"static/css/2.c5a51b70.chunk.css.map": "/static/css/2.c5a51b70.chunk.css.map",
|
||||
"static/css/2.20c81d8d.chunk.css.map": "/static/css/2.20c81d8d.chunk.css.map",
|
||||
"static/css/main.8cfac526.chunk.css.map": "/static/css/main.8cfac526.chunk.css.map",
|
||||
"static/js/2.55ef6ad7.chunk.js.LICENSE.txt": "/static/js/2.55ef6ad7.chunk.js.LICENSE.txt",
|
||||
"static/js/2.02087608.chunk.js.LICENSE.txt": "/static/js/2.02087608.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"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.43a31377.js",
|
||||
"static/css/2.c5a51b70.chunk.css",
|
||||
"static/js/2.55ef6ad7.chunk.js",
|
||||
"static/css/2.20c81d8d.chunk.css",
|
||||
"static/js/2.02087608.chunk.js",
|
||||
"static/css/main.8cfac526.chunk.css",
|
||||
"static/js/main.439bfd00.chunk.js"
|
||||
]
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link href="/styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.c5a51b70.chunk.css" rel="stylesheet"><link href="/static/css/main.8cfac526.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.55ef6ad7.chunk.js"></script><script src="/static/js/main.439bfd00.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="MinIO Console"/><link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap" rel="stylesheet"/><link href="/styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><link rel="manifest" href="/manifest.json"/><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="/static/css/2.c5a51b70.chunk.css" rel="stylesheet"><link href="/static/css/main.8cfac526.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="/static/js/2.55ef6ad7.chunk.js"></script><script src="/static/js/main.439bfd00.chunk.js"></script></body></html>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/2.02087608.chunk.js.map
Normal file
1
portal-ui/build/static/js/2.02087608.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
portal-ui/build/static/js/main.8c8fdb63.chunk.js
Normal file
2
portal-ui/build/static/js/main.8c8fdb63.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/main.8c8fdb63.chunk.js.map
Normal file
1
portal-ui/build/static/js/main.8c8fdb63.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -58,6 +58,7 @@ import HealthInfo from "./HealthInfo/HealthInfo";
|
||||
import Storage from "./Storage/Storage";
|
||||
import PodDetails from "./Tenants/TenantDetails/pods/PodDetails";
|
||||
import Metrics from "./Dashboard/Metrics";
|
||||
import Hop from "./Tenants/TenantDetails/hop/Hop";
|
||||
|
||||
const drawerWidth = 245;
|
||||
|
||||
@@ -359,6 +360,10 @@ const Console = ({
|
||||
component: TenantDetails,
|
||||
path: "/namespaces/:tenantNamespace/tenants/:tenantName",
|
||||
},
|
||||
{
|
||||
component: Hop,
|
||||
path: "/namespaces/:tenantNamespace/tenants/:tenantName/hop",
|
||||
},
|
||||
{
|
||||
component: PodDetails,
|
||||
path: "/namespaces/:tenantNamespace/tenants/:tenantName/pods/:podName",
|
||||
@@ -410,12 +415,19 @@ const Console = ({
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
let hideMenu = false;
|
||||
if (location.pathname === "/metrics") {
|
||||
hideMenu = true;
|
||||
} else if (location.pathname.endsWith("/hop")) {
|
||||
hideMenu = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{session.status === "ok" ? (
|
||||
<div className={classes.root}>
|
||||
<CssBaseline />
|
||||
{location.pathname !== "/metrics" && (
|
||||
{!hideMenu && (
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
classes={{
|
||||
|
||||
@@ -26,8 +26,8 @@ import Tab from "@material-ui/core/Tab";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import {
|
||||
setTenantDetailsLoad,
|
||||
setTenantName,
|
||||
setTenantInfo,
|
||||
setTenantName,
|
||||
setTenantTab,
|
||||
} from "../actions";
|
||||
import { ITenant } from "../ListTenants/types";
|
||||
@@ -193,7 +193,7 @@ const TenantDetails = ({
|
||||
label={
|
||||
<Fragment>
|
||||
<Link to={"/tenants"} className={classes.breadcrumLink}>
|
||||
Tenant
|
||||
Tenants
|
||||
</Link>
|
||||
{` > ${match.params["tenantName"]}`}
|
||||
<IconButton
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import get from "lodash/get";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
|
||||
@@ -31,6 +31,7 @@ import { ITenant } from "../ListTenants/types";
|
||||
import UsageBarWrapper from "../../Common/UsageBarWrapper/UsageBarWrapper";
|
||||
import UpdateTenantModal from "./UpdateTenantModal";
|
||||
import { AppState } from "../../../../store";
|
||||
import history from "./../../../../history";
|
||||
|
||||
interface ITenantsSummary {
|
||||
classes: any;
|
||||
@@ -319,6 +320,19 @@ const TenantSummary = ({
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Button
|
||||
size={"small"}
|
||||
color={"primary"}
|
||||
variant="contained"
|
||||
style={{ textDecoration: "none !important" }}
|
||||
onClick={() => {
|
||||
history.push(
|
||||
`/namespaces/${tenantNamespace}/tenants/${tenantName}/hop`
|
||||
);
|
||||
}}
|
||||
>
|
||||
Management UI
|
||||
</Button>
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
137
portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx
Normal file
137
portal-ui/src/screens/Console/Tenants/TenantDetails/hop/Hop.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
// 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/>.
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Link } from "react-router-dom";
|
||||
import { CircularProgress, IconButton } from "@material-ui/core";
|
||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||
import PageHeader from "../../../Common/PageHeader/PageHeader";
|
||||
import { containerForHeader } from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import ExitToAppIcon from "@material-ui/icons/ExitToApp";
|
||||
import history from "./../../../../../history";
|
||||
|
||||
interface IHopSimple {
|
||||
classes: any;
|
||||
match: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
breadcrumLink: {
|
||||
textDecoration: "none",
|
||||
color: "black",
|
||||
},
|
||||
iframeStyle: {
|
||||
border: 0,
|
||||
position: "absolute",
|
||||
height: "calc(100vh - 77px)",
|
||||
width: "100%",
|
||||
},
|
||||
divContainer: {
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 77,
|
||||
height: "calc(100vh - 77px)",
|
||||
width: "100%",
|
||||
},
|
||||
loader: {
|
||||
width: 100,
|
||||
margin: "auto",
|
||||
marginTop: 80,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const Hop = ({ classes, match }: IHopSimple) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
const tenantName = match.params["tenantName"];
|
||||
const tenantNamespace = match.params["tenantNamespace"];
|
||||
const consoleFrame = React.useRef<HTMLIFrameElement>(null);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PageHeader
|
||||
label={
|
||||
<Fragment>
|
||||
<Link to={"/tenants"} className={classes.breadcrumLink}>
|
||||
Tenants
|
||||
</Link>
|
||||
{` > `}
|
||||
<Link
|
||||
to={`/namespaces/${tenantNamespace}/tenants/${tenantName}`}
|
||||
className={classes.breadcrumLink}
|
||||
>
|
||||
{match.params["tenantName"]}
|
||||
</Link>
|
||||
{` > Management`}
|
||||
</Fragment>
|
||||
}
|
||||
actions={
|
||||
<React.Fragment>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label="Refresh List"
|
||||
component="span"
|
||||
onClick={() => {
|
||||
if (
|
||||
consoleFrame !== null &&
|
||||
consoleFrame.current !== null &&
|
||||
consoleFrame.current.contentDocument !== null
|
||||
) {
|
||||
consoleFrame.current.contentDocument.location.reload(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RefreshIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label="Refresh List"
|
||||
component="span"
|
||||
onClick={() => {
|
||||
history.push(
|
||||
`/namespaces/${tenantNamespace}/tenants/${tenantName}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ExitToAppIcon />
|
||||
</IconButton>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
<div className={classes.divContainer}>
|
||||
{loading && (
|
||||
<div className={classes.loader}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
)}
|
||||
<iframe
|
||||
ref={consoleFrame}
|
||||
className={classes.iframeStyle}
|
||||
title={"metrics"}
|
||||
src={`/api/proxy/${tenantNamespace}/${tenantName}/`}
|
||||
onLoad={(val) => {
|
||||
setLoading(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(Hop);
|
||||
Reference in New Issue
Block a user