1+ use std:: process:: Command ;
2+ use std:: str;
3+
4+ #[ derive( Debug , Clone ) ]
5+ pub enum Component {
6+ ControlPlane ,
7+ DataPlane ,
8+ }
9+
10+ impl From < String > for Component {
11+ fn from ( s : String ) -> Self {
12+ match s. to_lowercase ( ) . as_str ( ) {
13+ "control-plane" => Component :: ControlPlane ,
14+ "data-plane" => Component :: DataPlane ,
15+ //default will be control plane.
16+ _ => Component :: ControlPlane ,
17+ }
18+ }
19+ }
20+
21+ impl Component {
22+ fn to_label_selector ( & self ) -> & str {
23+ match self {
24+ Component :: ControlPlane => "component=control-plane" ,
25+ Component :: DataPlane => "component=data-plane" ,
26+ }
27+ }
28+ }
29+
30+ fn check_namespace_exists ( namespace : & str ) -> bool {
31+ let output = Command :: new ( "kubectl" )
32+ . args ( [ "get" , "namespace" , namespace] )
33+ . output ( ) ;
34+
35+ match output {
36+ Ok ( output) => output. status . success ( ) ,
37+ Err ( _) => false ,
38+ }
39+ }
40+
41+ fn get_available_namespaces ( ) -> Vec < String > {
42+ let output = Command :: new ( "kubectl" )
43+ . args ( [ "get" , "namespaces" , "--no-headers" , "-o" , "custom-columns=NAME:.metadata.name" ] )
44+ . output ( ) ;
45+
46+ match output {
47+ Ok ( output) if output. status . success ( ) => {
48+ let stdout = str:: from_utf8 ( & output. stdout ) . unwrap_or ( "" ) ;
49+ stdout. lines ( )
50+ . map ( |line| line. trim ( ) . to_string ( ) )
51+ . filter ( |line| !line. is_empty ( ) )
52+ . collect ( )
53+ }
54+ _ => Vec :: new ( ) ,
55+ }
56+ }
57+
58+ fn get_pods_for_service ( namespace : & str , service_name : & str ) -> Vec < String > {
59+ let output = Command :: new ( "kubectl" )
60+ . args ( [ "get" , "pods" , "-n" , namespace, "-l" , & format ! ( "app={}" , service_name) , "--no-headers" , "-o" , "custom-columns=NAME:.metadata.name" ] )
61+ . output ( ) ;
62+
63+ match output {
64+ Ok ( output) if output. status . success ( ) => {
65+ let stdout = str:: from_utf8 ( & output. stdout ) . unwrap_or ( "" ) ;
66+ stdout. lines ( )
67+ . map ( |line| line. trim ( ) . to_string ( ) )
68+ . filter ( |line| !line. is_empty ( ) )
69+ . collect ( )
70+ }
71+ _ => Vec :: new ( ) ,
72+ }
73+ }
74+
75+ fn get_pods_for_component ( namespace : & str , component : & Component ) -> Vec < String > {
76+ let output = Command :: new ( "kubectl" )
77+ . args ( [ "get" , "pods" , "-n" , namespace, "-l" , component. to_label_selector ( ) , "--no-headers" , "-o" , "custom-columns=NAME:.metadata.name" ] )
78+ . output ( ) ;
79+
80+ match output {
81+ Ok ( output) if output. status . success ( ) => {
82+ let stdout = str:: from_utf8 ( & output. stdout ) . unwrap_or ( "" ) ;
83+ stdout. lines ( )
84+ . map ( |line| line. trim ( ) . to_string ( ) )
85+ . filter ( |line| !line. is_empty ( ) )
86+ . collect ( )
87+ }
88+ _ => Vec :: new ( ) ,
89+ }
90+ }
91+
92+ fn get_all_pods ( namespace : & str ) -> Vec < String > {
93+ let output = Command :: new ( "kubectl" )
94+ . args ( [ "get" , "pods" , "-n" , namespace, "--no-headers" , "-o" , "custom-columns=NAME:.metadata.name" ] )
95+ . output ( ) ;
96+
97+ match output {
98+ Ok ( output) if output. status . success ( ) => {
99+ let stdout = str:: from_utf8 ( & output. stdout ) . unwrap_or ( "" ) ;
100+ stdout. lines ( )
101+ . map ( |line| line. trim ( ) . to_string ( ) )
102+ . filter ( |line| !line. is_empty ( ) )
103+ . collect ( )
104+ }
105+ _ => Vec :: new ( ) ,
106+ }
107+ }
108+
109+ pub fn logs_command ( service : Option < String > , component : Option < String > , namespace : Option < String > ) {
110+ let ns = namespace. unwrap_or_else ( || "cortexflow" . to_string ( ) ) ;
111+
112+ // namespace check
113+ if !check_namespace_exists ( & ns) {
114+ let available_namespaces = get_available_namespaces ( ) ;
115+
116+ println ! ( "\n ❌ Namespace '{}' not found" , ns) ;
117+ println ! ( "{}" , "=" . repeat( 50 ) ) ;
118+
119+ if !available_namespaces. is_empty ( ) {
120+ println ! ( "\n 📋 Available namespaces:" ) ;
121+ for available_ns in & available_namespaces {
122+ println ! ( " • {}" , available_ns) ;
123+ }
124+ } else {
125+ println ! ( "No namespaces found in the cluster." ) ;
126+ }
127+
128+ std:: process:: exit ( 1 ) ;
129+ }
130+
131+ // determine pods.
132+ let pods = match ( service, component) {
133+ ( Some ( service_name) , Some ( component_str) ) => {
134+ let comp = Component :: from ( component_str) ;
135+ println ! ( "Getting logs for service '{}' with component '{:?}' in namespace '{}'" , service_name, comp, ns) ;
136+
137+ let service_pods = get_pods_for_service ( & ns, & service_name) ;
138+ let component_pods = get_pods_for_component ( & ns, & comp) ;
139+
140+ // intersection
141+ service_pods. into_iter ( )
142+ . filter ( |pod| component_pods. contains ( pod) )
143+ . collect ( )
144+ }
145+ ( Some ( service_name) , None ) => {
146+ //only service
147+ println ! ( "Getting logs for service '{}' in namespace '{}'" , service_name, ns) ;
148+ get_pods_for_service ( & ns, & service_name)
149+ }
150+ ( None , Some ( component_str) ) => {
151+ //only component
152+ let comp = Component :: from ( component_str) ;
153+ println ! ( "Getting logs for component '{:?}' in namespace '{}'" , comp, ns) ;
154+ get_pods_for_component ( & ns, & comp)
155+ }
156+ ( None , None ) => {
157+ //neither, get all
158+ println ! ( "Getting logs for all pods in namespace '{}'" , ns) ;
159+ get_all_pods ( & ns)
160+ }
161+ } ;
162+
163+ if pods. is_empty ( ) {
164+ println ! ( "No pods found matching the specified criteria" ) ;
165+ return ;
166+ }
167+
168+ for pod in pods {
169+ println ! ( "\n {}" , "=" . repeat( 80 ) ) ;
170+ println ! ( "📋 Logs for pod: {}" , pod) ;
171+ println ! ( "{}" , "=" . repeat( 80 ) ) ;
172+
173+ let output = Command :: new ( "kubectl" )
174+ . args ( [ "logs" , & pod, "-n" , & ns, "--tail=50" ] )
175+ . output ( ) ;
176+
177+ match output {
178+ Ok ( output) => {
179+ if output. status . success ( ) {
180+ let stdout = str:: from_utf8 ( & output. stdout ) . unwrap_or ( "" ) ;
181+ if stdout. trim ( ) . is_empty ( ) {
182+ println ! ( "No logs available for pod '{}'" , pod) ;
183+ } else {
184+ println ! ( "{}" , stdout) ;
185+ }
186+ } else {
187+ let stderr = str:: from_utf8 ( & output. stderr ) . unwrap_or ( "Unknown error" ) ;
188+ eprintln ! ( "Error getting logs for pod '{}': {}" , pod, stderr) ;
189+ }
190+ }
191+ Err ( err) => {
192+ eprintln ! ( "Failed to execute kubectl logs for pod '{}': {}" , pod, err) ;
193+ }
194+ }
195+ }
196+ }
0 commit comments