1111//!
1212use std:: { collections:: BTreeMap , str:: FromStr } ;
1313
14- use indoc:: { formatdoc, indoc } ;
14+ use indoc:: formatdoc;
1515use snafu:: { OptionExt , ResultExt , Snafu } ;
1616use stackable_operator:: {
1717 builder:: {
@@ -41,8 +41,7 @@ use stackable_operator::{
4141 product_logging:: {
4242 self ,
4343 framework:: {
44- LoggingError , capture_shell_output, create_vector_shutdown_file_command,
45- remove_vector_shutdown_file_command,
44+ LoggingError , create_vector_shutdown_file_command, remove_vector_shutdown_file_command,
4645 } ,
4746 spec:: {
4847 AutomaticContainerLogConfig , ConfigMapLogConfig , ContainerLogConfig ,
@@ -666,7 +665,8 @@ impl ContainerConfig {
666665 ) ) ;
667666 }
668667 ContainerConfig :: FormatNameNodes { container_name, .. } => {
669- args. push_str ( & add_capture_shell_output ( container_name) ) ;
668+ args. push_str ( & bash_capture_shell_helper ( container_name) ) ;
669+ args. push_str ( "start_capture\n " ) ;
670670
671671 if let Some ( container_config) = merged_config. as_namenode ( ) . map ( |node| {
672672 node. logging
@@ -693,40 +693,35 @@ impl ContainerConfig {
693693 for namenode_id in {pod_names}
694694 do
695695 echo -n "Checking pod $namenode_id... "
696- {get_service_state_command}
696+ # We only redirect 2 (stderr) to 4 (console).
697+ # We leave 1 (stdout) alone so the $(...) can catch it.
698+ SERVICE_STATE=$({hadoop_home}/bin/hdfs haadmin -getServiceState "$namenode_id" 2>&4 | tail -n1 || true)
699+
697700 if [ "$SERVICE_STATE" == "active" ]
698701 then
699- ACTIVE_NAMENODE=$namenode_id
702+ ACTIVE_NAMENODE=" $namenode_id"
700703 echo "active"
701704 break
705+ else
706+ echo "unknown"
702707 fi
703- echo ""
704708 done
705709
706710 if [ ! -f "{NAMENODE_ROOT_DATA_DIR}/current/VERSION" ]
707711 then
708712 if [ -z ${{ACTIVE_NAMENODE+x}} ]
709713 then
710714 echo "Create pod $POD_NAME as active namenode."
711- # Restore original stdout/stderr from FD 3 and 4
712- exec 1>&3 2>&4
713- # Clean up (close FD 3 and 4)
714- exec 3>&- 4>&-
715- {hadoop_home}/bin/hdfs namenode -format -noninteractive
715+ exclude_from_capture {hadoop_home}/bin/hdfs namenode -format -noninteractive
716716 else
717717 echo "Create pod $POD_NAME as standby namenode."
718- # Restore original stdout/stderr from FD 3 and 4
719- exec 1>&3 2>&4
720- # Clean up (close FD 3 and 4)
721- exec 3>&- 4>&-
722- {hadoop_home}/bin/hdfs namenode -bootstrapStandby -nonInteractive
718+ exclude_from_capture {hadoop_home}/bin/hdfs namenode -bootstrapStandby -nonInteractive
723719 fi
724720 else
725721 cat "{NAMENODE_ROOT_DATA_DIR}/current/VERSION"
726722 echo "Pod $POD_NAME already formatted. Skipping..."
727723 fi
728724 "### ,
729- get_service_state_command = Self :: get_namenode_service_state_command( ) ,
730725 hadoop_home = Self :: HADOOP_HOME ,
731726 pod_names = namenode_podrefs
732727 . iter( )
@@ -736,8 +731,8 @@ impl ContainerConfig {
736731 ) ) ;
737732 }
738733 ContainerConfig :: FormatZooKeeper { container_name, .. } => {
739- args. push_str ( & add_capture_shell_output ( container_name) ) ;
740-
734+ args. push_str ( & bash_capture_shell_helper ( container_name) ) ;
735+ args . push_str ( "start_capture \n " ) ;
741736 if let Some ( container_config) = merged_config. as_namenode ( ) . map ( |node| {
742737 node. logging
743738 . for_container ( & NameNodeContainer :: FormatZooKeeper )
@@ -775,9 +770,7 @@ impl ContainerConfig {
775770 hadoop_home = Self :: HADOOP_HOME ,
776771 ) ) ;
777772 }
778- ContainerConfig :: WaitForNameNodes { container_name, .. } => {
779- args. push_str ( & add_capture_shell_output ( container_name) ) ;
780-
773+ ContainerConfig :: WaitForNameNodes { .. } => {
781774 if let Some ( container_config) = merged_config. as_datanode ( ) . map ( |node| {
782775 node. logging
783776 . for_container ( & DataNodeContainer :: WaitForNameNodes )
@@ -1585,17 +1578,44 @@ impl TryFrom<&str> for ContainerVolumeDirs {
15851578 }
15861579}
15871580
1588- fn add_capture_shell_output ( container_name : & str ) -> String {
1581+ fn bash_capture_shell_helper ( container_name : & str ) -> String {
15891582 let capture_shell_output = product_logging:: framework:: capture_shell_output (
15901583 STACKABLE_LOG_DIR ,
15911584 container_name,
15921585 // we do not access any of the crd config options for this and just log it to file
15931586 & AutomaticContainerLogConfig :: default ( ) ,
15941587 ) ;
1595- formatdoc ! { r###"
1596- # Save original stdout/stderr to FD 3 and 4
1597- exec 3>&1 4>&2
1598- {capture_shell_output}
1599- "###
1588+
1589+ formatdoc ! {
1590+ r###"
1591+ # Store the original stdout/stderr globally so we can always find our way back
1592+ # 3 and 4 are usually safe, but we'll be explicit.
1593+ exec 3>&1
1594+ exec 4>&2
1595+
1596+ start_capture() {{
1597+ # We redirect 1 and 2 to the background tee processes
1598+ {capture_shell_output}
1599+ }}
1600+
1601+ stop_capture() {{
1602+ # Restore stdout and stderr from our saved descriptors
1603+ exec 1>&3 2>&4
1604+ }}
1605+
1606+ exclude_from_capture() {{
1607+ # Temporarily restore original FDs just for the duration of this command
1608+ # We use 'local' for the exit code to keep things clean
1609+ set +e
1610+ "$@" 1>&3 2>&4
1611+ local exit_code=$?
1612+ set -e
1613+
1614+ # If the command failed, we manually trigger the exit since we set +e
1615+ if [ $exit_code -ne 0 ]; then
1616+ exit $exit_code
1617+ fi
1618+ }}
1619+ "###
16001620 }
16011621}
0 commit comments