diff --git a/portal-ui/src/screens/Console/Common/GenericWizard/WizardPage.tsx b/portal-ui/src/screens/Console/Common/GenericWizard/WizardPage.tsx
index 955be2e3c..38c80f6b1 100644
--- a/portal-ui/src/screens/Console/Common/GenericWizard/WizardPage.tsx
+++ b/portal-ui/src/screens/Console/Common/GenericWizard/WizardPage.tsx
@@ -103,6 +103,9 @@ const WizardPage = ({
>
{page.buttons.map((btn) => {
+ if (btn.componentRender) {
+ return btn.componentRender;
+ }
return (
.
export interface IWizardButton {
- label: string;
- type: string;
+ label?: string;
+ type?: string;
action?: (nextFunction: (to: string | number) => void) => void;
enabled?: boolean;
toPage?: number;
+ componentRender?: React.ReactNode;
}
export interface IWizardElement {
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx
index 708486c4b..144bcd0bf 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/AddTenant.tsx
@@ -27,15 +27,11 @@ import {
settingsCommon,
wizardCommon,
} from "../../Common/FormComponents/common/styleLibrary";
-import api from "../../../../common/api";
-import { generatePoolName, getBytes } from "../../../../common/utils";
import GenericWizard from "../../Common/GenericWizard/GenericWizard";
-import { IWizardElement } from "../../Common/GenericWizard/types";
-import { NewServiceAccount } from "../../Common/CredentialsPrompt/types";
-import { ErrorResponseHandler, ITenantCreator } from "../../../../common/types";
-import { KeyPair } from "../ListTenants/utils";
-
-import { getDefaultAffinity, getNodeSelector } from "../TenantDetails/utils";
+import {
+ IWizardButton,
+ IWizardElement,
+} from "../../Common/GenericWizard/types";
import CredentialsPrompt from "../../Common/CredentialsPrompt/CredentialsPrompt";
import { AppState } from "../../../../store";
import Configure from "./Steps/Configure";
@@ -57,10 +53,10 @@ import {
} from "./Steps/TenantResources/utils";
import HelpBox from "../../../../common/HelpBox";
import { StorageIcon } from "../../../../icons";
-import { setErrorSnackMessage } from "../../../../systemSlice";
import { selFeatures } from "../../consoleSlice";
import makeStyles from "@mui/styles/makeStyles";
import { resetAddTenantForm } from "./createTenantSlice";
+import CreateTenantButton from "./CreateTenantButton";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -77,32 +73,20 @@ const AddTenant = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const namespace = useSelector(
- (state: AppState) => state.createTenant.fields.nameTenant.namespace
- );
- const validPages = useSelector(
- (state: AppState) => state.createTenant.validPages
- );
- const fields = useSelector((state: AppState) => state.createTenant.fields);
- const certificates = useSelector(
- (state: AppState) => state.createTenant.certificates
- );
- const selectedStorageClass = useSelector(
- (state: AppState) =>
- state.createTenant.fields.nameTenant.selectedStorageClass
- );
const features = useSelector(selFeatures);
- const tolerations = useSelector(
- (state: AppState) => state.createTenant.tolerations
- );
// Modals
- const [showNewCredentials, setShowNewCredentials] = useState(false);
- const [createdAccount, setCreatedAccount] =
- useState(null);
+ const showNewCredentials = useSelector(
+ (state: AppState) => state.createTenant.showNewCredentials
+ );
+ const createdAccount = useSelector(
+ (state: AppState) => state.createTenant.createdAccount
+ );
// Fields
- const [addSending, setAddSending] = useState(false);
+ const addSending = useSelector(
+ (state: AppState) => state.createTenant.addingTenant
+ );
const [formRender, setFormRender] = useState(null);
useEffect(() => {
@@ -125,596 +109,6 @@ const AddTenant = () => {
setFormRender(setConfiguration);
}, [features]);
- /* Send Information to backend */
- useEffect(() => {
- const tenantName = fields.nameTenant.tenantName;
- const selectedStorageClass = fields.nameTenant.selectedStorageClass;
- const imageName = fields.configure.imageName;
- const customDockerhub = fields.configure.customDockerhub;
- const imageRegistry = fields.configure.imageRegistry;
- const imageRegistryUsername = fields.configure.imageRegistryUsername;
- const imageRegistryPassword = fields.configure.imageRegistryPassword;
- const exposeMinIO = fields.configure.exposeMinIO;
- const exposeConsole = fields.configure.exposeConsole;
- const idpSelection = fields.identityProvider.idpSelection;
- const openIDConfigurationURL =
- fields.identityProvider.openIDConfigurationURL;
- const openIDClientID = fields.identityProvider.openIDClientID;
- const openIDClaimName = fields.identityProvider.openIDClaimName;
- const openIDCallbackURL = fields.identityProvider.openIDCallbackURL;
- const openIDScopes = fields.identityProvider.openIDScopes;
- const openIDSecretID = fields.identityProvider.openIDSecretID;
- const ADURL = fields.identityProvider.ADURL;
- const ADSkipTLS = fields.identityProvider.ADSkipTLS;
- const ADServerInsecure = fields.identityProvider.ADServerInsecure;
- const ADGroupSearchBaseDN = fields.identityProvider.ADGroupSearchBaseDN;
- const ADGroupSearchFilter = fields.identityProvider.ADGroupSearchFilter;
- const ADUserDNs = fields.identityProvider.ADUserDNs;
- const ADLookupBindDN = fields.identityProvider.ADLookupBindDN;
- const ADLookupBindPassword = fields.identityProvider.ADLookupBindPassword;
- const ADUserDNSearchBaseDN = fields.identityProvider.ADUserDNSearchBaseDN;
- const ADUserDNSearchFilter = fields.identityProvider.ADUserDNSearchFilter;
- const ADServerStartTLS = fields.identityProvider.ADServerStartTLS;
- const accessKeys = fields.identityProvider.accessKeys;
- const secretKeys = fields.identityProvider.secretKeys;
- const minioCertificates = certificates.minioCertificates;
- const caCertificates = certificates.caCertificates;
- const consoleCaCertificates = certificates.consoleCaCertificates;
- const consoleCertificate = certificates.consoleCertificate;
- const serverCertificate = certificates.serverCertificate;
- const clientCertificate = certificates.clientCertificate;
- const vaultCertificate = certificates.vaultCertificate;
- const vaultCA = certificates.vaultCA;
- const gemaltoCA = certificates.gemaltoCA;
- const enableEncryption = fields.encryption.enableEncryption;
- const encryptionType = fields.encryption.encryptionType;
- const gemaltoEndpoint = fields.encryption.gemaltoEndpoint;
- const gemaltoToken = fields.encryption.gemaltoToken;
- const gemaltoDomain = fields.encryption.gemaltoDomain;
- const gemaltoRetry = fields.encryption.gemaltoRetry;
- const awsEndpoint = fields.encryption.awsEndpoint;
- const awsRegion = fields.encryption.awsRegion;
- const awsKMSKey = fields.encryption.awsKMSKey;
- const awsAccessKey = fields.encryption.awsAccessKey;
- const awsSecretKey = fields.encryption.awsSecretKey;
- const awsToken = fields.encryption.awsToken;
- const vaultEndpoint = fields.encryption.vaultEndpoint;
- const vaultEngine = fields.encryption.vaultEngine;
- const vaultNamespace = fields.encryption.vaultNamespace;
- const vaultPrefix = fields.encryption.vaultPrefix;
- const vaultAppRoleEngine = fields.encryption.vaultAppRoleEngine;
- const vaultId = fields.encryption.vaultId;
- const vaultSecret = fields.encryption.vaultSecret;
- const vaultRetry = fields.encryption.vaultRetry;
- const vaultPing = fields.encryption.vaultPing;
- const azureEndpoint = fields.encryption.azureEndpoint;
- const azureTenantID = fields.encryption.azureTenantID;
- const azureClientID = fields.encryption.azureClientID;
- const azureClientSecret = fields.encryption.azureClientSecret;
- const gcpProjectID = fields.encryption.gcpProjectID;
- const gcpEndpoint = fields.encryption.gcpEndpoint;
- const gcpClientEmail = fields.encryption.gcpClientEmail;
- const gcpClientID = fields.encryption.gcpClientID;
- const gcpPrivateKeyID = fields.encryption.gcpPrivateKeyID;
- const gcpPrivateKey = fields.encryption.gcpPrivateKey;
- const enableAutoCert = fields.security.enableAutoCert;
- const enableTLS = fields.security.enableTLS;
- const ecParity = fields.tenantSize.ecParity;
- const distribution = fields.tenantSize.distribution;
- const tenantCustom = fields.configure.tenantCustom;
- const logSearchEnabled = fields.configure.logSearchEnabled;
- const prometheusEnabled = fields.configure.prometheusEnabled;
- const logSearchVolumeSize = fields.configure.logSearchVolumeSize;
- const logSearchSelectedStorageClass =
- fields.configure.logSearchSelectedStorageClass;
- const logSearchImage = fields.configure.logSearchImage;
- const kesImage = fields.configure.kesImage;
- const logSearchPostgresImage = fields.configure.logSearchPostgresImage;
- const logSearchPostgresInitImage =
- fields.configure.logSearchPostgresInitImage;
- const prometheusImage = fields.configure.prometheusImage;
- const prometheusSidecarImage = fields.configure.prometheusSidecarImage;
- const prometheusInitImage = fields.configure.prometheusInitImage;
- const prometheusSelectedStorageClass =
- fields.configure.prometheusSelectedStorageClass;
- const prometheusVolumeSize = fields.configure.prometheusVolumeSize;
- const affinityType = fields.affinity.podAffinity;
- const nodeSelectorLabels = fields.affinity.nodeSelectorLabels;
- const withPodAntiAffinity = fields.affinity.withPodAntiAffinity;
-
- const tenantSecurityContext = fields.configure.tenantSecurityContext;
- const logSearchSecurityContext = fields.configure.logSearchSecurityContext;
- const logSearchPostgresSecurityContext =
- fields.configure.logSearchPostgresSecurityContext;
- const prometheusSecurityContext =
- fields.configure.prometheusSecurityContext;
- const kesSecurityContext = fields.encryption.kesSecurityContext;
- const kesReplicas = fields.encryption.replicas;
- const setDomains = fields.configure.setDomains;
- const minioDomains = fields.configure.minioDomains;
- const consoleDomain = fields.configure.consoleDomain;
-
- if (addSending) {
- const tolerationValues = tolerations.filter(
- (toleration) => toleration.key.trim() !== ""
- );
-
- const poolName = generatePoolName([]);
-
- let affinityObject = {};
-
- switch (affinityType) {
- case "default":
- affinityObject = {
- affinity: getDefaultAffinity(tenantName, poolName),
- };
- break;
- case "nodeSelector":
- affinityObject = {
- affinity: getNodeSelector(
- nodeSelectorLabels,
- withPodAntiAffinity,
- tenantName,
- poolName
- ),
- };
- break;
- }
-
- const erasureCode = ecParity.split(":")[1];
-
- let dataSend: ITenantCreator = {
- name: tenantName,
- namespace: namespace,
- access_key: "",
- secret_key: "",
- access_keys: [],
- secret_keys: [],
- enable_tls: enableTLS && enableAutoCert,
- enable_console: true,
- enable_prometheus: true,
- service_name: "",
- image: imageName,
- expose_minio: exposeMinIO,
- expose_console: exposeConsole,
- pools: [
- {
- name: poolName,
- servers: distribution.nodes,
- volumes_per_server: distribution.disks,
- volume_configuration: {
- size: distribution.pvSize,
- storage_class_name: selectedStorageClass,
- },
- securityContext: tenantCustom ? tenantSecurityContext : null,
- ...affinityObject,
- tolerations: tolerationValues,
- },
- ],
- erasureCodingParity: parseInt(erasureCode, 10),
- };
-
- // Set Resources
- if (
- fields.tenantSize.resourcesCPURequest !== "" ||
- fields.tenantSize.resourcesCPULimit !== "" ||
- fields.tenantSize.resourcesMemoryRequest !== "" ||
- fields.tenantSize.resourcesMemoryLimit !== ""
- ) {
- dataSend.pools[0].resources = {};
- // requests
- if (
- fields.tenantSize.resourcesCPURequest !== "" ||
- fields.tenantSize.resourcesMemoryRequest !== ""
- ) {
- dataSend.pools[0].resources.requests = {};
- if (fields.tenantSize.resourcesCPURequest !== "") {
- dataSend.pools[0].resources.requests.cpu = parseInt(
- fields.tenantSize.resourcesCPURequest
- );
- }
- if (fields.tenantSize.resourcesMemoryRequest !== "") {
- dataSend.pools[0].resources.requests.memory = parseInt(
- getBytes(fields.tenantSize.resourcesMemoryRequest, "Gi", true)
- );
- }
- }
- // limits
- if (
- fields.tenantSize.resourcesCPULimit !== "" ||
- fields.tenantSize.resourcesMemoryLimit !== ""
- ) {
- dataSend.pools[0].resources.limits = {};
- if (fields.tenantSize.resourcesCPULimit !== "") {
- dataSend.pools[0].resources.limits.cpu = parseInt(
- fields.tenantSize.resourcesCPULimit
- );
- }
- if (fields.tenantSize.resourcesMemoryLimit !== "") {
- dataSend.pools[0].resources.limits.memory = parseInt(
- getBytes(fields.tenantSize.resourcesMemoryLimit, "Gi", true)
- );
- }
- }
- }
- if (customDockerhub) {
- dataSend = {
- ...dataSend,
- image_registry: {
- registry: imageRegistry,
- username: imageRegistryUsername,
- password: imageRegistryPassword,
- },
- };
- }
-
- if (logSearchEnabled) {
- dataSend = {
- ...dataSend,
- logSearchConfiguration: {
- storageClass:
- logSearchSelectedStorageClass === "default"
- ? ""
- : logSearchSelectedStorageClass,
- storageSize: parseInt(logSearchVolumeSize),
- image: logSearchImage,
- postgres_image: logSearchPostgresImage,
- postgres_init_image: logSearchPostgresInitImage,
- securityContext: logSearchSecurityContext,
- postgres_securityContext: logSearchPostgresSecurityContext,
- },
- };
- }
-
- if (prometheusEnabled) {
- dataSend = {
- ...dataSend,
- prometheusConfiguration: {
- storageClass:
- prometheusSelectedStorageClass === "default"
- ? ""
- : prometheusSelectedStorageClass,
- storageSize: parseInt(prometheusVolumeSize),
- image: prometheusImage,
- sidecar_image: prometheusSidecarImage,
- init_image: prometheusInitImage,
- securityContext: prometheusSecurityContext,
- },
- };
- }
-
- let tenantCerts: any = null;
- let consoleCerts: any = null;
- let caCerts: any = null;
- let consoleCaCerts: any = null;
-
- if (caCertificates.length > 0) {
- caCerts = {
- ca_certificates: caCertificates
- .map((keyPair: KeyPair) => keyPair.encoded_cert)
- .filter((keyPair) => keyPair),
- };
- }
-
- if (consoleCaCertificates.length > 0) {
- consoleCaCerts = {
- console_ca_certificates: consoleCaCertificates
- .map((keyPair: KeyPair) => keyPair.encoded_cert)
- .filter((keyPair) => keyPair),
- };
- }
-
- if (enableTLS && minioCertificates.length > 0) {
- tenantCerts = {
- minio: minioCertificates
- .map((keyPair: KeyPair) => ({
- crt: keyPair.encoded_cert,
- key: keyPair.encoded_key,
- }))
- .filter((keyPair) => keyPair.crt && keyPair.key),
- };
- }
-
- if (
- enableTLS &&
- consoleCertificate.encoded_cert !== "" &&
- consoleCertificate.encoded_key !== ""
- ) {
- consoleCerts = {
- console: {
- crt: consoleCertificate.encoded_cert,
- key: consoleCertificate.encoded_key,
- },
- };
- }
-
- if (tenantCerts || consoleCerts || caCerts || consoleCaCerts) {
- dataSend = {
- ...dataSend,
- tls: {
- ...tenantCerts,
- ...consoleCerts,
- ...caCerts,
- ...consoleCaCerts,
- },
- };
- }
-
- if (enableEncryption) {
- let insertEncrypt = {};
-
- switch (encryptionType) {
- case "gemalto":
- let gemaltoCAIntroduce = {};
-
- if (gemaltoCA.encoded_cert !== "") {
- gemaltoCAIntroduce = {
- ca: gemaltoCA.encoded_cert,
- };
- }
- insertEncrypt = {
- gemalto: {
- keysecure: {
- endpoint: gemaltoEndpoint,
- credentials: {
- token: gemaltoToken,
- domain: gemaltoDomain,
- retry: parseInt(gemaltoRetry),
- },
- tls: {
- ...gemaltoCAIntroduce,
- },
- },
- },
- };
- break;
- case "aws":
- insertEncrypt = {
- aws: {
- secretsmanager: {
- endpoint: awsEndpoint,
- region: awsRegion,
- kmskey: awsKMSKey,
- credentials: {
- accesskey: awsAccessKey,
- secretkey: awsSecretKey,
- token: awsToken,
- },
- },
- },
- };
- break;
- case "azure":
- insertEncrypt = {
- azure: {
- keyvault: {
- endpoint: azureEndpoint,
- credentials: {
- tenant_id: azureTenantID,
- client_id: azureClientID,
- client_secret: azureClientSecret,
- },
- },
- },
- };
- break;
- case "gcp":
- insertEncrypt = {
- gcp: {
- secretmanager: {
- project_id: gcpProjectID,
- endpoint: gcpEndpoint,
- credentials: {
- client_email: gcpClientEmail,
- client_id: gcpClientID,
- private_key_id: gcpPrivateKeyID,
- private_key: gcpPrivateKey,
- },
- },
- },
- };
- break;
- case "vault":
- let vaultKeyPair = null;
- let vaultCAInsert = null;
- if (
- vaultCertificate.encoded_key !== "" &&
- vaultCertificate.encoded_cert !== ""
- ) {
- vaultKeyPair = {
- key: vaultCertificate.encoded_key,
- crt: vaultCertificate.encoded_cert,
- };
- }
- if (vaultCA.encoded_cert !== "") {
- vaultCAInsert = {
- ca: vaultCA.encoded_cert,
- };
- }
- let vaultTLS = null;
- if (vaultKeyPair || vaultCAInsert) {
- vaultTLS = {
- tls: {
- ...vaultKeyPair,
- ...vaultCAInsert,
- },
- };
- }
- insertEncrypt = {
- vault: {
- endpoint: vaultEndpoint,
- engine: vaultEngine,
- namespace: vaultNamespace,
- prefix: vaultPrefix,
- approle: {
- engine: vaultAppRoleEngine,
- id: vaultId,
- secret: vaultSecret,
- retry: parseInt(vaultRetry),
- },
- ...vaultTLS,
- status: {
- ping: parseInt(vaultPing),
- },
- },
- };
- break;
- }
-
- let encryptionServerKeyPair: any = {};
- let encryptionClientKeyPair: any = {};
-
- if (
- clientCertificate.encoded_key !== "" &&
- clientCertificate.encoded_cert !== ""
- ) {
- encryptionClientKeyPair = {
- client: {
- key: clientCertificate.encoded_key,
- crt: clientCertificate.encoded_cert,
- },
- };
- }
-
- if (
- serverCertificate.encoded_key !== "" &&
- serverCertificate.encoded_cert !== ""
- ) {
- encryptionServerKeyPair = {
- server: {
- key: serverCertificate.encoded_key,
- crt: serverCertificate.encoded_cert,
- },
- };
- }
-
- dataSend = {
- ...dataSend,
- encryption: {
- replicas: kesReplicas,
- securityContext: kesSecurityContext,
- image: kesImage,
- ...encryptionClientKeyPair,
- ...encryptionServerKeyPair,
- ...insertEncrypt,
- },
- };
- }
-
- let dataIDP: any = {};
- switch (idpSelection) {
- case "Built-in":
- let keyarray = [];
- for (let i = 0; i < accessKeys.length; i++) {
- keyarray.push({
- access_key: accessKeys[i],
- secret_key: secretKeys[i],
- });
- }
- dataIDP = {
- keys: keyarray,
- };
- break;
- case "OpenID":
- dataIDP = {
- oidc: {
- configuration_url: openIDConfigurationURL,
- client_id: openIDClientID,
- secret_id: openIDSecretID,
- claim_name: openIDClaimName,
- callback_url: openIDCallbackURL,
- scopes: openIDScopes,
- },
- };
- break;
- case "AD":
- dataIDP = {
- active_directory: {
- url: ADURL,
- skip_tls_verification: ADSkipTLS,
- server_insecure: ADServerInsecure,
- group_search_base_dn: ADGroupSearchBaseDN,
- group_search_filter: ADGroupSearchFilter,
- user_dns: ADUserDNs,
- lookup_bind_dn: ADLookupBindDN,
- lookup_bind_password: ADLookupBindPassword,
- user_dn_search_base_dn: ADUserDNSearchBaseDN,
- user_dn_search_filter: ADUserDNSearchFilter,
- server_start_tls: ADServerStartTLS,
- },
- };
- break;
- }
-
- let domains: any = {};
- let sendDomain: any = {};
-
- if (setDomains) {
- if (consoleDomain !== "") {
- domains.console = consoleDomain;
- }
-
- const filteredDomains = minioDomains.filter((dom) => dom.trim() !== "");
-
- if (filteredDomains.length > 0) {
- domains.minio = filteredDomains;
- }
-
- if (Object.keys(domains).length > 0) {
- sendDomain.domains = domains;
- }
- }
-
- dataSend = {
- ...dataSend,
- ...sendDomain,
- idp: { ...dataIDP },
- };
- api
- .invoke("POST", `/api/v1/tenants`, dataSend)
- .then((res) => {
- const consoleSAList = get(res, "console", []);
-
- let newSrvAcc: NewServiceAccount = {
- idp: get(res, "externalIDP", false),
- console: [],
- };
-
- if (consoleSAList) {
- if (Array.isArray(consoleSAList)) {
- const consoleItem = consoleSAList.map((consoleKey) => {
- return {
- accessKey: consoleKey.access_key,
- secretKey: consoleKey.secret_key,
- api: "s3v4",
- path: "auto",
- url: consoleKey.url,
- };
- });
-
- newSrvAcc.console = consoleItem;
- } else {
- newSrvAcc = {
- console: {
- accessKey: res.console.access_key,
- secretKey: res.console.secret_key,
- url: res.console.url,
- },
- };
- }
- }
- setAddSending(false);
- setShowNewCredentials(true);
- setCreatedAccount(newSrvAcc);
- })
- .catch((err: ErrorResponseHandler) => {
- setAddSending(false);
- dispatch(setErrorSnackMessage(err));
- });
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [addSending]);
-
const cancelButton = {
label: "Cancel",
type: "other",
@@ -724,25 +118,9 @@ const AddTenant = () => {
history.push("/tenants");
},
};
- const requiredPages = [
- "nameTenant",
- "tenantSize",
- "configure",
- "affinity",
- "identityProvider",
- "security",
- "encryption",
- ];
- const createButton = {
- label: "Create",
- type: "submit",
- enabled:
- !addSending &&
- selectedStorageClass !== "" &&
- requiredPages.every((v) => validPages.includes(v)),
- action: () => {
- setAddSending(true);
- },
+
+ const createButton: IWizardButton = {
+ componentRender: ,
};
const wizardSteps: IWizardElement[] = [
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/CreateTenantButton.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/CreateTenantButton.tsx
new file mode 100644
index 000000000..d53cf8253
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/CreateTenantButton.tsx
@@ -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 .
+
+import { Button } from "@mui/material";
+import React from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { AppState } from "../../../../store";
+import { requiredPages } from "./common";
+import { createTenantAsync } from "./thunks/createTenantThunk";
+
+const CreateTenantButton = () => {
+ const dispatch = useDispatch();
+
+ const addSending = useSelector(
+ (state: AppState) => state.createTenant.addingTenant
+ );
+
+ const validPages = useSelector(
+ (state: AppState) => state.createTenant.validPages
+ );
+
+ const selectedStorageClass = useSelector(
+ (state: AppState) =>
+ state.createTenant.fields.nameTenant.selectedStorageClass
+ );
+
+ const enabled =
+ !addSending &&
+ selectedStorageClass !== "" &&
+ requiredPages.every((v) => validPages.includes(v));
+
+ return (
+
+ );
+};
+
+export default CreateTenantButton;
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AWSKMSAdd.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AWSKMSAdd.tsx
index 2e4c09fb4..3e5313447 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AWSKMSAdd.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AWSKMSAdd.tsx
@@ -48,12 +48,6 @@ const AWSKMSAdd = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const enableEncryption = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.enableEncryption
- );
- const encryptionType = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.encryptionType
- );
const awsEndpoint = useSelector(
(state: AppState) => state.createTenant.fields.encryption.awsEndpoint
);
@@ -78,33 +72,29 @@ const AWSKMSAdd = () => {
useEffect(() => {
let encryptionValidation: IValidation[] = [];
- if (enableEncryption) {
- if (encryptionType === "aws") {
- encryptionValidation = [
- ...encryptionValidation,
- {
- fieldKey: "aws_endpoint",
- required: true,
- value: awsEndpoint,
- },
- {
- fieldKey: "aws_region",
- required: true,
- value: awsRegion,
- },
- {
- fieldKey: "aws_accessKey",
- required: true,
- value: awsAccessKey,
- },
- {
- fieldKey: "aws_secretKey",
- required: true,
- value: awsSecretKey,
- },
- ];
- }
- }
+ encryptionValidation = [
+ ...encryptionValidation,
+ {
+ fieldKey: "aws_endpoint",
+ required: true,
+ value: awsEndpoint,
+ },
+ {
+ fieldKey: "aws_region",
+ required: true,
+ value: awsRegion,
+ },
+ {
+ fieldKey: "aws_accessKey",
+ required: true,
+ value: awsAccessKey,
+ },
+ {
+ fieldKey: "aws_secretKey",
+ required: true,
+ value: awsSecretKey,
+ },
+ ];
const commonVal = commonFormValidation(encryptionValidation);
@@ -116,15 +106,7 @@ const AWSKMSAdd = () => {
);
setValidationErrors(commonVal);
- }, [
- enableEncryption,
- encryptionType,
- awsEndpoint,
- awsRegion,
- awsSecretKey,
- awsAccessKey,
- dispatch,
- ]);
+ }, [awsEndpoint, awsRegion, awsSecretKey, awsAccessKey, dispatch]);
// Common
const updateField = useCallback(
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AzureKMSAdd.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AzureKMSAdd.tsx
index 49f2a0487..06105bbfd 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AzureKMSAdd.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/AzureKMSAdd.tsx
@@ -48,13 +48,6 @@ const AzureKMSAdd = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const enableEncryption = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.enableEncryption
- );
- const encryptionType = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.encryptionType
- );
-
const azureEndpoint = useSelector(
(state: AppState) => state.createTenant.fields.encryption.azureEndpoint
);
@@ -74,33 +67,29 @@ const AzureKMSAdd = () => {
useEffect(() => {
let encryptionValidation: IValidation[] = [];
- if (enableEncryption) {
- if (encryptionType === "azure") {
- encryptionValidation = [
- ...encryptionValidation,
- {
- fieldKey: "azure_endpoint",
- required: true,
- value: azureEndpoint,
- },
- {
- fieldKey: "azure_tenant_id",
- required: true,
- value: azureTenantID,
- },
- {
- fieldKey: "azure_client_id",
- required: true,
- value: azureClientID,
- },
- {
- fieldKey: "azure_client_secret",
- required: true,
- value: azureClientSecret,
- },
- ];
- }
- }
+ encryptionValidation = [
+ ...encryptionValidation,
+ {
+ fieldKey: "azure_endpoint",
+ required: true,
+ value: azureEndpoint,
+ },
+ {
+ fieldKey: "azure_tenant_id",
+ required: true,
+ value: azureTenantID,
+ },
+ {
+ fieldKey: "azure_client_id",
+ required: true,
+ value: azureClientID,
+ },
+ {
+ fieldKey: "azure_client_secret",
+ required: true,
+ value: azureClientSecret,
+ },
+ ];
const commonVal = commonFormValidation(encryptionValidation);
@@ -113,8 +102,6 @@ const AzureKMSAdd = () => {
setValidationErrors(commonVal);
}, [
- enableEncryption,
- encryptionType,
azureEndpoint,
azureTenantID,
azureClientID,
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/GemaltoKMSAdd.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/GemaltoKMSAdd.tsx
index ac55192ef..b262b42be 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/GemaltoKMSAdd.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/GemaltoKMSAdd.tsx
@@ -53,12 +53,6 @@ const GemaltoKMSAdd = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const enableEncryption = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.enableEncryption
- );
- const encryptionType = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.encryptionType
- );
const gemaltoCA = useSelector(
(state: AppState) => state.createTenant.certificates.gemaltoCA
);
@@ -81,35 +75,31 @@ const GemaltoKMSAdd = () => {
useEffect(() => {
let encryptionValidation: IValidation[] = [];
- if (enableEncryption) {
- if (encryptionType === "gemalto") {
- encryptionValidation = [
- ...encryptionValidation,
- {
- fieldKey: "gemalto_endpoint",
- required: true,
- value: gemaltoEndpoint,
- },
- {
- fieldKey: "gemalto_token",
- required: true,
- value: gemaltoToken,
- },
- {
- fieldKey: "gemalto_domain",
- required: true,
- value: gemaltoDomain,
- },
- {
- fieldKey: "gemalto_retry",
- required: false,
- value: gemaltoRetry,
- customValidation: parseInt(gemaltoRetry) < 0,
- customValidationMessage: "Value needs to be 0 or greater",
- },
- ];
- }
- }
+ encryptionValidation = [
+ ...encryptionValidation,
+ {
+ fieldKey: "gemalto_endpoint",
+ required: true,
+ value: gemaltoEndpoint,
+ },
+ {
+ fieldKey: "gemalto_token",
+ required: true,
+ value: gemaltoToken,
+ },
+ {
+ fieldKey: "gemalto_domain",
+ required: true,
+ value: gemaltoDomain,
+ },
+ {
+ fieldKey: "gemalto_retry",
+ required: false,
+ value: gemaltoRetry,
+ customValidation: parseInt(gemaltoRetry) < 0,
+ customValidationMessage: "Value needs to be 0 or greater",
+ },
+ ];
const commonVal = commonFormValidation(encryptionValidation);
@@ -121,15 +111,7 @@ const GemaltoKMSAdd = () => {
);
setValidationErrors(commonVal);
- }, [
- enableEncryption,
- encryptionType,
- gemaltoEndpoint,
- gemaltoToken,
- gemaltoDomain,
- gemaltoRetry,
- dispatch,
- ]);
+ }, [gemaltoEndpoint, gemaltoToken, gemaltoDomain, gemaltoRetry, dispatch]);
// Common
const updateField = useCallback(
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/VaultKMSAdd.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/VaultKMSAdd.tsx
index ee4183218..7b622f545 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/VaultKMSAdd.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/Encryption/VaultKMSAdd.tsx
@@ -55,13 +55,6 @@ const VaultKMSAdd = () => {
const dispatch = useDispatch();
const classes = useStyles();
- const enableEncryption = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.enableEncryption
- );
- const encryptionType = useSelector(
- (state: AppState) => state.createTenant.fields.encryption.encryptionType
- );
-
const vaultEndpoint = useSelector(
(state: AppState) => state.createTenant.fields.encryption.vaultEndpoint
);
@@ -102,42 +95,38 @@ const VaultKMSAdd = () => {
useEffect(() => {
let encryptionValidation: IValidation[] = [];
- if (enableEncryption) {
- if (encryptionType === "vault") {
- encryptionValidation = [
- ...encryptionValidation,
- {
- fieldKey: "vault_endpoint",
- required: true,
- value: vaultEndpoint,
- },
- {
- fieldKey: "vault_id",
- required: true,
- value: vaultId,
- },
- {
- fieldKey: "vault_secret",
- required: true,
- value: vaultSecret,
- },
- {
- fieldKey: "vault_ping",
- required: false,
- value: vaultPing,
- customValidation: parseInt(vaultPing) < 0,
- customValidationMessage: "Value needs to be 0 or greater",
- },
- {
- fieldKey: "vault_retry",
- required: false,
- value: vaultRetry,
- customValidation: parseInt(vaultRetry) < 0,
- customValidationMessage: "Value needs to be 0 or greater",
- },
- ];
- }
- }
+ encryptionValidation = [
+ ...encryptionValidation,
+ {
+ fieldKey: "vault_endpoint",
+ required: true,
+ value: vaultEndpoint,
+ },
+ {
+ fieldKey: "vault_id",
+ required: true,
+ value: vaultId,
+ },
+ {
+ fieldKey: "vault_secret",
+ required: true,
+ value: vaultSecret,
+ },
+ {
+ fieldKey: "vault_ping",
+ required: false,
+ value: vaultPing,
+ customValidation: parseInt(vaultPing) < 0,
+ customValidationMessage: "Value needs to be 0 or greater",
+ },
+ {
+ fieldKey: "vault_retry",
+ required: false,
+ value: vaultRetry,
+ customValidation: parseInt(vaultRetry) < 0,
+ customValidationMessage: "Value needs to be 0 or greater",
+ },
+ ];
const commonVal = commonFormValidation(encryptionValidation);
@@ -150,8 +139,6 @@ const VaultKMSAdd = () => {
setValidationErrors(commonVal);
}, [
- enableEncryption,
- encryptionType,
vaultEndpoint,
vaultEngine,
vaultId,
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantResources/NameTenantMain.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantResources/NameTenantMain.tsx
index a03395be3..859b9653c 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantResources/NameTenantMain.tsx
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantResources/NameTenantMain.tsx
@@ -58,6 +58,7 @@ import {
setLimitSize,
setStorageClassesList,
setStorageType,
+ setTenantName,
updateAddField,
} from "../../createTenantSlice";
import { selFeatures } from "../../../../consoleSlice";
@@ -76,6 +77,31 @@ const styles = (theme: Theme) =>
...wizardCommon,
});
+const NameTenantField = () => {
+ const dispatch = useDispatch();
+ const tenantName = useSelector(
+ (state: AppState) => state.createTenant.fields.nameTenant.tenantName
+ );
+
+ const tenantNameError = useSelector(
+ (state: AppState) => state.createTenant.validationErrors["tenant-name"]
+ );
+
+ return (
+ ) => {
+ dispatch(setTenantName(e.target.value));
+ }}
+ label="Name"
+ value={tenantName}
+ required
+ error={tenantNameError || ""}
+ />
+ );
+};
+
interface INameTenantMainScreen {
classes: any;
formToRender?: IMkEnvs;
@@ -84,9 +110,6 @@ interface INameTenantMainScreen {
const NameTenantMain = ({ classes, formToRender }: INameTenantMainScreen) => {
const dispatch = useDispatch();
- const tenantName = useSelector(
- (state: AppState) => state.createTenant.fields.nameTenant.tenantName
- );
const namespace = useSelector(
(state: AppState) => state.createTenant.fields.nameTenant.namespace
);
@@ -219,14 +242,6 @@ const NameTenantMain = ({ classes, formToRender }: INameTenantMainScreen) => {
}
const commonValidation = commonFormValidation([
- {
- fieldKey: "tenant-name",
- required: true,
- pattern: /^[a-z0-9-]{3,63}$/,
- customPatternMessage:
- "Name only can contain lowercase letters, numbers and '-'. Min. Length: 3",
- value: tenantName,
- },
{
fieldKey: "namespace",
required: true,
@@ -237,7 +252,6 @@ const NameTenantMain = ({ classes, formToRender }: INameTenantMainScreen) => {
]);
const isValid =
- !("tenant-name" in commonValidation) &&
!("namespace" in commonValidation) &&
((formToRender === IMkEnvs.default && storageClasses.length > 0) ||
(formToRender !== IMkEnvs.default && selectedStorageType !== ""));
@@ -248,7 +262,6 @@ const NameTenantMain = ({ classes, formToRender }: INameTenantMainScreen) => {
}, [
storageClasses,
namespace,
- tenantName,
dispatch,
emptyNamespace,
loadingNamespaceInfo,
@@ -293,18 +306,7 @@ const NameTenantMain = ({ classes, formToRender }: INameTenantMainScreen) => {
- ) => {
- updateField("tenantName", e.target.value);
- frmValidationCleanup("tenant-name");
- }}
- label="Name"
- value={tenantName}
- required
- error={validationErrors["tenant-name"] || ""}
- />
+
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/common.ts b/portal-ui/src/screens/Console/Tenants/AddTenant/common.ts
new file mode 100644
index 000000000..554c0647b
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/common.ts
@@ -0,0 +1,24 @@
+// 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 .
+export const requiredPages = [
+ "nameTenant",
+ "tenantSize",
+ "configure",
+ "affinity",
+ "identityProvider",
+ "security",
+ "encryption",
+];
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantAPI.ts b/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantAPI.ts
new file mode 100644
index 000000000..b2a341b8f
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantAPI.ts
@@ -0,0 +1,61 @@
+// 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 .
+
+import api from "../../../../common/api";
+import get from "lodash/get";
+import { NewServiceAccount } from "../../Common/CredentialsPrompt/types";
+import { ErrorResponseHandler, ITenantCreator } from "../../../../common/types";
+
+export const createTenantCall = (dataSend: ITenantCreator) => {
+ return new Promise((resolve, reject) => {
+ api
+ .invoke("POST", `/api/v1/tenants`, dataSend)
+ .then((res) => {
+ const consoleSAList = get(res, "console", []);
+
+ let newSrvAcc: NewServiceAccount = {
+ idp: get(res, "externalIDP", false),
+ console: [],
+ };
+
+ if (consoleSAList) {
+ if (Array.isArray(consoleSAList)) {
+ newSrvAcc.console = consoleSAList.map((consoleKey) => {
+ return {
+ accessKey: consoleKey.access_key,
+ secretKey: consoleKey.secret_key,
+ api: "s3v4",
+ path: "auto",
+ url: consoleKey.url,
+ };
+ });
+ } else {
+ newSrvAcc = {
+ console: {
+ accessKey: res.console.access_key,
+ secretKey: res.console.secret_key,
+ url: res.console.url,
+ },
+ };
+ }
+ }
+ resolve(newSrvAcc);
+ })
+ .catch((err: ErrorResponseHandler) => {
+ reject(err);
+ });
+ });
+};
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantSlice.ts b/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantSlice.ts
index fedfb8600..db83c0554 100644
--- a/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantSlice.ts
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/createTenantSlice.ts
@@ -33,19 +33,29 @@ import {
} from "./Steps/TenantResources/utils";
import { getBytesNumber } from "../../../../common/utils";
import { CertificateFile, FileValue, KeyFileValue } from "../tenantsSlice";
+import { NewServiceAccount } from "../../Common/CredentialsPrompt/types";
+import { createTenantAsync } from "./thunks/createTenantThunk";
+import { commonFormValidation } from "../../../../utils/validationFunctions";
+import { flipValidPageInState } from "./sliceUtils";
export interface ICreateTenant {
+ addingTenant: boolean;
page: number;
validPages: string[];
+ validationErrors: { [key: string]: string };
storageClasses: Opts[];
limitSize: any;
fields: IFieldStore;
certificates: ICertificatesItems;
nodeSelectorPairs: LabelKeyPair[];
tolerations: ITolerationModel[];
+ // after creation states
+ createdAccount: NewServiceAccount | null;
+ showNewCredentials: boolean;
}
const initialState: ICreateTenant = {
+ addingTenant: false,
page: 0,
// We can assume all the other pages are valid with default configuration except for 'nameTenant'
// because the user still have to choose a namespace and a name for the tenant
@@ -57,6 +67,7 @@ const initialState: ICreateTenant = {
"security",
"encryption",
],
+ validationErrors: {},
storageClasses: [],
limitSize: {},
fields: {
@@ -340,6 +351,8 @@ const initialState: ICreateTenant = {
operator: ITolerationOperator.Equal,
},
],
+ createdAccount: null,
+ showNewCredentials: false,
};
export const createTenantSlice = createSlice({
@@ -382,7 +395,6 @@ export const createTenantSlice = createSlice({
}>
) => {
let originValidPages = state.validPages;
-
if (action.payload.valid) {
if (!originValidPages.includes(action.payload.pageName)) {
originValidPages.push(action.payload.pageName);
@@ -393,7 +405,6 @@ export const createTenantSlice = createSlice({
const newSetOfPages = originValidPages.filter(
(elm) => elm !== action.payload.pageName
);
-
state.validPages = [...newSetOfPages];
}
},
@@ -658,302 +669,304 @@ export const createTenantSlice = createSlice({
};
},
resetAddTenantForm: (state) => {
- state = {
- page: 0,
- // We can assume all the other pages are valid with default configuration except for 'nameTenant'
- // because the user still have to choose a namespace and a name for the tenant
- validPages: [
- "tenantSize",
- "configure",
- "affinity",
- "identityProvider",
- "security",
- "encryption",
- ],
- storageClasses: [],
- limitSize: {},
- fields: {
- nameTenant: {
- tenantName: "",
- namespace: "",
- selectedStorageClass: "",
- selectedStorageType: "",
+ state.addingTenant = false;
+ state.page = 0;
+ // We can assume all the other pages are valid with default configuration except for 'nameTenant'
+ // because the user still have to choose a namespace and a name for the tenant
+ state.validPages = [
+ "tenantSize",
+ "configure",
+ "affinity",
+ "identityProvider",
+ "security",
+ "encryption",
+ ];
+ state.validationErrors = {};
+ state.storageClasses = [];
+ state.limitSize = {};
+ state.fields = {
+ nameTenant: {
+ tenantName: "",
+ namespace: "",
+ selectedStorageClass: "",
+ selectedStorageType: "",
+ },
+ configure: {
+ customImage: false,
+ imageName: "",
+ customDockerhub: false,
+ imageRegistry: "",
+ imageRegistryUsername: "",
+ imageRegistryPassword: "",
+ exposeMinIO: true,
+ exposeConsole: true,
+ tenantCustom: false,
+ logSearchEnabled: true,
+ prometheusEnabled: true,
+ logSearchVolumeSize: "5",
+ logSearchSizeFactor: "Gi",
+ logSearchSelectedStorageClass: "default",
+ logSearchImage: "",
+ kesImage: "",
+ logSearchPostgresImage: "",
+ logSearchPostgresInitImage: "",
+ prometheusVolumeSize: "5",
+ prometheusSizeFactor: "Gi",
+ prometheusSelectedStorageClass: "default",
+ prometheusImage: "",
+ prometheusSidecarImage: "",
+ prometheusInitImage: "",
+ setDomains: false,
+ consoleDomain: "",
+ minioDomains: [""],
+ tenantSecurityContext: {
+ runAsUser: "1000",
+ runAsGroup: "1000",
+ fsGroup: "1000",
+ runAsNonRoot: true,
},
- configure: {
- customImage: false,
- imageName: "",
- customDockerhub: false,
- imageRegistry: "",
- imageRegistryUsername: "",
- imageRegistryPassword: "",
- exposeMinIO: true,
- exposeConsole: true,
- tenantCustom: false,
- logSearchEnabled: true,
- prometheusEnabled: true,
- logSearchVolumeSize: "5",
- logSearchSizeFactor: "Gi",
- logSearchSelectedStorageClass: "default",
- logSearchImage: "",
- kesImage: "",
- logSearchPostgresImage: "",
- logSearchPostgresInitImage: "",
- prometheusVolumeSize: "5",
- prometheusSizeFactor: "Gi",
- prometheusSelectedStorageClass: "default",
- prometheusImage: "",
- prometheusSidecarImage: "",
- prometheusInitImage: "",
- setDomains: false,
- consoleDomain: "",
- minioDomains: [""],
- tenantSecurityContext: {
- runAsUser: "1000",
- runAsGroup: "1000",
- fsGroup: "1000",
- runAsNonRoot: true,
- },
- logSearchSecurityContext: {
- runAsUser: "1000",
- runAsGroup: "1000",
- fsGroup: "1000",
- runAsNonRoot: true,
- },
- logSearchPostgresSecurityContext: {
- runAsUser: "999",
- runAsGroup: "999",
- fsGroup: "999",
- runAsNonRoot: true,
- },
- prometheusSecurityContext: {
- runAsUser: "1000",
- runAsGroup: "1000",
- fsGroup: "1000",
- runAsNonRoot: true,
- },
+ logSearchSecurityContext: {
+ runAsUser: "1000",
+ runAsGroup: "1000",
+ fsGroup: "1000",
+ runAsNonRoot: true,
},
- identityProvider: {
- idpSelection: "Built-in",
- accessKeys: [getRandomString(16)],
- secretKeys: [getRandomString(32)],
- openIDConfigurationURL: "",
- openIDClientID: "",
- openIDSecretID: "",
- openIDCallbackURL: "",
- openIDClaimName: "",
- openIDScopes: "",
- ADURL: "",
- ADSkipTLS: false,
- ADServerInsecure: false,
- ADGroupSearchBaseDN: "",
- ADGroupSearchFilter: "",
- ADUserDNs: [""],
- ADLookupBindDN: "",
- ADLookupBindPassword: "",
- ADUserDNSearchBaseDN: "",
- ADUserDNSearchFilter: "",
- ADServerStartTLS: false,
+ logSearchPostgresSecurityContext: {
+ runAsUser: "999",
+ runAsGroup: "999",
+ fsGroup: "999",
+ runAsNonRoot: true,
},
- security: {
- enableAutoCert: true,
- enableCustomCerts: false,
- enableTLS: true,
- },
- encryption: {
- enableEncryption: false,
- encryptionType: "vault",
- gemaltoEndpoint: "",
- gemaltoToken: "",
- gemaltoDomain: "",
- gemaltoRetry: "0",
- awsEndpoint: "",
- awsRegion: "",
- awsKMSKey: "",
- awsAccessKey: "",
- awsSecretKey: "",
- awsToken: "",
- vaultEndpoint: "",
- vaultEngine: "",
- vaultNamespace: "",
- vaultPrefix: "",
- vaultAppRoleEngine: "",
- vaultId: "",
- vaultSecret: "",
- vaultRetry: "0",
- vaultPing: "0",
- azureEndpoint: "",
- azureTenantID: "",
- azureClientID: "",
- azureClientSecret: "",
- gcpProjectID: "",
- gcpEndpoint: "",
- gcpClientEmail: "",
- gcpClientID: "",
- gcpPrivateKeyID: "",
- gcpPrivateKey: "",
- enableCustomCertsForKES: false,
- replicas: "1",
- kesSecurityContext: {
- runAsUser: "1000",
- runAsGroup: "1000",
- fsGroup: "1000",
- runAsNonRoot: true,
- },
- },
- tenantSize: {
- volumeSize: "1024",
- sizeFactor: "Gi",
- drivesPerServer: "4",
- nodes: "4",
- memoryNode: "2",
- ecParity: "",
- ecParityChoices: [],
- cleanECChoices: [],
- untouchedECField: true,
- distribution: {
- error: "",
- nodes: 0,
- persistentVolumes: 0,
- disks: 0,
- },
- ecParityCalc: {
- error: 0,
- defaultEC: "",
- erasureCodeSet: 0,
- maxEC: "",
- rawCapacity: "0",
- storageFactors: [],
- },
- limitSize: {},
- cpuToUse: "0",
- // resource request
- resourcesSpecifyLimit: false,
- resourcesCPURequestError: "",
- resourcesCPURequest: "",
- resourcesCPULimitError: "",
- resourcesCPULimit: "",
- resourcesMemoryRequestError: "",
- resourcesMemoryRequest: "",
- resourcesMemoryLimitError: "",
- resourcesMemoryLimit: "",
- resourcesSize: {
- error: "",
- memoryRequest: 0,
- memoryLimit: 0,
- cpuRequest: 0,
- cpuLimit: 0,
- },
- maxAllocatableResources: {
- min_allocatable_mem: 0,
- min_allocatable_cpu: 0,
- cpu_priority: {
- max_allocatable_cpu: 0,
- max_allocatable_mem: 0,
- },
- mem_priority: {
- max_allocatable_cpu: 0,
- max_allocatable_mem: 0,
- },
- },
- maxCPUsUse: "0",
- maxMemorySize: "0",
- integrationSelection: {
- driveSize: { driveSize: "0", sizeUnit: "B" },
- CPU: 0,
- typeSelection: "",
- memory: 0,
- drivesPerServer: 0,
- storageClass: "",
- },
- },
- affinity: {
- nodeSelectorLabels: "",
- podAffinity: "default",
- withPodAntiAffinity: true,
+ prometheusSecurityContext: {
+ runAsUser: "1000",
+ runAsGroup: "1000",
+ fsGroup: "1000",
+ runAsNonRoot: true,
},
},
- certificates: {
- minioCertificates: [
- {
- id: Date.now().toString(),
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- ],
- caCertificates: [
- {
- id: Date.now().toString(),
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- ],
- consoleCaCertificates: [
- {
- id: Date.now().toString(),
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- ],
- consoleCertificate: {
- id: "console_cert_pair",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- serverCertificate: {
- id: "encryptionServerCertificate",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- clientCertificate: {
- id: "encryptionClientCertificate",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- vaultCertificate: {
- id: "encryptionVaultCertificate",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- vaultCA: {
- id: "encryptionVaultCA",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
- },
- gemaltoCA: {
- id: "encryptionGemaltoCA",
- key: "",
- cert: "",
- encoded_key: "",
- encoded_cert: "",
+ identityProvider: {
+ idpSelection: "Built-in",
+ accessKeys: [getRandomString(16)],
+ secretKeys: [getRandomString(32)],
+ openIDConfigurationURL: "",
+ openIDClientID: "",
+ openIDSecretID: "",
+ openIDCallbackURL: "",
+ openIDClaimName: "",
+ openIDScopes: "",
+ ADURL: "",
+ ADSkipTLS: false,
+ ADServerInsecure: false,
+ ADGroupSearchBaseDN: "",
+ ADGroupSearchFilter: "",
+ ADUserDNs: [""],
+ ADLookupBindDN: "",
+ ADLookupBindPassword: "",
+ ADUserDNSearchBaseDN: "",
+ ADUserDNSearchFilter: "",
+ ADServerStartTLS: false,
+ },
+ security: {
+ enableAutoCert: true,
+ enableCustomCerts: false,
+ enableTLS: true,
+ },
+ encryption: {
+ enableEncryption: false,
+ encryptionType: "vault",
+ gemaltoEndpoint: "",
+ gemaltoToken: "",
+ gemaltoDomain: "",
+ gemaltoRetry: "0",
+ awsEndpoint: "",
+ awsRegion: "",
+ awsKMSKey: "",
+ awsAccessKey: "",
+ awsSecretKey: "",
+ awsToken: "",
+ vaultEndpoint: "",
+ vaultEngine: "",
+ vaultNamespace: "",
+ vaultPrefix: "",
+ vaultAppRoleEngine: "",
+ vaultId: "",
+ vaultSecret: "",
+ vaultRetry: "0",
+ vaultPing: "0",
+ azureEndpoint: "",
+ azureTenantID: "",
+ azureClientID: "",
+ azureClientSecret: "",
+ gcpProjectID: "",
+ gcpEndpoint: "",
+ gcpClientEmail: "",
+ gcpClientID: "",
+ gcpPrivateKeyID: "",
+ gcpPrivateKey: "",
+ enableCustomCertsForKES: false,
+ replicas: "1",
+ kesSecurityContext: {
+ runAsUser: "1000",
+ runAsGroup: "1000",
+ fsGroup: "1000",
+ runAsNonRoot: true,
},
},
- nodeSelectorPairs: [{ key: "", value: "" }],
- tolerations: [
- {
- key: "",
- tolerationSeconds: { seconds: 0 },
- value: "",
- effect: ITolerationEffect.NoSchedule,
- operator: ITolerationOperator.Equal,
+ tenantSize: {
+ volumeSize: "1024",
+ sizeFactor: "Gi",
+ drivesPerServer: "4",
+ nodes: "4",
+ memoryNode: "2",
+ ecParity: "",
+ ecParityChoices: [],
+ cleanECChoices: [],
+ untouchedECField: true,
+ distribution: {
+ error: "",
+ nodes: 0,
+ persistentVolumes: 0,
+ disks: 0,
},
- ],
+ ecParityCalc: {
+ error: 0,
+ defaultEC: "",
+ erasureCodeSet: 0,
+ maxEC: "",
+ rawCapacity: "0",
+ storageFactors: [],
+ },
+ limitSize: {},
+ cpuToUse: "0",
+ // resource request
+ resourcesSpecifyLimit: false,
+ resourcesCPURequestError: "",
+ resourcesCPURequest: "",
+ resourcesCPULimitError: "",
+ resourcesCPULimit: "",
+ resourcesMemoryRequestError: "",
+ resourcesMemoryRequest: "",
+ resourcesMemoryLimitError: "",
+ resourcesMemoryLimit: "",
+ resourcesSize: {
+ error: "",
+ memoryRequest: 0,
+ memoryLimit: 0,
+ cpuRequest: 0,
+ cpuLimit: 0,
+ },
+ maxAllocatableResources: {
+ min_allocatable_mem: 0,
+ min_allocatable_cpu: 0,
+ cpu_priority: {
+ max_allocatable_cpu: 0,
+ max_allocatable_mem: 0,
+ },
+ mem_priority: {
+ max_allocatable_cpu: 0,
+ max_allocatable_mem: 0,
+ },
+ },
+ maxCPUsUse: "0",
+ maxMemorySize: "0",
+ integrationSelection: {
+ driveSize: { driveSize: "0", sizeUnit: "B" },
+ CPU: 0,
+ typeSelection: "",
+ memory: 0,
+ drivesPerServer: 0,
+ storageClass: "",
+ },
+ },
+ affinity: {
+ nodeSelectorLabels: "",
+ podAffinity: "default",
+ withPodAntiAffinity: true,
+ },
};
+ state.certificates = {
+ minioCertificates: [
+ {
+ id: Date.now().toString(),
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ ],
+ caCertificates: [
+ {
+ id: Date.now().toString(),
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ ],
+ consoleCaCertificates: [
+ {
+ id: Date.now().toString(),
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ ],
+ consoleCertificate: {
+ id: "console_cert_pair",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ serverCertificate: {
+ id: "encryptionServerCertificate",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ clientCertificate: {
+ id: "encryptionClientCertificate",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ vaultCertificate: {
+ id: "encryptionVaultCertificate",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ vaultCA: {
+ id: "encryptionVaultCA",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ gemaltoCA: {
+ id: "encryptionGemaltoCA",
+ key: "",
+ cert: "",
+ encoded_key: "",
+ encoded_cert: "",
+ },
+ };
+ state.nodeSelectorPairs = [{ key: "", value: "" }];
+ state.tolerations = [
+ {
+ key: "",
+ tolerationSeconds: { seconds: 0 },
+ value: "",
+ effect: ITolerationEffect.NoSchedule,
+ operator: ITolerationOperator.Equal,
+ },
+ ];
+ state.createdAccount = null;
+ state.showNewCredentials = false;
},
setKeyValuePairs: (state, action: PayloadAction) => {
state.nodeSelectorPairs = action.payload;
@@ -1057,6 +1070,45 @@ export const createTenantSlice = createSlice({
setIDP: (state, action: PayloadAction) => {
state.fields.identityProvider.idpSelection = action.payload;
},
+ setTenantName: (state, action: PayloadAction) => {
+ state.fields.nameTenant.tenantName = action.payload;
+ delete state.validationErrors["tenant-name"];
+
+ const commonValidation = commonFormValidation([
+ {
+ fieldKey: "tenant-name",
+ required: true,
+ pattern: /^[a-z0-9-]{3,63}$/,
+ customPatternMessage:
+ "Name only can contain lowercase letters, numbers and '-'. Min. Length: 3",
+ value: action.payload,
+ },
+ ]);
+
+ let isValid = false;
+ if ("tenant-name" in commonValidation) {
+ isValid = true;
+ state.validationErrors["tenant-name"] = commonValidation["tenant-name"];
+ }
+
+ flipValidPageInState(state, "nameTenant", isValid);
+ },
+ },
+ extraReducers: (builder) => {
+ builder
+ .addCase(createTenantAsync.pending, (state, action) => {
+ state.addingTenant = true;
+ state.createdAccount = null;
+ state.showNewCredentials = false;
+ })
+ .addCase(createTenantAsync.rejected, (state, action) => {
+ state.addingTenant = false;
+ })
+ .addCase(createTenantAsync.fulfilled, (state, action) => {
+ state.addingTenant = false;
+ state.createdAccount = action.payload;
+ state.showNewCredentials = true;
+ });
},
});
@@ -1097,6 +1149,7 @@ export const {
addIDPADUsrAtIndex,
removeIDPADUsrAtIndex,
setIDP,
+ setTenantName,
} = createTenantSlice.actions;
export default createTenantSlice.reducer;
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/sliceUtils.ts b/portal-ui/src/screens/Console/Tenants/AddTenant/sliceUtils.ts
new file mode 100644
index 000000000..56b72e075
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/sliceUtils.ts
@@ -0,0 +1,36 @@
+// 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 .
+
+import { ICreateTenant } from "./createTenantSlice";
+import { Draft } from "@reduxjs/toolkit";
+
+export const flipValidPageInState = (
+ state: Draft,
+ pageName: string,
+ valid: boolean
+) => {
+ let originValidPages = state.validPages;
+ if (valid) {
+ if (!originValidPages.includes(pageName)) {
+ originValidPages.push(pageName);
+
+ state.validPages = [...originValidPages];
+ }
+ } else {
+ const newSetOfPages = originValidPages.filter((elm) => elm !== pageName);
+ state.validPages = [...newSetOfPages];
+ }
+};
diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/thunks/createTenantThunk.ts b/portal-ui/src/screens/Console/Tenants/AddTenant/thunks/createTenantThunk.ts
new file mode 100644
index 000000000..5ba2bc62c
--- /dev/null
+++ b/portal-ui/src/screens/Console/Tenants/AddTenant/thunks/createTenantThunk.ts
@@ -0,0 +1,590 @@
+// 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 .
+
+import { createAsyncThunk } from "@reduxjs/toolkit";
+import { AppState } from "../../../../../store";
+import { generatePoolName, getBytes } from "../../../../../common/utils";
+import { getDefaultAffinity, getNodeSelector } from "../../TenantDetails/utils";
+import { ITenantCreator } from "../../../../../common/types";
+import { KeyPair } from "../../ListTenants/utils";
+import { createTenantCall } from "../createTenantAPI";
+import { setErrorSnackMessage } from "../../../../../systemSlice";
+
+export const createTenantAsync = createAsyncThunk(
+ "createTenant/createTenantAsync",
+ async (_, { getState, rejectWithValue, dispatch }) => {
+ const state = getState() as AppState;
+
+ let fields = state.createTenant.fields;
+ let certificates = state.createTenant.certificates;
+
+ const tenantName = fields.nameTenant.tenantName;
+ const selectedStorageClass = fields.nameTenant.selectedStorageClass;
+ const imageName = fields.configure.imageName;
+ const customDockerhub = fields.configure.customDockerhub;
+ const imageRegistry = fields.configure.imageRegistry;
+ const imageRegistryUsername = fields.configure.imageRegistryUsername;
+ const imageRegistryPassword = fields.configure.imageRegistryPassword;
+ const exposeMinIO = fields.configure.exposeMinIO;
+ const exposeConsole = fields.configure.exposeConsole;
+ const idpSelection = fields.identityProvider.idpSelection;
+ const openIDConfigurationURL =
+ fields.identityProvider.openIDConfigurationURL;
+ const openIDClientID = fields.identityProvider.openIDClientID;
+ const openIDClaimName = fields.identityProvider.openIDClaimName;
+ const openIDCallbackURL = fields.identityProvider.openIDCallbackURL;
+ const openIDScopes = fields.identityProvider.openIDScopes;
+ const openIDSecretID = fields.identityProvider.openIDSecretID;
+ const ADURL = fields.identityProvider.ADURL;
+ const ADSkipTLS = fields.identityProvider.ADSkipTLS;
+ const ADServerInsecure = fields.identityProvider.ADServerInsecure;
+ const ADGroupSearchBaseDN = fields.identityProvider.ADGroupSearchBaseDN;
+ const ADGroupSearchFilter = fields.identityProvider.ADGroupSearchFilter;
+ const ADUserDNs = fields.identityProvider.ADUserDNs;
+ const ADLookupBindDN = fields.identityProvider.ADLookupBindDN;
+ const ADLookupBindPassword = fields.identityProvider.ADLookupBindPassword;
+ const ADUserDNSearchBaseDN = fields.identityProvider.ADUserDNSearchBaseDN;
+ const ADUserDNSearchFilter = fields.identityProvider.ADUserDNSearchFilter;
+ const ADServerStartTLS = fields.identityProvider.ADServerStartTLS;
+ const accessKeys = fields.identityProvider.accessKeys;
+ const secretKeys = fields.identityProvider.secretKeys;
+ const minioCertificates = certificates.minioCertificates;
+ const caCertificates = certificates.caCertificates;
+ const consoleCaCertificates = certificates.consoleCaCertificates;
+ const consoleCertificate = certificates.consoleCertificate;
+ const serverCertificate = certificates.serverCertificate;
+ const clientCertificate = certificates.clientCertificate;
+ const vaultCertificate = certificates.vaultCertificate;
+ const vaultCA = certificates.vaultCA;
+ const gemaltoCA = certificates.gemaltoCA;
+ const enableEncryption = fields.encryption.enableEncryption;
+ const encryptionType = fields.encryption.encryptionType;
+ const gemaltoEndpoint = fields.encryption.gemaltoEndpoint;
+ const gemaltoToken = fields.encryption.gemaltoToken;
+ const gemaltoDomain = fields.encryption.gemaltoDomain;
+ const gemaltoRetry = fields.encryption.gemaltoRetry;
+ const awsEndpoint = fields.encryption.awsEndpoint;
+ const awsRegion = fields.encryption.awsRegion;
+ const awsKMSKey = fields.encryption.awsKMSKey;
+ const awsAccessKey = fields.encryption.awsAccessKey;
+ const awsSecretKey = fields.encryption.awsSecretKey;
+ const awsToken = fields.encryption.awsToken;
+ const vaultEndpoint = fields.encryption.vaultEndpoint;
+ const vaultEngine = fields.encryption.vaultEngine;
+ const vaultNamespace = fields.encryption.vaultNamespace;
+ const vaultPrefix = fields.encryption.vaultPrefix;
+ const vaultAppRoleEngine = fields.encryption.vaultAppRoleEngine;
+ const vaultId = fields.encryption.vaultId;
+ const vaultSecret = fields.encryption.vaultSecret;
+ const vaultRetry = fields.encryption.vaultRetry;
+ const vaultPing = fields.encryption.vaultPing;
+ const azureEndpoint = fields.encryption.azureEndpoint;
+ const azureTenantID = fields.encryption.azureTenantID;
+ const azureClientID = fields.encryption.azureClientID;
+ const azureClientSecret = fields.encryption.azureClientSecret;
+ const gcpProjectID = fields.encryption.gcpProjectID;
+ const gcpEndpoint = fields.encryption.gcpEndpoint;
+ const gcpClientEmail = fields.encryption.gcpClientEmail;
+ const gcpClientID = fields.encryption.gcpClientID;
+ const gcpPrivateKeyID = fields.encryption.gcpPrivateKeyID;
+ const gcpPrivateKey = fields.encryption.gcpPrivateKey;
+ const enableAutoCert = fields.security.enableAutoCert;
+ const enableTLS = fields.security.enableTLS;
+ const ecParity = fields.tenantSize.ecParity;
+ const distribution = fields.tenantSize.distribution;
+ const tenantCustom = fields.configure.tenantCustom;
+ const logSearchEnabled = fields.configure.logSearchEnabled;
+ const prometheusEnabled = fields.configure.prometheusEnabled;
+ const logSearchVolumeSize = fields.configure.logSearchVolumeSize;
+ const logSearchSelectedStorageClass =
+ fields.configure.logSearchSelectedStorageClass;
+ const logSearchImage = fields.configure.logSearchImage;
+ const kesImage = fields.configure.kesImage;
+ const logSearchPostgresImage = fields.configure.logSearchPostgresImage;
+ const logSearchPostgresInitImage =
+ fields.configure.logSearchPostgresInitImage;
+ const prometheusImage = fields.configure.prometheusImage;
+ const prometheusSidecarImage = fields.configure.prometheusSidecarImage;
+ const prometheusInitImage = fields.configure.prometheusInitImage;
+ const prometheusSelectedStorageClass =
+ fields.configure.prometheusSelectedStorageClass;
+ const prometheusVolumeSize = fields.configure.prometheusVolumeSize;
+ const affinityType = fields.affinity.podAffinity;
+ const nodeSelectorLabels = fields.affinity.nodeSelectorLabels;
+ const withPodAntiAffinity = fields.affinity.withPodAntiAffinity;
+
+ const tenantSecurityContext = fields.configure.tenantSecurityContext;
+ const logSearchSecurityContext = fields.configure.logSearchSecurityContext;
+ const logSearchPostgresSecurityContext =
+ fields.configure.logSearchPostgresSecurityContext;
+ const prometheusSecurityContext =
+ fields.configure.prometheusSecurityContext;
+ const kesSecurityContext = fields.encryption.kesSecurityContext;
+ const kesReplicas = fields.encryption.replicas;
+ const setDomains = fields.configure.setDomains;
+ const minioDomains = fields.configure.minioDomains;
+ const consoleDomain = fields.configure.consoleDomain;
+
+ let tolerations = state.createTenant.tolerations;
+ let namespace = state.createTenant.fields.nameTenant.namespace;
+
+ const tolerationValues = tolerations.filter(
+ (toleration) => toleration.key.trim() !== ""
+ );
+
+ const poolName = generatePoolName([]);
+
+ let affinityObject = {};
+
+ switch (affinityType) {
+ case "default":
+ affinityObject = {
+ affinity: getDefaultAffinity(tenantName, poolName),
+ };
+ break;
+ case "nodeSelector":
+ affinityObject = {
+ affinity: getNodeSelector(
+ nodeSelectorLabels,
+ withPodAntiAffinity,
+ tenantName,
+ poolName
+ ),
+ };
+ break;
+ }
+
+ const erasureCode = ecParity.split(":")[1];
+
+ let dataSend: ITenantCreator = {
+ name: tenantName,
+ namespace: namespace,
+ access_key: "",
+ secret_key: "",
+ access_keys: [],
+ secret_keys: [],
+ enable_tls: enableTLS && enableAutoCert,
+ enable_console: true,
+ enable_prometheus: true,
+ service_name: "",
+ image: imageName,
+ expose_minio: exposeMinIO,
+ expose_console: exposeConsole,
+ pools: [
+ {
+ name: poolName,
+ servers: distribution.nodes,
+ volumes_per_server: distribution.disks,
+ volume_configuration: {
+ size: distribution.pvSize,
+ storage_class_name: selectedStorageClass,
+ },
+ securityContext: tenantCustom ? tenantSecurityContext : null,
+ ...affinityObject,
+ tolerations: tolerationValues,
+ },
+ ],
+ erasureCodingParity: parseInt(erasureCode, 10),
+ };
+
+ // Set Resources
+ if (
+ fields.tenantSize.resourcesCPURequest !== "" ||
+ fields.tenantSize.resourcesCPULimit !== "" ||
+ fields.tenantSize.resourcesMemoryRequest !== "" ||
+ fields.tenantSize.resourcesMemoryLimit !== ""
+ ) {
+ dataSend.pools[0].resources = {};
+ // requests
+ if (
+ fields.tenantSize.resourcesCPURequest !== "" ||
+ fields.tenantSize.resourcesMemoryRequest !== ""
+ ) {
+ dataSend.pools[0].resources.requests = {};
+ if (fields.tenantSize.resourcesCPURequest !== "") {
+ dataSend.pools[0].resources.requests.cpu = parseInt(
+ fields.tenantSize.resourcesCPURequest
+ );
+ }
+ if (fields.tenantSize.resourcesMemoryRequest !== "") {
+ dataSend.pools[0].resources.requests.memory = parseInt(
+ getBytes(fields.tenantSize.resourcesMemoryRequest, "Gi", true)
+ );
+ }
+ }
+ // limits
+ if (
+ fields.tenantSize.resourcesCPULimit !== "" ||
+ fields.tenantSize.resourcesMemoryLimit !== ""
+ ) {
+ dataSend.pools[0].resources.limits = {};
+ if (fields.tenantSize.resourcesCPULimit !== "") {
+ dataSend.pools[0].resources.limits.cpu = parseInt(
+ fields.tenantSize.resourcesCPULimit
+ );
+ }
+ if (fields.tenantSize.resourcesMemoryLimit !== "") {
+ dataSend.pools[0].resources.limits.memory = parseInt(
+ getBytes(fields.tenantSize.resourcesMemoryLimit, "Gi", true)
+ );
+ }
+ }
+ }
+ if (customDockerhub) {
+ dataSend = {
+ ...dataSend,
+ image_registry: {
+ registry: imageRegistry,
+ username: imageRegistryUsername,
+ password: imageRegistryPassword,
+ },
+ };
+ }
+
+ if (logSearchEnabled) {
+ dataSend = {
+ ...dataSend,
+ logSearchConfiguration: {
+ storageClass:
+ logSearchSelectedStorageClass === "default"
+ ? ""
+ : logSearchSelectedStorageClass,
+ storageSize: parseInt(logSearchVolumeSize),
+ image: logSearchImage,
+ postgres_image: logSearchPostgresImage,
+ postgres_init_image: logSearchPostgresInitImage,
+ securityContext: logSearchSecurityContext,
+ postgres_securityContext: logSearchPostgresSecurityContext,
+ },
+ };
+ }
+
+ if (prometheusEnabled) {
+ dataSend = {
+ ...dataSend,
+ prometheusConfiguration: {
+ storageClass:
+ prometheusSelectedStorageClass === "default"
+ ? ""
+ : prometheusSelectedStorageClass,
+ storageSize: parseInt(prometheusVolumeSize),
+ image: prometheusImage,
+ sidecar_image: prometheusSidecarImage,
+ init_image: prometheusInitImage,
+ securityContext: prometheusSecurityContext,
+ },
+ };
+ }
+
+ let tenantCerts: any = null;
+ let consoleCerts: any = null;
+ let caCerts: any = null;
+ let consoleCaCerts: any = null;
+
+ if (caCertificates.length > 0) {
+ caCerts = {
+ ca_certificates: caCertificates
+ .map((keyPair: KeyPair) => keyPair.encoded_cert)
+ .filter((keyPair) => keyPair),
+ };
+ }
+
+ if (consoleCaCertificates.length > 0) {
+ consoleCaCerts = {
+ console_ca_certificates: consoleCaCertificates
+ .map((keyPair: KeyPair) => keyPair.encoded_cert)
+ .filter((keyPair) => keyPair),
+ };
+ }
+
+ if (enableTLS && minioCertificates.length > 0) {
+ tenantCerts = {
+ minio: minioCertificates
+ .map((keyPair: KeyPair) => ({
+ crt: keyPair.encoded_cert,
+ key: keyPair.encoded_key,
+ }))
+ .filter((keyPair) => keyPair.crt && keyPair.key),
+ };
+ }
+
+ if (
+ enableTLS &&
+ consoleCertificate.encoded_cert !== "" &&
+ consoleCertificate.encoded_key !== ""
+ ) {
+ consoleCerts = {
+ console: {
+ crt: consoleCertificate.encoded_cert,
+ key: consoleCertificate.encoded_key,
+ },
+ };
+ }
+
+ if (tenantCerts || consoleCerts || caCerts || consoleCaCerts) {
+ dataSend = {
+ ...dataSend,
+ tls: {
+ ...tenantCerts,
+ ...consoleCerts,
+ ...caCerts,
+ ...consoleCaCerts,
+ },
+ };
+ }
+
+ if (enableEncryption) {
+ let insertEncrypt = {};
+
+ switch (encryptionType) {
+ case "gemalto":
+ let gemaltoCAIntroduce = {};
+
+ if (gemaltoCA.encoded_cert !== "") {
+ gemaltoCAIntroduce = {
+ ca: gemaltoCA.encoded_cert,
+ };
+ }
+ insertEncrypt = {
+ gemalto: {
+ keysecure: {
+ endpoint: gemaltoEndpoint,
+ credentials: {
+ token: gemaltoToken,
+ domain: gemaltoDomain,
+ retry: parseInt(gemaltoRetry),
+ },
+ tls: {
+ ...gemaltoCAIntroduce,
+ },
+ },
+ },
+ };
+ break;
+ case "aws":
+ insertEncrypt = {
+ aws: {
+ secretsmanager: {
+ endpoint: awsEndpoint,
+ region: awsRegion,
+ kmskey: awsKMSKey,
+ credentials: {
+ accesskey: awsAccessKey,
+ secretkey: awsSecretKey,
+ token: awsToken,
+ },
+ },
+ },
+ };
+ break;
+ case "azure":
+ insertEncrypt = {
+ azure: {
+ keyvault: {
+ endpoint: azureEndpoint,
+ credentials: {
+ tenant_id: azureTenantID,
+ client_id: azureClientID,
+ client_secret: azureClientSecret,
+ },
+ },
+ },
+ };
+ break;
+ case "gcp":
+ insertEncrypt = {
+ gcp: {
+ secretmanager: {
+ project_id: gcpProjectID,
+ endpoint: gcpEndpoint,
+ credentials: {
+ client_email: gcpClientEmail,
+ client_id: gcpClientID,
+ private_key_id: gcpPrivateKeyID,
+ private_key: gcpPrivateKey,
+ },
+ },
+ },
+ };
+ break;
+ case "vault":
+ let vaultKeyPair = null;
+ let vaultCAInsert = null;
+ if (
+ vaultCertificate.encoded_key !== "" &&
+ vaultCertificate.encoded_cert !== ""
+ ) {
+ vaultKeyPair = {
+ key: vaultCertificate.encoded_key,
+ crt: vaultCertificate.encoded_cert,
+ };
+ }
+ if (vaultCA.encoded_cert !== "") {
+ vaultCAInsert = {
+ ca: vaultCA.encoded_cert,
+ };
+ }
+ let vaultTLS = null;
+ if (vaultKeyPair || vaultCAInsert) {
+ vaultTLS = {
+ tls: {
+ ...vaultKeyPair,
+ ...vaultCAInsert,
+ },
+ };
+ }
+ insertEncrypt = {
+ vault: {
+ endpoint: vaultEndpoint,
+ engine: vaultEngine,
+ namespace: vaultNamespace,
+ prefix: vaultPrefix,
+ approle: {
+ engine: vaultAppRoleEngine,
+ id: vaultId,
+ secret: vaultSecret,
+ retry: parseInt(vaultRetry),
+ },
+ ...vaultTLS,
+ status: {
+ ping: parseInt(vaultPing),
+ },
+ },
+ };
+ break;
+ }
+
+ let encryptionServerKeyPair: any = {};
+ let encryptionClientKeyPair: any = {};
+
+ if (
+ clientCertificate.encoded_key !== "" &&
+ clientCertificate.encoded_cert !== ""
+ ) {
+ encryptionClientKeyPair = {
+ client: {
+ key: clientCertificate.encoded_key,
+ crt: clientCertificate.encoded_cert,
+ },
+ };
+ }
+
+ if (
+ serverCertificate.encoded_key !== "" &&
+ serverCertificate.encoded_cert !== ""
+ ) {
+ encryptionServerKeyPair = {
+ server: {
+ key: serverCertificate.encoded_key,
+ crt: serverCertificate.encoded_cert,
+ },
+ };
+ }
+
+ dataSend = {
+ ...dataSend,
+ encryption: {
+ replicas: kesReplicas,
+ securityContext: kesSecurityContext,
+ image: kesImage,
+ ...encryptionClientKeyPair,
+ ...encryptionServerKeyPair,
+ ...insertEncrypt,
+ },
+ };
+ }
+
+ let dataIDP: any = {};
+ switch (idpSelection) {
+ case "Built-in":
+ let keyarray = [];
+ for (let i = 0; i < accessKeys.length; i++) {
+ keyarray.push({
+ access_key: accessKeys[i],
+ secret_key: secretKeys[i],
+ });
+ }
+ dataIDP = {
+ keys: keyarray,
+ };
+ break;
+ case "OpenID":
+ dataIDP = {
+ oidc: {
+ configuration_url: openIDConfigurationURL,
+ client_id: openIDClientID,
+ secret_id: openIDSecretID,
+ claim_name: openIDClaimName,
+ callback_url: openIDCallbackURL,
+ scopes: openIDScopes,
+ },
+ };
+ break;
+ case "AD":
+ dataIDP = {
+ active_directory: {
+ url: ADURL,
+ skip_tls_verification: ADSkipTLS,
+ server_insecure: ADServerInsecure,
+ group_search_base_dn: ADGroupSearchBaseDN,
+ group_search_filter: ADGroupSearchFilter,
+ user_dns: ADUserDNs,
+ lookup_bind_dn: ADLookupBindDN,
+ lookup_bind_password: ADLookupBindPassword,
+ user_dn_search_base_dn: ADUserDNSearchBaseDN,
+ user_dn_search_filter: ADUserDNSearchFilter,
+ server_start_tls: ADServerStartTLS,
+ },
+ };
+ break;
+ }
+
+ let domains: any = {};
+ let sendDomain: any = {};
+
+ if (setDomains) {
+ if (consoleDomain !== "") {
+ domains.console = consoleDomain;
+ }
+
+ const filteredDomains = minioDomains.filter((dom) => dom.trim() !== "");
+
+ if (filteredDomains.length > 0) {
+ domains.minio = filteredDomains;
+ }
+
+ if (Object.keys(domains).length > 0) {
+ sendDomain.domains = domains;
+ }
+ }
+
+ dataSend = {
+ ...dataSend,
+ ...sendDomain,
+ idp: { ...dataIDP },
+ };
+
+ const response = createTenantCall(dataSend)
+ .then((resp) => {
+ return resp;
+ })
+ .catch((err) => {
+ dispatch(setErrorSnackMessage(err));
+ return rejectWithValue(err);
+ });
+ return response;
+ }
+);
diff --git a/portal-ui/src/screens/Console/Tenants/types.ts b/portal-ui/src/screens/Console/Tenants/types.ts
index 85d0ab120..4fecd3a9f 100644
--- a/portal-ui/src/screens/Console/Tenants/types.ts
+++ b/portal-ui/src/screens/Console/Tenants/types.ts
@@ -384,5 +384,3 @@ export interface ITenantIdentityProviderResponse {
user_dn_search_filter: string;
};
}
-
-export type FieldsToHandle = INameTenantFields;
diff --git a/restapi/errors.go b/restapi/errors.go
index dec5c577e..50f5ab07b 100644
--- a/restapi/errors.go
+++ b/restapi/errors.go
@@ -27,7 +27,7 @@ import (
)
var (
- ErrDefault = errors.New("an errors occurred, please try again")
+ ErrDefault = errors.New("an error occurred, please try again")
ErrInvalidLogin = errors.New("invalid Login")
ErrForbidden = errors.New("403 Forbidden")
ErrFileTooLarge = errors.New("413 File too Large")