Merge gvisor-website

This commit is contained in:
Adin Scannell
2020-05-06 14:15:15 -07:00
175 changed files with 21414 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
_site
node_modules
content/docs/user_guide/compatibility/linux/
content/.jekyll-cache/
syscalls.json
.sass-cache/
+29
View File
@@ -0,0 +1,29 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Build the system call doc generator.
FROM gcr.io/cloud-builders/go as syscalls
WORKDIR /src
COPY go.mod go.sum /src/
COPY cmd/generate-syscall-docs /src/cmd/generate-syscall-docs
RUN CGO_ENABLED=0 go build -o /bin/generate-syscall-docs gvisor.dev/website/cmd/generate-syscall-docs
# Generate the static site.
FROM jekyll/jekyll as jekyll
USER root
WORKDIR /site
RUN gem install html-proofer:3.10.2 nokogiri:1.10.1
RUN gem install jekyll-autoprefixer webrick jekyll-inline-svg
COPY --from=syscalls /bin/generate-syscall-docs /bin/generate-syscall-docs
CMD ["sh", "-c", "cat syscalls.json | /bin/generate-syscall-docs -out content/docs/user_guide/compatibility/ && jekyll build -t -s content -d _site && cp -a static/* _site && (cd _site && /usr/gem/bin/htmlproofer --disable-external --check-html .)"]
+42
View File
@@ -0,0 +1,42 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
build:
@bazel run //runsc -- help syscalls -format json -filename $(PWD)/syscalls.json
@docker build -t gvisor-website .
@docker run -v $$PWD:/work -w /work gcr.io/cloud-builders/npm ci
@$(MAKE) update
.PHONY: build
lint:
@docker run -v $$PWD:/work -w /work gcr.io/cloud-builders/npm run lint-md
.PHONY: lint
update: lint
@mkdir -p _site && sudo chmod a+rw _site
@docker run -v $$PWD:/site -w /site gvisor-website || ($(MAKE) clean && exit 1)
@sudo chown -R $$(id -u):$$(id -g) _site
.PHONY: build
clean:
@sudo rm -rf _site node_modules syscalls.json
.PHONY: clean
server:
@go run gvisor.dev/website/cmd/gvisor-website
.PHONY: server
deploy: update
@docker run --entrypoint=gcloud gvisor-website app deploy app.yaml
.PHONY: deploy
+49
View File
@@ -0,0 +1,49 @@
# gVisor Website
This repository holds the content for the gVisor website, including
documentation.
## Requirements
Building the website requires Docker.
## Contributing to Documentation
### Using Github
You can use the "Edit this page" link on any documentation page to edit the page
content directly via GitHub and submit a pull request. This should generally be
done for relatively small changes.
### Using Git
You can submit pull requests by making changes in a Git branch. See more
information on GitHub pull requests
[here](https://help.github.com/en/articles/about-pull-requests).
Documentation is located in the [content/docs/](content/docs/) directory.
## Building
You can build the site locally by running:
```
make build
```
Incremental changes can be generated using:
```
make update
```
And the site can be served locally using:
```
make server
```
Access the site at `http://localhost:8080`.
The above will build all parts of the site, including the serving components.
+23
View File
@@ -0,0 +1,23 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
runtime: go112
main: gvisor.dev/website/cmd/gvisor-website
handlers:
- url: /.*
secure: always
script: auto
- url: /rebuild
secure: always
script: auto
+35
View File
@@ -0,0 +1,35 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
steps:
- name: 'gcr.io/cloud-builders/npm'
args: ['ci']
- name: 'gcr.io/cloud-builders/npm'
args: ['run', 'lint-md']
- name: 'gcr.io/cloud-builders/bazel'
args: ['run', '//runsc', '--', 'help', 'syscalls', '-o', 'json', '--filename', '/workspace/website/syscalls.json']
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gvisor-website', 'website']
- name: 'gvisor-website'
dir: 'website'
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
dir: 'website'
args:
- '-c'
- >
if [[ "$PROJECT_ID" == "gvisor-website" && "$BRANCH_NAME" == "master" ]]; then
gcloud app deploy app.yaml;
fi
timeout: 900s
+208
View File
@@ -0,0 +1,208 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"text/template"
)
type CompatibilityInfo map[string]map[string]ArchInfo
// ArchInfo is compatbility doc for an architecture.
type ArchInfo struct {
// Syscalls maps syscall number for the architecture to the doc.
Syscalls map[uintptr]SyscallDoc `json:"syscalls"`
}
// SyscallDoc represents a single item of syscall documentation.
type SyscallDoc struct {
Name string `json:"name"`
Support string `json:"support"`
Note string `json:"note,omitempty"`
URLs []string `json:"urls,omitempty"`
}
var mdTemplate = template.Must(template.New("out").Parse(`---
title: {{.OS}}/{{.Arch}}
description: Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}}
layout: docs
category: Compatibility
weight: 50
permalink: /docs/user_guide/compatibility/{{.OS}}/{{.Arch}}/
noedit: true
---
This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and
their compatibility status in gVisor. gVisor does not support all syscalls and
some syscalls may have a partial implementation.
This page is automatically generated from the source code.
Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial
implementation. There are currently {{.Unsupported}} unsupported
syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}}
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Support</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{{range $i, $syscall := .Syscalls}}
<tr>
<td><a class="doc-table-anchor" id="{{.Name}}"></a>{{.Number}}</td>
<td><a href="http://man7.org/linux/man-pages/man2/{{.Name}}.2.html" target="_blank" rel="noopener">{{.Name}}</a></td>
<td>{{.Support}}</td>
<td>{{.Note}} {{range $i, $url := .URLs}}<br/>See: <a href="{{.}}">{{.}}</a>{{end}}</td>
</tr>
{{end}}
</tbody>
</table>
`))
// Fatalf writes a message to stderr and exits with error code 1
func Fatalf(format string, a ...interface{}) {
fmt.Fprintf(os.Stderr, format, a...)
os.Exit(1)
}
func main() {
inputFlag := flag.String("in", "-", "File to input ('-' for stdin)")
outputDir := flag.String("out", ".", "Directory to output files.")
flag.Parse()
var input io.Reader
if *inputFlag == "-" {
input = os.Stdin
} else {
i, err := os.Open(*inputFlag)
if err != nil {
Fatalf("Error opening %q: %v", *inputFlag, err)
}
input = i
}
input = bufio.NewReader(input)
var info CompatibilityInfo
d := json.NewDecoder(input)
if err := d.Decode(&info); err != nil {
Fatalf("Error reading json: %v", err)
}
weight := 0
for osName, osInfo := range info {
for archName, archInfo := range osInfo {
outDir := filepath.Join(*outputDir, osName)
outFile := filepath.Join(outDir, archName+".md")
if err := os.MkdirAll(outDir, 0755); err != nil {
Fatalf("Error creating directory %q: %v", *outputDir, err)
}
f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
Fatalf("Error opening file %q: %v", outFile, err)
}
defer f.Close()
weight += 10
data := struct {
OS string
Arch string
Weight int
Total int
Supported int
Unsupported int
Undocumented int
Syscalls []struct {
Name string
Number uintptr
Support string
Note string
URLs []string
}
}{
OS: strings.Title(osName),
Arch: archName,
Weight: weight,
Total: 0,
Supported: 0,
Unsupported: 0,
Undocumented: 0,
Syscalls: []struct {
Name string
Number uintptr
Support string
Note string
URLs []string
}{},
}
for num, s := range archInfo.Syscalls {
switch s.Support {
case "Full Support", "Partial Support":
data.Supported++
case "Unimplemented":
data.Unsupported++
default:
data.Undocumented++
}
data.Total++
for i := range s.URLs {
if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") {
s.URLs[i] = "https://" + s.URLs[i]
}
}
data.Syscalls = append(data.Syscalls, struct {
Name string
Number uintptr
Support string
Note string
URLs []string
}{
Name: s.Name,
Number: num,
Support: s.Support,
Note: s.Note, // TODO urls
URLs: s.URLs,
})
}
sort.Slice(data.Syscalls, func(i, j int) bool {
return data.Syscalls[i].Number < data.Syscalls[j].Number
})
if err := mdTemplate.Execute(f, data); err != nil {
Fatalf("Error writing file %q: %v", outFile, err)
}
}
}
}
+210
View File
@@ -0,0 +1,210 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"regexp"
"strings"
)
var redirects = map[string]string{
// Github redirects
"/change": "https://github.com/google/gvisor",
"/issue": "https://github.com/google/gvisor/issues",
"/issue/new": "https://github.com/google/gvisor/issues/new",
"/pr": "https://github.com/google/gvisor/pulls",
// For links
"/faq": "/docs/user_guide/faq/",
// Redirects to compatibility docs.
"/c": "/docs/user_guide/compatibility/",
"/c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64/",
// Redirect for old urls
"/docs/user_guide/compatibility/amd64/": "/docs/user_guide/compatibility/linux/amd64/",
"/docs/user_guide/compatibility/amd64": "/docs/user_guide/compatibility/linux/amd64/",
"/docs/user_guide/kubernetes/": "/docs/user_guide/quick_start/kubernetes/",
"/docs/user_guide/kubernetes": "/docs/user_guide/quick_start/kubernetes/",
"/docs/user_guide/oci/": "/docs/user_guide/quick_start/oci/",
"/docs/user_guide/oci": "/docs/user_guide/quick_start/oci/",
"/docs/user_guide/docker/": "/docs/user_guide/quick_start/docker/",
"/docs/user_guide/docker": "/docs/user_guide/quick_start/docker/",
// Deprecated, but links continue to work.
"/cl": "https://gvisor-review.googlesource.com",
}
var prefixHelpers = map[string]string{
"change": "https://github.com/google/gvisor/commit/%s",
"issue": "https://github.com/google/gvisor/issues/%s",
"pr": "https://github.com/google/gvisor/pull/%s",
// Redirects to compatibility docs.
"c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64/#%s",
// Deprecated, but links continue to work.
"cl": "https://gvisor-review.googlesource.com/c/gvisor/+/%s",
}
var (
validId = regexp.MustCompile(`^[A-Za-z0-9-]*/?$`)
goGetHTML5 = `<!doctype html><html><head><meta charset=utf-8>
<meta name="go-import" content="gvisor.dev/gvisor git https://github.com/google/gvisor">
<meta name="go-import" content="gvisor.dev/website git https://github.com/google/gvisor-website">
<title>Go-get</title></head><body></html>`
)
// cronHandler wraps an http.Handler to check that the request is from the App
// Engine Cron service.
// See: https://cloud.google.com/appengine/docs/standard/go112/scheduling-jobs-with-cron-yaml#validating_cron_requests
func cronHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Appengine-Cron") != "true" {
http.NotFound(w, r)
return
}
// Fallthrough.
h.ServeHTTP(w, r)
})
}
// wrappedHandler wraps an http.Handler.
//
// If the query parameters include go-get=1, then we redirect to a single
// static page that allows us to serve arbitrary Go packages.
func wrappedHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gg, ok := r.URL.Query()["go-get"]
if ok && len(gg) == 1 && gg[0] == "1" {
// Serve a trivial html page.
w.Write([]byte(goGetHTML5))
return
}
// Fallthrough.
h.ServeHTTP(w, r)
})
}
// redirectWithQuery redirects to the given target url preserving query parameters.
func redirectWithQuery(w http.ResponseWriter, r *http.Request, target string) {
url := target
if qs := r.URL.RawQuery; qs != "" {
url += "?" + qs
}
http.Redirect(w, r, url, http.StatusFound)
}
// hostRedirectHandler redirects the www. domain to the naked domain.
func hostRedirectHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.Host, "www.") {
// Redirect to the naked domain.
r.URL.Scheme = "https" // Assume https.
r.URL.Host = r.Host[4:] // Remove the 'www.'
http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
return
}
if *projectId != "" && r.Host == *projectId+".appspot.com" && *customHost != "" {
// Redirect to the custom domain.
r.URL.Scheme = "https" // Assume https.
r.URL.Host = *customHost
http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
return
}
h.ServeHTTP(w, r)
})
}
// prefixRedirectHandler returns a handler that redirects to the given formated url.
func prefixRedirectHandler(prefix, baseURL string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if p := r.URL.Path; p == prefix {
// Redirect /prefix/ to /prefix.
http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
return
}
id := r.URL.Path[len(prefix):]
if !validId.MatchString(id) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
target := fmt.Sprintf(baseURL, id)
redirectWithQuery(w, r, target)
})
}
// redirectHandler returns a handler that redirects to the given url.
func redirectHandler(target string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
redirectWithQuery(w, r, target)
})
}
// redirectRedirects registers redirect http handlers.
func registerRedirects(mux *http.ServeMux) {
if mux == nil {
mux = http.DefaultServeMux
}
for prefix, baseURL := range prefixHelpers {
p := "/" + prefix + "/"
mux.Handle(p, hostRedirectHandler(wrappedHandler(prefixRedirectHandler(p, baseURL))))
}
for path, redirect := range redirects {
mux.Handle(path, hostRedirectHandler(wrappedHandler(redirectHandler(redirect))))
}
}
// registerStatic registers static file handlers
func registerStatic(mux *http.ServeMux, staticDir string) {
if mux == nil {
mux = http.DefaultServeMux
}
mux.Handle("/", hostRedirectHandler(wrappedHandler(http.FileServer(http.Dir(staticDir)))))
}
func envFlagString(name, def string) string {
if val := os.Getenv(name); val != "" {
return val
}
return def
}
var (
addr = flag.String("http", envFlagString("HTTP", ":8080"), "HTTP service address")
staticDir = flag.String("static-dir", envFlagString("STATIC_DIR", "_site"), "static files directory")
// Uses the standard GOOGLE_CLOUD_PROJECT environment variable set by App Engine.
projectId = flag.String("project-id", envFlagString("GOOGLE_CLOUD_PROJECT", ""), "The App Engine project ID.")
customHost = flag.String("custom-domain", envFlagString("CUSTOM_DOMAIN", "gvisor.dev"), "The application's custom domain.")
)
func main() {
flag.Parse()
registerRedirects(nil)
registerStatic(nil, *staticDir)
log.Printf("Listening on %s...", *addr)
log.Fatal(http.ListenAndServe(*addr, nil))
}
+20
View File
@@ -0,0 +1,20 @@
destination: _site
markdown: kramdown
kramdown:
syntax_highlighter: rouge
toc_levels: "2,3"
highlighter: rouge
paginate: 10
paginate_path: "/blog/page:num/"
plugins:
- jekyll-paginate
- jekyll-autoprefixer
- jekyll-inline-svg
site_url: https://gvisor.dev
svg:
optimize: true
defaults:
- scope:
path: ""
values:
layout: default
+3
View File
@@ -0,0 +1,3 @@
amscanne:
name: Adin Scannell
email: ascannell@google.com
+1
View File
@@ -0,0 +1 @@
../../../GOVERNANCE.md
+1
View File
@@ -0,0 +1 @@
../../../SECURITY.md
+18
View File
@@ -0,0 +1,18 @@
By
{% assign last_pos=include.authors.size | minus: 1 %}
{% assign and_pos=include.authors.size | minus: 2 %}
{% for i in (0..last_pos) %}
{% assign author_id=include.authors[i] %}
{% assign author=site.authors[author_id] %}
{% if author %}
<a href="{{ author[1] }}">{{ author[0] }}</a>
{% else %}
{{ author_id }}
{% endif %}
{% if i == and_pos %}
and
{% elsif i < and_pos %}
,
{% endif %}
{% endfor %}
on <span class="text-muted">{{ include.date | date_to_long_string }}</span>
+35
View File
@@ -0,0 +1,35 @@
<div class="container">
<div class="row">
<div class="col-sm-4 col-md-2">
<p>About</p>
<ul class="list-unstyled">
<li><a href="/roadmap">Roadmap</a></li>
<li><a href="/docs/community/">Contributing</a></li>
<li><a href="https://gvisor.googlesource.com/community/+/refs/heads/master/README.md">Governance</a></li>
<li><a href="https://policies.google.com/privacy">Privacy Policy</a></li>
</ul>
</div>
<div class="col-sm-4 col-md-2">
<p>Support</p>
<ul class="list-unstyled">
<li><a href="https://github.com/google/gvisor/issues">Issues</a></li>
<li><a href="/docs">Documentation</a></li>
<li><a href="/docs/user_guide/FAQ">FAQ</a></li>
</ul>
</div>
<div class="col-sm-4 col-md-2">
<p>Connect</p>
<ul class="list-unstyled">
<li><a href="https://github.com/google/gvisor">GitHub</a></li>
<li><a href="https://groups.google.com/forum/#!forum/gvisor-users">User Mailing List</a></li>
<li><a href="https://groups.google.com/forum/#!forum/gvisor-dev">Developer Mailing List</a></li>
<li><a href="https://gitter.im/gvisor/community">Gitter Chat</a></li>
</ul>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<p>&copy; {{ 'now' | date: "%Y" }} Google LLC</p>
</div>
</div>
</div>
+59
View File
@@ -0,0 +1,59 @@
<footer class="footer">
{% include footer-links.html %}
</footer>
<script src="/assets/js/jquery-3.3.1.min.js" integrity="sha384-FZl05tHmJtKNdb6j461opwSK1w4LdKWpehJe28rPTqG2kcPmGzQuvPSLN7q8tsD6" crossorigin="anonymous"></script>
<script src="/assets/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="/assets/js/d3.v4.min.js" integrity="sha384-1EOYqz4UgZkewWm70NbT1JBUXSQpOIS2AaJy6/evZH+lXOrt9ITSJbFctNeyBoIJ" crossorigin="anonymous"></script>
<script>
var shiftWindow = function() {
if (location.hash.length !== 0) {
window.scrollBy(0, -50);
}
};
window.addEventListener("hashchange", shiftWindow);
var highlightCurrentSidebarNav = function() {
var href = location.pathname;
var item = $('#sidebar-nav [href$="' + href + '"]');
if (item) {
var li = item.parent();
li.addClass("active");
if (li.parent() && li.parent().is("ul")) {
do {
var ul = li.parent();
if (ul.hasClass("collapse")) {
ul.collapse("show");
}
li = ul.parent();
} while (li && li.is("li"));
}
}
};
$(document).ready(function() {
// Scroll to anchor of location hash, adjusted for fixed navbar.
window.setTimeout(function() {
shiftWindow();
}, 1);
// Flip the caret when submenu toggles are clicked.
$(".sidebar-submenu").on("show.bs.collapse", function() {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.addClass("dropup");
}
});
$(".sidebar-submenu").on("hide.bs.collapse", function() {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.removeClass("dropup");
}
});
// Highlight the current page on the sidebar nav.
highlightCurrentSidebarNav();
});
</script>
+205
View File
@@ -0,0 +1,205 @@
{::nomarkdown}
{% assign fn = include.id | remove: " " | remove: "-" | downcase %}
<figure><a href="{{ include.url }}"><svg id="{{ include.id }}" width=500 height=200 onload="render_{{ fn }}()"><title>{{ include.title }}</title></svg></a></figure>
<script type="text/javascript">
function render_{{ fn }}() {
d3.csv("{{ include.url }}", function(d, i, columns) {
return d; // Transformed below.
}, function(error, data) {
if (error) throw(error);
// Create a new data that pivots on runtime.
//
// To start, we have:
// runtime, ..., result
// runc, ..., 1
// runsc, ..., 2
//
// In the end we want:
// ..., runsc, runc
// ..., 1, 2
// Filter by metric, if required.
if ("{{ include.metric }}" != "") {
orig_columns = data.columns;
data = data.filter(d => d.metric == "{{ include.metric }}");
data.columns = orig_columns;
}
// Filter by method, if required.
if ("{{ include.method }}" != "") {
orig_columns = data.columns;
data = data.filter(d => d.method == "{{ include.method }}");
data.columns = orig_columns.filter(key => key != "method");
}
// Enumerate runtimes.
var runtimes = Array.from(new Set(data.map(d => d.runtime)));
var metrics = Array.from(new Set(data.map(d => d.metric)));
if (metrics.length < 1) {
console.log(data);
throw("need at least one metric");
} else if (metrics.length == 1) {
metric = metrics[0];
data.columns = data.columns.filter(key => key != "metric");
} else {
metric = ""; // Used for grouping.
}
var isSubset = function(a, sup) {
var ap = Object.getOwnPropertyNames(a);
for (var i = 0; i < ap.length; i++) {
if (a[ap[i]] !== sup[ap[i]]) {
return false;
}
}
return true;
};
// Execute a pivot to include runtimes as attributes.
var new_data = data.map(function(data_item) {
// Generate a prototype data item.
var proto_item = Object.assign({}, data_item);
delete proto_item.runtime;
delete proto_item.result;
var next_item = Object.assign({}, proto_item);
// Find all matching runtime items.
data.forEach(function(d) {
if (isSubset(proto_item, d)) {
// Add the result result.
next_item[d.runtime] = d.result;
}
});
return next_item;
});
// Remove any duplication.
new_data = Array.from(new Set(new_data));
new_data.columns = data.columns;
new_data.columns = new_data.columns.filter(key => key != "runtime" && key != "result");
new_data.columns = new_data.columns.concat(runtimes);
data = new_data;
// Slice based on the first key.
if (data.columns.length != runtimes.length) {
x0_key = new_data.columns[0];
var x1_domain = data.columns.slice(1);
} else {
x0_key = "runtime";
var x1_domain = runtimes;
}
// Determine varaible margins.
var x0_domain = data.map(d => d[x0_key]);
var margin_bottom_pad = 0;
if (x0_domain.length > 8) {
margin_bottom_pad = 50;
}
// Use log scale if required.
var y_min = 0;
if ({{ include.log | default: "false" }}) {
// Need to cap lower end of the domain at 1.
y_min = 1;
}
if ({{ include.y_min | default: "false" }}) {
y_min = "{{ include.y_min }}";
}
var svg = d3.select("#{{ include.id }}"),
margin = {top: 20, right: 20, bottom: 30 + margin_bottom_pad, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x0 = d3.scaleBand()
.rangeRound([margin.left / 2, width - (4 * margin.right)])
.paddingInner(0.1);
var x1 = d3.scaleBand()
.padding(0.05);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
if ({{ include.log | default: "false" }}) {
y = d3.scaleLog()
.rangeRound([height, 0]);
}
var z = d3.scaleOrdinal()
.range(["#262362", "#FBB03B", "#286FD7", "#6b486b"]);
// Set all domains.
x0.domain(x0_domain);
x1.domain(x1_domain).rangeRound([0, x0.bandwidth()]);
y.domain([y_min, d3.max(data, d => d3.max(x1_domain, key => parseFloat(d[key])))]).nice();
// The data.
g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d[x0_key]) + ",0)"; })
.selectAll("rect")
.data(d => x1_domain.map(key => ({key, value: d[key]})))
.enter().append("rect")
.attr("x", d => x1(d.key))
.attr("y", d => y(d.value))
.attr("width", x1.bandwidth())
.attr("height", d => y(y_min) - y(d.value))
.attr("fill", d => z(d.key));
// X0 ticks and labels.
var x0_axis = g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0));
if (x0_domain.length > 8) {
x0_axis.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
}
// Y ticks and top-label.
if (metric == "default") {
metric = ""; // Don't display.
}
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", -30.0)
.attr("y", y(y.ticks().pop()) - 10.0)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text(metric);
// The legend.
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(x1_domain.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
});
}
</script>
{:/}
+18
View File
@@ -0,0 +1,18 @@
<nav class="navbar navbar-expand-sm navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-brand">
<a href="/">
<img src="/assets/logos/logo_solo_on_dark.svg" height="25px" class="d-inline-block align-top" style="margin-right: 10px;" alt="logo"/>
gVisor
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/docs">Documentation</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="https://github.com/google/gvisor">GitHub</a></li>
</ul>
</div>
</div>
</nav>
+30
View File
@@ -0,0 +1,30 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% if page.title %}
<title>{{ page.title }} - gVisor</title>
{% else %}
<title>gVisor</title>
{% endif %}
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site_root }}">
<!-- Dependencies. -->
<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/css/fontawesome.min.css" rel="stylesheet">
<!-- Our own style sheet. -->
<link rel="stylesheet" type="text/css" href="/css/main.css">
<link rel="icon" type="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/assets/favicons/favicon-16x16.png" sizes="16x16">
{% if page.title %}
<meta name="og:title" content="{{ page.title }}">
{% else %}
<meta name="og:title" content="gVisor">
{% endif %}
{% if page.description %}
<meta name="og:description" content="{{ page.description }}">
{% endif %}
<meta name="og:image" content="{{ site.site_url }}/assets/logos/logo_solo_on_white_bordered.svg">
</head>
+10
View File
@@ -0,0 +1,10 @@
<nav aria-label="...">
<ul class="pager">
{% if paginator.previous_page %}
<li class="previous"><a href="{{ paginator.previous_page_path }}"><span aria-hidden="true">&larr;</span> Newer</a></li>
{% endif %}
{% if paginator.next_page %}
<li class="next"><a href="{{ paginator.next_page_path }}">Older <span aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
+2
View File
@@ -0,0 +1,2 @@
> Note: gVisor supports only x86\_64 and requires Linux 4.14.77+
> ([older Linux](/docs/user_guide/networking/#gso)).

Some files were not shown because too many files have changed in this diff Show More