44 "context"
55 "fmt"
66 "io"
7+ "path/filepath"
78 "strings"
89 "time"
910
@@ -70,10 +71,7 @@ func (c *CollectLogs) Collect(progressChan chan<- interface{}) (CollectorResult,
7071 }
7172
7273 for _ , containerName := range containerNames {
73- if len (containerNames ) == 1 {
74- containerName = "" // if there was only one container, use the old behavior of not including the container name in the path
75- }
76- podLogs , err := savePodLogs (ctx , c .BundlePath , client , pod , c .Collector .Name , containerName , c .Collector .Limits , false )
74+ podLogs , err := savePodLogs (ctx , c .BundlePath , client , & pod , c .Collector .Name , containerName , c .Collector .Limits , false )
7775 if err != nil {
7876 key := fmt .Sprintf ("%s/%s-errors.json" , c .Collector .Name , pod .Name )
7977 if containerName != "" {
@@ -91,7 +89,7 @@ func (c *CollectLogs) Collect(progressChan chan<- interface{}) (CollectorResult,
9189 }
9290 } else {
9391 for _ , container := range c .Collector .ContainerNames {
94- containerLogs , err := savePodLogs (ctx , c .BundlePath , client , pod , c .Collector .Name , container , c .Collector .Limits , false )
92+ containerLogs , err := savePodLogs (ctx , c .BundlePath , client , & pod , c .Collector .Name , container , c .Collector .Limits , false )
9593 if err != nil {
9694 key := fmt .Sprintf ("%s/%s/%s-errors.json" , c .Collector .Name , pod .Name , container )
9795 err := output .SaveResult (c .BundlePath , key , marshalErrors ([]string {err .Error ()}))
@@ -111,7 +109,7 @@ func (c *CollectLogs) Collect(progressChan chan<- interface{}) (CollectorResult,
111109 return output , nil
112110}
113111
114- func listPodsInSelectors (ctx context.Context , client * kubernetes.Clientset , namespace string , selector []string ) ([]corev1.Pod , []string ) {
112+ func listPodsInSelectors (ctx context.Context , client kubernetes.Interface , namespace string , selector []string ) ([]corev1.Pod , []string ) {
115113 serializedLabelSelector := strings .Join (selector , "," )
116114
117115 listOptions := metav1.ListOptions {
@@ -126,20 +124,54 @@ func listPodsInSelectors(ctx context.Context, client *kubernetes.Clientset, name
126124 return pods .Items , nil
127125}
128126
129- func savePodLogs (ctx context.Context , bundlePath string , client * kubernetes.Clientset , pod corev1.Pod , name , container string , limits * troubleshootv1beta2.LogLimits , follow bool ) (CollectorResult , error ) {
127+ func savePodLogs (
128+ ctx context.Context ,
129+ bundlePath string ,
130+ client * kubernetes.Clientset ,
131+ pod * corev1.Pod ,
132+ collectorName , container string ,
133+ limits * troubleshootv1beta2.LogLimits ,
134+ follow bool ,
135+ ) (CollectorResult , error ) {
136+ return savePodLogsWithInterface (ctx , bundlePath , client , pod , collectorName , container , limits , follow )
137+ }
138+
139+ func savePodLogsWithInterface (
140+ ctx context.Context ,
141+ bundlePath string ,
142+ client kubernetes.Interface ,
143+ pod * corev1.Pod ,
144+ collectorName , container string ,
145+ limits * troubleshootv1beta2.LogLimits ,
146+ follow bool ,
147+ ) (CollectorResult , error ) {
130148 podLogOpts := corev1.PodLogOptions {
131149 Follow : follow ,
132150 Container : container ,
133151 }
134152
135- setLogLimits ( & podLogOpts , limits , convertMaxAgeToTime )
153+ result := NewResult ( )
136154
137- fileKey := fmt .Sprintf ("%s/%s" , name , pod .Name )
155+ // TODO: Abstract away hard coded directory structure paths
156+ // Maybe create a FS provider or something similar
157+ filePathPrefix := filepath .Join (
158+ "cluster-resources" , "pods" , "logs" , pod .Namespace , pod .Name , pod .Spec .Containers [0 ].Name ,
159+ )
160+
161+ // TODO: If collectorName is empty, the path is stored with a leading slash
162+ // Retain this behavior otherwise analysers in the wild may break
163+ // Analysers that need to find a file in the root of the bundle should
164+ // prefix the path with a slash e.g /file.txt. This behavior should be
165+ // properly deprecated in the future.
166+ linkRelPathPrefix := fmt .Sprintf ("%s/%s" , collectorName , pod .Name )
138167 if container != "" {
139- fileKey = fmt .Sprintf ("%s/%s/%s" , name , pod .Name , container )
168+ linkRelPathPrefix = fmt .Sprintf ("%s/%s/%s" , collectorName , pod .Name , container )
169+ filePathPrefix = filepath .Join (
170+ "cluster-resources" , "pods" , "logs" , pod .Namespace , pod .Name , container ,
171+ )
140172 }
141173
142- result := NewResult ( )
174+ setLogLimits ( & podLogOpts , limits , convertMaxAgeToTime )
143175
144176 req := client .CoreV1 ().Pods (pod .Namespace ).GetLogs (pod .Name , & podLogOpts )
145177 podLogs , err := req .Stream (ctx )
@@ -148,11 +180,13 @@ func savePodLogs(ctx context.Context, bundlePath string, client *kubernetes.Clie
148180 }
149181 defer podLogs .Close ()
150182
151- logWriter , err := result .GetWriter (bundlePath , fileKey + ".log" )
183+ logWriter , err := result .GetWriter (bundlePath , filePathPrefix + ".log" )
152184 if err != nil {
153185 return nil , errors .Wrap (err , "failed to get log writer" )
154186 }
155- defer result .CloseWriter (bundlePath , fileKey + ".log" , logWriter )
187+ // NOTE: deferred calls are executed in LIFO order i.e called in reverse order
188+ defer result .SymLinkResult (bundlePath , linkRelPathPrefix + ".log" , filePathPrefix + ".log" )
189+ defer result .CloseWriter (bundlePath , filePathPrefix + ".log" , logWriter )
156190
157191 _ , err = io .Copy (logWriter , podLogs )
158192 if err != nil {
@@ -168,11 +202,13 @@ func savePodLogs(ctx context.Context, bundlePath string, client *kubernetes.Clie
168202 }
169203 defer podLogs .Close ()
170204
171- prevLogWriter , err := result .GetWriter (bundlePath , fileKey + "-previous.log" )
205+ prevLogWriter , err := result .GetWriter (bundlePath , filePathPrefix + "-previous.log" )
172206 if err != nil {
173207 return nil , errors .Wrap (err , "failed to get previous log writer" )
174208 }
175- defer result .CloseWriter (bundlePath , fileKey + "-previous.log" , logWriter )
209+ // NOTE: deferred calls are executed in LIFO order i.e called in reverse order
210+ defer result .SymLinkResult (bundlePath , linkRelPathPrefix + "-previous.log" , filePathPrefix + "-previous.log" )
211+ defer result .CloseWriter (bundlePath , filePathPrefix + "-previous.log" , logWriter )
176212
177213 _ , err = io .Copy (prevLogWriter , podLogs )
178214 if err != nil {
0 commit comments