1
0
Fork 0

*: more hackdoc updates

Change-Id: Ib9830c66fe36c423d38f447905c470b67cde5399
master
q3k 2020-04-10 21:20:53 +02:00
parent 4f7cc0064f
commit 8adbd49051
15 changed files with 241 additions and 57 deletions

View File

@ -1,5 +1,4 @@
hscloud
=======
![](doc/img/hscloud-smol.png)
`hscloud` is the main monorepo of the Warsaw Hackerspace infrastructure code.
@ -14,7 +13,14 @@ For a pleaseant web viewing experience, [see this documentation in hackdoc](http
Getting started
---------------
You will need Bash and Bazel (1.2.0+). Clone this repo, cd into it and:
You will need Bash and Bazel (1.2.0+).
First, clone the repository:
git clone https://gerrit.hackerspace.pl/hscloud
cd hscloud
Then, set up everything:
. ./env.sh # setup PATH and hscloud_root
tools/install.sh # build tools
@ -26,10 +32,12 @@ This does not pollute your system, and you can work on multiple hscloud checkout
What now?
---------
If you want to use our Kubernetes cluster to run some stuff, see [//cluster/doc/user](cluster/doc/user).
If you want to use our Kubernetes cluster to run some stuff, see [//cluster/doc/user.md](cluster/doc/user.md).
If you're looking for administrative docs about cluster maintenance, see [//cluster/doc/admin](cluster/doc/admin).
If you're looking for administrative docs about cluster maintenance, see [//cluster/doc/admin.md](cluster/doc/admin.md).
If you want to browse the source of `hscloud` in a web browser, use [gerrit's gitiles](https://gerrit.hackerspace.pl/plugins/gitiles/hscloud/+/refs/heads/master/).
If you want to learn how to contribute to this repository, see [//doc/codelab/gerrit](doc/codelab/gerrit).
If you want help, talk to q3k, informatic or your therapist.

View File

@ -197,6 +197,7 @@ http_archive(
],
sha256 = "d8c45ee70ec39a57e7a05e5027c32b1576cc7f16d9dd37135b0eddde45cf1b10",
)
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_repository(
@ -207,8 +208,11 @@ go_repository(
# Invoke go_rules_dependencies depending on host platform.
load("//tools:go_sdk.bzl", "gen_imports")
gen_imports(name = "go_sdk_imports")
load("@go_sdk_imports//:imports.bzl", "load_go_sdk")
load_go_sdk()
gazelle_dependencies()
@ -2012,3 +2016,9 @@ go_repository(
commit = "6a3e2ff9e7c564f36873c2e36413f634534f1c44",
importpath = "github.com/xanzy/ssh-agent",
)
go_repository(
name = "com_github_gabriel_vasile_mimetype",
commit = "06500030e7d26826f68caa5ca7d98c315c4caa28",
importpath = "github.com/gabriel-vasile/mimetype",
)

View File

@ -1,23 +1,10 @@
HSCloud Clusters
================
Admin documentation. For user documentation, see [//cluster/doc/user.md](/cluster/doc/user.md).
Current cluster: `k0.hswaw.net`
Accessing via kubectl
---------------------
prodaccess # get a short-lived certificate for your use via SSO
# if youre local username is not the same as your HSWAW SSO
# username, pass `-username foo`
kubectl version
kubectl top nodes
Every user gets a `personal-$username` namespace. Feel free to use it for your own purposes, but watch out for resource usage!
kubectl run -n personal-$username run --image=alpine:latest -it foo
To proceed further you should be somewhat familiar with Kubernetes. Otherwise the rest of terminology might not make sense. We recommend going through the original Kubernetes tutorials.
Persistent Storage (waw2)
-------------------------
@ -64,9 +51,10 @@ Ceph - Debugging
We run Ceph via Rook. The Rook operator is running in the `ceph-rook-system` namespace. To debug Ceph issues, start by looking at its logs.
A dashboard is available at https://ceph-waw2.hswaw.net/, to get the admin password run:
A dashboard is available at https://ceph-waw2.hswaw.net/ and https://ceph-waw3.hswaw.net, to get the admin password run:
kubectl -n ceph-waw2 get secret rook-ceph-dashboard-password -o yaml | grep "password:" | awk '{print $2}' | base64 --decode ; echo
kubectl -n ceph-waw2 get secret rook-ceph-dashboard-password -o yaml | grep "password:" | awk '{print $2}' | base64 --decode ; echo
Ceph - Backups
@ -75,6 +63,7 @@ Ceph - Backups
Kubernetes PVs backed in Ceph RBDs get backed up using Benji. An hourly cronjob runs in every Ceph cluster. You can also manually trigger a run by doing:
kubectl -n ceph-waw2 create job --from=cronjob/ceph-waw2-benji ceph-waw2-benji-manual-$(date +%s)
kubectl -n ceph-waw3 create job --from=cronjob/ceph-waw3-benji ceph-waw3-benji-manual-$(date +%s)
Ceph ObjectStorage pools (RADOSGW) are _not_ backed up yet!
@ -83,8 +72,7 @@ Ceph - Object Storage
To create an object store user consult rook.io manual (https://rook.io/docs/rook/v0.9/ceph-object-store-user-crd.html)
User authentication secret is generated in ceph cluster namespace (`ceph-waw2`),
thus may need to be manually copied into application namespace. (see
`app/registry/prod.jsonnet` comment)
thus may need to be manually copied into application namespace. (see `app/registry/prod.jsonnet` comment)
`tools/rook-s3cmd-config` can be used to generate test configuration file for s3cmd.
Remember to append `:default-placement` to your region name (ie. `waw-hdd-redundant-1-object:default-placement`)

6
cluster/doc/index.md Normal file
View File

@ -0,0 +1,6 @@
Warsaw Hackerspace Kubernetes Cluster
=====================================
**User documentation**: [user.md](user.md).
**Admin documentation**: [admin.md](admin.md).

58
cluster/doc/user.md Normal file
View File

@ -0,0 +1,58 @@
Warsaw Hackerspace Kubernetes Clusters
======================================
End-user^Whacker documentation.
Intro
-----
We run Kubernetes, a cluster system on our production machines. This allows you to schedule software to run without having to worry about traditional deployment, or where your particular piece of code is actually running. This document will not teach you how to use Kubernetes, but will give you a short hands-on example on how to access it, and then point you in the right direction for general documentation to follow.
Accessing Kubernetes
--------------------
Kubernetes is accessed fully via an API, for which there exists a standard command line tool: `kubectl`. If you've check out hscloud and followed the instructions in [//README.md]("/README.md"), you should have that tool built and available for you to use.
Before you can use `kubectl`, however, you will need to authenticate yourself. To do that, run `prodaccess`. This will issue you short-term (~hours) credentials that `kubectl` can then pass on to Kubernetes to authenticate itself.
$ prodaccess
Enter SSO/LDAP password for q3k@hackerspace.pl:
Good evening professor. I see you have driven here in your Ferrari.
If `prodaccess` is not on your $PATH, ensure you have sourced `env.sh` from the root of hscloud and ran `tools/install.sh`.
By default, `prodaccess` will use your local user name to authenticate as `<user>@hackerspce.pl`. If your Hackerspace SSO name is different, specify it using the `-u` flag to prodaccess, eg. `prodaccess -u informatic`.
You can now check that you indeed have access to Kubernetes:
$ kubectl version # show version of Kubernetes
$ kubectl top nodes # show node (machine/server) statistics
You are now fully set up to schedule your own jobs on `k0.hswaw.net`, our currently only Kubernetes cluster.
Running Stuff
-------------
We have a fairly extensive role-based access control system set up to provide a level of multi-tenancy of our Kubernetes cluster. What this means is that you will not be able to modify other people's stuff. Indeed, by default, you barely have any access. So as you can experiment with Kubernetes, we automatically provision you a personal namespace (`personal-$USER`) in Kubernetes. This acts as your own playground, where you can run anything you want, as long as it doesn't eat into our resources too much.
For example, to run an Alpine Linux Docker image in your own namespace:
kubectl -n personal-$USER run --image=alpine:latest -it foo
This will create a Kubernetes deployment named foo, running the `alpine:latest` Docker image, and drop you in an interactive shell in it. Naturally, replace `$USER` with your SSO username if it's different from your system username.
Once you're done, delete the Deployment:
kubectl -n personal-$USER delete deployment foo
Pod Security
------------
Apart from the RBAC (role based access control) that prevents you from poling at things that you shouldn't over the API, we have one more security measure in place. Throught a Kubernetes mechanism called 'PodSecurityPolicy' we limit what pods (ie. containers) can do. Notably, pods will by default not be able to access any host data, run in privileged mode, or even setuid to a different uid. The most notable side effect of this is that some basic system tools within pods will not work: ie., apt on Ubuntu.
More Kubernetes
---------------
We highly recommend following the [Kubernetes Basics](https://kubernetes.io/docs/tutorials/kubernetes-basics/) tutorial as a first step in using Kubernetes for real world applications.
For defining production jobs, we use a language called `Jsonnet` via a tool called `kubecfg`. This is to replace some more popular tools that other Kubernetes systems use, eg. Helm. For more information about that, ping q3k so that he writes a codelab about it :).

View File

@ -1,3 +1,4 @@
load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_layer", "container_push")
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
@ -18,3 +19,28 @@ go_binary(
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
container_layer(
name = "layer_bin",
files = [
":depotview",
],
directory = "/devtools/",
)
container_image(
name = "runtime",
base = "@prodimage-bionic//image",
layers = [
":layer_bin",
],
)
container_push(
name = "push",
image = ":runtime",
format = "Docker",
registry = "registry.k0.hswaw.net",
repository = "devtools/depotview",
tag = "{BUILD_TIMESTAMP}-{STABLE_GIT_COMMIT}",
)

View File

@ -3,6 +3,11 @@ depotview
Git-as-a-service over gRPC. Useful to get read-only access to hscloud.
Production
----------
There's a prod instance running at depotview.devtools-prod.svc.cluster.local.
Development
-----------

View File

@ -1,3 +1,4 @@
load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_layer", "container_push")
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
@ -15,6 +16,7 @@ go_library(
"//devtools/hackdoc/source:go_default_library",
"//go/mirko:go_default_library",
"//go/pki:go_default_library",
"@com_github_gabriel_vasile_mimetype//:go_default_library",
"@com_github_golang_glog//:go_default_library",
"@in_gopkg_russross_blackfriday_v2//:go_default_library",
"@org_golang_google_grpc//:go_default_library",
@ -26,3 +28,28 @@ go_binary(
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
container_layer(
name = "layer_bin",
files = [
":hackdoc",
],
directory = "/devtools/",
)
container_image(
name = "runtime",
base = "@prodimage-bionic//image",
layers = [
":layer_bin",
],
)
container_push(
name = "push",
image = ":runtime",
format = "Docker",
registry = "registry.k0.hswaw.net",
repository = "devtools/hackdoc",
tag = "{BUILD_TIMESTAMP}-{STABLE_GIT_COMMIT}",
)

View File

@ -18,6 +18,6 @@ Local Rendering
To run hackdoc locally on a filesystem checkout (ie. when working on docs, templates, or hackdoc itself), run:
bazel run //devtools/hackdoc:local
bazel run //devtools/hackdoc -- -hspki_disable -docroot /path/to/hscloud
The output log should tell you where hackdoc just started listening at. Currently this is `127.0.0.1:8080` by default. You can change this by passing a `-listen` flag, eg. `-listen 127.0.0.1:4242`.

View File

@ -8,7 +8,6 @@ go_library(
deps = [
"//devtools/hackdoc/source:go_default_library",
"@com_github_burntsushi_toml//:go_default_library",
"@com_github_golang_glog//:go_default_library",
],
)

View File

@ -111,7 +111,6 @@ func (s *service) handler(w http.ResponseWriter, r *http.Request) {
return
}
glog.Infof("%+v", r.URL.Query())
ref := r.URL.Query().Get("ref")
if ref == "" {
ref = flagGitwebDefaultBranch
@ -206,7 +205,7 @@ func (r *request) handlePageAuto(dirpath string) {
}
if file {
r.handleMarkdown(fpath, cfg)
http.Redirect(r.w, r.r, "/"+fpath, 302)
return
}
}
@ -238,13 +237,18 @@ func (r *request) handlePage(page string) {
if file {
parts := strings.Split(r.rpath, "/")
dirpath := strings.Join(parts[:(len(parts)-1)], "/")
// TODO(q3k): figure out this hack, hopefully by implementing a real path type
if dirpath == "/" {
dirpath = "//"
}
cfg, err := config.ForPath(r.ctx, r.source, dirpath)
if err != nil {
glog.Errorf("could not get config for path %q: %w", dirpath, err)
r.handle500()
return
}
r.handleMarkdown(r.rpath, cfg)
r.handleFile(r.rpath, cfg)
return
}

View File

@ -8,6 +8,7 @@ import (
"code.hackerspace.pl/hscloud/devtools/hackdoc/config"
"github.com/gabriel-vasile/mimetype"
"github.com/golang/glog"
"gopkg.in/russross/blackfriday.v2"
)
@ -31,6 +32,7 @@ func renderMarkdown(input []byte, ref string) []byte {
q["ref"] = []string{ref}
u.RawQuery = q.Encode()
node.Destination = []byte(u.String())
glog.Infof("link fix %q -> %q", dest, u.String())
}
}
return r.RenderNode(&buf, node, entering)
@ -38,7 +40,12 @@ func renderMarkdown(input []byte, ref string) []byte {
return buf.Bytes()
}
func (r *request) handleMarkdown(path string, cfg *config.Config) {
type pathPart struct {
Label string
Path string
}
func (r *request) handleFile(path string, cfg *config.Config) {
data, err := r.source.ReadFile(r.ctx, path)
if err != nil {
glog.Errorf("ReadFile(%q): %w", err)
@ -46,30 +53,55 @@ func (r *request) handleMarkdown(path string, cfg *config.Config) {
return
}
rendered := renderMarkdown([]byte(data), r.ref)
// TODO(q3k): do MIME detection instead.
if strings.HasSuffix(path, ".md") {
rendered := renderMarkdown([]byte(data), r.ref)
r.logRequest("serving markdown at %s, cfg %+v", path, cfg)
r.logRequest("serving markdown at %s, cfg %+v", path, cfg)
// TODO(q3k): allow markdown files to override which template to load
tmpl, ok := cfg.Templates["default"]
if !ok {
glog.Errorf("No default template found for %s", path)
// TODO(q3k): implement fallback template
r.w.Write(rendered)
return
}
pathInDepot := strings.TrimPrefix(path, "//")
pathParts := []pathPart{
{Label: "//", Path: "/"},
}
parts := strings.Split(pathInDepot, "/")
fullPath := ""
for i, p := range parts {
label := p
if i != len(parts)-1 {
label = label + "/"
}
fullPath += "/" + p
pathParts = append(pathParts, pathPart{Label: label, Path: fullPath})
}
vars := map[string]interface{}{
"Rendered": template.HTML(rendered),
"Title": path,
"Path": path,
"PathInDepot": pathInDepot,
"PathParts": pathParts,
"HackdocURL": flagHackdocURL,
"WebLinks": r.source.WebLinks(pathInDepot),
}
err = tmpl.Execute(r.w, vars)
if err != nil {
glog.Errorf("Could not execute template for %s: %v", err)
}
// TODO(q3k): allow markdown files to override which template to load
tmpl, ok := cfg.Templates["default"]
if !ok {
glog.Errorf("No default template found for %s", path)
// TODO(q3k): implement fallback template
r.w.Write(rendered)
return
}
pathInDepot := strings.TrimPrefix(path, "//")
vars := map[string]interface{}{
"Rendered": template.HTML(rendered),
"Title": path,
"Path": path,
"PathInDepot": pathInDepot,
"HackdocURL": flagHackdocURL,
"WebLinks": r.source.WebLinks(pathInDepot),
}
err = tmpl.Execute(r.w, vars)
if err != nil {
glog.Errorf("Could not execute template for %s: %v", err)
}
// Just serve the file.
mime := mimetype.Detect(data)
r.w.Header().Set("Content-Type", mime.String())
r.w.Write(data)
}

View File

@ -58,7 +58,7 @@ body {
}
.column {
max-width: 80em;
width: 80em;
padding: 1rem 0 1rem 0;
}
@ -85,8 +85,16 @@ body {
color: #b30014;
}
.header span.muted {
.header span.part {
color: #666;
padding-left: 0.2em;
}
.header span.part a {
color: rgb(27, 106, 203);
}
.header span.part a:visited {
color: rgb(27, 106, 203);
}
.footer {
@ -98,6 +106,14 @@ body {
text-align: right;
}
.footer .left {
float: left;
}
.footer .right {
float: right;
}
.footer a {
color: #bbb;
}
@ -164,15 +180,20 @@ ul li::before {
<div class="column">
<div class="page">
<div class="header">
<span class="red">hackdoc:</span><span>{{ .Path }}</span>
{{ range .WebLinks }}
<span class="muted">[{{ .Kind }} <a href="{{ .LinkURL }}">{{ .LinkLabel }}</a>]</span>
{{ end }}
<span class="red">hackdoc:</span>
{{ range .PathParts }}<span class="part"><a href="{{ .Path }}">{{ .Label }}</a></span>{{ end }}
<span class="red" style="margin-left: 1em;">shortcuts:</span> <a href="/">root</a>, <a href="/cluster/doc">cluster docs</a>, <a href="/doc/codelabs">codelabs</a>
</div>
{{ .Rendered }}
</div>
<div class="footer">
Generated by <a href="{{ .HackdocURL }}/devtools/hackdoc">hackdoc</a>.
<div class="left">
View in:
{{ range .WebLinks }}
<span class="muted">[{{ .Kind }} <a href="{{ .LinkURL }}">{{ .LinkLabel }}</a>]</span>
{{ end }}
</div>
<div class="right">Generated by <a href="{{ .HackdocURL }}/devtools/hackdoc">hackdoc</a>.</div>
</div>
</div>
</div>

BIN
doc/img/hscloud-smol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
doc/img/hscloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB