github.com/Cloud-Foundations/Dominator@v0.3.4/imagebuilder/httpd/showArchive.go (about) 1 package httpd 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "net/http" 8 "path/filepath" 9 "sort" 10 11 "github.com/Cloud-Foundations/Dominator/imagebuilder/logarchiver" 12 "github.com/Cloud-Foundations/Dominator/lib/format" 13 "github.com/Cloud-Foundations/Dominator/lib/html" 14 ) 15 16 type userBuildCountType struct { 17 summary *logarchiver.RequestorSummary 18 username string 19 } 20 21 func showBuildInfos(writer io.Writer, buildInfos *logarchiver.BuildInfos, 22 showError bool) { 23 fmt.Fprintln(writer, `<style> 24 table, th, td { 25 border-collapse: collapse; 26 } 27 </style>`) 28 fmt.Fprintln(writer, "<body>") 29 fmt.Fprintln(writer, "<h3>") 30 imageNames := buildInfos.ImagesByAge 31 if len(imageNames) < len(buildInfos.Builds) { 32 imageNames = make([]string, 0, len(buildInfos.Builds)) 33 for imageName := range buildInfos.Builds { 34 imageNames = append(imageNames, imageName) 35 } 36 sort.Strings(imageNames) 37 } 38 fmt.Fprintln(writer, `<table border="1">`) 39 columns := []string{"Image Name", "Build log", "Duration"} 40 if showError { 41 columns = append(columns, "Error") 42 } 43 tw, _ := html.NewTableWriter(writer, true, columns...) 44 for _, imageName := range imageNames { 45 buildInfo := buildInfos.Builds[imageName] 46 columns := []string{ 47 imageName, 48 fmt.Sprintf("<a href=\"showBuildLog?%s\">log</a>", imageName), 49 format.Duration(buildInfo.Duration), 50 } 51 if showError { 52 columns = append(columns, buildInfo.Error) 53 } 54 tw.WriteRow("", "", columns...) 55 } 56 tw.Close() 57 fmt.Fprintln(writer, "</body>") 58 } 59 60 func (s state) showAllBuildsHandler(w http.ResponseWriter, req *http.Request) { 61 s.showBuildsHandler(w, req, true, true) 62 } 63 64 func (s state) showBuildLogHandler(w http.ResponseWriter, 65 req *http.Request) { 66 imageName := filepath.Clean(req.URL.RawQuery) 67 reader, err := s.buildLogReporter.GetBuildLog(imageName) 68 if err != nil { 69 http.NotFound(w, req) 70 return 71 } 72 defer reader.Close() 73 writer := bufio.NewWriter(w) 74 defer writer.Flush() 75 io.Copy(writer, reader) 76 } 77 78 func (s state) showBuildLogArchiveHandler(w http.ResponseWriter, 79 req *http.Request) { 80 writer := bufio.NewWriter(w) 81 defer writer.Flush() 82 fmt.Fprintln(writer, "<title>build log archive</title>") 83 fmt.Fprintln(writer, `<style> 84 table, th, td { 85 border-collapse: collapse; 86 } 87 </style>`) 88 fmt.Fprintln(writer, "<body>") 89 fmt.Fprintln(writer, "<h3>") 90 summary := s.buildLogReporter.GetSummary() 91 fmt.Fprintln(writer, "Build summary per image stream:<br>") 92 var numBuilds, numGoodBuilds, numErrorBuilds uint64 93 streamNames := make([]string, 0, len(summary.Streams)) 94 for streamName, streamSummary := range summary.Streams { 95 numBuilds += streamSummary.NumBuilds 96 numGoodBuilds += streamSummary.NumGoodBuilds 97 numErrorBuilds += streamSummary.NumErrorBuilds 98 streamNames = append(streamNames, streamName) 99 } 100 sort.Strings(streamNames) 101 fmt.Fprintln(writer, `<table border="1">`) 102 tw, _ := html.NewTableWriter(writer, true, 103 "Image Stream", "Num Builds", "Num Good", "Num Bad") 104 for _, streamName := range streamNames { 105 streamSummary := summary.Streams[streamName] 106 tw.WriteRow("", "", 107 streamName, 108 fmt.Sprintf("<a href=\"showStreamAllBuilds?%s\">%d</a>", 109 streamName, streamSummary.NumBuilds), 110 fmt.Sprintf("<a href=\"showStreamGoodBuilds?%s\">%d</a>", 111 streamName, streamSummary.NumGoodBuilds), 112 fmt.Sprintf("<a href=\"showStreamErrorBuilds?%s\">%d</a>", 113 streamName, streamSummary.NumErrorBuilds)) 114 } 115 tw.WriteRow("", "", 116 "<b>TOTAL</b>", 117 fmt.Sprintf("<a href=\"showAllBuilds\">%d</a>", numBuilds), 118 fmt.Sprintf("<a href=\"showGoodBuilds\">%d</a>", numGoodBuilds), 119 fmt.Sprintf("<a href=\"showErrorBuilds\">%d</a>", numErrorBuilds)) 120 tw.Close() 121 fmt.Fprintln(writer, "<p>") 122 fmt.Fprintln(writer, "Build summary per requestor:<br>") 123 userBuildCounts := make([]userBuildCountType, 0, len(summary.Requestors)) 124 for username, requestorSummary := range summary.Requestors { 125 userBuildCounts = append(userBuildCounts, 126 userBuildCountType{requestorSummary, username}) 127 } 128 sort.Slice(userBuildCounts, func(i, j int) bool { 129 return userBuildCounts[i].summary.NumBuilds > 130 userBuildCounts[j].summary.NumBuilds 131 }) 132 fmt.Fprintln(writer, `<table border="1">`) 133 tw, _ = html.NewTableWriter(writer, true, "Username", "Num Builds", 134 "Num Good", "Num Bad") 135 for _, userBuildCount := range userBuildCounts { 136 if userBuildCount.username == "" { 137 userBuildCount.username = "imaginator" 138 } 139 tw.WriteRow("", "", 140 userBuildCount.username, 141 fmt.Sprintf("<a href=\"showRequestorAllBuilds?%s\">%d</a>", 142 userBuildCount.username, userBuildCount.summary.NumBuilds), 143 fmt.Sprintf("<a href=\"showRequestorGoodBuilds?%s\">%d</a>", 144 userBuildCount.username, userBuildCount.summary.NumGoodBuilds), 145 fmt.Sprintf("<a href=\"showRequestorErrorBuilds?%s\">%d</a>", 146 userBuildCount.username, userBuildCount.summary.NumErrorBuilds)) 147 } 148 tw.Close() 149 fmt.Fprintln(writer, "</body>") 150 } 151 152 func (s state) showBuildsHandler(w http.ResponseWriter, 153 req *http.Request, showGood bool, showError bool) { 154 logType := "none" 155 if showGood && !showError { 156 logType = "good" 157 } else if showGood && showError { 158 logType = "all" 159 } else if showError { 160 logType = "bad" 161 } 162 buildInfos := s.buildLogReporter.GetBuildInfos(showGood, showError) 163 writer := bufio.NewWriter(w) 164 defer writer.Flush() 165 fmt.Fprintf(writer, "<title>build log archive (%s)</title>", logType) 166 showBuildInfos(writer, buildInfos, showError) 167 } 168 169 func (s state) showGoodBuildsHandler(w http.ResponseWriter, req *http.Request) { 170 s.showBuildsHandler(w, req, true, false) 171 } 172 173 func (s state) showErrorBuildsHandler(w http.ResponseWriter, 174 req *http.Request) { 175 s.showBuildsHandler(w, req, false, true) 176 } 177 178 func (s state) showStreamAllBuildsHandler(w http.ResponseWriter, 179 req *http.Request) { 180 s.showStreamBuildsHandler(w, req, true, true) 181 } 182 183 func (s state) showStreamBuildsHandler(w http.ResponseWriter, 184 req *http.Request, showGood bool, showError bool) { 185 logType := "none" 186 if showGood && !showError { 187 logType = "good" 188 } else if showGood && showError { 189 logType = "all" 190 } else if showError { 191 logType = "bad" 192 } 193 streamName := filepath.Clean(req.URL.RawQuery) 194 buildInfos := s.buildLogReporter.GetBuildInfosForStream(streamName, 195 showGood, showError) 196 if buildInfos == nil { 197 http.NotFound(w, req) 198 return 199 } 200 writer := bufio.NewWriter(w) 201 defer writer.Flush() 202 fmt.Fprintf(writer, "<title>build log archive (%s)</title>", logType) 203 showBuildInfos(writer, buildInfos, showError) 204 } 205 206 func (s state) showStreamGoodBuildsHandler(w http.ResponseWriter, 207 req *http.Request) { 208 s.showStreamBuildsHandler(w, req, true, false) 209 } 210 211 func (s state) showStreamErrorBuildsHandler(w http.ResponseWriter, 212 req *http.Request) { 213 s.showStreamBuildsHandler(w, req, false, true) 214 } 215 216 func (s state) showRequestorAllBuildsHandler(w http.ResponseWriter, 217 req *http.Request) { 218 s.showRequestorBuildsHandler(w, req, true, true) 219 } 220 221 func (s state) showRequestorBuildsHandler(w http.ResponseWriter, 222 req *http.Request, showGood bool, showError bool) { 223 logType := "none" 224 if showGood && !showError { 225 logType = "good" 226 } else if showGood && showError { 227 logType = "all" 228 } else if showError { 229 logType = "bad" 230 } 231 username := filepath.Clean(req.URL.RawQuery) 232 if username == "imaginator" { 233 username = "" 234 } 235 buildInfos := s.buildLogReporter.GetBuildInfosForRequestor(username, 236 showGood, showError) 237 if buildInfos == nil { 238 http.NotFound(w, req) 239 return 240 } 241 writer := bufio.NewWriter(w) 242 defer writer.Flush() 243 fmt.Fprintf(writer, "<title>build log archive (%s)</title>", logType) 244 showBuildInfos(writer, buildInfos, showError) 245 } 246 247 func (s state) showRequestorGoodBuildsHandler(w http.ResponseWriter, 248 req *http.Request) { 249 s.showRequestorBuildsHandler(w, req, true, false) 250 } 251 252 func (s state) showRequestorErrorBuildsHandler(w http.ResponseWriter, 253 req *http.Request) { 254 s.showRequestorBuildsHandler(w, req, false, true) 255 }