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  }