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 bd31093e81 AMBARI-26580: Ambari Web React: Component actions for
masters/slaves-Delete (#4108)
bd31093e81 is described below
commit bd31093e81609b5381fa6b69330b0145357aa13c
Author: Sandeep Kumar <[email protected]>
AuthorDate: Wed Feb 4 11:05:41 2026 +0530
AMBARI-26580: Ambari Web React: Component actions for masters/slaves-Delete
(#4108)
---
ambari-web/latest/src/Utils/Utility.ts | 2 +-
.../latest/src/hooks/useComponentAddDelete.tsx | 1068 ++++++++++++++++++++
.../latest/src/screens/Hosts/HostSummary.tsx | 34 +-
ambari-web/latest/src/screens/Hosts/actions.tsx | 24 +
ambari-web/latest/src/screens/Hosts/utils.tsx | 52 +-
5 files changed, 1176 insertions(+), 4 deletions(-)
diff --git a/ambari-web/latest/src/Utils/Utility.ts
b/ambari-web/latest/src/Utils/Utility.ts
index 5b06a23455..3aabd48d35 100644
--- a/ambari-web/latest/src/Utils/Utility.ts
+++ b/ambari-web/latest/src/Utils/Utility.ts
@@ -69,7 +69,7 @@ const command: any = {
"Included:": "Recommission:",
};
-const serviceMap: any = {
+export const serviceMap: any = {
HDFS: "HDFS",
YARN: "YARN",
MAPREDUCE2: "MapReduce2",
diff --git a/ambari-web/latest/src/hooks/useComponentAddDelete.tsx
b/ambari-web/latest/src/hooks/useComponentAddDelete.tsx
new file mode 100644
index 0000000000..e73057d427
--- /dev/null
+++ b/ambari-web/latest/src/hooks/useComponentAddDelete.tsx
@@ -0,0 +1,1068 @@
+/**
+ * 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 { get, set, compact, map, flatten, isArray, has } from "lodash";
+import { useState, useRef, useContext, useEffect } from "react";
+import { t } from "i18next";
+import { IHost } from "../models/host";
+import { AppContext } from "../store/context";
+import { IHostComponent } from "../models/hostComponent";
+import modalManager from "../store/ModalManager";
+import { serviceMap } from "../Utils/Utility";
+import { HostsApi } from "../api/hostsApi";
+import { getComponentDisplayName, getServiceByConfigTypeMap,
zooKeeperRelatedServices } from "../screens/Hosts/utils";
+import RecommendationModal from "../components/RecommendationModal";
+// import AddHiveComponentsInitializer from
"../../../Initializers/AddHiveComponentsInitializer";
+// import AddZooKeeperComponentsInitializer from
"../../../Initializers/AddZooKeeperComponentsInitializer";
+// import RecommendationModal from "../../../components/RecommendationModal";
+
+function useComponentAddDelete(
+ clusterComponents: any,
+ stackServices: any,
+ getConfigByName: Function,
+ setAllHostModels?: (
+ data: IHost[] | ((prevModels: IHost[]) => IHost[])
+ ) => void
+) {
+ const { clusterName, services } = useContext(AppContext);
+ // const { allServiceModels } = useContext(ServiceContext);
+ // const isNameNodeHAEnabled =
+ // allServiceModels["hdfs"]?.isNameNodeHaEnabled || false;
+ const [configs, setConfigs] = useState({});
+ // const [isReconfigureRequired, setIsReconfigureRequired] = useState(false);
+ const isReconfigureRequired = useRef(false);
+
+ const [isConfigsLoadingInProgress, setIsConfigsLoadingInProgress] =
+ useState(false);
+ //@ts-ignore
+ const [allPropertiesToChangeState, setAllPropertiesToChangeState] = useState(
+ []
+ );
+
+ const [recommendedPropertiesToChange, setRecommendedPropertiesToChange] =
+ useState<any>([]);
+ const recommendedPropertiesToChangeRef = useRef<any>(
+ recommendedPropertiesToChange
+ );
+ const componentHere = useRef<IHostComponent | null>(null);
+ const allPropertiesToChange: any = useRef([]);
+ const requiredPropertiesToChange: any = useRef([]);
+ const groupedPropertiesToChange: any = useRef([]);
+ const _deletedHostComponentError = useRef<string>("");
+ const componentProperties = useRef([]);
+
+ useEffect(() => {
+ setAllPropertiesToChangeState(allPropertiesToChange.current);
+ }, [allPropertiesToChange.current]);
+
+ const deleteAndReconfigureComponent = async (
+ componentsMapItem: any,
+ component: IHostComponent
+ ) => {
+ componentHere.current = component;
+ if (componentsMapItem.deletePropertyName) {
+ set(
+ componentProperties.current,
+ componentsMapItem.deletePropertyName,
+ true
+ );
+ }
+ await loadComponentRelatedConfigs(
+ componentsMapItem.configTagsCallbackName,
+ componentsMapItem.configsCallbackName
+ );
+ modalManager.show(
+ <RecommendationModal
+ isOpen={true}
+ onClose={() => {
+ modalManager.hide();
+ }}
+ componentDisplayName={getComponentDisplayName(component)}
+ add={false}
+
recommendedPropertiesToChange={recommendedPropertiesToChangeRef.current}
+ selectRecommendedProperties={(newProperties: any) => {
+ recommendedPropertiesToChangeRef.current = newProperties;
+ }}
+ //@ts-ignore
+ setRecommendedPropertiesToChange={setRecommendedPropertiesToChange}
+ callback={(properties: any) => {
+ setRecommendedPropertiesToChange(properties);
+ _doDeleteHostComponent(component, () => {
+ applyConfigsCustomization();
+ putConfigsToServer(
+ groupedPropertiesToChange.current,
+ get(component, "componentName")
+ );
+ clearConfigsChanges();
+ });
+ }}
+ />
+ );
+ };
+
+ useEffect(() => {
+ recommendedPropertiesToChangeRef.current = recommendedPropertiesToChange;
+ }, [recommendedPropertiesToChange]);
+
+ const putConfigsToServer = async (
+ groups: any,
+ componentName: any
+ ): Promise<void> => {
+ const requests: Promise<any>[] = [];
+ if (isArray(groups)) {
+ groups = flatten(groups);
+ }
+ if (groups.length) {
+ groups.forEach((group: any) => {
+ const desiredConfigs = [];
+ const properties = group.properties;
+ for (let site in properties) {
+ if (!properties.hasOwnProperty(site) || !properties[site]) continue;
+ desiredConfigs.push({
+ type: site,
+ properties: properties[site],
+ properties_attributes: group.properties_attributes[site],
+ service_config_version_note: t(
+ "hosts.host.configs.save.note"
+ ).replace("{0}", componentName),
+ });
+ }
+ if (desiredConfigs.length > 0) {
+ const data = {
+ desired_config: desiredConfigs,
+ componentName: componentName,
+ };
+ requests.push(
+ HostsApi.commonServiceConfigurations(clusterName, data)
+ );
+ }
+ });
+ }
+ try {
+ await Promise.all(requests);
+ } catch (error) {
+ console.error("Error while saving configurations: ", error);
+ }
+ };
+
+ const applyConfigsCustomization = () => {
+ recommendedPropertiesToChangeRef.current.forEach((property: any) => {
+ const value = property.saveRecommended
+ ? property.recommendedValue
+ : property.initialValue;
+ const filename = property.propertyFileName;
+ if (isArray(groupedPropertiesToChange.current)) {
+ groupedPropertiesToChange.current = flatten(
+ groupedPropertiesToChange.current
+ );
+ }
+ if (groupedPropertiesToChange.current.length) {
+ var group = groupedPropertiesToChange.current.find(
+ (item: { properties: Record<string, any> }) => {
+ return item.properties && has(item.properties, filename);
+ }
+ );
+ if (group) {
+ if (!group.properties[filename]) {
+ group.properties[filename] = {};
+ }
+ group.properties[filename][property.propertyName] = value;
+ }
+ }
+ });
+ };
+
+ const _doDeleteHostComponent = async (
+ component: IHostComponent,
+ deleteComponentSuccessCallback?: Function,
+ callback?: Function
+ ) => {
+ const componentName = get(component, "componentName");
+ const hostName = get(component, "hostName");
+ const url = componentName
+ ?
`/clusters/${clusterName}/hosts/${hostName}/host_components/${componentName}`
+ : `/clusters/${clusterName}/hosts/${hostName}`;
+
+ try {
+ await HostsApi.componentDelete(url);
+ if (setAllHostModels) {
+ setAllHostModels((prevModels: IHost[]) => {
+ return prevModels.map((host) => {
+ if (host.hostName === hostName) {
+ const updatedHost = Object.create(Object.getPrototypeOf(host));
+ Object.assign(updatedHost, {
+ ...host,
+ hostComponents: host.hostComponents.filter(
+ (hostComponent) =>
+ hostComponent.componentName !== componentName
+ ),
+ });
+ return updatedHost as IHost;
+ }
+ return host;
+ });
+ });
+ }
+ if (deleteComponentSuccessCallback) {
+ deleteComponentSuccessCallback(componentName, hostName);
+ }
+
+ if (callback) {
+ callback();
+ }
+ _deletedHostComponentError.current = "";
+ } catch (err) {
+ _deletedHostComponentError.current = JSON.stringify(err);
+ }
+ };
+
+ const loadZookeeperConfigs = async (data: any, _opt: any, params: any) => {
+ const urlParams = constructZookeeperConfigUrlParams(data).join("|");
+ if (urlParams.length > 0) {
+ const response = await HostsApi.reAssignLoadConfigs(
+ clusterName,
+ urlParams
+ );
+ params.callback(response);
+ }
+ };
+
+ const saveZkConfigs = (data: any) => {
+ let configs: any = {};
+ let attributes: any = {};
+ saveLoadedConfigs(data);
+ data.items.forEach((item: any) => {
+ configs[item.type] = item.properties;
+ attributes[item.type] = item.properties_attributes || {};
+ });
+ updateZkConfigs(configs);
+ var groups: any = [];
+ var serviceNames = map(services, "ServiceInfo.service_name");
+ var zookeeperRelatedServices = zooKeeperRelatedServices.slice(0);
+ // if (isNameNodeHAEnabled) {
+ // zookeeperRelatedServices.push({
+ // serviceName: "HDFS",
+ // typesToLoad: ["core-site"],
+ // typesToSave: ["core-site"],
+ // });
+ // }
+ zookeeperRelatedServices.forEach((service: any) => {
+ if (serviceNames.includes(service.serviceName)) {
+ var group: any = {
+ properties: {},
+ properties_attributes: {},
+ };
+
+ service.typesToSave.forEach((type: string) => {
+ if (configs[type]) {
+ group.properties[type] = configs[type];
+ group.properties_attributes[type] = attributes[type];
+ }
+ });
+ groups.push(group);
+ }
+ });
+ setConfigsChanges(groups);
+ };
+
+ const loadRangerConfigs = async (data: any, _opt: any, params: any) => {
+ const urlParams = getUrlParamsForConfigsRequest(data, [
+ "core-site",
+ "hdfs-site",
+ "kms-env",
+ "kms-site",
+ ]);
+ const response = await HostsApi.adminGetAllConfigurations(
+ clusterName,
+ urlParams
+ );
+ params.callback(response);
+ };
+
+ const onLoadRangerConfigs = (data: any) => {
+ const hdfsProperties = [
+ {
+ type: "core-site",
+ name: "hadoop.security.key.provider.path",
+ },
+ {
+ type: "hdfs-site",
+ name: "dfs.encryption.key.provider.uri",
+ },
+ ],
+ kmsSiteProperties = [
+ {
+ name: "hadoop.kms.cache.enable",
+ notHaValue: "true",
+ haValue: "false",
+ },
+ {
+ name: "hadoop.kms.authentication.zk-dt-secret-manager.enable",
+ notHaValue: "false",
+ haValue: "true",
+ },
+ {
+ name: "hadoop.kms.cache.timeout.ms",
+ notHaValue: "600000",
+ haValue: "0",
+ },
+ {
+ name: "hadoop.kms.current.key.cache.timeout.ms",
+ notHaValue: "30000",
+ haValue: "0",
+ },
+ {
+ name: "hadoop.kms.authentication.signer.secret.provider",
+ notHaValue: "random",
+ haValue: "zookeeper",
+ },
+ {
+ name:
"hadoop.kms.authentication.signer.secret.provider.zookeeper.auth.type",
+ notHaValue: "kerberos",
+ haValue: "none",
+ },
+ {
+ name:
"hadoop.kms.authentication.signer.secret.provider.zookeeper.connection.string",
+ notHaValue: "#HOSTNAME#:#PORT#,...",
+ haValue: getZookeeperConnectionString(),
+ },
+ ],
+ rkmsHosts = getRangerKMSServerHosts(),
+ rkmsHostsStr = rkmsHosts.join(";"),
+ isHA = rkmsHosts.length > 1,
+ rkmsPort = data.items.find(
+ (item: { type: string; properties: Record<string, any> }) =>
+ item.type === "kms-env"
+ )?.properties["kms_port"],
+ newValue = "kms://http@" + rkmsHostsStr + ":" + rkmsPort + "/kms",
+ coreSiteConfigs = data.items.find(
+ (item: {
+ type: string;
+ properties: Record<string, any>;
+ properties_attributes?: Record<string, any>;
+ }) => item.type === "core-site"
+ ),
+ hdfsSiteConfigs = data.items.find(
+ (item: { type: string }) => item.type === "hdfs-site"
+ ),
+ kmsSiteConfigs = data.items.find(
+ (item: { type: string }) => item.type === "kms-site"
+ ),
+ groups = [
+ {
+ properties: {
+ "core-site": coreSiteConfigs.properties,
+ "hdfs-site": hdfsSiteConfigs.properties,
+ },
+ properties_attributes: {
+ "core-site": coreSiteConfigs.properties_attributes,
+ "hdfs-site": hdfsSiteConfigs.properties_attributes,
+ },
+ },
+ {
+ properties: {
+ "kms-site": kmsSiteConfigs.properties,
+ },
+ properties_attributes: {
+ "kms-site": kmsSiteConfigs.properties_attributes,
+ },
+ },
+ ],
+ propertiesToChange = allPropertiesToChange.current;
+
+ saveLoadedConfigs(data);
+ hdfsProperties.forEach((property) => {
+ const typeConfigs = data.items.find(
+ (item: { type: string; properties: Record<string, any> }) =>
+ item.type === property.type
+ )?.properties,
+ currentValue = typeConfigs[property.name],
+ pattern = new RegExp("^kms:\\/\\/http@(.+):" + rkmsPort + "\\/kms$"),
+ patternMatch = currentValue && currentValue.match(pattern),
+ currentHostsList =
+ patternMatch && patternMatch[1].split(";").sort().join(";");
+ if (currentHostsList !== rkmsHostsStr) {
+ typeConfigs[property.name] = newValue;
+ if (isReconfigureRequired.current) {
+ const propertyFileName = property.type,
+ propertyName = property.name,
+ service =
+ getServiceByConfigTypeMap(stackServices)[propertyFileName],
+ configObject = getConfigByName(propertyName, propertyFileName);
+ const displayName = configObject && configObject.displayName;
+
+ // Ensure service display name is populated - fallback to serviceMap
if needed
+ let serviceDisplayName =
+ service && service.StackServices?.display_name;
+ if (!serviceDisplayName) {
+ const serviceNameMapping: Record<string, string> = {
+ "hive-site": "Hive",
+ "webhcat-site": "Hive",
+ "hive-env": "Hive",
+ "yarn-site": "YARN",
+ "hbase-site": "HBase",
+ "accumulo-site": "Accumulo",
+ "kafka-broker": "Kafka",
+ "application-properties": "Atlas",
+ "infra-solr-env": "Ambari Infra Solr",
+ "storm-site": "Storm",
+ "core-site": "HDFS",
+ "hdfs-site": "HDFS",
+ "kms-site": "Ranger KMS",
+ "kms-env": "Ranger KMS",
+ "zoo.cfg": "ZooKeeper",
+ };
+ serviceDisplayName =
+ serviceNameMapping[propertyFileName] || propertyFileName;
+ }
+
+ propertiesToChange.push({
+ propertyFileName,
+ propertyName,
+ propertyTitle: configObject && `Service Config: ${displayName}`,
+ propertyDescription: configObject && configObject.description,
+ serviceDisplayName: serviceDisplayName,
+ initialValue: currentValue,
+ recommendedValue: newValue,
+ saveRecommended: true,
+ });
+ }
+ }
+ });
+
+ kmsSiteProperties.forEach((property) => {
+ const currentValue = kmsSiteConfigs.properties[property.name];
+ const newValue = isHA ? property.haValue : property.notHaValue;
+ kmsSiteConfigs.properties[property.name] = newValue;
+
+ propertiesToChange.push({
+ propertyFileName: "kms-site",
+ propertyName: property.name,
+ serviceDisplayName: serviceMap["RANGER_KMS"],
+ initialValue: currentValue,
+ recommendedValue: newValue,
+ saveRecommended: true,
+ });
+ });
+
+ allPropertiesToChange.current = propertiesToChange;
+ setConfigsChanges(groups);
+ };
+
+ const setConfigsChanges = (groups: any) => {
+ groupedPropertiesToChange.current.push(groups);
+ if (allPropertiesToChange.current.length) {
+ setConfigsChangesForDisplay();
+ } else {
+ setIsConfigsLoadingInProgress(false);
+ }
+ };
+
+ const setConfigsChangesForDisplay = () => {
+ allPropertiesToChange.current.forEach((property: any) => {
+ const stackProperty = getConfigByName(
+ property.propertyName,
+ property.propertyFileName
+ );
+ if (
+ stackProperty &&
+ (!stackProperty.isEditable || !stackProperty.isReconfigurable)
+ ) {
+ requiredPropertiesToChange.current.push(property);
+ } else {
+ set(property, "saveRecommeded", true);
+ set(property, "saveRecommended", true);
+ recommendedPropertiesToChangeRef.current.push(property);
+ setRecommendedPropertiesToChange(
+ recommendedPropertiesToChangeRef.current
+ );
+ }
+ });
+ setIsConfigsLoadingInProgress(false);
+ };
+
+ const loadHiveConfigs = async (data: any, _opt: any, params: any) => {
+ const urlParams = getUrlParamsForConfigsRequest(data, [
+ "hive-site",
+ "webcat-site",
+ "hive-env",
+ "core-site",
+ ]);
+ const response = await HostsApi.adminGetAllConfigurations(
+ clusterName,
+ urlParams
+ );
+ return params.callback(response);
+ };
+
+ const onLoadHiveConfigs = (data: any, _opt: any, _params: any) => {
+ let port = "";
+ let configs: any = {};
+ let attributes: any = {};
+ let userSetup: any = {};
+ // let localDB: any = {
+ masterComponentHosts: getHiveHosts()
+ // };
+ let dependencies: any = {
+ hiveMetastorePort: "",
+ };
+ // let initializer = new AddHiveComponentsInitializer(); TODO
+ saveLoadedConfigs(data);
+ data.items.forEach((item: any) => {
+ configs[item.type] = item.properties;
+ attributes[item.type] = item.properties_attributes || {};
+ });
+
+ var propertiesToChange = allPropertiesToChange.current;
+
+ port = configs["hive-site"]["hive.metastore.uris"].match(/:[0-9]{2,4}/);
+ port = port ? port[0].slice(1) : "9083";
+ dependencies.hiveMetastorePort = port;
+ userSetup.hiveUser = configs["hive-env"]["hive_user"];
+ // @ts-ignore
+ initializer.setup(userSetup.hiveUser);
+
+ ["hive-site", "webhcat-site", "hive-env", "core-site"].forEach(
+ (fileName) => {
+ if (configs[fileName]) {
+ Object.keys(configs[fileName]).forEach((propertyName) => {
+ const currentValue = configs[fileName][propertyName];
+ const propertyDef = {
+ name: propertyName,
+ value: currentValue,
+ filename: fileName,
+ };
+ // TODO: Use initializer to get default value
+ // const configProperty = initializer.initialValue(
+ // propertyDef,
+ // localDB,
+ // dependencies
+ // );
+ // initializer.updateSiteObj(configs[fileName], configProperty);
+ if (
+ isReconfigureRequired.current &&
+ currentValue !== configs[fileName][propertyName]
+ ) {
+ const service =
+ getServiceByConfigTypeMap(stackServices)[fileName];
+ const configObject = getConfigByName(propertyName, fileName);
+ const displayName = configObject && configObject.displayName;
+
+ // Ensure service display name is populated - fallback to
serviceMap if needed
+ let serviceDisplayName =
+ service && service.StackServices?.display_name;
+ if (!serviceDisplayName) {
+ // Fallback logic for service name mapping
+ const serviceNameMapping: Record<string, string> = {
+ "hive-site": "Hive",
+ "webhcat-site": "Hive",
+ "hive-env": "Hive",
+ "yarn-site": "YARN",
+ "hbase-site": "HBase",
+ "accumulo-site": "Accumulo",
+ "kafka-broker": "Kafka",
+ "application-properties": "Atlas",
+ "infra-solr-env": "Ambari Infra Solr",
+ "storm-site": "Storm",
+ "core-site": "HDFS",
+ "zoo.cfg": "ZooKeeper",
+ };
+ serviceDisplayName = serviceNameMapping[fileName] || fileName;
+ }
+
+ propertiesToChange.push({
+ propertyFileName: fileName,
+ propertyName,
+ propertyTitle:
+ configObject &&
+ t("installer.controls.serviceConfigPopover.title")
+ .replace("{0}", displayName)
+ .replace(
+ "{1}",
+ displayName === propertyName ? "" : propertyName
+ ),
+ propertyDescription: configObject && configObject.description,
+ serviceDisplayName: serviceDisplayName,
+ initialValue: currentValue,
+ recommendedValue: propertyDef.value,
+ saveRecommended: true,
+ });
+ }
+ });
+ }
+ }
+ );
+ // initializer.cleanup();
+ //@ts-ignore
+ const uniquePropertiesToChange = propertiesToChange.filter(
+ (property: any, index: any, self: any) => {
+ const uniqueKey =
`${property.propertyFileName}-${property.propertyName}`;
+ return (
+ index ===
+ self.findIndex(
+ (p: any) => `${p.propertyFileName}-${p.propertyName}` === uniqueKey
+ )
+ );
+ }
+ );
+
+ allPropertiesToChange.current = uniquePropertiesToChange;
+
+ const newGroups = [
+ {
+ properties: {
+ "hive-site": configs["hive-site"],
+ "webhcat-site": configs["webhcat-site"],
+ "hive-env": configs["hive-env"],
+ },
+ properties_attributes: {
+ "hive-site": attributes["hive-site"],
+ "webhcat-site": attributes["webhcat-site"],
+ "hive-env": attributes["hive-env"],
+ },
+ },
+ {
+ properties: {
+ "core-site": configs["core-site"],
+ },
+ properties_attributes: {
+ "core-site": attributes["core-site"],
+ },
+ },
+ ];
+ // initializer.cleanup(); TODO
+ setConfigsChanges(newGroups);
+ };
+
+ const getZookeeperConnectionString = () => {
+ const zkHosts = get(clusterComponents, "items", [])
+ .filter((item: any) => {
+ return (
+ get(item, "ServiceComponentInfo.component_name") ===
+ "ZOOKEEPER_SERVER"
+ );
+ })
+ .flatMap((item: any) => get(item, "host_components", []))
+ .map((hostComponent: any) => {
+ return get(hostComponent, "HostRoles.host_name");
+ });
+ return zkHosts
+ .map((host: any) => {
+ return host + ":2181";
+ })
+ .join(",");
+ };
+
+ const functionMapping = {
+ loadZookeeperConfigs,
+ saveZkConfigs,
+ loadRangerConfigs,
+ onLoadRangerConfigs,
+ loadHiveConfigs,
+ onLoadHiveConfigs,
+ };
+
+ const loadComponentRelatedConfigs = async (
+ configTagsCallbackName: keyof typeof functionMapping,
+ configsCallbackName: keyof typeof functionMapping
+ ) => {
+ clearConfigsChanges();
+ setIsConfigsLoadingInProgress(true);
+ //setIsReconfigureRequired(true);
+ isReconfigureRequired.current = true;
+ const configTagsCallback =
+ functionMapping[configTagsCallbackName as keyof typeof functionMapping];
+ const configsCallback =
+ functionMapping[configsCallbackName as keyof typeof functionMapping];
+ await loadConfigs(configTagsCallback, configsCallback);
+ };
+
+ const loadConfigs = async (
+ configTagsCallback: Function,
+ configsCallback: Function
+ ) => {
+ try {
+ const params = {
+ callback: configsCallback,
+ };
+ if (
+ typeof configTagsCallback !== "function" ||
+ typeof configsCallback !== "function"
+ ) {
+ throw new Error(
+ "Invalid function references passed to loadComponentRelatedConfigs"
+ );
+ }
+ const response = await HostsApi.configTags(clusterName);
+ return await configTagsCallback(response, {}, params);
+ } catch (err) {
+ console.error("Error in loading configs: ", err);
+ }
+ };
+
+ const constructZookeeperConfigUrlParams = (data: any) => {
+ const urlParams: any = [];
+
+ let zookeeperRelatedServices = zooKeeperRelatedServices.slice(0);
+ // handle HA enabled case.
+ // if (isNameNodeHAEnabled) {
+ // zookeeperRelatedServices.push({
+ // serviceName: "HDFS",
+ // typesToLoad: ["core-site"],
+ // typesToSave: ["core-site"],
+ // });
+ // }
+ zookeeperRelatedServices.forEach((service: any) => {
+ if (
+ services.some(
+ (svc: any) => svc.ServiceInfo?.service_name === service.serviceName
+ )
+ ) {
+ service.typesToLoad.forEach((type: any) => {
+ if (data.Clusters.desired_configs[type]) {
+ urlParams.push(
+ "(type=" +
+ type +
+ "&tag=" +
+ data.Clusters.desired_configs[type].tag +
+ ")"
+ );
+ }
+ });
+ }
+ });
+ return urlParams;
+ };
+
+ const saveLoadedConfigs = (data: any) => {
+ setConfigs({
+ items: data.items.map((item: any) => {
+ return {
+ type: item.type,
+ properties_attributes: item.properties_attributes,
+ properties: item.properties,
+ };
+ }),
+ });
+ };
+
+ const clearConfigsChanges = (shouldKeepLoadingConfigs: boolean = false) => {
+ var arrayNames = [
+ "allPropertiesToChange",
+ "recommendedPropertiesToChange",
+ "requiredPropertiesToChange",
+ "groupedPropertiesToChange",
+ ];
+ arrayNames.forEach((name: string) => {
+ if (name === "allPropertiesToChange") {
+ allPropertiesToChange.current = [];
+ } else if (name === "recommendedPropertiesToChange") {
+ setRecommendedPropertiesToChange([]);
+ } else if (name === "requiredPropertiesToChange") {
+ requiredPropertiesToChange.current = [];
+ } else if (name === "groupedPropertiesToChange") {
+ groupedPropertiesToChange.current = [];
+ }
+ });
+ // setIsReconfigureRequired(false);
+ isReconfigureRequired.current = false;
+ if (!shouldKeepLoadingConfigs) {
+ setConfigs({});
+ }
+ };
+
+ const getUrlParamsForConfigsRequest = (data: any, configTypes: string[]) => {
+ return compact(
+ configTypes.map((type) => {
+ const tag = get(data, `Clusters.desired_configs.${type}.tag`, null);
+ return tag ? `(type=${type}&tag=${tag})` : null;
+ })
+ ).join("|");
+ };
+
+ const getRangerKMSServerHosts = () => {
+ var rkmsHosts = get(clusterComponents, "items", [])
+ .filter((item: any) => {
+ return (
+ get(item, "ServiceComponentInfo.component_name") ===
+ "RANGER_KMS_SERVER"
+ );
+ })
+ .flatMap((item: any) => get(item, "host_components", []))
+ .map((hostComponent: any) => {
+ return get(hostComponent, "HostRoles.host_name");
+ });
+
+ const rangerKMSServerHost = get(
+ componentProperties.current,
+ "rangerKMSServerHost",
+ null
+ );
+
+ if (rangerKMSServerHost) {
+ rkmsHosts.push(rangerKMSServerHost);
+ }
+
+ if (
+ get(componentProperties.current, "fromDeleteHost", false) ||
+ get(componentProperties.current, "deleteRangerKMSServer", false)
+ ) {
+ rkmsHosts = rkmsHosts.filter(
+ (host: string) => host !== get(componentHere.current, "hostName")
+ );
+ }
+ return rkmsHosts.sort();
+ };
+
+ const getHiveHosts = () => {
+ var removePerformed =
+ get(componentProperties.current, "fromDeleteHost", false) ||
+ get(componentProperties.current, "deleteHiveMetaStore", false) ||
+ get(componentProperties.current, "deleteHiveServer", false) ||
+ get(componentProperties.current, "deleteWebHCatServer", false);
+ var hiveMasterComponents = [
+ "WEBHCAT_SERVER",
+ "HIVE_METASTORE",
+ "HIVE_SERVER",
+ ];
+ var masterComponentsMap = hiveMasterComponents
+ .map((componentName: string) => {
+ return bootstrapHostsMapping(componentName);
+ })
+ .reduce((p: any, c: any) => {
+ return p.concat(c);
+ });
+
+ if (removePerformed) {
+ set(componentProperties.current, "deleteHiveMetaStore", false);
+ set(componentProperties.current, "deleteHiveServer", false);
+ set(componentProperties.current, "deleteWebHCatServer", false);
+ set(componentProperties.current, "fromDeleteHost", false);
+ masterComponentsMap = masterComponentsMap.map((masterComponent) => {
+ masterComponent.isInstalled =
+ masterComponent.hostName !== get(componentHere.current, "hostName");
+ return masterComponent;
+ });
+ }
+
+ if (get(componentProperties.current, "hiveMetastoreHost", false)) {
+ masterComponentsMap.push({
+ component: "HIVE_METASTORE",
+ hostName: get(componentProperties.current, "hiveMetastoreHost", ""),
+ isInstalled: !removePerformed,
+ });
+ set(componentProperties.current, "hiveMetastoreHost", "");
+ }
+
+ if (get(componentProperties.current, "hiveServerHost", false)) {
+ masterComponentsMap.push({
+ component: "HIVE_SERVER",
+ hostName: get(componentProperties.current, "hiveServerHost", ""),
+ isInstalled: !removePerformed,
+ });
+ set(componentProperties.current, "hiveServerHost", "");
+ }
+
+ if (get(componentProperties.current, "webhcatServerHost", false)) {
+ masterComponentsMap.push({
+ component: "webhcatServerHost",
+ hostName: get(componentProperties.current, "webhcatServerHost", ""),
+ isInstalled: !removePerformed,
+ });
+ set(componentProperties.current, "webhcatServerHost", "");
+ }
+ return masterComponentsMap;
+ };
+
+ const bootstrapHostsMapping = (
+ componentName: string,
+ hostNames: string[] = []
+ ) => {
+ if (
+ hostNames === null ||
+ hostNames === undefined ||
+ hostNames.length === 0
+ ) {
+ hostNames = get(clusterComponents, "items", [])
+ .filter((item: any) => {
+ return (
+ get(item, "ServiceComponentInfo.component_name") === componentName
+ );
+ })
+ .flatMap((item: any) => get(item, "host_components", []))
+ .map((hostComponent: any) => {
+ return get(hostComponent, "HostRoles.host_name");
+ });
+ }
+ return hostNames.map((hostName: string) => {
+ return {
+ component: componentName,
+ hostName: hostName,
+ isInstalled: true,
+ };
+ });
+ };
+
+ const updateZkConfigs = (configs: any) => {
+ // const portValue = configs["zoo.cfg"]?.clientPort;
+ // const zkPort = typeof portValue === "undefined" ? "2181" : portValue;
+ // const infraSolrZnode =
+ // configs["infra-solr-env"]?.infra_solr_znode || "/ambari-solr";
+
+ // const initializer = new AddZooKeeperComponentsInitializer(); TODO
+ //@ts-ignore
+ initializer.setup();
+ const hostComponentsTopology: any = {
+ masterComponentHosts: [],
+ };
+ const propertiesToChange = allPropertiesToChange.current;
+ const masterComponents = bootstrapHostsMapping("ZOOKEEPER_SERVER");
+
+ if (
+ get(componentProperties.current, "fromDeleteHost", false) ||
+ get(componentProperties.current, "fromDeleteZkServer", false)
+ ) {
+ set(componentProperties.current, "fromDeleteHost", false);
+ set(componentProperties.current, "fromDeleteZkServer", false);
+ const removedHost = masterComponents.find(
+ (host) => host.hostName === get(componentHere.current, "hostName")
+ );
+ if (removedHost) {
+ removedHost.isInstalled = false;
+ }
+ } else if (get(componentProperties.current, "addZooKeeperServer", false)) {
+ set(componentProperties.current, "addZooKeeperServer", false);
+ const changedSelectedHostName = get(
+ componentProperties.current,
+ "selectedHost",
+ ""
+ );
+ const componentHost = get(componentHere, "hostName", "");
+ const selectedHostName = changedSelectedHostName
+ ? changedSelectedHostName
+ : componentHost;
+ masterComponents.push({
+ component: "ZOOKEEPER_SERVER",
+ hostName: selectedHostName,
+ isInstalled: true,
+ });
+ }
+
+ // TODO
+ // const dependencies = {
+ // zkClientPort: zkPort,
+ // infraSolrZnode,
+ // };
+
+ hostComponentsTopology.masterComponentHosts = masterComponents;
+
+ Object.keys(configs).forEach((fileName) => {
+ const properties = configs[fileName];
+ Object.keys(properties).forEach((propertyName) => {
+ const currentValue = properties[propertyName];
+ const propertyDef = {
+ filename: fileName,
+ name: propertyName,
+ value: currentValue,
+ };
+ //TODO
+ // const configProperty = initializer.initialValue(
+ // propertyDef,
+ // hostComponentsTopology,
+ // dependencies
+ // );
+
+ // initializer.updateSiteObj(configs[fileName], configProperty);
+
+ if (currentValue !== configs[fileName][propertyName]) {
+ const service = getServiceByConfigTypeMap(stackServices)[fileName];
+ const configObject = getConfigByName(propertyName, fileName);
+ const displayName = configObject && configObject.displayName;
+
+ // Ensure service display name is populated - fallback to serviceMap
if needed
+ let serviceDisplayName =
+ service && service.StackServices?.display_name;
+ if (!serviceDisplayName) {
+ // Fallback logic for service name mapping
+ const serviceNameMapping: Record<string, string> = {
+ "hive-site": "Hive",
+ "webhcat-site": "Hive",
+ "hive-env": "Hive",
+ "yarn-site": "YARN",
+ "hbase-site": "HBase",
+ "accumulo-site": "Accumulo",
+ "kafka-broker": "Kafka",
+ "application-properties": "Atlas",
+ "infra-solr-env": "Ambari Infra Solr",
+ "storm-site": "Storm",
+ "core-site": "HDFS",
+ "zoo.cfg": "ZooKeeper",
+ };
+ serviceDisplayName = serviceNameMapping[fileName] || fileName;
+ }
+
+ propertiesToChange.push({
+ propertyFileName: fileName,
+ propertyName,
+ propertyTitle:
+ configObject &&
+ t("installer.controls.serviceConfigPopover.title")
+ .replace("{0}", displayName)
+ .replace(
+ "{1}",
+ displayName === propertyName ? "" : propertyName
+ ),
+ propertyDescription: configObject && configObject.description,
+ serviceDisplayName: serviceDisplayName,
+ initialValue: currentValue,
+ recommendedValue: propertyDef.value,
+ saveRecommended: true,
+ });
+ }
+ });
+ });
+
+ allPropertiesToChange.current = propertiesToChange;
+ };
+
+ return {
+ deleteAndReconfigureComponent,
+ _doDeleteHostComponent,
+ loadComponentRelatedConfigs,
+ saveLoadedConfigs,
+ configs,
+ setConfigs,
+ // setIsReconfigureRequired,
+ setIsConfigsLoadingInProgress,
+ isReconfigureRequired: isReconfigureRequired.current,
+ isConfigsLoadingInProgress,
+ allPropertiesToChange,
+ recommendedPropertiesToChange,
+ requiredPropertiesToChange,
+ groupedPropertiesToChange,
+ _deletedHostComponentError,
+ clearConfigsChanges,
+ loadConfigs,
+ getUrlParamsForConfigsRequest,
+ applyConfigsCustomization,
+ putConfigsToServer,
+ setRecommendedPropertiesToChange,
+ };
+}
+
+export default useComponentAddDelete;
diff --git a/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
b/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
index a0a684078f..579d4ae518 100644
--- a/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
+++ b/ambari-web/latest/src/screens/Hosts/HostSummary.tsx
@@ -88,7 +88,8 @@ import {
executeCustomCommand,
installClients,
installComponent,
- refreshComponentConfigs
+ refreshComponentConfigs,
+ deleteComponent,
} from "./actions";
import { AppContext } from "../../store/context";
import IHost from "../../models/host";
@@ -107,6 +108,7 @@ import { hostMetricsOption } from "./constants";
import usePolling from "../../hooks/usePolling";
import classNames from "classnames";
import { useAuth } from "../../hooks/useAuth";
+import useComponentAddDelete from "../../hooks/useComponentAddDelete";
type HostSummaryProps = {
allHostModels: IHost[];
@@ -135,6 +137,22 @@ export default function HostsSummary({
//Note:- Below states should be part of the context
const [allComponents, setAllComponents] = useState<IHostComponent[]>([]);
const [addableComponents, setAddableComponents] = useState<any[]>([]);
+ // const { services: stackServices } = useStackServices(); //TODO will be
added later.
+ // const { getConfigByName } = useConfigs([], stackServices as any); //
TODO will be added later.
+
+ const stackServices = "";
+ const getConfigByName = () => {};
+
+ // const serviceConfigMap = getServiceByConfigTypeMap(stackServices);
+ const {
+ deleteAndReconfigureComponent,
+ _doDeleteHostComponent,
+ } = useComponentAddDelete(
+ clusterComponents,
+ stackServices,
+ getConfigByName,
+ setAllHostModels
+ );
const [summary, setSummary] = useState({
Hostname: "",
@@ -828,7 +846,19 @@ export default function HostsSummary({
: ""
}
onClick={() => {
- //TODO: Will be implemented in future PR
+ if (
+ !isDeleteComponentDisabled(
+ component,
+ get(clusterComponents, "items", [])
+ )
+ ) {
+ const data = {
+ deleteAndReconfigureComponent,
+ _doDeleteHostComponent,
+ navigate,
+ };
+ deleteComponent(component, data);
+ }
}}
>
Delete
diff --git a/ambari-web/latest/src/screens/Hosts/actions.tsx
b/ambari-web/latest/src/screens/Hosts/actions.tsx
index d61260d650..12048140d0 100644
--- a/ambari-web/latest/src/screens/Hosts/actions.tsx
+++ b/ambari-web/latest/src/screens/Hosts/actions.tsx
@@ -19,6 +19,7 @@
import { capitalize, cloneDeep, get, set, uniq } from "lodash";
import { HostsApi } from "../../api/hostsApi";
import {
+ addDeleteComponentsMap,
doDecommissionRegionServer,
doRecommissionAndStart,
getComponentDisplayName,
@@ -42,6 +43,7 @@ import ConfirmationModal from
"../../components/ConfirmationModal";
import { IHost } from "../../models/host";
import { t } from "i18next";
import { CompatibleComponent, ComponentDependency } from
"./utils/ComponentDependency";
+import RecommendationModal from "../../components/RecommendationModal";
export const sendComponentCommand = async (
component: IHostComponent,
@@ -686,4 +688,26 @@ export const refreshComponentConfigs = async (component:
IHostComponent) => {
});
await HostsApi.clusterRequests(clusterName, data);
+};
+export const deleteComponent = async (component: IHostComponent, data: any) =>
{
+ const componentName = get(component, "componentName");
+ const componentsMapItem = get(addDeleteComponentsMap, componentName);
+
+ if (componentsMapItem) {
+ data.deleteAndReconfigureComponent(componentsMapItem, component);
+ } else if (componentName === "JOURNALNODE") {
+ data.navigate("/main/services/highAvailability/JournalNode/manage/step1");
+ } else {
+ modalManager.show(
+ <RecommendationModal
+ isOpen={true}
+ onClose={() => {
+ modalManager.hide();
+ }}
+ componentDisplayName={getComponentDisplayName(component)}
+ add={false}
+ callback={() => data._doDeleteHostComponent(component)}
+ />
+ );
+ }
};
\ No newline at end of file
diff --git a/ambari-web/latest/src/screens/Hosts/utils.tsx
b/ambari-web/latest/src/screens/Hosts/utils.tsx
index 26a70dc26c..325d9feda4 100644
--- a/ambari-web/latest/src/screens/Hosts/utils.tsx
+++ b/ambari-web/latest/src/screens/Hosts/utils.tsx
@@ -226,6 +226,44 @@ const serviceSpecificParams = {
SSM: "host_components/processes/HostComponentProcess",
};
+export const zooKeeperRelatedServices = [
+ {
+ serviceName: "HIVE",
+ typesToLoad: ["hive-site", "webhcat-site"],
+ typesToSave: ["hive-site", "webhcat-site"],
+ },
+ {
+ serviceName: "YARN",
+ typesToLoad: ["yarn-site", "zoo.cfg"],
+ typesToSave: ["yarn-site"],
+ },
+ {
+ serviceName: "HBASE",
+ typesToLoad: ["hbase-site"],
+ typesToSave: ["hbase-site"],
+ },
+ {
+ serviceName: "ACCUMULO",
+ typesToLoad: ["accumulo-site"],
+ typesToSave: ["accumulo-site"],
+ },
+ {
+ serviceName: "KAFKA",
+ typesToLoad: ["kafka-broker"],
+ typesToSave: ["kafka-broker"],
+ },
+ {
+ serviceName: "ATLAS",
+ typesToLoad: ["application-properties", "infra-solr-env"],
+ typesToSave: ["application-properties"],
+ },
+ {
+ serviceName: "STORM",
+ typesToLoad: ["storm-site"],
+ typesToSave: ["storm-site"],
+ },
+];
+
var requestsRunningStatus = {
updateServiceMetric: false,
};
@@ -1480,4 +1518,16 @@ const createServiceComponent = (
}).ServiceComponentInfo.service_name;
HostsApi.commonCreateComponent(clusterName, serviceName, payload);
}
-};
\ No newline at end of file
+};
+
+export function getServiceByConfigTypeMap(stackServices: any) {
+ let ret: any = {};
+ stackServices?.forEach(function (s: any) {
+ Object.keys(get(s, "StackServices.config_types", {})).forEach(function (
+ ct
+ ) {
+ ret[ct] = s;
+ });
+ });
+ return ret;
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]