This is an automated email from the ASF dual-hosted git repository.
arshad pushed a commit to branch frontend-refactor
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/frontend-refactor by this push:
new ce37d24d7f AMBARI-26385: Ambari Web React: Regenerate keytabs (#4065)
ce37d24d7f is described below
commit ce37d24d7f3720695db6450f55381e51353e8268
Author: Sandeep Kumar <[email protected]>
AuthorDate: Sun Sep 14 21:46:02 2025 +0530
AMBARI-26385: Ambari Web React: Regenerate keytabs (#4065)
---
ambari-web/latest/src/components/Modal.tsx | 2 +-
.../src/screens/Kerberos/InvalidKdcPopup.tsx | 94 ++++++++++++
.../src/screens/Kerberos/RegenerateKeytabs.tsx | 165 +++++++++++++++++++++
3 files changed, 260 insertions(+), 1 deletion(-)
diff --git a/ambari-web/latest/src/components/Modal.tsx
b/ambari-web/latest/src/components/Modal.tsx
index 8acbcb0749..a632851f1d 100644
--- a/ambari-web/latest/src/components/Modal.tsx
+++ b/ambari-web/latest/src/components/Modal.tsx
@@ -23,7 +23,7 @@ import classNames from "classnames";
export type ModalProps = {
isOpen: boolean;
onClose: () => void;
- modalTitle: string;
+ modalTitle: any;
modalBody: ReactNode;
className?:string;
successCallback: () => void;
diff --git a/ambari-web/latest/src/screens/Kerberos/InvalidKdcPopup.tsx
b/ambari-web/latest/src/screens/Kerberos/InvalidKdcPopup.tsx
new file mode 100644
index 0000000000..b4c1dca143
--- /dev/null
+++ b/ambari-web/latest/src/screens/Kerberos/InvalidKdcPopup.tsx
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { useState } from "react";
+import Modal from "../../components/Modal";
+import { Alert, Form } from "react-bootstrap";
+import { translate } from "../../Utils/Utility";
+
+type InvalidKDCPopupProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ handleSave: (adminPrincipal: string, adminPassword: string,
saveCredentials: boolean) => void;
+};
+
+export default function InvalidKDCPopup({isOpen, onClose, handleSave}:
InvalidKDCPopupProps): React.ReactElement {
+ const [adminPrincipal, setAdminPrincipal] = useState("");
+ const [adminPassword, setAdminPassword] = useState("");
+ const [saveCredentials, setSaveCredentials] = useState(false);
+
+ function getModalBody() {
+ return (
+ <>
+ <Alert variant="warning">
+ Warning: Missing KDC administrator credentials. Please enter
admin principal and password.
+ </Alert>
+ <Form>
+ <Form.Group controlId="adminPrincipal">
+ <Form.Label>Admin Principal</Form.Label>
+ <Form.Control
+ type="text"
+ value={adminPrincipal}
+ onChange={(e) => setAdminPrincipal(e.target.value)}
+ />
+ </Form.Group>
+ <Form.Group controlId="adminPassword">
+ <Form.Label>Admin Password</Form.Label>
+ <Form.Control
+ type="password"
+ value={adminPassword}
+ onChange={(e) => setAdminPassword(e.target.value)}
+ />
+ </Form.Group>
+ <Form.Group controlId="saveCredentials">
+ <Form.Check
+ type="checkbox"
+ label="Save Admin Credentials"
+ checked={saveCredentials}
+ onChange={(e) => setSaveCredentials(e.target.checked)}
+ />
+ </Form.Group>
+ </Form>
+ </>
+ )
+ }
+
+ async function handleSaveDetails() {
+ handleSave(adminPrincipal, adminPassword, saveCredentials);
+ }
+
+ return (
+ <>
+ <Modal
+ isOpen={isOpen}
+ onClose={() => onClose()}
+ modalTitle={translate("popup.invalid.KDC.header")}
+ modalBody={getModalBody()}
+ options={{
+ okButtonText: "SAVE",
+ cancelableViaIcon: true,
+ cancelableViaBtn: true,
+ modalSize: "modal-md",
+ }}
+ successCallback={() => {
+ handleSaveDetails();
+ }}
+ />
+ </>
+ )
+}
\ No newline at end of file
diff --git a/ambari-web/latest/src/screens/Kerberos/RegenerateKeytabs.tsx
b/ambari-web/latest/src/screens/Kerberos/RegenerateKeytabs.tsx
new file mode 100644
index 0000000000..212b1ba9b2
--- /dev/null
+++ b/ambari-web/latest/src/screens/Kerberos/RegenerateKeytabs.tsx
@@ -0,0 +1,165 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { useContext, useEffect, useRef, useState } from "react";
+import { ProgressStatus } from "../../constants";
+import usePolling from "../../hooks/usePolling";
+import { isFinished } from "../../Utils/Utility";
+import { AppContext } from "../../store/context";
+import { RequestApi } from "../../api/requestApi";
+import KerberosApi from "../../api/kerberosApi";
+import InvalidKDCPopup from "./InvalidKdcPopup";
+
+type RegenerateKeytabsProps = {
+ missingHostCheck: boolean;
+ restartComponentsCheck: boolean;
+};
+
+export default function RegenerateKeytabs({
+ missingHostCheck,
+ restartComponentsCheck,
+}: RegenerateKeytabsProps) {
+ // @ts-ignore
+ const [showBgOperation, setShowBgOperation] = useState(false);
+ const [showInvalidKDCPopup, setShowInvalidKDCPopup] = useState(false);
+ const requestId = useRef<string | number>("");
+ const restartCheckRef = useRef(restartComponentsCheck);
+ const { clusterName } = useContext(AppContext);
+
+ const { stopPolling, pausePolling, resumePolling } = usePolling(
+ getRequestStatus,
+ 3000
+ );
+
+ useEffect(() => {
+ regenerate();
+ }, []);
+
+ useEffect(() => {
+ if (restartComponentsCheck) {
+ resumePolling();
+ } else {
+ pausePolling();
+ }
+ }, [restartComponentsCheck]);
+
+ async function getRequestStatus() {
+ if (!restartCheckRef.current) pausePolling();
+
+ const requestStatus: any = await RequestApi.getRequestStatus(
+ clusterName,
+ requestId.current as string
+ );
+ const { Requests } = requestStatus;
+ if (isFinished(Requests.request_status)) {
+ if (Requests.request_status === ProgressStatus.COMPLETED) {
+ stopPolling();
+ if (restartCheckRef.current) restartComponents();
+ }
+ }
+ }
+
+ async function restartComponents() {
+ const restartPayload = {
+ RequestInfo: {
+ command: "RESTART",
+ context: "Restart all services",
+ operation_level: "host_component",
+ },
+ "Requests/resource_filters": [
+ {
+ hosts_predicate: `HostRoles/cluster_name=${clusterName}`,
+ },
+ ],
+ };
+ const requestData = await RequestApi.postRequest(
+ clusterName,
+ restartPayload
+ );
+ requestId.current = requestData.Requests.id;
+ }
+
+ async function regenerate() {
+ const payload = {
+ Clusters: {
+ security_type: "KERBEROS",
+ },
+ };
+ try {
+ const params = missingHostCheck
+ ? "regenerate_keytabs=missing"
+ : "regenerate_keytabs=all";
+ const requestData = await RequestApi.regenerateKeytabs(
+ clusterName,
+ payload,
+ params
+ );
+ requestId.current = requestData.Requests.id;
+ if (requestId.current !== "") setShowBgOperation(true);
+ } catch (error) {
+ console.log("Error regenerating keytabs: ", error);
+ setShowInvalidKDCPopup(true);
+ }
+ }
+
+ const handleSaveInvalidKDC = async (
+ adminPrincipal: string,
+ adminPassword: string,
+ saveCredentials: boolean
+ ) => {
+ setShowInvalidKDCPopup(false);
+ const payload = {
+ Credential: {
+ key: adminPassword,
+ principal: adminPrincipal,
+ type: saveCredentials ? "persisted" : "temporary",
+ },
+ };
+
+ try {
+ await KerberosApi.postKDCAdminCredentials(
+ clusterName,
+ payload
+ );
+
+ // Retry the regenerateKeytabs API call with the provided credentials
+ await regenerate();
+ } catch (error) {
+ console.error("Error posting KDC Admin Credentials:", error);
+ }
+ };
+
+ return (
+ <>
+ {/* {showBgOperation ? (
+ <BackgroundOperations
+ isOpen={showBgOperation}
+ onClose={() => setShowBgOperation(false)}
+ rootLevel={ViewLevel.REQUESTS}
+ requestId={requestId.current}
+ />
+ ) : null} */}
+
+ <InvalidKDCPopup
+ isOpen={showInvalidKDCPopup}
+ onClose={() => setShowInvalidKDCPopup(false)}
+ handleSave={handleSaveInvalidKDC}
+ />
+ </>
+ );
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]