License Page UI Updates (#1444)
* License Page UI Updates Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Lint Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -20,15 +20,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/minio/pkg/env"
|
|
||||||
"github.com/minio/pkg/licverifier"
|
"github.com/minio/pkg/licverifier"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSubnetURL
|
|
||||||
func GetSubnetURL() string {
|
|
||||||
return env.Get(ConsoleSubnetURL, "https://subnet.min.io")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLicenseInfoFromJWT will return license metadata from a jwt string license
|
// GetLicenseInfoFromJWT will return license metadata from a jwt string license
|
||||||
func GetLicenseInfoFromJWT(license string, publicKeys []string) (*licverifier.LicenseInfo, error) {
|
func GetLicenseInfoFromJWT(license string, publicKeys []string) (*licverifier.LicenseInfo, error) {
|
||||||
if license == "" {
|
if license == "" {
|
||||||
|
|||||||
@@ -18,10 +18,14 @@
|
|||||||
package subnet
|
package subnet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/minio/pkg/licverifier"
|
||||||
|
|
||||||
"github.com/minio/console/models"
|
"github.com/minio/console/models"
|
||||||
"github.com/minio/madmin-go"
|
"github.com/minio/madmin-go"
|
||||||
mc "github.com/minio/mc/cmd"
|
mc "github.com/minio/mc/cmd"
|
||||||
@@ -81,7 +85,12 @@ func GetOrganizations(client cluster.HTTPClientI, token string) ([]*models.Subne
|
|||||||
return organizations, nil
|
return organizations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(client cluster.HTTPClientI, admInfo madmin.InfoMessage, apiKey, token, accountID string) (string, error) {
|
type LicenseTokenConfig struct {
|
||||||
|
APIKey string
|
||||||
|
License string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(client cluster.HTTPClientI, admInfo madmin.InfoMessage, apiKey, token, accountID string) (*LicenseTokenConfig, error) {
|
||||||
var headers map[string]string
|
var headers map[string]string
|
||||||
regInfo := GetClusterRegInfo(admInfo)
|
regInfo := GetClusterRegInfo(admInfo)
|
||||||
regURL := subnetRegisterURL()
|
regURL := subnetRegisterURL()
|
||||||
@@ -89,23 +98,71 @@ func Register(client cluster.HTTPClientI, admInfo madmin.InfoMessage, apiKey, to
|
|||||||
regURL += "?api_key=" + apiKey
|
regURL += "?api_key=" + apiKey
|
||||||
} else {
|
} else {
|
||||||
if accountID == "" || token == "" {
|
if accountID == "" || token == "" {
|
||||||
return "", errors.New("missing accountID or authentication token")
|
return nil, errors.New("missing accountID or authentication token")
|
||||||
}
|
}
|
||||||
headers = subnetAuthHeaders(token)
|
headers = subnetAuthHeaders(token)
|
||||||
regURL += "?aid=" + accountID
|
regURL += "?aid=" + accountID
|
||||||
}
|
}
|
||||||
regToken, err := GenerateRegToken(regInfo)
|
regToken, err := GenerateRegToken(regInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
reqPayload := mc.ClusterRegistrationReq{Token: regToken}
|
reqPayload := mc.ClusterRegistrationReq{Token: regToken}
|
||||||
resp, err := subnetPostReq(client, regURL, reqPayload, headers)
|
resp, err := subnetPostReq(client, regURL, reqPayload, headers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
respJSON := gjson.Parse(resp)
|
||||||
|
subnetAPIKey := respJSON.Get("api_key").String()
|
||||||
|
licenseJwt := respJSON.Get("license").String()
|
||||||
|
|
||||||
|
if subnetAPIKey != "" {
|
||||||
|
return &LicenseTokenConfig{
|
||||||
|
APIKey: subnetAPIKey,
|
||||||
|
License: licenseJwt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("subnet api key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicKey = "/downloads/license-pubkey.pem"
|
||||||
|
|
||||||
|
// downloadSubnetPublicKey will download the current subnet public key.
|
||||||
|
func downloadSubnetPublicKey(client cluster.HTTPClientI) (string, error) {
|
||||||
|
// Get the public key directly from Subnet
|
||||||
|
url := fmt.Sprintf("%s%s", subnetBaseURL(), publicKey)
|
||||||
|
resp, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
subnetAPIKey := gjson.Parse(resp).Get("api_key").String()
|
defer resp.Body.Close()
|
||||||
if subnetAPIKey != "" {
|
buf := new(bytes.Buffer)
|
||||||
return subnetAPIKey, nil
|
_, err = buf.ReadFrom(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
return "", errors.New("subnet api key not found")
|
return buf.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLicense parses the license with the bundle public key and return it's information
|
||||||
|
func ParseLicense(client cluster.HTTPClientI, license string) (*licverifier.LicenseInfo, error) {
|
||||||
|
var publicKeys []string
|
||||||
|
|
||||||
|
subnetPubKey, err := downloadSubnetPublicKey(client)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
// there was an issue getting the subnet public key
|
||||||
|
// use hardcoded public keys instead
|
||||||
|
publicKeys = OfflinePublicKeys
|
||||||
|
} else {
|
||||||
|
publicKeys = append(publicKeys, subnetPubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
licenseInfo, err := GetLicenseInfoFromJWT(license, publicKeys)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return licenseInfo, nil
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
377
portal-ui/src/screens/Console/License/LicensePlans.tsx
Normal file
377
portal-ui/src/screens/Console/License/LicensePlans.tsx
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2022 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React, { Fragment } from "react";
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import ActivationModal from "./ActivationModal";
|
||||||
|
import { planButtons, planDetails, planItems } from "./utils";
|
||||||
|
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import { Theme } from "@mui/material/styles";
|
||||||
|
import createStyles from "@mui/styles/createStyles";
|
||||||
|
import { SubnetInfo } from "./types";
|
||||||
|
import withStyles from "@mui/styles/withStyles";
|
||||||
|
|
||||||
|
const styles = (theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
planItemsPadding: {
|
||||||
|
border: "1px solid #EAEDEE",
|
||||||
|
borderTop: 0,
|
||||||
|
maxWidth: 1180,
|
||||||
|
},
|
||||||
|
planItemsBorder: {
|
||||||
|
height: 7,
|
||||||
|
backgroundColor: "#07193E",
|
||||||
|
},
|
||||||
|
|
||||||
|
link: {
|
||||||
|
textDecoration: "underline !important",
|
||||||
|
color: theme.palette.info.main,
|
||||||
|
},
|
||||||
|
linkButton: {
|
||||||
|
fontFamily: '"Lato", sans-serif',
|
||||||
|
fontWeight: "normal",
|
||||||
|
textTransform: "none",
|
||||||
|
fontSize: "inherit",
|
||||||
|
height: 0,
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
tableContainer: {
|
||||||
|
marginLeft: 28,
|
||||||
|
},
|
||||||
|
detailsContainerBorder: {
|
||||||
|
borderLeft: "1px solid #e2e2e2",
|
||||||
|
},
|
||||||
|
detailsTitle: {
|
||||||
|
fontSize: 19,
|
||||||
|
fontWeight: 700,
|
||||||
|
marginBottom: 26,
|
||||||
|
paddingTop: 18,
|
||||||
|
lineHeight: 1,
|
||||||
|
},
|
||||||
|
currPlan: {
|
||||||
|
color: "white",
|
||||||
|
backgroundColor: "#4CCB92",
|
||||||
|
},
|
||||||
|
planHeader: {
|
||||||
|
padding: 8,
|
||||||
|
},
|
||||||
|
detailsPrice: {
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: 700,
|
||||||
|
},
|
||||||
|
detailsCapacityMax: {
|
||||||
|
minHeight: 28,
|
||||||
|
fontSize: 10,
|
||||||
|
},
|
||||||
|
itemContainer: {
|
||||||
|
height: 36,
|
||||||
|
"& .item:last-child": {
|
||||||
|
borderRight: "1px solid #e5e5e5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
itemContainerDetail: {
|
||||||
|
height: 48,
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
height: "100%",
|
||||||
|
borderLeft: "1px solid #e5e5e5",
|
||||||
|
textAlign: "center",
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: 700,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
alignContent: "center",
|
||||||
|
borderTop: "1px solid #e5e5e5",
|
||||||
|
},
|
||||||
|
|
||||||
|
itemFirst: {
|
||||||
|
borderLeft: 0,
|
||||||
|
borderRight: 0,
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
textAlign: "left",
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
checkIcon: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: "#385973",
|
||||||
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingBottom: 24,
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
borderLeft: "1px solid #e2e2e2",
|
||||||
|
},
|
||||||
|
buttonContainerBlank: {
|
||||||
|
border: 0,
|
||||||
|
},
|
||||||
|
buttonContainerHighlighted: {
|
||||||
|
borderTop: 0,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
textTransform: "none",
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 700,
|
||||||
|
},
|
||||||
|
activateLink: {
|
||||||
|
color: "#1C5A8D",
|
||||||
|
fontWeight: "bold",
|
||||||
|
clear: "both",
|
||||||
|
background: "none",
|
||||||
|
border: "none",
|
||||||
|
textDecoration: "underline",
|
||||||
|
cursor: "pointer",
|
||||||
|
},
|
||||||
|
currentPlanBG: {
|
||||||
|
background: "#022A4A 0% 0% no-repeat padding-box",
|
||||||
|
color: "#FFFFFF",
|
||||||
|
borderTop: "1px solid #52687d",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IRegisterStatus {
|
||||||
|
classes: any;
|
||||||
|
activateProductModal: any;
|
||||||
|
closeModalAndFetchLicenseInfo: any;
|
||||||
|
licenseInfo: SubnetInfo | undefined;
|
||||||
|
setLicenseModal: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
operatorMode: boolean;
|
||||||
|
currentPlanID: number;
|
||||||
|
setActivateProductModal: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LicensePlans = ({
|
||||||
|
classes,
|
||||||
|
activateProductModal,
|
||||||
|
closeModalAndFetchLicenseInfo,
|
||||||
|
licenseInfo,
|
||||||
|
setLicenseModal,
|
||||||
|
operatorMode,
|
||||||
|
currentPlanID,
|
||||||
|
setActivateProductModal,
|
||||||
|
}: IRegisterStatus) => {
|
||||||
|
const planDetailsFiltered = planDetails.filter((item) => {
|
||||||
|
if (licenseInfo) {
|
||||||
|
if (item.title === "Community") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const planButtonsFiltered = planButtons.filter((item) => {
|
||||||
|
if (licenseInfo) {
|
||||||
|
if (item.plan === "Community") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const gridColWidth = licenseInfo ? 4 : 3;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<div className={classes.planItemsBorder} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} className={clsx(classes.planItemsPadding)}>
|
||||||
|
<Grid container>
|
||||||
|
<ActivationModal
|
||||||
|
open={activateProductModal}
|
||||||
|
closeModal={() => closeModalAndFetchLicenseInfo()}
|
||||||
|
/>
|
||||||
|
<Grid container item xs={12} className={classes.tableContainer}>
|
||||||
|
<Grid container item xs={12}>
|
||||||
|
<Grid item xs={gridColWidth} />
|
||||||
|
{planDetailsFiltered.map((details: any) => {
|
||||||
|
let currentPlan =
|
||||||
|
(!licenseInfo && details.title === "Community") ||
|
||||||
|
(licenseInfo &&
|
||||||
|
licenseInfo.plan.toLowerCase() ===
|
||||||
|
details.title.toLowerCase());
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
key={details.id}
|
||||||
|
container
|
||||||
|
item
|
||||||
|
xs={gridColWidth}
|
||||||
|
justifyContent={"center"}
|
||||||
|
className={clsx(classes.detailsContainerBorder, {
|
||||||
|
[classes.currPlan]: currentPlan,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Grid item xs={10} className={classes.planHeader}></Grid>
|
||||||
|
<Grid item xs={10} className={classes.detailsTitle}>
|
||||||
|
{details.title}
|
||||||
|
{currentPlan && (
|
||||||
|
<Fragment>
|
||||||
|
<div style={{ fontSize: 10 }}>CURRENT PLAN</div>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={10} className={classes.detailsPrice}>
|
||||||
|
{details.price}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={10} className={classes.detailsCapacityMax}>
|
||||||
|
{details.capacityMax || ""}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
{planItems.map((item: any) => {
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
key={item.id}
|
||||||
|
container
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
className={clsx(
|
||||||
|
classes.itemContainer,
|
||||||
|
item.communityDetail && classes.itemContainerDetail
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={gridColWidth}
|
||||||
|
className={clsx(
|
||||||
|
classes.item,
|
||||||
|
classes.field,
|
||||||
|
classes.itemFirst
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.field}
|
||||||
|
</Grid>
|
||||||
|
{planDetailsFiltered.map((pd) => {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
item
|
||||||
|
xs={gridColWidth}
|
||||||
|
className={clsx(classes.item)}
|
||||||
|
>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{item.plans[pd.title].label === "N/A" ? (
|
||||||
|
""
|
||||||
|
) : item.plans[pd.title].label === "Yes" ? (
|
||||||
|
<CheckCircleIcon className={classes.checkIcon} />
|
||||||
|
) : (
|
||||||
|
<Fragment>
|
||||||
|
{item.plans[pd.title].link ? (
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
className={clsx(
|
||||||
|
classes.link,
|
||||||
|
classes.linkButton
|
||||||
|
)}
|
||||||
|
onClick={() => setLicenseModal(true)}
|
||||||
|
>
|
||||||
|
{item.plans[pd.title].label}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
item.plans[pd.title].label
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
{item.plans[pd.title].detail !== undefined && (
|
||||||
|
<Grid item xs={12}>
|
||||||
|
{item.plans[pd.title].detail}
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Grid container item xs={12}>
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={gridColWidth}
|
||||||
|
className={clsx(
|
||||||
|
classes.buttonContainer,
|
||||||
|
classes.buttonContainerBlank
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{planButtonsFiltered.map((button: any, index: any) => {
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
key={button.id}
|
||||||
|
container
|
||||||
|
item
|
||||||
|
xs={gridColWidth}
|
||||||
|
style={{ textAlign: "center" }}
|
||||||
|
className={clsx(classes.buttonContainer, {
|
||||||
|
[classes.buttonContainerHighlighted]:
|
||||||
|
button.text === "Subscribe",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Button
|
||||||
|
variant={
|
||||||
|
button.text === "Join Slack"
|
||||||
|
? "outlined"
|
||||||
|
: "contained"
|
||||||
|
}
|
||||||
|
color="primary"
|
||||||
|
className={clsx(classes.button)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
href="#"
|
||||||
|
disabled={
|
||||||
|
licenseInfo &&
|
||||||
|
licenseInfo.plan.toLowerCase() ===
|
||||||
|
button.plan.toLowerCase()
|
||||||
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
window.open(
|
||||||
|
`${button.link}/?ref=${
|
||||||
|
operatorMode ? "op" : "con"
|
||||||
|
}`,
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{currentPlanID !== index && index > 0
|
||||||
|
? button.text2
|
||||||
|
: button.text}
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStyles(styles)(LicensePlans);
|
||||||
@@ -14,12 +14,20 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export const planDetails = [
|
export interface IPlanDetails {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
price: string;
|
||||||
|
capacityMax: string;
|
||||||
|
capacityMin?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const planDetails: IPlanDetails[] = [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
title: "Community",
|
title: "Community",
|
||||||
price: "N/A",
|
price: "Open Source",
|
||||||
capacityMax: "Open Source",
|
capacityMax: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -37,113 +45,221 @@ export const planDetails = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const planItems = [
|
export interface IPlanItemValue {
|
||||||
|
label: string;
|
||||||
|
detail?: string;
|
||||||
|
link?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPlanItemValues {
|
||||||
|
[index: string]: IPlanItemValue;
|
||||||
|
}
|
||||||
|
export interface IPlanItem {
|
||||||
|
id: number;
|
||||||
|
field: string;
|
||||||
|
plans: IPlanItemValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const planItems: IPlanItem[] = [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
field: "License",
|
field: "License",
|
||||||
community: "GNU AGPL v3",
|
plans: {
|
||||||
communityLink: true,
|
Community: {
|
||||||
communityDetail: "",
|
label: "GNU AGPL v3",
|
||||||
standard: "Commercial License",
|
detail: "",
|
||||||
standardDetail: "",
|
link: true,
|
||||||
enterprise: "Commercial License",
|
},
|
||||||
enterpriseDetail: "",
|
Standard: {
|
||||||
|
label: "Commercial License",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Commercial License",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
field: "Software Release",
|
field: "Software Release",
|
||||||
community: "Upstream",
|
plans: {
|
||||||
standard: "1 Year Long Term Support",
|
Community: {
|
||||||
enterprise: "5 Years Long Term Support",
|
label: "Upstream",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "1 Year Long Term Support",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "5 Years Long Term Support",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
field: "SLA",
|
field: "SLA",
|
||||||
community: "No SLA",
|
plans: {
|
||||||
standard: "<48 Hours (Local Business Hours)",
|
Community: {
|
||||||
enterprise: "<1 hour",
|
label: "No SLA",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "<48 Hours (Local Business Hours)",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "<1 hour",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
field: "Support",
|
field: "Support",
|
||||||
community: "Community:",
|
plans: {
|
||||||
communityDetail: "Public Slack Channel + Github Issues",
|
Community: {
|
||||||
standard: "L4 Direct Engineering",
|
label: "Community:",
|
||||||
standardDetail: " support via SUBNET",
|
detail: "Public Slack Channel + Github Issues",
|
||||||
enterprise: "L4 Direct Engineering",
|
},
|
||||||
enterpriseDetail: "support via SUBNET",
|
Standard: {
|
||||||
|
label: "L4 Direct Engineering",
|
||||||
|
detail: " support via SUBNET",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "L4 Direct Engineering",
|
||||||
|
detail: "support via SUBNET",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
field: "Security Updates & Critical Bugs",
|
field: "Security Updates & Critical Bugs",
|
||||||
community: "Self Update",
|
plans: {
|
||||||
standard: "Continuous Scan and Alert",
|
Community: {
|
||||||
enterprise: "Continuous Scan and Alert",
|
label: "Self Update",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "Continuous Scan and Alert",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Continuous Scan and Alert",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
field: "Panic Button",
|
field: "Panic Button",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "1 per year",
|
Community: {
|
||||||
enterprise: "Unlimited",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "1 per year",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Unlimited",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
field: "Health Diagnostics",
|
field: "Health Diagnostics",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "24/7/365",
|
Community: {
|
||||||
enterprise: "24/7/365",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "24/7/365",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "24/7/365",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
field: "Annual Architecture Review",
|
field: "Annual Architecture Review",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "N/A",
|
Community: {
|
||||||
enterprise: "Yes",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Yes",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 7,
|
id: 7,
|
||||||
field: "Annual Performance Review",
|
field: "Annual Performance Review",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "N/A",
|
Community: {
|
||||||
enterprise: "Yes",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Yes",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 8,
|
||||||
field: "Indemnification",
|
field: "Indemnification",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "N/A",
|
Community: {
|
||||||
enterprise: "Yes",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Yes",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 9,
|
id: 9,
|
||||||
field: "Security + Policy Review",
|
field: "Security + Policy Review",
|
||||||
community: "N/A",
|
plans: {
|
||||||
standard: "N/A",
|
Community: {
|
||||||
enterprise: "Yes",
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Standard: {
|
||||||
|
label: "N/A",
|
||||||
|
},
|
||||||
|
Enterprise: {
|
||||||
|
label: "Yes",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const planButtons = [
|
export interface IPlanButton {
|
||||||
|
id: number;
|
||||||
|
text: string;
|
||||||
|
text2: string;
|
||||||
|
link: string;
|
||||||
|
plan: string;
|
||||||
|
}
|
||||||
|
export const planButtons: IPlanButton[] = [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
text: "Join Slack",
|
text: "Join Slack",
|
||||||
text2: "",
|
text2: "",
|
||||||
link: "https://slack.min.io",
|
link: "https://slack.min.io",
|
||||||
plan: "community",
|
plan: "Community",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
text: "Subscribe",
|
text: "Subscribe",
|
||||||
text2: "Sign up",
|
text2: "Sign up",
|
||||||
link: "https://subnet.min.io/subscription",
|
link: "https://subnet.min.io/subscription",
|
||||||
plan: "standard",
|
plan: "Standard",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
text: "Subscribe",
|
text: "Subscribe",
|
||||||
text2: "Sign up",
|
text2: "Sign up",
|
||||||
link: "https://subnet.min.io/subscription",
|
link: "https://subnet.min.io/subscription",
|
||||||
plan: "enterprise",
|
plan: "Enterprise",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import { Theme } from "@mui/material/styles";
|
|||||||
import createStyles from "@mui/styles/createStyles";
|
import createStyles from "@mui/styles/createStyles";
|
||||||
import {
|
import {
|
||||||
actionsTray,
|
actionsTray,
|
||||||
searchField,
|
|
||||||
containerForHeader,
|
containerForHeader,
|
||||||
|
searchField,
|
||||||
} from "../Common/FormComponents/common/styleLibrary";
|
} from "../Common/FormComponents/common/styleLibrary";
|
||||||
import withStyles from "@mui/styles/withStyles";
|
import withStyles from "@mui/styles/withStyles";
|
||||||
import { Button, Grid, Link, Typography } from "@mui/material";
|
import { Button, Grid, Link, Typography } from "@mui/material";
|
||||||
@@ -30,7 +30,6 @@ import { CopyIcon, UsersIcon } from "../../../icons";
|
|||||||
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||||
import OnlineRegistrationIcon from "../../../icons/OnlineRegistrationIcon";
|
import OnlineRegistrationIcon from "../../../icons/OnlineRegistrationIcon";
|
||||||
import OfflineRegistrationBackIcon from "../../../icons/OfflineRegistrationBackIcon";
|
|
||||||
import OfflineRegistrationIcon from "../../../icons/OfflineRegistrationIcon";
|
import OfflineRegistrationIcon from "../../../icons/OfflineRegistrationIcon";
|
||||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@@ -55,9 +54,11 @@ import {
|
|||||||
IAM_PAGES,
|
IAM_PAGES,
|
||||||
IAM_PAGES_PERMISSIONS,
|
IAM_PAGES_PERMISSIONS,
|
||||||
} from "../../../common/SecureComponent/permissions";
|
} from "../../../common/SecureComponent/permissions";
|
||||||
import VerifiedIcon from "../../../icons/VerifiedIcon";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { setErrorSnackMessage } from "../../../actions";
|
import { setErrorSnackMessage } from "../../../actions";
|
||||||
|
import HelpBox from "../../../common/HelpBox";
|
||||||
|
import SettingsIcon from "../../../icons/SettingsIcon";
|
||||||
|
import RegisterStatus from "./RegisterStatus";
|
||||||
|
|
||||||
interface IRegister {
|
interface IRegister {
|
||||||
classes: any;
|
classes: any;
|
||||||
@@ -201,7 +202,9 @@ const Register = ({ classes, displayErrorMessage }: IRegister) => {
|
|||||||
setLoadingLicenseInfo(false);
|
setLoadingLicenseInfo(false);
|
||||||
})
|
})
|
||||||
.catch((err: ErrorResponseHandler) => {
|
.catch((err: ErrorResponseHandler) => {
|
||||||
displayErrorMessage(err);
|
if (err.errorMessage !== "License not found") {
|
||||||
|
displayErrorMessage(err);
|
||||||
|
}
|
||||||
setClusterRegistered(false);
|
setClusterRegistered(false);
|
||||||
setLoadingLicenseInfo(false);
|
setLoadingLicenseInfo(false);
|
||||||
});
|
});
|
||||||
@@ -224,6 +227,7 @@ const Register = ({ classes, displayErrorMessage }: IRegister) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err: ErrorResponseHandler) => {
|
.catch((err: ErrorResponseHandler) => {
|
||||||
|
console.log(err);
|
||||||
displayErrorMessage(err);
|
displayErrorMessage(err);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
@@ -440,7 +444,7 @@ const Register = ({ classes, displayErrorMessage }: IRegister) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
href="https://min.io/product/subnet"
|
href="https://min.io/product/subnet"
|
||||||
>
|
>
|
||||||
Learn more about SUBNET
|
Learn more about SUBNET.
|
||||||
</Link>
|
</Link>
|
||||||
</Grid>
|
</Grid>
|
||||||
<br />
|
<br />
|
||||||
@@ -563,33 +567,14 @@ const Register = ({ classes, displayErrorMessage }: IRegister) => {
|
|||||||
<PageHeader label="Register" />
|
<PageHeader label="Register" />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Grid item xs={12} className={classes.boxy}>
|
<Grid item xs={12} className={classes.boxy}>
|
||||||
{clusterRegistered && (
|
{clusterRegistered && <RegisterStatus />}
|
||||||
<Grid container>
|
|
||||||
<Grid item xs={12} className={classes.registeredStatus}>
|
|
||||||
Register Status:
|
|
||||||
<VerifiedIcon />
|
|
||||||
<span>Registered</span>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={6} className={classes.registerActivationIcon}>
|
<Grid item xs={6} className={classes.registerActivationIcon}>
|
||||||
{title}
|
{title}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6} className={classes.registerActivationMode}>
|
<Grid item xs={6} className={classes.registerActivationMode}>
|
||||||
{onlineActivation ? (
|
{onlineActivation ? (
|
||||||
<Fragment>
|
<Fragment />
|
||||||
<OfflineRegistrationBackIcon />
|
|
||||||
<Link
|
|
||||||
className={classes.link}
|
|
||||||
onClick={() => {
|
|
||||||
fetchSubnetRegToken();
|
|
||||||
setOnlineActivation(!onlineActivation);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Offline Activation
|
|
||||||
</Link>
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
) : (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<OnlineRegistrationBackIcon />
|
<OnlineRegistrationBackIcon />
|
||||||
@@ -606,6 +591,32 @@ const Register = ({ classes, displayErrorMessage }: IRegister) => {
|
|||||||
|
|
||||||
{clusterRegistrationForm}
|
{clusterRegistrationForm}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{onlineActivation && (
|
||||||
|
<Grid item xs={12} marginTop={"15px"}>
|
||||||
|
<HelpBox
|
||||||
|
title={"Proxy Configuration"}
|
||||||
|
iconComponent={<SettingsIcon />}
|
||||||
|
help={
|
||||||
|
<Fragment>
|
||||||
|
For airgap/firewalled environments it is possible to configure
|
||||||
|
a proxy to connect to Subnet.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Alternatively you can try{" "}
|
||||||
|
<Link
|
||||||
|
className={classes.link}
|
||||||
|
onClick={() => {
|
||||||
|
fetchSubnetRegToken();
|
||||||
|
setOnlineActivation(!onlineActivation);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Offline Activation.
|
||||||
|
</Link>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
62
portal-ui/src/screens/Console/Support/RegisterStatus.tsx
Normal file
62
portal-ui/src/screens/Console/Support/RegisterStatus.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2022 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { Grid } from "@mui/material";
|
||||||
|
import VerifiedIcon from "../../../icons/VerifiedIcon";
|
||||||
|
import React from "react";
|
||||||
|
import { Theme } from "@mui/material/styles";
|
||||||
|
import createStyles from "@mui/styles/createStyles";
|
||||||
|
import withStyles from "@mui/styles/withStyles";
|
||||||
|
|
||||||
|
const styles = (theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
registeredStatus: {
|
||||||
|
border: "1px solid #E2E2E2",
|
||||||
|
padding: "24px 24px 24px 24px",
|
||||||
|
borderRadius: 2,
|
||||||
|
marginBottom: 25,
|
||||||
|
backgroundColor: "#FBFAFA",
|
||||||
|
"& .min-icon": {
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
marginLeft: 48,
|
||||||
|
marginRight: 13,
|
||||||
|
verticalAlign: "middle",
|
||||||
|
marginTop: -3,
|
||||||
|
},
|
||||||
|
"& span": {
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IRegisterStatus {
|
||||||
|
classes: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function RegisterStatus({ classes }: IRegisterStatus) {
|
||||||
|
return (
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={12} className={classes.registeredStatus}>
|
||||||
|
Register Status:
|
||||||
|
<VerifiedIcon />
|
||||||
|
<span>Registered</span>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles)(RegisterStatus);
|
||||||
@@ -20,6 +20,7 @@ package restapi
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/minio/console/cluster"
|
"github.com/minio/console/cluster"
|
||||||
@@ -57,11 +58,14 @@ func registerSubnetHandlers(api *operations.ConsoleAPI) {
|
|||||||
})
|
})
|
||||||
// Get subnet info
|
// Get subnet info
|
||||||
api.AdminAPISubnetInfoHandler = admin_api.SubnetInfoHandlerFunc(func(params admin_api.SubnetInfoParams, session *models.Principal) middleware.Responder {
|
api.AdminAPISubnetInfoHandler = admin_api.SubnetInfoHandlerFunc(func(params admin_api.SubnetInfoParams, session *models.Principal) middleware.Responder {
|
||||||
err := GetSubnetInfoResponse(session)
|
client := &cluster.HTTPClient{
|
||||||
|
Client: GetConsoleHTTPClient(),
|
||||||
|
}
|
||||||
|
resp, err := GetSubnetInfoResponse(session, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return admin_api.NewSubnetInfoDefault(int(err.Code)).WithPayload(err)
|
return admin_api.NewSubnetInfoDefault(int(err.Code)).WithPayload(err)
|
||||||
}
|
}
|
||||||
return admin_api.NewSubnetInfoOK()
|
return admin_api.NewSubnetInfoOK().WithPayload(resp)
|
||||||
})
|
})
|
||||||
// Get subnet registration token
|
// Get subnet registration token
|
||||||
api.AdminAPISubnetRegTokenHandler = admin_api.SubnetRegTokenHandlerFunc(func(params admin_api.SubnetRegTokenParams, session *models.Principal) middleware.Responder {
|
api.AdminAPISubnetRegTokenHandler = admin_api.SubnetRegTokenHandlerFunc(func(params admin_api.SubnetRegTokenParams, session *models.Principal) middleware.Responder {
|
||||||
@@ -78,11 +82,11 @@ func SubnetRegisterWithAPIKey(ctx context.Context, minioClient MinioAdmin, apiKe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
subnetAPIKey, err := subnet.Register(httpClient, serverInfo, apiKey, "", "")
|
registerResult, err := subnet.Register(httpClient, serverInfo, apiKey, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
configStr := "subnet license= api_key=" + subnetAPIKey
|
configStr := fmt.Sprintf("subnet license=%s api_key=%s", registerResult.License, registerResult.APIKey)
|
||||||
_, err = minioClient.setConfigKV(ctx, configStr)
|
_, err = minioClient.setConfigKV(ctx, configStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -179,26 +183,28 @@ func GetSubnetLoginWithMFAResponse(params admin_api.SubnetLoginMFAParams) (*mode
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubnetKeyFromMinIOConfig(ctx context.Context, minioClient MinioAdmin, key string) (string, error) {
|
func GetSubnetKeyFromMinIOConfig(ctx context.Context, minioClient MinioAdmin) (*subnet.LicenseTokenConfig, error) {
|
||||||
sh, err := minioClient.helpConfigKV(ctx, "subnet", "", false)
|
sh, err := minioClient.helpConfigKV(ctx, "subnet", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf, err := minioClient.getConfigKV(ctx, "subnet")
|
buf, err := minioClient.getConfigKV(ctx, "subnet")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
tgt, err := madmin.ParseSubSysTarget(buf, sh)
|
tgt, err := madmin.ParseSubSysTarget(buf, sh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res := subnet.LicenseTokenConfig{}
|
||||||
for _, kv := range tgt.KVS {
|
for _, kv := range tgt.KVS {
|
||||||
if kv.Key == key {
|
if kv.Key == "api_key" {
|
||||||
return kv.Value, nil
|
res.APIKey = kv.Value
|
||||||
|
} else if kv.Key == "license" {
|
||||||
|
res.License = kv.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", errors.New("")
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubnetRegister(ctx context.Context, minioClient MinioAdmin, httpClient cluster.HTTPClientI, params admin_api.SubnetRegisterParams) error {
|
func GetSubnetRegister(ctx context.Context, minioClient MinioAdmin, httpClient cluster.HTTPClientI, params admin_api.SubnetRegisterParams) error {
|
||||||
@@ -206,11 +212,11 @@ func GetSubnetRegister(ctx context.Context, minioClient MinioAdmin, httpClient c
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
subnetAPIKey, err := subnet.Register(httpClient, serverInfo, "", *params.Body.Token, *params.Body.AccountID)
|
registerResult, err := subnet.Register(httpClient, serverInfo, "", *params.Body.Token, *params.Body.AccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
configStr := "subnet license= api_key=" + subnetAPIKey
|
configStr := fmt.Sprintf("subnet license=%s api_key=%s", registerResult.License, registerResult.APIKey)
|
||||||
_, err = minioClient.setConfigKV(ctx, configStr)
|
_, err = minioClient.setConfigKV(ctx, configStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -235,21 +241,35 @@ func GetSubnetRegisterResponse(session *models.Principal, params admin_api.Subne
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubnetInfoResponse(session *models.Principal) *models.Error {
|
func GetSubnetInfoResponse(session *models.Principal, client cluster.HTTPClientI) (*models.License, *models.Error) {
|
||||||
|
fmt.Println("quack")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
mAdmin, err := NewMinioAdminClient(session)
|
mAdmin, err := NewMinioAdminClient(session)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return prepareError(err)
|
return nil, prepareError(err)
|
||||||
}
|
}
|
||||||
adminClient := AdminClient{Client: mAdmin}
|
adminClient := AdminClient{Client: mAdmin}
|
||||||
apiKey, err := GetSubnetKeyFromMinIOConfig(ctx, adminClient, "api_key")
|
subnetTokens, err := GetSubnetKeyFromMinIOConfig(ctx, adminClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return prepareError(err)
|
return nil, prepareError(err)
|
||||||
}
|
}
|
||||||
if apiKey == "" {
|
if subnetTokens.APIKey == "" {
|
||||||
return prepareError(errLicenseNotFound)
|
return nil, prepareError(errLicenseNotFound)
|
||||||
}
|
}
|
||||||
return nil
|
licenseInfo, err := subnet.ParseLicense(client, subnetTokens.License)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
license := &models.License{
|
||||||
|
Email: licenseInfo.Email,
|
||||||
|
AccountID: licenseInfo.AccountID,
|
||||||
|
StorageCapacity: licenseInfo.StorageCapacity,
|
||||||
|
Plan: licenseInfo.Plan,
|
||||||
|
ExpiresAt: licenseInfo.ExpiresAt.String(),
|
||||||
|
Organization: licenseInfo.Organization,
|
||||||
|
}
|
||||||
|
return license, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSubnetRegToken(ctx context.Context, minioClient MinioAdmin) (string, error) {
|
func GetSubnetRegToken(ctx context.Context, minioClient MinioAdmin) (string, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user