Skip to content

Commit

Permalink
Integrate APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
radhikav1 committed Sep 21, 2023
1 parent 9d2e2f8 commit 04b5133
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 61 deletions.
31 changes: 31 additions & 0 deletions app/cdap/api/serviceaccounts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright © 2023 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

import DataSourceConfigurer from 'services/datasource/DataSourceConfigurer';
import { apiCreator } from 'services/resource-helper';

const dataSrc = DataSourceConfigurer.getInstance();
const basePath = '/namespaces/:namespace/credentials';
const identityBasePath = `${basePath}/workloadIdentity`;

export const ServiceAccountsApi = {
listServiceAccounts: apiCreator(dataSrc, 'GET', 'REQUEST', `${identityBasePath}`),
createWorkloadIdentity: apiCreator(dataSrc, 'PUT', 'REQUEST', `${identityBasePath}`),
validateWorkloadIdentity: apiCreator(dataSrc, 'POST', 'REQUEST', `${identityBasePath}/validate`),
getWorkloadIdentity: apiCreator(dataSrc, 'GET', 'REQUEST', `${identityBasePath}`),
deleteWorkloadIdentity: apiCreator(dataSrc, 'DELETE', 'REQUEST', `${identityBasePath}`),
getNamespaceDetails: apiCreator(dataSrc, 'GET', 'REQUEST', '/namespaces/:namespace'),
};
6 changes: 4 additions & 2 deletions app/cdap/components/NamespaceAdmin/AdminTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ export const AdminTabs = () => {
const sourceControlManagementEnabled = useFeatureFlagDefaultFalse(
'source.control.management.git.enabled'
);
const namespacedServiceAccountsEnabled = true; /*useFeatureFlagDefaultFalse(
const namespacedServiceAccountsEnabled = useFeatureFlagDefaultFalse(
'feature.namespaced.service.accounts.enabled'
);*/
);

// const namespacedServiceAccountsEnabled = true; // for testing locally

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import React, { useState } from 'react';
import T from 'i18n-react';
import { ConfirmDialog, SeverityType } from 'components/shared/ConfirmDialog';
import { deleteServiceAccount } from 'components/NamespaceAdmin/store/ActionCreator';

const PREFIX = 'features.ServiceAccounts';

