istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/bug-report/pkg/archive/archive.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package archive 16 17 import ( 18 "archive/tar" 19 "compress/gzip" 20 "io" 21 "os" 22 "path/filepath" 23 "strings" 24 "sync" 25 ) 26 27 const ( 28 bugReportSubdir = "bug-report" 29 proxyLogsPathSubdir = "proxies" 30 istioLogsPathSubdir = "istio" 31 clusterInfoSubdir = "cluster" 32 analyzeSubdir = "analyze" 33 operatorLogsPathSubdir = "operator" 34 cniLogsPathSubdir = "cni" 35 ) 36 37 var ( 38 tmpDir string 39 initDir sync.Once 40 ) 41 42 // DirToArchive is the dir to archive. 43 func DirToArchive(rootDir string) string { 44 return filepath.Dir(getRootDir(rootDir)) 45 } 46 47 // OutputRootDir is the root dir of output artifacts. 48 func OutputRootDir(rootDir string) string { 49 return getRootDir(rootDir) 50 } 51 52 func ProxyOutputPath(rootDir, namespace, pod string) string { 53 return filepath.Join(getRootDir(rootDir), proxyLogsPathSubdir, namespace, pod) 54 } 55 56 func IstiodPath(rootDir, namespace, pod string) string { 57 return filepath.Join(getRootDir(rootDir), istioLogsPathSubdir, namespace, pod) 58 } 59 60 func OperatorPath(rootDir, namespace, pod string) string { 61 return filepath.Join(getRootDir(rootDir), operatorLogsPathSubdir, namespace, pod) 62 } 63 64 func AnalyzePath(rootDir, namespace string) string { 65 return filepath.Join(getRootDir(rootDir), analyzeSubdir, namespace) 66 } 67 68 func ClusterInfoPath(rootDir string) string { 69 return filepath.Join(getRootDir(rootDir), clusterInfoSubdir) 70 } 71 72 func CniPath(rootDir, pod string) string { 73 return filepath.Join(getRootDir(rootDir), cniLogsPathSubdir, pod) 74 } 75 76 // Create creates a gzipped tar file from srcDir and writes it to outPath. 77 func Create(srcDir, outPath string) error { 78 mw, err := os.Create(outPath) 79 if err != nil { 80 return err 81 } 82 defer mw.Close() 83 gzw := gzip.NewWriter(mw) 84 defer gzw.Close() 85 86 tw := tar.NewWriter(gzw) 87 defer tw.Close() 88 89 return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error { 90 if err != nil { 91 return err 92 } 93 if !fi.Mode().IsRegular() { 94 return nil 95 } 96 header, err := tar.FileInfoHeader(fi, fi.Name()) 97 if err != nil { 98 return err 99 } 100 header.Name = strings.TrimPrefix(strings.Replace(file, srcDir, "", -1), string(filepath.Separator)) 101 header.Size = fi.Size() 102 header.Mode = int64(fi.Mode()) 103 header.ModTime = fi.ModTime() 104 if err := tw.WriteHeader(header); err != nil { 105 return err 106 } 107 108 f, err := os.Open(file) 109 if err != nil { 110 return err 111 } 112 defer f.Close() 113 114 if _, err := io.Copy(tw, f); err != nil { 115 return err 116 } 117 return nil 118 }) 119 } 120 121 func getRootDir(rootDir string) string { 122 if rootDir != "" { 123 return rootDir 124 } 125 initDir.Do(func() { 126 // Extra subdir so archive extracts under new ./bug-report subdir. 127 tmpDir = filepath.Join(os.TempDir(), bugReportSubdir, bugReportSubdir) 128 }) 129 return tmpDir 130 }