Skip to content

Commit

Permalink
KMS Support for cluster creation
Browse files Browse the repository at this point in the history
Signed-off-by: Kanika Murarka <kmurarka@redhat.com>
  • Loading branch information
Kanika Murarka committed Nov 18, 2020
1 parent 9d55fc6 commit 7213815
Show file tree
Hide file tree
Showing 18 changed files with 656 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.ocs-install-kms {
&__form-url {
display: inline-flex;
width: 100%;
}

&__form-address {
width: 70%;
}

&__form-port {
width: 30%;
}
}
Original file line number Diff line number Diff line change
@@ -1,67 +1,200 @@
import * as React from 'react';
import { FormGroup, TextInput } from '@patternfly/react-core';
import {
FormGroup,
TextInput,
FormSelect,
FormSelectOption,
Button,
ValidatedOptions,
} from '@patternfly/react-core';
import { State, Action } from '../ocs-install/attached-devices/create-sc/state';
import {
InternalClusterState,
InternalClusterAction,
ActionType,
} from '../ocs-install/internal-mode/reducer';
import {
setDispatch,
Validation,
VALIDATIONS,
ValidationMessage,
} from '../../utils/common-ocs-install-el';
import { KMSProviders } from '../../constants/ocs-install';
import './kms-config.scss';
import * as _ from 'lodash';
import { advancedKMSModal } from '../modals/advanced-kms-modal/advanced-kms-modal';
import { setDispatch, parseURL } from './utils';

const validate = (valid: boolean): Validation => {
let validation: Validation;
if (!valid) {
validation = VALIDATIONS.REQUIRED_FIELD_KMS;
}
return validation;
};

/* @TODO - complete KMS View in follow up PR */
export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mode }) => {
const { kms } = state;
const validation: Validation = validate(kms.hasHandled);
const [kmsProvider, setKMSProvider] = React.useState<string>(KMSProviders[0].name);

const setServiceName = (name: string) => {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, name }, mode, dispatch);
};

const setAddress = (address: string) => {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, address }, mode, dispatch);
};

const setAddressPort = (port: string) => {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, port }, mode, dispatch);
};

const setToken = (token: string) => {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, token }, mode, dispatch);
};

const validateAddress = () => {
return parseURL(kms.address.trim()) ? ValidatedOptions.default : ValidatedOptions.error;
};

const validateAddressMessage = () => {
if (kms.address === '') {
return 'This is a required field';
}
return 'Please enter a URL';
};

const validatePort = () => {
return _.isNaN(kms.port) || kms.port < 0 || !kms.port
? ValidatedOptions.error
: ValidatedOptions.default;
};

const validatePortMessage = () => {
if (!kms.port) {
return 'This is a required field';
}
return 'Please enter a valid port';
};

React.useEffect(() => {
if (!kms.name) {
if (
!kms.name ||
!kms.address ||
!kms.token ||
!kms.port ||
validateAddress() === ValidatedOptions.error ||
validatePort() === ValidatedOptions.error
) {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, hasHandled: false }, mode, dispatch);
} else {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, hasHandled: true }, mode, dispatch);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [kms.name]);
}, [kms.name, kms.address, kms.token, kms.port]);

const getServiceName = (name: string) => {
setDispatch(ActionType.SET_KMS_ENCRYPTION, { ...kms, name }, mode, dispatch);
const openAdvancedModal = () => {
return advancedKMSModal({
state,
dispatch,
mode,
});
};

return (
<>
<div className="co-m-pane__form">
<FormGroup
fieldId="kms-provider"
label="Key Management Service Provider"
className="ocs-install-encryption__form-body"
>
<FormSelect
value={kmsProvider}
onChange={(e) => setKMSProvider(e)}
id="kms-provider-name"
name="kms-provider-name"
aria-label="kms-provider-name"
isDisabled
>
{KMSProviders.map((provider) => (
<FormSelectOption value={provider.value} label={provider.name} />
))}
</FormSelect>
</FormGroup>
<FormGroup
fieldId="kms-service-name"
label="Service Name"
className="co-m-pane__form ocs-install-encryption__form-body"
className="ocs-install-encryption__form-body"
helperTextInvalid="This is a required field"
validated={kms.name === '' ? ValidatedOptions.error : ValidatedOptions.default}
isRequired
>
<TextInput
value={kms.name}
onChange={getServiceName}
isRequired
onChange={setServiceName}
type="text"
id="kms-service-name"
name="kms-service-name"
isRequired
validated={kms.name === '' ? ValidatedOptions.error : ValidatedOptions.default}
/>
{validation && <ValidationMessage validation={validation} />}
</FormGroup>
</>
<div className="ocs-install-kms__form-url">
<FormGroup
fieldId="kms-service-address"
label="Address"
className="ocs-install-kms__form-address ocs-install-encryption__form-body"
helperTextInvalid={validateAddressMessage()}
validated={validateAddress()}
isRequired
>
<TextInput
value={kms.address}
onChange={setAddress}
className="ocs-install-kms__form-address--padding"
type="url"
id="kms-address"
name="kms-address"
isRequired
validated={validateAddress()}
/>
</FormGroup>
<FormGroup
fieldId="kms-service-address-port"
label="Port"
className="ocs-install-kms__form-port ocs-install-encryption__form-body--small-padding"
helperTextInvalid={validatePortMessage()}
validated={validatePort()}
isRequired
>
<TextInput
value={kms.port}
onChange={setAddressPort}
type="text"
id="kms-address-port"
name="kms-address-port"
isRequired
validated={validatePort()}
/>
</FormGroup>
</div>
<FormGroup
fieldId="kms-service-token"
label="Token"
className="ocs-install-encryption__form-body"
helperTextInvalid="This is a required field"
validated={kms.token === '' ? ValidatedOptions.error : ValidatedOptions.default}
isRequired
>
<TextInput
value={kms.token}
onChange={setToken}
type="text"
id="kms-token"
name="kms-token"
isRequired
validated={kms.token === '' ? ValidatedOptions.error : ValidatedOptions.default}
/>
</FormGroup>
<Button
variant="link"
className="ocs-install-encryption__form-body"
onClick={openAdvancedModal}
>
Advanced Settings
</Button>
</div>
);
};