Expand All @@ -34,23 +35,13 @@ export const DeleteConfirmDialog = ({
const [deleteErrorMsg, setDeleteErrorMsg] = useState(null);
const [extendedErrorMsg, setExtendedErrorMsg] = useState(null);

const deleteHanlder = (serviceAcnt) => {
// Just for testing
// alert('delete');
// const sampleErrorResponse =
// 'Error occurred : ' +
// "Exception in thread 'main' java.util.InputMismatchException" +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)' +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)' +
// 'at java.base/java.util.Scanner.throwFor(Scanner.java:939)' +
// 'at java.base/java.util.Scanner.next(Scanner.java:1594)' +
// 'at java.base/java.util.Scanner.nextFloat(Scanner.java:2496)';
// setExtendedErrorMsg({ response: sampleErrorResponse });
setDeleteErrorMsg(T.translate(`${PREFIX}.failedToDelete`));
const deleteHanlder = () => {
deleteServiceAccount().subscribe(closeFn, (err) => {
setDeleteErrorMsg(T.translate(`${PREFIX}.failedToDelete`));
if (err.response) {
setExtendedErrorMsg({ response: err.response });
}
});
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import T from 'i18n-react';
import styled from 'styled-components';
import TextField from '@material-ui/core/TextField';
import { ConfirmDialog, Severity, SeverityType } from 'components/shared/ConfirmDialog';
import {
validateServiceAccount,
addServiceAccount,
getNamespaceDetails,
} from 'components/NamespaceAdmin/store/ActionCreator';

const PREFIX = 'features.ServiceAccounts';
const GCLOUD_COMMAND_TEXT =
Expand Down Expand Up @@ -72,19 +77,24 @@ export const EditConfirmDialog = ({
setCopyableExtendedMessage(GCLOUD_COMMAND_TEXT);
};

// validates and then saves
const handleSave = () => {
// TO DO
// call API to SAVE credential provider SA
const isSaveSuccessful = false;

// for testing : remove while commiting
// isSaveSuccessful = selectedServiceAcnt === 'yes' ? true : false;

if (isSaveSuccessful) {
closeDialog();
} else {
showErrorMessage();
}
getNamespaceDetails().subscribe((result) => {
const reqObj = { identity: result.identity, serviceAccount: selectedServiceAcnt };
validateServiceAccount(reqObj).subscribe(
(res) => {
// validation success, so proceed for save
addServiceAccount(reqObj).subscribe(closeDialog, (err) => {
// save failed
showErrorMessage('failedToSave', err);
});
},
(err) => {
// validation failed
showErrorMessage('failedToValidate', err);
}
);
});
};

const closeDialog = () => {
Expand All @@ -94,18 +104,15 @@ export const EditConfirmDialog = ({
setCopyableExtendedMessage(null);
};

const showErrorMessage = () => {
setSaveStatus(SeverityType.ERROR);
const showErrorMessage = (failedStage, errorObj) => {
setCopyableExtendedMessage(null);
// just for testing
// selectedServiceAcnt === 'fail'
// ? setSaveStatusMsg(T.translate(`${PREFIX}.failedToValidate`))
// : setSaveStatusMsg(T.translate(`${PREFIX}.failedToSave`));

// setSaveStatusMsg(T.translate(`${PREFIX}.saveErrorMessage`));
setSaveStatusDetails({
response: 'Sample Error message for testing : Error occurred it is not intergrated with API',
});
setSaveStatus(SeverityType.ERROR);
setSaveStatusMsg(T.translate(`${PREFIX}.${failedStage}`));
if (errorObj.response) {
setSaveStatusDetails({
response: errorObj.response,
});
}
};

const getEditDialogContent = () => {
Expand Down
33 changes: 15 additions & 18 deletions app/cdap/components/NamespaceAdmin/ServiceAccounts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,39 +37,36 @@ const SubTitleBox = styled(Box)`
`;

const ServiceAccountsView = ({ serviceacnts }) => {
// mock data
// serviceacnts = [{ name: 'serviceaccount1' }, { name: 'serviceaccount2' }];

const [showPopover, setShowPopover] = useState(false);
const [selectedServiceAcnt, setSelectedServiceAcnt] = useState(null);
const [isSaveDialogOpen, setSaveDialogOpen] = React.useState(false);
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);

const handleSaveDialogClose = () => {
setSaveDialogOpen(false);
};

const showAddDialog = () => {
setSaveDialogOpen(true);
setSelectedServiceAcnt(null);
};

const showEditDialog = (serviceAcnt) => {
setSelectedServiceAcnt(serviceAcnt.name);
const showSaveDialog = (serviceAcnt) => {
setSelectedServiceAcnt(serviceAcnt);
setSaveDialogOpen(true);
setShowPopover(false);
};

const closeDeleteConfirmation = () => {
setDeleteDialogOpen(false);
const closeSaveDialog = () => {
setSaveDialogOpen(false);
};

const showDeleteConfirmation = (serviceAcnt) => {
setSelectedServiceAcnt(serviceAcnt.name);
setSelectedServiceAcnt(serviceAcnt);
setShowPopover(false);
setDeleteDialogOpen(true);
};

const closeDeleteConfirmation = () => {
setDeleteDialogOpen(false);
};

const renderDeleteConfirmDialog = () => {
return (
<DeleteConfirmDialog
Expand All @@ -86,7 +83,7 @@ const ServiceAccountsView = ({ serviceacnts }) => {
selectedServiceAcnt={selectedServiceAcnt}
setSelectedServiceAcnt={setSelectedServiceAcnt}
isShow={isSaveDialogOpen}
closeFn={handleSaveDialogClose}
closeFn={closeSaveDialog}
isShowHelp={true}
></EditConfirmDialog>
);
Expand Down Expand Up @@ -115,20 +112,20 @@ const ServiceAccountsView = ({ serviceacnts }) => {
const actions: IAction[] = [
{
label: T.translate('commons.edit'),
actionFn: () => showEditDialog(serviceAcnt),
actionFn: () => showSaveDialog(serviceAcnt.serviceAccount),
},
{
label: 'separator',
},
{
label: T.translate('commons.delete'),
actionFn: () => showDeleteConfirmation(serviceAcnt),
actionFn: () => showDeleteConfirmation(serviceAcnt.serviceAccount),
},
];

return (
<TableRow key={`${serviceAcnt.name}`}>
<TableCell>{serviceAcnt.name}</TableCell>
<TableRow key={`${serviceAcnt.serviceAccount}`}>
<TableCell>{serviceAcnt.serviceAccount}</TableCell>
<TableCell>
<ActionsPopover actions={actions} showPopover={showPopover} />
</TableCell>
Expand All @@ -145,7 +142,7 @@ const ServiceAccountsView = ({ serviceacnts }) => {

const mapStateToProps = (state) => {
return {
serviceacnts: state.serviceacnts,
serviceacnts: state.serviceaccounts,
};
};

Expand Down
2 changes: 2 additions & 0 deletions app/cdap/components/NamespaceAdmin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
getDrivers,
getConnections,
getAndSetSourceControlManagement,
getServiceAccounts,
} from 'components/NamespaceAdmin/store/ActionCreator';
import { Provider } from 'react-redux';
import Store from 'components/NamespaceAdmin/store';
Expand Down Expand Up @@ -60,6 +61,7 @@ const NamespaceAdmin = () => {
getConnections(namespace);
getProfiles(namespace);
getAndSetSourceControlManagement(namespace);
getServiceAccounts(namespace);

eventEmitter.on(globalEvents.NSPREFERENCESSAVED, getPreferences);
eventEmitter.on(globalEvents.ARTIFACTUPLOAD, getDrivers);
Expand Down
58 changes: 57 additions & 1 deletion app/cdap/components/NamespaceAdmin/store/ActionCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import Store, {
NamespaceAdminActions,
} from 'components/NamespaceAdmin/store';
import { objectQuery, PIPELINE_ARTIFACTS } from 'services/helpers';
import { getCurrentNamespace } from 'services/NamespaceStore';
import { fetchNamespaceDetails, getCurrentNamespace } from 'services/NamespaceStore';
import { GLOBALS, SCOPES } from 'services/global-constants';
import { Observable } from 'rxjs/Observable';
import { catchError, switchMap } from 'rxjs/operators';
import { ConnectionsApi } from 'api/connections';
import { ServiceAccountsApi } from 'api/serviceaccounts';
import { ISourceControlManagementConfig } from '../SourceControlManagement/types';
import { of } from 'rxjs/observable/of';

Expand Down Expand Up @@ -183,6 +184,7 @@ export function getConnections(namespace) {
}

export function deleteConnection(conn: IConnection) {
debugger;
const params = {
context: getCurrentNamespace(),
connectionId: conn.name,
Expand Down Expand Up @@ -300,6 +302,60 @@ const getBodyForSubmit = (formState, validate = false) => {
};
};

export function getServiceAccounts(namespace) {
const requestNamespace = namespace ? namespace : getCurrentNamespace();

// for testing. remove before commit {
// const sampleResponse = { identity: 'Test_identity_value', serviceAccount: 'TEST_GSA_EMAIL' };
// Store.dispatch({
// type: NamespaceAdminActions.setServiceAccounts,
// payload: {
// serviceaccounts: [sampleResponse],
// },
// });

ServiceAccountsApi.listServiceAccounts({ namespace: requestNamespace }).subscribe((res) => {
Store.dispatch({
type: NamespaceAdminActions.setServiceAccounts,
payload: {
serviceaccounts: res,
},
});
});
}

export function deleteServiceAccount() {
const params = {
namespace: getCurrentNamespace(),
};

return ServiceAccountsApi.deleteWorkloadIdentity(params).map(() => {
getServiceAccounts(getCurrentNamespace());
});
}

export function validateServiceAccount(reqObj: Object) {
const params = {
namespace: getCurrentNamespace(),
};
return ServiceAccountsApi.validateWorkloadIdentity(params, reqObj);
}

export function getNamespaceDetails() {
const params = {
namespace: getCurrentNamespace(),
};
return ServiceAccountsApi.getNamespaceDetails(params);
}

export function addServiceAccount(reqObj: Object) {
const params = {
namespace: getCurrentNamespace(),
};

return ServiceAccountsApi.createWorkloadIdentity(params, reqObj);
}

export function reset() {
Store.dispatch({
type: NamespaceAdminActions.reset,
Expand Down
13 changes: 13 additions & 0 deletions app/cdap/components/NamespaceAdmin/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const NamespaceAdminActions = {
setPreferences: 'SET_PREFERENCES',
setDrivers: 'SET_DRIVERS',
setConnections: 'SET_CONNECTIONS',
setServiceAccounts: 'SET_SERVICE_ACCOUNTS',
setSourceControlManagementConfig: 'SET_SOURCE_CONTROL_MANAGEMENT_CONFIG',
reset: 'NAMESPACE_ADMIN_RESET',
};
Expand Down Expand Up @@ -61,6 +62,11 @@ interface IPlugin {
type: string;
}

interface IServiceAccount {
identity: string;
serviceAccount: string;
}

// TODO: this should probably be under the Connections component
export interface IConnection {
connectionType: string;
Expand All @@ -86,6 +92,7 @@ interface INamespaceAdmin {
drivers: IDriver[];
connections: IConnection[];
sourceControlManagementConfig: ISourceControlManagementConfig;
serviceaccounts: IServiceAccount[];
}

type INamespaceAdminState = Partial<INamespaceAdmin>;
Expand All @@ -103,6 +110,7 @@ const defaultInitialState: Partial<INamespaceAdminState> = {
drivers: [],
connections: [],
sourceControlManagementConfig: null,
serviceaccounts: [],
};

const namespaceAdmin: Reducer<INamespaceAdminState> = (state = defaultInitialState, action) => {
Expand Down Expand Up @@ -147,6 +155,11 @@ const namespaceAdmin: Reducer<INamespaceAdminState> = (state = defaultInitialSta
...state,
sourceControlManagementConfig: action.payload.sourceControlManagementConfig,
};
case NamespaceAdminActions.setServiceAccounts:
return {
...state,
serviceaccounts: action.payload.serviceaccounts,
};
case NamespaceAdminActions.reset:
return {
...defaultInitialState,
Expand Down

0 comments on commit 04b5133

Please sign in to comment.