@@ -20,6 +20,7 @@ import (
20
20
"encoding/json"
21
21
"fmt"
22
22
"io"
23
+
23
24
"net"
24
25
"os"
25
26
"path"
@@ -29,21 +30,27 @@ import (
29
30
"time"
30
31
31
32
"github.com/cheggaaa/pb/v3"
33
+ "github.com/spf13/afero"
32
34
"github.com/spf13/cobra"
33
35
"golang.org/x/sync/errgroup"
34
36
"golang.org/x/time/rate"
35
37
"gopkg.in/yaml.v2"
38
+ corev1 "k8s.io/api/core/v1"
36
39
"k8s.io/apimachinery/pkg/api/meta"
37
40
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38
41
k8sruntime "k8s.io/apimachinery/pkg/runtime"
42
+ utilerror "k8s.io/apimachinery/pkg/util/errors"
43
+ "k8s.io/apimachinery/pkg/util/sets"
39
44
"k8s.io/client-go/kubernetes"
40
45
"k8s.io/client-go/rest"
41
46
"k8s.io/klog/v2"
42
47
43
48
"antrea.io/antrea/pkg/antctl/raw"
44
49
"antrea.io/antrea/pkg/antctl/runtime"
50
+ "antrea.io/antrea/pkg/apis/crd/v1beta1"
45
51
systemv1beta1 "antrea.io/antrea/pkg/apis/system/v1beta1"
46
52
antrea "antrea.io/antrea/pkg/client/clientset/versioned"
53
+ "antrea.io/antrea/pkg/util/compress"
47
54
"antrea.io/antrea/pkg/util/ip"
48
55
"antrea.io/antrea/pkg/util/k8s"
49
56
)
@@ -59,6 +66,10 @@ const (
59
66
// Command is the support bundle command implementation.
60
67
var Command * cobra.Command
61
68
69
+ var (
70
+ defaultFS = afero .NewOsFs ()
71
+ )
72
+
62
73
var option = & struct {
63
74
dir string
64
75
labelSelector string
@@ -533,6 +544,20 @@ func controllerRemoteRunE(cmd *cobra.Command, args []string) error {
533
544
return fmt .Errorf ("failed to create clientset: %w" , err )
534
545
}
535
546
547
+ if err := os .MkdirAll (option .dir , 0700 | os .ModeDir ); err != nil {
548
+ return fmt .Errorf ("error when creating output dir: %w" , err )
549
+ }
550
+
551
+ f , err := os .Create (filepath .Join (option .dir , "clusterinfo" ))
552
+ if err != nil {
553
+ return err
554
+ }
555
+ defer f .Close ()
556
+ err = getClusterInfo (f , k8sClientset )
557
+ if err != nil {
558
+ return err
559
+ }
560
+
536
561
var controllerClient * rest.RESTClient
537
562
var agentClients map [string ]* rest.RESTClient
538
563
@@ -577,29 +602,17 @@ func controllerRemoteRunE(cmd *cobra.Command, args []string) error {
577
602
return fmt .Errorf ("no matched Nodes found to collect agent bundles" )
578
603
}
579
604
580
- if err := os .MkdirAll (option .dir , 0700 | os .ModeDir ); err != nil {
581
- return fmt .Errorf ("error when creating output dir: %w" , err )
582
- }
583
605
amount := len (agentClients ) * 2
584
606
if controllerClient != nil {
585
607
amount += 2
586
608
}
587
609
bar := barTmpl .Start (amount )
588
610
defer bar .Finish ()
589
611
defer bar .Set ("prefix" , "Finish " )
590
- f , err := os .Create (filepath .Join (option .dir , "clusterinfo" ))
591
- if err != nil {
592
- return err
593
- }
594
- defer f .Close ()
595
- err = getClusterInfo (f , k8sClientset )
596
- if err != nil {
597
- return err
598
- }
599
612
600
613
results := requestAll (agentClients , controllerClient , bar )
601
614
results = downloadAll (agentClients , controllerClient , dir , bar , results )
602
- return processResults (results , dir )
615
+ return processResults (antreaClientset , k8sClientset , results , dir )
603
616
}
604
617
605
618
func genErrorMsg (resultMap map [string ]error ) string {
@@ -611,8 +624,9 @@ func genErrorMsg(resultMap map[string]error) string {
611
624
}
612
625
613
626
// processResults will output the failed nodes and their reasons if any. If no data was collected,
614
- // error is returned, otherwise will return nil.
615
- func processResults (resultMap map [string ]error , dir string ) error {
627
+ // error is returned, otherwise will return nil. For failed nodes and controller, will also try to get logs from
628
+ // kubernetes api.
629
+ func processResults (antreaClientset antrea.Interface , k8sClient kubernetes.Interface , resultMap map [string ]error , dir string ) error {
616
630
resultStr := ""
617
631
var failedNodes []string
618
632
allFailed := true
@@ -628,7 +642,8 @@ func processResults(resultMap map[string]error, dir string) error {
628
642
}
629
643
}
630
644
631
- if resultMap ["" ] != nil {
645
+ controllerFail := resultMap ["" ] != nil
646
+ if controllerFail {
632
647
fmt .Println ("Controller Info Failed Reason: " + resultMap ["" ].Error ())
633
648
}
634
649
@@ -641,9 +656,184 @@ func processResults(resultMap map[string]error, dir string) error {
641
656
err = writeFailedNodes (dir , failedNodes )
642
657
}
643
658
659
+ if controllerFail {
660
+ err := downloadControllerBundleFromKubernetes (antreaClientset , k8sClient , dir )
661
+ if err != nil {
662
+ fmt .Println ("Failed to download controller logs from kubernetes api: " + err .Error ())
663
+ } else {
664
+ allFailed = false
665
+ }
666
+ }
667
+
668
+ // download logs from kubernetes api
669
+ if failedNodes != nil {
670
+ err := downloadAgentBundleFromKubernetes (antreaClientset , k8sClient , failedNodes , dir )
671
+ if err != nil {
672
+ fmt .Println ("Failed to download agent logs from kubernetes api: " + err .Error ())
673
+ } else {
674
+ allFailed = false
675
+ }
676
+ }
677
+
644
678
if allFailed {
645
679
return fmt .Errorf ("no data was collected: %s" , genErrorMsg (resultMap ))
646
680
} else {
647
681
return err
648
682
}
649
683
}
684
+
685
+ func downloadControllerBundleFromKubernetes (antreaClientset antrea.Interface , k8sClient kubernetes.Interface , dir string ) error {
686
+ var errors []error
687
+ controllerInfo , err := antreaClientset .CrdV1beta1 ().AntreaControllerInfos ().Get (context .TODO (), "antrea-controller" , metav1.GetOptions {})
688
+ if err != nil {
689
+ errors = append (errors , err )
690
+ }
691
+
692
+ pods , err := k8sClient .CoreV1 ().Pods ("kube-system" ).List (context .TODO (), metav1.ListOptions {
693
+ ResourceVersion : "0" ,
694
+ LabelSelector : "app=antrea,component=antrea-controller" ,
695
+ })
696
+ if err != nil {
697
+ return err
698
+ }
699
+
700
+ for _ , pod := range pods .Items {
701
+ tmpDir , err := afero .TempDir (defaultFS , "" , "bundle_tmp_" )
702
+ if err != nil {
703
+ errors = append (errors , err )
704
+ continue
705
+ }
706
+ defer defaultFS .RemoveAll (tmpDir )
707
+
708
+ if controllerInfo != nil {
709
+ data , err := yaml .Marshal (controllerInfo )
710
+ if err != nil {
711
+ errors = append (errors , err )
712
+ } else {
713
+ err = afero .WriteFile (defaultFS , filepath .Join (tmpDir , "controllerinfo" ), data , 0644 )
714
+ errors = append (errors , err )
715
+ }
716
+ }
717
+
718
+ err = downloadPodLogs (k8sClient , "controller" , pod .Namespace , pod .Name , []string {"antrea-controller" }, dir , tmpDir )
719
+ errors = append (errors , err )
720
+ }
721
+ return utilerror .NewAggregate (errors )
722
+ }
723
+
724
+ func downloadAgentBundleFromKubernetes (antreaClientset antrea.Interface , k8sClient kubernetes.Interface , failedNodes []string , dir string ) error {
725
+ var errors []error
726
+ agentInfoList , err := antreaClientset .CrdV1beta1 ().AntreaAgentInfos ().List (context .TODO (), metav1.ListOptions {ResourceVersion : "0" })
727
+ if err != nil {
728
+ // in case when there are no agentInfo exist, but there are still pods running. we can ignore this error
729
+ // and get pod logs
730
+ errors = append (errors , err )
731
+ }
732
+
733
+ agentInfoMap := map [string ]v1beta1.AntreaAgentInfo {}
734
+ for _ , agentInfo := range agentInfoList .Items {
735
+ agentInfoMap [agentInfo .Name ] = agentInfo
736
+ }
737
+
738
+ pods , err := k8sClient .CoreV1 ().Pods ("kube-system" ).List (context .TODO (), metav1.ListOptions {
739
+ ResourceVersion : "0" ,
740
+ LabelSelector : "app=antrea,component=antrea-agent" ,
741
+ })
742
+ if err != nil {
743
+ return err
744
+ }
745
+
746
+ failedNodesSet := sets .NewString (failedNodes ... )
747
+
748
+ for _ , pod := range pods .Items {
749
+
750
+ tmpDir , err := afero .TempDir (defaultFS , "" , "bundle_tmp_" )
751
+ if err != nil {
752
+ errors = append (errors , err )
753
+ continue
754
+ }
755
+ defer defaultFS .RemoveAll (tmpDir )
756
+
757
+ if ! failedNodesSet .Has (pod .Spec .NodeName ) {
758
+ continue
759
+ }
760
+
761
+ if agentInfo , ok := agentInfoMap [pod .Spec .NodeName ]; ok {
762
+ data , err := yaml .Marshal (agentInfo )
763
+ if err != nil {
764
+ errors = append (errors , err )
765
+ }
766
+ err = afero .WriteFile (defaultFS , filepath .Join (tmpDir , "agentinfo" ), data , 0644 )
767
+ errors = append (errors , err )
768
+ }
769
+
770
+ var containerNames []string
771
+ for _ , container := range pod .Spec .Containers {
772
+ containerNames = append (containerNames , container .Name )
773
+ }
774
+ for _ , container := range pod .Spec .InitContainers {
775
+ containerNames = append (containerNames , container .Name )
776
+ }
777
+
778
+ err = downloadPodLogs (k8sClient , "agent_" + pod .Spec .NodeName , pod .Namespace , pod .Name , containerNames , dir , tmpDir )
779
+ errors = append (errors , err )
780
+
781
+ }
782
+ return utilerror .NewAggregate (errors )
783
+
784
+ }
785
+
786
+ func downloadPodLogs (k8sClient kubernetes.Interface , comp string , namespace string , podName string , containers []string , dir string , tmpDir string ) error {
787
+ var errors []error
788
+
789
+ for _ , containerName := range containers {
790
+ containerDirName := containerName
791
+ if strings .HasPrefix (containerName , "antrea-" ) {
792
+ containerDirName = strings .ReplaceAll (containerName , "antrea-" , "" )
793
+ }
794
+
795
+ podLogDir := filepath .Join (tmpDir , "logs" , containerDirName )
796
+ err := os .MkdirAll (podLogDir , 0755 )
797
+ if err != nil {
798
+ return err
799
+ }
800
+
801
+ fileName := filepath .Join (podLogDir , containerName + ".log" )
802
+ f , err := os .Create (fileName )
803
+ if err != nil {
804
+ errors = append (errors , err )
805
+ continue
806
+ }
807
+
808
+ logOption := & corev1.PodLogOptions {
809
+ Container : containerName ,
810
+ }
811
+ logs := k8sClient .CoreV1 ().Pods (namespace ).GetLogs (podName , logOption )
812
+ logStream , err := logs .Stream (context .TODO ())
813
+ if err != nil {
814
+ errors = append (errors , err )
815
+ f .Close ()
816
+ continue
817
+ }
818
+
819
+ _ , err = io .Copy (f , logStream )
820
+ errors = append (errors , err )
821
+ err = logStream .Close ()
822
+ errors = append (errors , err )
823
+ f .Close ()
824
+ }
825
+
826
+ gzFileName := filepath .Join (dir , comp + ".tar.gz" )
827
+
828
+ f , err := os .Create (gzFileName )
829
+ if err != nil {
830
+ errors = append (errors , err )
831
+ } else {
832
+ _ , err := compress .PackDir (tmpDir , f )
833
+ errors = append (errors , err )
834
+ f .Close ()
835
+ }
836
+
837
+ return utilerror .NewAggregate (errors )
838
+
839
+ }
0 commit comments