type KMSConfigureProps = {
state: State | InternalClusterState;
dispatch: React.Dispatch<Action | InternalClusterAction>;
mode: string;
state?: InternalClusterState | State;
dispatch?: React.Dispatch<Action | InternalClusterAction>;
mode?: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import * as React from 'react';
import { KMSConfig, KMSConfigMap } from '../ocs-install/types';
import { K8sResourceKind, ConfigMapKind, SecretKind } from '@console/internal/module/k8s/types';
import { ConfigMapModel, SecretModel } from '@console/internal/models';
import { CEPH_STORAGE_NAMESPACE, MODES } from '../../constants';
import { k8sCreate } from '@console/internal/module/k8s/resource';
import { Action } from '../ocs-install/attached-devices/create-sc/state';
import { InternalClusterAction } from '../ocs-install/internal-mode/reducer';
import * as _ from 'lodash';

export const parseURL = (url: string) => {
try {
return new URL(url);
} catch (e) {
return null;
}
};

export const kmsResources = (kms: KMSConfig) => {
const tokenSecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: 'ocs-kms-vault-token',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
data: kms.token,
},
};
const resources: Promise<K8sResourceKind>[] = [];

const parsedAddress = parseURL(kms.address);

const configData: KMSConfigMap = {
KMS_PROVIDER: 'vault',
VAULT_ADDR: `${parsedAddress.protocol + parsedAddress.hostname}:${kms.port}`,
VAULT_BACKEND_PATH: kms.backend,
VAULT_CACERT: kms.caCert?.metadata.name,
VAULT_TLS_SERVER_NAME: kms.tls,
VAULT_CLIENT_CERT: kms.clientCert?.metadata.name,
VAULT_CLIENT_KEY: kms.clientKey?.metadata.name,
VAULT_NAMESPACE: kms.providerNamespace,
};
const configMapObj: ConfigMapKind = {
apiVersion: ConfigMapModel.apiVersion,
kind: ConfigMapModel.kind,
data: {
...configData,
},
metadata: {
name: 'ocs-vault-connection-details',
namespace: CEPH_STORAGE_NAMESPACE,
},
};

if (kms.caCert) {
resources.push(k8sCreate(SecretModel, kms.caCert, CEPH_STORAGE_NAMESPACE));
}

if (kms.clientCert) {
resources.push(k8sCreate(SecretModel, kms.clientCert, CEPH_STORAGE_NAMESPACE));
}

if (kms.clientKey) {
resources.push(k8sCreate(SecretModel, kms.clientKey, CEPH_STORAGE_NAMESPACE));
}

resources.push(k8sCreate(SecretModel, tokenSecret, CEPH_STORAGE_NAMESPACE));
resources.push(k8sCreate(ConfigMapModel, configMapObj, CEPH_STORAGE_NAMESPACE));
return resources;
};

export const setDispatch = (
keyType: any,
valueType: any,
mode: string,
dispatch: React.Dispatch<Action | InternalClusterAction>,
) => {
const stateType = mode === MODES.ATTACHED_DEVICES ? _.camelCase(keyType) : keyType;
const stateValue =
mode === MODES.ATTACHED_DEVICES ? { value: valueType } : { payload: valueType };
dispatch({ type: stateType, ...stateValue });
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.ceph-advanced-kms {
&__form-body {
padding: var(--pf-global--spacer--md) 0 !important;
}
}

0 comments on commit 7213815

Please sign in to comment.