mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge gvisor-website
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
_site
|
||||
node_modules
|
||||
content/docs/user_guide/compatibility/linux/
|
||||
content/.jekyll-cache/
|
||||
syscalls.json
|
||||
.sass-cache/
|
||||
@@ -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 .)"]
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
Executable
+20
@@ -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
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
amscanne:
|
||||
name: Adin Scannell
|
||||
email: ascannell@google.com
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../GOVERNANCE.md
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../SECURITY.md
|
||||
Executable
+18
@@ -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>
|
||||
Executable
+35
@@ -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>© {{ 'now' | date: "%Y" }} Google LLC</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Executable
+59
@@ -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>
|
||||
Executable
+205
@@ -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>
|
||||
{:/}
|
||||
Executable
+18
@@ -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>
|
||||
Executable
+30
@@ -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>
|
||||
Executable
+10
@@ -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">←</span> Newer</a></li>
|
||||
{% endif %}
|
||||
{% if paginator.next_page %}
|
||||
<li class="next"><a href="{{ paginator.next_page_path }}">Older <span aria-hidden="true">→</span></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
+2
@@ -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
Reference in New Issue
Block a user