diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json
index a66320a29..d2e632030 100644
--- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json
+++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json
@@ -10,8 +10,11 @@
"24 hours": "24 hours",
"404: Not Found": "404: Not Found",
"7 days": "7 days",
+ "A CA certificate to be trusted when connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the CA certificate format is in a PEM encoded X.509 format. To use a CA certificate, drag the file to the text box or browse for it. To use the system CA certificates, leave the field empty.": "A CA certificate to be trusted when connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the CA certificate format is in a PEM encoded X.509 format. To use a CA certificate, drag the file to the text box or browse for it. To use the system CA certificates, leave the field empty.",
"A Secret containing credentials and other confidential information.": "A Secret containing credentials and other confidential information.",
"A Secret containing credentials and other confidential information. Empty may be used for the host provider.": "A Secret containing credentials and other confidential information. Empty may be used for the host provider.",
+ "A user name for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the user name is in the format of username@user-domain. For example: admin@internal.": "A user name for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the user name is in the format of username@user-domain. For example: admin@internal.",
+ "A user password for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint.": "A user password for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint.",
"Actions": "Actions",
"Add source and target providers for the migration.": "Add source and target providers for the migration.",
"Application credential ID": "Application credential ID",
@@ -28,7 +31,9 @@
"Authentication type": "Authentication type",
"Bandwidth": "Bandwidth",
"CA certificate": "CA certificate",
+ "CA certificate - disabled and ignored when 'Skip certificate validation' is checked": "CA certificate - disabled and ignored when 'Skip certificate validation' is checked",
"CA certificate - disabled when skip certificate validation is checked": "CA certificate - disabled when skip certificate validation is checked",
+ "CA certificate - leave empty to use system CA certificates": "CA certificate - leave empty to use system CA certificates",
"CA certificate - leave empty to use system certificates": "CA certificate - leave empty to use system certificates",
"Cancel": "Cancel",
"Cancel scheduled cutover": "Cancel scheduled cutover",
@@ -65,7 +70,6 @@
"Credentials": "Credentials",
"Critical concerns": "Critical concerns",
"Custom certification used to verify the OpenStack REST API server, when empty use system certificate.": "Custom certification used to verify the OpenStack REST API server, when empty use system certificate.",
- "Custom certification used to verify the RH Virtualization REST API server, when empty use system certificate.": "Custom certification used to verify the RH Virtualization REST API server, when empty use system certificate.",
"Data centers": "Data centers",
"Data stores": "Data stores",
"Dates are compared in UTC. End of the interval is included.": "Dates are compared in UTC. End of the interval is included.",
@@ -113,9 +117,13 @@
"Error: Name is required and must be a unique within a namespace and valid Kubernetes name (i.e., must contain no more than 253 characters, consists of lower case alphanumeric characters , '-' or '.' and starts and ends with an alphanumeric character).": "Error: Name is required and must be a unique within a namespace and valid Kubernetes name (i.e., must contain no more than 253 characters, consists of lower case alphanumeric characters , '-' or '.' and starts and ends with an alphanumeric character).",
"Error: NFS mount end point should be in the form NFS_SERVER:EXPORTED_DIRECTORY, for example: 10.10.0.10:/ova.": "Error: NFS mount end point should be in the form NFS_SERVER:EXPORTED_DIRECTORY, for example: 10.10.0.10:/ova.",
"Error: Password is required and must be valid.": "Error: Password is required and must be valid.",
+ "Error: The format of the provided CA Certificate is invalid. Ensure the CA certificate format is in a PEM encoded X.509 format.": "Error: The format of the provided CA Certificate is invalid. Ensure the CA certificate format is in a PEM encoded X.509 format.",
"Error: The format of the provided URL is invalid. Ensure the URL includes a scheme, a domain name, and a path. For example: https://rhv-host-example.com/ovirt-engine/api.": "Error: The format of the provided URL is invalid. Ensure the URL includes a scheme, a domain name, and a path. For example: https://rhv-host-example.com/ovirt-engine/api.",
"Error: The format of the provided URL is invalid. Ensure the URL includes a scheme, a domain name, and a path. For example: https://vCenter-host-example.com/sdk.": "Error: The format of the provided URL is invalid. Ensure the URL includes a scheme, a domain name, and a path. For example: https://vCenter-host-example.com/sdk.",
+ "Error: The format of the provided user name is invalid. Ensure the user name doesn't include whitespace characters.": "Error: The format of the provided user name is invalid. Ensure the user name doesn't include whitespace characters.",
+ "Error: The format of the provided user password is invalid. Ensure the user password doesn't include whitespace characters.": "Error: The format of the provided user password is invalid. Ensure the user password doesn't include whitespace characters.",
"Error: This field must be a boolean.": "Error: This field must be a boolean.",
+ "Error: this field must be set to a boolean value.": "Error: this field must be set to a boolean value.",
"Error: token is a required field, the token must be a valid kubernetes token.": "Error: token is a required field, the token must be a valid kubernetes token.",
"Error: URL is required and must be valid.": "Error: URL is required and must be valid.",
"Error: URL must be valid.": "Error: URL must be valid.",
@@ -146,6 +154,7 @@
"Host": "Host",
"Host cluster": "Host cluster",
"Hosts": "Hosts",
+ "If true (check box is checked), the provider's CA certificate won't be validated.": "If true (check box is checked), the provider's CA certificate won't be validated.",
"If true, the provider's REST API TLS certificate won't be validated.": "If true, the provider's REST API TLS certificate won't be validated.",
"If true, the provider's TLS certificate won't be validated.": "If true, the provider's TLS certificate won't be validated.",
"Image": "Image",
@@ -229,6 +238,8 @@
"No StorageMaps found in namespace <1>{namespace}1>.": "No StorageMaps found in namespace <1>{namespace}1>.",
"No StorageMaps found.": "No StorageMaps found.",
"Not Ready": "Not Ready",
+ "Note: If this field is checked/true, the migration from this provider will be insecure.
Insecure migration means that the transferred data is sent over an insecure connection and potentially sensitive data could be exposed.": "Note: If this field is checked/true, the migration from this provider will be insecure.
Insecure migration means that the transferred data is sent over an insecure connection and potentially sensitive data could be exposed.",
+ "Note: Use the Manager CA certificate unless it was replaced by a third-party certificate, in which case use the Manager Apache CA certificate.
You can retrieve the Manager CA certificate at: <1>https://‹rhv-host-example.com›/ovirt-engine/services/pki-resource?resource=ca-certificate&format=X509-PEM-CA1> .": "Note: Use the Manager CA certificate unless it was replaced by a third-party certificate, in which case use the Manager Apache CA certificate.
You can retrieve the Manager CA certificate at: <1>https://‹rhv-host-example.com›/ovirt-engine/services/pki-resource?resource=ca-certificate&format=X509-PEM-CA1> .",
"NUMA": "NUMA",
"Number of cluster in provider": "Number of cluster in provider",
"Number of data centers in provider": "Number of data centers in provider",
@@ -306,8 +317,6 @@
"Restore default columns": "Restore default columns",
"Return to the providers list page": "Return to the providers list page",
"Reveal values": "Reveal values",
- "RH Virtualization engine REST API password credentials.": "RH Virtualization engine REST API password credentials.",
- "RH Virtualization engine REST API user name.": "RH Virtualization engine REST API user name.",
"Run the migration plan.": "Run the migration plan.",
"Running - performing incremental data copies": "Running - performing incremental data copies",
"Running - preparing for cutover": "Running - preparing for cutover",
@@ -353,7 +362,6 @@
"Target provider": "Target provider",
"Template": "Template",
"Tenant": "Tenant",
- "The CA certificate is the /etc/pki/ovirt-engine/apache-ca.pem file on the Manager machine.": "The CA certificate is the /etc/pki/ovirt-engine/apache-ca.pem file on the Manager machine.",
"The interval in minutes for precopy. Default value is 60.": "The interval in minutes for precopy. Default value is 60.",
"The interval in seconds for snapshot pooling. Default value is 10.": "The interval in seconds for snapshot pooling. Default value is 10.",
"The limit for CPU usage by the controller, specified in milliCPU. Default value is 500m.": "The limit for CPU usage by the controller, specified in milliCPU. Default value is 500m.",
@@ -424,6 +432,7 @@
"Warning concerns": "Warning concerns",
"Warning: The provided URL does not end with the RHVM API endpoint path: \"/ovirt-engine/api\". Ensure the URL includes the correct path. For example: https://rhv-host-example.com/ovirt-engine/api.": "Warning: The provided URL does not end with the RHVM API endpoint path: \"/ovirt-engine/api\". Ensure the URL includes the correct path. For example: https://rhv-host-example.com/ovirt-engine/api.",
"Warning: The provided URL does not end with the SDK endpoint path: \"/sdk\". Ensure the URL includes the correct path. For example: https://vCenter-host-example.com/sdk.": "Warning: The provided URL does not end with the SDK endpoint path: \"/sdk\". Ensure the URL includes the correct path. For example: https://vCenter-host-example.com/sdk.",
+ "Warning: The provided user name does not include the user domain. Ensure the user name is in the format of username@user-domain. For example: admin@internal.": "Warning: The provided user name does not include the user domain. Ensure the user name is in the format of username@user-domain. For example: admin@internal.",
"Welcome": "Welcome",
"When a plan is archived, its history, metadata, and logs are deleted. The plan cannot be edited or restarted but it can be viewed.": "When a plan is archived, its history, metadata, and logs are deleted. The plan cannot be edited or restarted but it can be viewed.",
"YAML": "YAML",
diff --git a/packages/forklift-console-plugin/src/modules/Providers/utils/validators/common.ts b/packages/forklift-console-plugin/src/modules/Providers/utils/validators/common.ts
index 13a0b57be..8e58a5dfa 100644
--- a/packages/forklift-console-plugin/src/modules/Providers/utils/validators/common.ts
+++ b/packages/forklift-console-plugin/src/modules/Providers/utils/validators/common.ts
@@ -90,3 +90,9 @@ export function validateNoSpaces(value: string) {
// any string without spaces
return /^[^\s]+$/.test(value);
}
+
+export function validateUsernameAndDomain(value: string) {
+ // any string without spaces that includes appearance of the at '@' sign
+ // example: user@domain
+ return /^[^\s]+(@+)+[^\s]+$/.test(value);
+}
diff --git a/packages/forklift-console-plugin/src/modules/Providers/utils/validators/secret-fields/ovirtSecretFieldValidator.ts b/packages/forklift-console-plugin/src/modules/Providers/utils/validators/secret-fields/ovirtSecretFieldValidator.ts
index 4ec5efba5..3614a8856 100644
--- a/packages/forklift-console-plugin/src/modules/Providers/utils/validators/secret-fields/ovirtSecretFieldValidator.ts
+++ b/packages/forklift-console-plugin/src/modules/Providers/utils/validators/secret-fields/ovirtSecretFieldValidator.ts
@@ -1,5 +1,5 @@
import { Validation } from '../../types';
-import { validateNoSpaces, validatePublicCert } from '../common';
+import { validateNoSpaces, validatePublicCert, validateUsernameAndDomain } from '../common';
/**
* Validates form input fields based on their id.
@@ -10,6 +10,7 @@ import { validateNoSpaces, validatePublicCert } from '../common';
* @return {Validation} - The validation state of the form field. Can be one of the following:
* 'default' - The default state of the form field, used when the field is empty or a value hasn't been entered yet.
* 'success' - The field's value has passed validation.
+ * 'warning' - The field's value might fail the validation, but it's not mandatory and not disabling the form saving.
* 'error' - The field's value has failed validation.
*/
export const ovirtSecretFieldValidator = (id: string, value: string) => {
@@ -19,7 +20,7 @@ export const ovirtSecretFieldValidator = (id: string, value: string) => {
switch (id) {
case 'user':
- validationState = validateUser(trimmedValue) ? 'success' : 'error';
+ validationState = validateUser(trimmedValue);
break;
case 'password':
validationState = validatePassword(trimmedValue) ? 'success' : 'error';
@@ -39,7 +40,11 @@ export const ovirtSecretFieldValidator = (id: string, value: string) => {
};
const validateUser = (value: string) => {
- return validateNoSpaces(value);
+ return validateNoSpaces(value)
+ ? validateUsernameAndDomain(value)
+ ? 'success'
+ : 'warning'
+ : 'error';
};
const validatePassword = (value: string) => {
diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.style.css b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.style.css
index 2bc9f9426..20017bef9 100644
--- a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.style.css
+++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.style.css
@@ -1,5 +1,5 @@
.forklift-page-secret-title-div {
- padding-top: var(--pf-global--spacer--sm);
+ padding-top: var(--pf-global--spacer--xl);
padding-bottom: var(--pf-global--spacer--xm);
}
diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/edit/OvirtCredentialsEdit.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/edit/OvirtCredentialsEdit.tsx
index 40537ee88..d4be27737 100644
--- a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/edit/OvirtCredentialsEdit.tsx
+++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/edit/OvirtCredentialsEdit.tsx
@@ -1,4 +1,5 @@
import React, { useCallback, useReducer } from 'react';
+import { Trans } from 'react-i18next';
import { Base64 } from 'js-base64';
import {
ovirtSecretFieldValidator,
@@ -7,6 +8,7 @@ import {
} from 'src/modules/Providers/utils';
import { useForkliftTranslation } from 'src/utils/i18n';
+import { ExternalLink } from '@kubev2v/common';
import {
Button,
Checkbox,
@@ -14,10 +16,12 @@ import {
FileUpload,
Form,
FormGroup,
+ Popover,
TextInput,
} from '@patternfly/react-core';
import EyeIcon from '@patternfly/react-icons/dist/esm/icons/eye-icon';
import EyeSlashIcon from '@patternfly/react-icons/dist/esm/icons/eye-slash-icon';
+import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon';
import { EditComponentProps } from '../BaseCredentialsSection';
@@ -29,12 +33,74 @@ export const OvirtCredentialsEdit: React.FC = ({ secret, onC
const insecureSkipVerify = safeBase64Decode(secret?.data?.insecureSkipVerify || '') === 'true';
const cacert = safeBase64Decode(secret?.data?.cacert || '');
+ const usernameHelperTextMsgs = {
+ error: t(
+ "Error: The format of the provided user name is invalid. Ensure the user name doesn't include whitespace characters.",
+ ),
+ warning: t(
+ 'Warning: The provided user name does not include the user domain. Ensure the user name is in the format of username@user-domain. For example: admin@internal.',
+ ),
+ success: t(
+ 'A user name for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the user name is in the format of username@user-domain. For example: admin@internal.',
+ ),
+ };
+
+ const passwordHelperTextMsgs = {
+ error: t(
+ "Error: The format of the provided user password is invalid. Ensure the user password doesn't include whitespace characters.",
+ ),
+ success: t(
+ 'A user password for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint.',
+ ),
+ };
+
+ const insecureSkipVerifyHelperTextMsgs = {
+ error: t('Error: this field must be set to a boolean value.'),
+ success: t("If true (check box is checked), the provider's CA certificate won't be validated."),
+ };
+
+ const cacertHelperTextMsgs = {
+ error: t(
+ 'Error: The format of the provided CA Certificate is invalid. Ensure the CA certificate format is in a PEM encoded X.509 format.',
+ ),
+ success: t(
+ 'A CA certificate to be trusted when connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the CA certificate format is in a PEM encoded X.509 format. To use a CA certificate, drag the file to the text box or browse for it. To use the system CA certificates, leave the field empty.',
+ ),
+ };
+
+ const insecureSkipVerifyHelperTextPopover = (
+
+ {
+ 'Note: If this field is checked/true, the migration from this provider will be insecure.
Insecure migration means that the transferred data is sent over an insecure connection and potentially sensitive data could be exposed.'
+ }
+
+ );
+
+ const cacertHelperTextPopover = (
+
+ {
+ 'Note: Use the Manager CA certificate unless it was replaced by a third-party certificate, in which case use the Manager Apache CA certificate.
You can retrieve the Manager CA certificate at: '
+ }
+
+ https://‹rhv-host-example.com›/ovirt-engine/services/pki-resource?resource=ca-certificate&format=X509-PEM-CA
+
+ {' .'}
+
+ );
+
const initialState = {
passwordHidden: true,
validation: {
user: 'default' as Validation,
password: 'default' as Validation,
+ insecureSkipVerify: 'default' as Validation,
cacert: 'default' as Validation,
+ // The 'warning' validation state is currently supported only for the 'user' field.
+ userHelperText: usernameHelperTextMsgs.success,
},
};
@@ -61,7 +127,25 @@ export const OvirtCredentialsEdit: React.FC = ({ secret, onC
const handleChange = useCallback(
(id, value) => {
const validationState = ovirtSecretFieldValidator(id, value);
- dispatch({ type: 'SET_FIELD_VALIDATED', payload: { field: id, validationState } });
+ dispatch({
+ type: 'SET_FIELD_VALIDATED',
+ payload: { field: id, validationState },
+ });
+
+ // The 'warning' validation state is currently supported only for the 'user' field.
+ switch (id) {
+ case 'user':
+ dispatch({
+ type: 'SET_FIELD_VALIDATED',
+ payload: {
+ field: 'userHelperText',
+ validationState: usernameHelperTextMsgs[validationState],
+ },
+ });
+ break;
+ default:
+ break;
+ }
// don't trim fields that allow spaces
const encodedValue = ['cacert'].includes(id)
@@ -83,9 +167,9 @@ export const OvirtCredentialsEdit: React.FC = ({ secret, onC
label={t('Username')}
isRequired
fieldId="user"
- helperText={t('RH Virtualization engine REST API user name.')}
+ helperText={state.validation.userHelperText}
validated={state.validation.user}
- helperTextInvalid={t('Error: Username is required and must be valid.')}
+ helperTextInvalid={state.validation.userHelperText}
>
= ({ secret, onC
label={t('Password')}
isRequired
fieldId="password"
- helperText={t('RH Virtualization engine REST API password credentials.')}
+ helperText={passwordHelperTextMsgs.success}
validated={state.validation.password}
- helperTextInvalid={t('Error: Password is required and must be valid.')}
+ helperTextInvalid={passwordHelperTextMsgs.error}
>
= ({ secret, onC
Skip certificate validation}
+ bodyContent={
{insecureSkipVerifyHelperTextPopover}
}
+ alertSeverityVariant="info"
+ >
+
+
+ }
fieldId="insecureSkipVerify"
- helperText={t("If true, the provider's REST API TLS certificate won't be validated.")}
+ helperText={insecureSkipVerifyHelperTextMsgs.success}
validated={state.validation.insecureSkipVerify}
- helperTextInvalid={t('Error: Insecure Skip Verify must be a boolean value.')}
+ helperTextInvalid={insecureSkipVerifyHelperTextMsgs.error}
>
= ({ secret, onC
CA certificate}
+ bodyContent={
{cacertHelperTextPopover}
}
+ alertSeverityVariant="info"
+ >
+
+
}
fieldId="cacert"
- helperText={t(
- 'Custom certification used to verify the RH Virtualization REST API server, when empty use system certificate.',
- )}
+ helperText={cacertHelperTextMsgs.success}
validated={state.validation.cacert}
- helperTextInvalid={t('Error: CA Certificate must be valid.')}
+ helperTextInvalid={cacertHelperTextMsgs.error}
>
= ({ secret, rev
const items = [];
const fields = {
- user: { label: t('Username'), description: t('RH Virtualization engine REST API user name.') },
+ user: {
+ label: t('Username'),
+ description: t(
+ 'A user name for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the user name is in the format of username@user-domain. For example: admin@internal.',
+ ),
+ },
password: {
label: t('Password'),
- description: t('RH Virtualization engine REST API password credentials.'),
+ description: t(
+ 'A user password for connecting to the Red Hat Virtualization Manager (RHVM) API endpoint.',
+ ),
},
insecureSkipVerify: {
label: t('Skip certificate validation'),
- description: t("If true, the provider's REST API TLS certificate won't be validated."),
+ description: t(
+ "If true (check box is checked), the provider's CA certificate won't be validated.",
+ ),
+ helperTextPopover: (
+
+ {
+ 'Note: If this field is checked/true, the migration from this provider will be insecure.
Insecure migration means that the transferred data is sent over an insecure connection and potentially sensitive data could be exposed.'
+ }
+
+ ),
},
cacert: {
label: t('CA certificate'),
description: t(
- 'The CA certificate is the /etc/pki/ovirt-engine/apache-ca.pem file on the Manager machine.',
+ 'A CA certificate to be trusted when connecting to the Red Hat Virtualization Manager (RHVM) API endpoint. Ensure the CA certificate format is in a PEM encoded X.509 format. To use a CA certificate, drag the file to the text box or browse for it. To use the system CA certificates, leave the field empty.',
+ ),
+ helperTextPopover: (
+
+ {
+ 'Note: Use the Manager CA certificate unless it was replaced by a third-party certificate, in which case use the Manager Apache CA certificate.
You can retrieve the Manager CA certificate at: '
+ }
+
+ https://‹rhv-host-example.com›/ovirt-engine/services/pki-resource?resource=ca-certificate&format=X509-PEM-CA
+
+ {' .'}
+
),
},
};
@@ -38,9 +78,18 @@ export const OvirtCredentialsList: React.FC = ({ secret, rev
items.push(
<>