chore: Significantly restructure folder layout

This moves the various projects from "type-based" folders (such as
"services" or "tools") into more appropriate semantic folders (such as
"nix", "ops" or "web").

Deprecated projects (nixcon-demo & gotest) which only existed for
testing/demonstration purposes have been removed.

(Note: *all* builds are broken with this commit)
This commit is contained in:
Vincent Ambo 2019-12-20 20:18:41 +00:00
parent e52eed3cd4
commit 03bfe08e1d
110 changed files with 1 additions and 998 deletions

11
ops/infra/dns/import Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -ue
# Imports a zone file into a Google Cloud DNS zone of the same name
readonly ZONE="${1}"
gcloud dns record-sets import "${ZONE}" \
--project composite-watch-759 \
--zone-file-format \
--delete-all-existing \
--zone "${ZONE}"

View file

@ -0,0 +1,15 @@
;; -*- mode: zone; -*-
;; Do not delete these
kontemplate.works. 21600 IN NS ns-cloud-d1.googledomains.com.
kontemplate.works. 21600 IN NS ns-cloud-d2.googledomains.com.
kontemplate.works. 21600 IN NS ns-cloud-d3.googledomains.com.
kontemplate.works. 21600 IN NS ns-cloud-d4.googledomains.com.
kontemplate.works. 21600 IN SOA ns-cloud-d1.googledomains.com. cloud-dns-hostmaster.google.com. 4 21600 3600 259200 300
;; Github site setup
kontemplate.works. 60 IN A 185.199.108.153
kontemplate.works. 60 IN A 185.199.109.153
kontemplate.works. 60 IN A 185.199.110.153
kontemplate.works. 60 IN A 185.199.111.153
www.kontemplate.works. 60 IN CNAME tazjin.github.io.

8
ops/infra/dns/oslo-pub Normal file
View file

@ -0,0 +1,8 @@
;; Do not delete these
oslo.pub. 21600 IN NS ns-cloud-c1.googledomains.com.
oslo.pub. 21600 IN NS ns-cloud-c2.googledomains.com.
oslo.pub. 21600 IN NS ns-cloud-c3.googledomains.com.
oslo.pub. 21600 IN NS ns-cloud-c4.googledomains.com.
oslo.pub. 21600 IN SOA ns-cloud-c1.googledomains.com. cloud-dns-hostmaster.google.com. 4 21600 3600 1209600 300
oslo.pub. 60 IN A 46.21.106.241

View file

@ -0,0 +1,33 @@
;; -*- mode: zone; -*-
;; Do not delete these
tazj.in. 21600 IN NS ns-cloud-a1.googledomains.com.
tazj.in. 21600 IN NS ns-cloud-a2.googledomains.com.
tazj.in. 21600 IN NS ns-cloud-a3.googledomains.com.
tazj.in. 21600 IN NS ns-cloud-a4.googledomains.com.
tazj.in. 21600 IN SOA ns-cloud-a1.googledomains.com. cloud-dns-hostmaster.google.com. 123 21600 3600 1209600 300
;; Email setup
tazj.in. 300 IN MX 1 aspmx.l.google.com.
tazj.in. 300 IN MX 5 alt1.aspmx.l.google.com.
tazj.in. 300 IN MX 5 alt2.aspmx.l.google.com.
tazj.in. 300 IN MX 10 alt3.aspmx.l.google.com.
tazj.in. 300 IN MX 10 alt4.aspmx.l.google.com.
tazj.in. 300 IN TXT "v=spf1 include:_spf.google.com ~all"
google._domainkey.tazj.in. 21600 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9AphX/WJf8zVXQB5Jk0Ry1MI6ARa6vEyAoJtpjpt9Nbm7XU4qVWFRJm+L0VFd5EZ5YDPJTIZ90lJE3/B8vae2ipnoGbJbj8LaVSzzIPMbWmhPhX3fkLJFdkv7xRDMDn730iYXRlfkgv6GsqbS8vZt7mzxx4mpnePTI323yjRVkwRW8nGVbsmB25ZoG1/0985" "kg4mSYxzWeJ2ozCPFhT4sfMtZMXe/4QEkJz/zkod29KZfFJmLgEaf73WLdBX8kdwbhuh2PYXt/PwzUrRzF5ujVCsSaTZwdRVPErcf+yo4NvedelTjjs8rFVfoJiaDD1q2bQ3w0gDEBWPdC2VP7k9zwIDAQAB"
;; Site verifications
tazj.in. 3600 IN TXT "keybase-site-verification=gC4kzEmnLzY7F669PjN-pw2Cf__xHqcxQ08Gb-W9dhE"
tazj.in. 300 IN TXT "google-site-verification=d3_MI1OwD6q2OT42Vvh0I9w2u3Q5KFBu-PieNUE1Fig"
www.tazj.in. 3600 IN TXT "keybase-site-verification=ER8m_byyqAhzeIy9TyzkAU1H2p2yHtpvImuB_XrRF2U"
;; Blog "storage engine"
blog.tazj.in. 21600 IN NS ns-cloud-c1.googledomains.com.
blog.tazj.in. 21600 IN NS ns-cloud-c2.googledomains.com.
blog.tazj.in. 21600 IN NS ns-cloud-c3.googledomains.com.
blog.tazj.in. 21600 IN NS ns-cloud-c4.googledomains.com.
;; Webpage records setup
tazj.in. 300 IN A 34.98.120.189
www.tazj.in. 300 IN A 34.98.120.189
git.tazj.in. 300 IN A 34.98.120.189
files.tazj.in. 300 IN CNAME c.storage.googleapis.com.

3
ops/infra/gcp/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.terraform
*.tfstate
*.tfstate.backup

111
ops/infra/gcp/default.tf Normal file
View file

@ -0,0 +1,111 @@
# Terraform configuration for the GCP project 'tazjins-infrastructure'
provider "google" {
project = "tazjins-infrastructure"
region = "europe-north1"
}
# Configure a storage bucket in which to keep Terraform state and
# other data, such as Nixery's layers.
resource "google_storage_bucket" "tazjins-data" {
name = "tazjins-data"
location = "EU"
}
terraform {
backend "gcs" {
bucket = "tazjins-data"
prefix = "terraform"
}
}
# Configure enabled APIs
resource "google_project_services" "primary" {
project = "tazjins-infrastructure"
services = [
"bigquery-json.googleapis.com",
"bigquerystorage.googleapis.com",
"cloudapis.googleapis.com",
"clouddebugger.googleapis.com",
"cloudfunctions.googleapis.com",
"cloudkms.googleapis.com",
"cloudtrace.googleapis.com",
"compute.googleapis.com",
"container.googleapis.com",
"containerregistry.googleapis.com",
"datastore.googleapis.com",
"dns.googleapis.com",
"iam.googleapis.com",
"iamcredentials.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"oslogin.googleapis.com",
"pubsub.googleapis.com",
"run.googleapis.com",
"servicemanagement.googleapis.com",
"serviceusage.googleapis.com",
"sourcerepo.googleapis.com",
"sql-component.googleapis.com",
"storage-api.googleapis.com",
"storage-component.googleapis.com",
]
}
# Configure the main Kubernetes cluster in which services are deployed
resource "google_container_cluster" "primary" {
name = "tazjin-cluster"
location = "europe-north1"
remove_default_node_pool = true
initial_node_count = 1
}
resource "google_container_node_pool" "primary_nodes" {
name = "primary-nodes"
location = "europe-north1"
cluster = google_container_cluster.primary.name
node_count = 1
node_config {
preemptible = true
machine_type = "n1-standard-2"
oauth_scopes = [
"storage-rw",
"logging-write",
"monitoring",
"https://www.googleapis.com/auth/source.read_only",
]
}
}
# Configure a service account for which GCS URL signing keys can be created.
resource "google_service_account" "nixery" {
account_id = "nixery"
display_name = "Nixery service account"
}
# Configure Cloud KMS for secret encryption
resource "google_kms_key_ring" "tazjins_keys" {
name = "tazjins-keys"
location = "europe-north1"
lifecycle {
prevent_destroy = true
}
}
resource "google_kms_crypto_key" "kontemplate_key" {
name = "kontemplate-key"
key_ring = google_kms_key_ring.tazjins_keys.id
lifecycle {
prevent_destroy = true
}
}
# Configure the git repository that contains everything.
resource "google_sourcerepo_repository" "depot" {
name = "depot"
}

View file

@ -0,0 +1,73 @@
---
apiVersion: v1
kind: Secret
metadata:
name: gcsr-secrets
type: Opaque
data:
username: "Z2l0LXRhemppbi5nbWFpbC5jb20="
# This credential is a GCSR 'gitcookie' token.
password: '{{ passLookup "gcsr-tazjin-password" | b64enc }}'
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cgit
labels:
app: cgit
spec:
replicas: 2
selector:
matchLabels:
app: cgit
template:
metadata:
labels:
app: cgit
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: cgit
image: nixery.local/shell/services.cgit-taz:{{ gitHEAD }}
command: [ "cgit-launch" ]
env:
- name: HOME
value: /git
volumeMounts:
- name: git-volume
mountPath: /git
- name: sync-gcsr
image: nixery.local/shell/services.sync-gcsr:{{ gitHEAD }}
command: [ "sync-gcsr" ]
env:
- name: SYNC_USER
valueFrom:
secretKeyRef:
name: gcsr-secrets
key: username
- name: SYNC_PASS
valueFrom:
secretKeyRef:
name: gcsr-secrets
key: password
volumeMounts:
- name: git-volume
mountPath: /git
volumes:
- name: git-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: cgit
spec:
selector:
app: cgit
ports:
- protocol: TCP
port: 80
targetPort: 8080

View file

@ -0,0 +1,19 @@
(config :port 4242
:data-dir "/var/lib/gemma/")
(deftask bathroom/wipe-mirror 7)
(deftask bathroom/wipe-counter 7)
;; Bedroom tasks
(deftask bedroom/change-sheets 7)
(deftask bedroom/vacuum 10)
;; Kitchen tasks
(deftask kitchen/normal-trash 3)
(deftask kitchen/green-trash 5)
(deftask kitchen/blue-trash 5)
(deftask kitchen/wipe-counters 3)
(deftask kitchen/vacuum 5 "Kitchen has more crumbs and such!")
;; Entire place
(deftask clean-windows 60)

View file

@ -0,0 +1,8 @@
---
apiVersion: networking.gke.io/v1beta1
kind: ManagedCertificate
metadata:
name: {{ .domain | replace "." "-" }}
spec:
domains:
- {{ .domain }}

View file

@ -0,0 +1,35 @@
# This resource configures the HTTPS load balancer that is used as the
# entrypoint to all HTTPS services running in the cluster.
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: https-ingress
annotations:
networking.gke.io/managed-certificates: tazj-in, git-tazj-in, www-tazj-in, oslo-pub
spec:
rules:
# Route blog to the blog ...
- host: tazj.in
http:
paths:
- path: /*
backend:
serviceName: tazblog
servicePort: 8000
# Route git.tazj.in to the cgit pods
- host: git.tazj.in
http:
paths:
- path: /*
backend:
serviceName: nginx
servicePort: 6756
# Route oslo.pub to the nginx instance which serves redirects
- host: oslo.pub
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 6756

View file

@ -0,0 +1,59 @@
daemon off;
worker_processes 1;
error_log stderr;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status": "$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
access_log /dev/stdout json_combined;
sendfile on;
keepalive_timeout 65;
server {
listen 80 default_server;
location / {
return 200 "ok";
}
}
server {
listen 80;
server_name oslo.pub;
location / {
return 302 https://www.google.com/maps/d/viewer?mid=1pJIYY9cuEdt9DuMTbb4etBVq7hs;
}
}
server {
listen 80;
server_name git.tazj.in;
# Static assets must always hit the root.
location ~ ^/(favicon\.ico|cgit\.(css|png))$ {
proxy_pass http://cgit;
}
# Everything else hits the depot directly.
location / {
proxy_pass http://cgit/cgit.cgi/depot/;
}
}
}

View file

@ -0,0 +1,60 @@
# Deploy an nginx instance which serves ... redirects.
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
nginx.conf: {{ insertFile "nginx.conf" | toJson }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
config: {{ insertFile "nginx.conf" | sha1sum }}
spec:
containers:
- name: tazblog
image: nixery.local/shell/third_party.nginx:{{ .version }}
command: ["/bin/bash", "-c"]
args:
- |
cd /run
echo 'nogroup:x:30000:nobody' >> /etc/group
echo 'nobody:x:30000:30000:nobody:/tmp:/bin/bash' >> /etc/passwd
exec nginx -c /etc/nginx/nginx.conf
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx
- name: nginx-rundir
mountPath: /run
volumes:
- name: nginx-conf
configMap:
name: nginx-conf
- name: nginx-rundir
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 6756
targetPort: 80

View file

@ -0,0 +1,67 @@
# Deploys an instance of Nixery into the cluster.
#
# The service via which Nixery is exposed has a private DNS entry
# pointing to it, which makes it possible to resolve `nixery.local`
# in-cluster without things getting nasty.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nixery
namespace: kube-public
labels:
app: nixery
spec:
replicas: 1
selector:
matchLabels:
app: nixery
template:
metadata:
labels:
app: nixery
spec:
containers:
- name: nixery
image: eu.gcr.io/tazjins-infrastructure/nixery:{{ .version }}
volumeMounts:
- name: nixery-secrets
mountPath: /var/nixery
env:
- name: BUCKET
value: {{ .bucket}}
- name: PORT
value: "{{ .port }}"
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /var/nixery/gcs-key.json
- name: GCS_SIGNING_KEY
value: /var/nixery/gcs-key.pem
- name: GCS_SIGNING_ACCOUNT
value: {{ .account }}
- name: GIT_SSH_COMMAND
value: 'ssh -F /var/nixery/ssh_config'
- name: NIXERY_PKGS_REPO
value: {{ .repo }}
- name: NIX_POPULARITY_URL
value: 'https://storage.googleapis.com/nixery-layers/popularity/{{ .popularity }}'
volumes:
- name: nixery-secrets
secret:
secretName: nixery-secrets
defaultMode: 256
---
apiVersion: v1
kind: Service
metadata:
name: nixery
namespace: kube-public
annotations:
cloud.google.com/load-balancer-type: "Internal"
spec:
selector:
app: nixery
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 8080

View file

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzBM6ydst77jDHNcTFWKD9Fw4SReqyNEEp2MtQBk2wt94U4yLp8MQIuNeOEn1GaDEX4RGCxqai/2UVF1w9ZNdU+v2fXcKWfkKuGQH2XcNfXor2cVNObd40H78++iZiv3nmM/NaEdkTbTBbi925cRy9u5FgItDgsJlyKNRglCb0fr6KlgpvWjL20dp/eeZ8a/gLniHK8PnEsgERQSvJnsyFpxxVhxtoUiyLWpXDl4npf/rQr0eRDf4Q5sN/nbTwksapPHfze8dKcaoA7A2NqT3bJ6DPGrwVCzGRtGw/SXJwFwmmtAl9O6BklpeReyiknSxc+KOtrjDW6O0r6yvymD5Z nixery

View file

@ -0,0 +1,2 @@
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
140.82.118.4 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==

View file

@ -0,0 +1,18 @@
# The secrets below are encrypted using keys stored in Cloud KMS and
# templated in by kontemplate when deploying.
#
# Not all of the values are actually secret (see the matching)
---
apiVersion: v1
kind: Secret
metadata:
name: nixery-secrets
namespace: kube-public
type: Opaque
data:
gcs-key.json: {{ passLookup "nixery-gcs-json" | b64enc }}
gcs-key.pem: {{ passLookup "nixery-gcs-pem" | b64enc }}
id_nixery: {{ printf "%s\n" (passLookup "nixery-ssh-private") | b64enc }}
id_nixery.pub: {{ insertFile "id_nixery.pub" | b64enc }}
known_hosts: {{ insertFile "known_hosts" | b64enc }}
ssh_config: {{ insertFile "ssh_config" | b64enc }}

View file

@ -0,0 +1,4 @@
Match host *
User tazjin@google.com
IdentityFile /var/nixery/id_nixery
UserKnownHostsFile /var/nixery/known_hosts

View file

@ -0,0 +1,38 @@
# Kontemplate configuration for the primary GKE cluster in the project
# 'tazjins-infrastructure'.
---
context: gke_tazjins-infrastructure_europe-north1_tazjin-cluster
include:
# SSL certificates (provisioned by Google)
- name: tazj-in-cert
path: https-cert
values:
domain: tazj.in
- name: www-tazj-in-cert
path: https-cert
values:
domain: www.tazj.in
- name: git-tazj-in-cert
path: https-cert
values:
domain: git.tazj.in
- name: oslo-pub-cert
path: https-cert
values:
domain: oslo.pub
# Services
- name: nixery
values:
port: 8080
version: xkm36vrbcnzxdccybzdrx4qzfcfqfrhg
bucket: tazjins-data
account: nixery@tazjins-infrastructure.iam.gserviceaccount.com
repo: ssh://tazjin@gmail.com@source.developers.google.com:2022/p/tazjins-infrastructure/r/depot
popularity: 'popularity-nixos-unstable-3140fa89c51233397f496f49014f6b23216667c2.json'
- name: tazblog
- name: cgit
- name: https-lb
- name: nginx
values:
version: a349d5e9145ae9a6c89f62ec631f01fb180de546

View file

@ -0,0 +1,34 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tazblog
labels:
app: tazblog
spec:
replicas: 2
selector:
matchLabels:
app: tazblog
template:
metadata:
labels:
app: tazblog
spec:
containers:
- name: tazblog
image: nixery.local/shell/services.tazblog:{{ gitHEAD }}
command: [ "tazblog" ]
---
apiVersion: v1
kind: Service
metadata:
name: tazblog
spec:
type: NodePort
selector:
app: tazblog
ports:
- protocol: TCP
port: 8000
targetPort: 8000

3
ops/infra/nixos/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
hardware-configuration.nix
local-configuration.nix
result

23
ops/infra/nixos/README.md Normal file
View file

@ -0,0 +1,23 @@
NixOS configuration
===================
My NixOS configuration! It configures most of the packages I require
on my systems, sets up Emacs the way I need and does a bunch of other
interesting things.
In contrast with earlier versions of this configuration, the Nix
channel versions are now pinned in Nix (see the beginning of
[packages.nix][]).
Machine-local configuration is kept in files with the naming scheme
`$hostname-configuration.nix` and **must** be symlinked to
`local-configuration.nix` before the first configuration run.
I'm publishing this repository (and my [emacs configuration][]) as a
convenience for myself, but also as a resource that people looking for
example Nix or Emacs configurations can browse through.
Feel free to ping me with any questions you might have.
[packages.nix]: packages.nix
[emacs configuration]: https://github.com/tazjin/emacs.d

View file

@ -0,0 +1,200 @@
# Local configuration for 'adho' (Thinkpad T470s)
{ config, pkgs, ...}:
{
boot.initrd.luks.devices.adho.device = "/dev/disk/by-uuid/722006b0-9654-4ea1-8703-e0cf9ac1905e";
boot.kernelModules = [ "kvm-intel" ];
services.xserver.libinput.enable = true;
services.xserver.videoDrivers = [ "intel" ];
programs.light.enable = true;
# Office printer configuration
services.printing.enable = true;
services.printing.drivers = [ pkgs.hplip ];
services.avahi.enable = true;
services.avahi.nssmdns = true;
# Enable VirtualBox to update Beatstep Pro firmware:
virtualisation.virtualbox.host.enable = true;
virtualisation.virtualbox.host.enableExtensionPack = true;
# Enable LXC/LXD for Nixini work
virtualisation.lxd.enable = true;
# Give me more entropy:
services.haveged.enable = true;
# Disable sandbox to let work-builds function:
nix.useSandbox = false;
# Yubikey related:
services.pcscd.enable = true;
environment.systemPackages = with pkgs; [
cfssl
libp11
opensc
yubico-piv-tool
];
networking = {
hostName = "adho";
wireless.enable = true;
wireless.userControlled.enable = true;
wireless.networks = {
# Welcome to roast club!
"How do I computer?" = {
psk = "washyourface";
};
# On the go!
"Rumpetroll" = {
psk = "fisk1234";
# If this network exists, chances are that I want it:
priority = 10;
};
# Public places in Oslo:
"Abelone" = {
psk = "speakeasy";
};
"Wurst" = {
psk = "wurst2015";
};
"postkontoret" = {
psk = "postkontoret";
};
# Eugene's apartment:
"GET_5G_4FD250" = {
psk = "62636342";
};
# FSCONS 2017
"uioguest" = {};
# Hackeriet!
"hackeriet.no" = {
psk = "hackeriet.no";
};
# Cafe Sara
"Sara Nett" = {
psk = "sarabar1989";
};
# The Dubliner
"DubGjest" = {
# of course
psk = "Guinness";
};
"MAGNAT Guest" = {
psk = "elmolino021";
};
"BrewDog" = {
psk = "welovebeer";
};
# Dima's
"What's a Bad Idea?" = {
psk = "DQDxzrzIvy0YtDwH";
};
# Loke's
"VMC28F76E" = {
psk = "d2ftQnr6xppw";
};
"SafetyWiFi - Teknologihuset" = {
psk = "tech4ever";
};
"Selvaag Pluss" = {
psk = "detlilleekstra";
};
"Langler" = {
psk = "Oslo2018";
};
# Pils & Programmering
"BEKKguest" = {
psk = "guest7890";
};
"Homan-Gjest" = {
psk = "haveaniceday";
};
# Røverstaden
"Roverstaden" = {
psk = "r0verstaden2018";
};
"The Brew Dock" = {
psk = "realbeer";
};
"econ-guest" = {
psk = "Finance2010";
};
"KabelBox-2FD0" = {
psk = "92433048597489095671";
};
"TheKasbah" = {
psk = "couscous";
};
# Kitty's misspelled network.
"How do I Computer?" = {
psk = "herpderpponies";
};
# NixCon 2018
"Coin Street Community Builders " = {
psk = "3vents2016";
};
"KH2 Gjest" = {
psk = "haenfindag";
};
# Forest & Brown
"Forest Guest" = {
psk = "437B99AC5B";
};
"Gatwick FREE Wi-Fi" = {};
"mycloud" = {};
"Norwegian Internet Access" = {};
"NSB_INTERAKTIV" = {};
"The Thief" = {};
"espressohouse" = {};
"Gotanet Open" = {};
"wifi.flytoget.no" = {};
"AIRPORT" = {};
"ilcaffelovesyou" = {};
"WIFIonICE" = {};
"Lorry Gjest" = {};
"Amundsengjest" = {};
"Beer Palace Gjest" = {};
"ibis" = {};
"GoogleGuest" = {};
};
};
hardware.bluetooth.enable = true;
# Configure POSIX queue limits (for work)
systemd.tmpfiles.rules = let mqueue = "/proc/sys/fs/mqueue"; in [
"w ${mqueue}/msgsize_max - - - - ${toString (64 * 1024)}"
"w ${mqueue}/msg_max - - - - 50"
];
}

View file

@ -0,0 +1,102 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, lib, pkgs, ... }:
{
imports =
[
./desktop.nix
./dotfiles.nix
./hardware-configuration.nix
./local-configuration.nix
./mail.nix
./packages.nix
];
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.cleanTmpDir = true;
hardware.pulseaudio.enable = true;
time.timeZone = "Europe/Oslo";
# Configure audio setup for JACK + Overtone
boot.kernelModules = [ "snd-seq" "snd-rawmidi" ];
hardware.pulseaudio.package = pkgs.pulseaudioFull;
# Update Intel microcode on boot (both machines have Intel CPUs):
hardware.cpu.intel.updateMicrocode = true;
networking = {
# Don't use ISP's DNS servers:
nameservers = [
"1.1.1.1"
"1.0.0.1"
];
# Open Chromecast-related ports & servedir
firewall.allowedTCPPorts = [ 3000 5556 5558 ];
};
# Generate an immutable /etc/resolv.conf from the nameserver settings
# above (otherwise DHCP overwrites it):
environment.etc."resolv.conf" = with lib; with pkgs; {
source = writeText "resolv.conf" ''
${concatStringsSep "\n" (map (ns: "nameserver ${ns}") config.networking.nameservers)}
options edns0
'';
};
# Configure emacs:
# (actually, that's a lie, this only installs emacs!)
services.emacs = {
install = true;
defaultEditor = true;
package = import ./emacs.nix { inherit pkgs; };
};
services.openssh.enable = true;
# Enable GNOME keyring (required for Evolution)
services.gnome3.gnome-keyring.enable = true;
virtualisation = {
# Configure Docker (with socket activation):
# Side note: ... why is this in virtualisation? ...
docker.enable = true;
docker.autoPrune.enable = true;
};
# Configure various other applications:
programs = {
java.enable = true;
java.package = pkgs.openjdk;
fish.enable = true;
ssh.startAgent = true;
};
services.postgresql.enable = true;
# Configure user account
users.defaultUserShell = pkgs.fish;
users.extraUsers.vincent = {
extraGroups = [ "wheel" "docker" "vboxusers" "lxd" ];
isNormalUser = true;
uid = 1000;
shell = pkgs.fish;
};
security.sudo = {
enable = true;
extraConfig = "wheel ALL=(ALL:ALL) SETENV: ALL";
};
# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "18.03"; # Did you read the comment?
}

View file

@ -0,0 +1,6 @@
{ ... }:
builtins.throw ''
The Nix derivations at infra/nixos are not meant to be evaluated
like a derivation as they represent NixOS configuration.
''

View file

@ -0,0 +1,82 @@
# Configuration for the desktop environment
{ config, lib, pkgs, ... }:
let emacs = import ./emacs.nix { inherit pkgs; };
screenLock = pkgs.writeShellScriptBin "screen-lock" ''
find ${pkgs.wallpapers} -name "*.png" | shuf -n1 | xargs i3lock -f -t -i
'';
in {
# Configure basic X-server stuff:
services.xserver = {
enable = true;
layout = "us,no";
xkbOptions = "caps:super, grp:shifts_toggle, parens:swap_brackets";
exportConfiguration = true;
# Give EXWM permission to control the session.
displayManager.sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localuser:$USER";
# Use the pre 18.09 default display manager (slim)
displayManager.slim.enable = true;
};
# Add a shell script with random screen lock wallpaper selection
environment.systemPackages = [ screenLock ];
# Apparently when you have house guests they complain about your screen tearing!
services.compton.enable = true;
services.compton.backend = "xrender";
# Configure desktop environment:
services.xserver.windowManager.session = lib.singleton {
name = "exwm";
start = ''
${emacs}/bin/emacs --eval '(progn (server-start) (exwm-enable))'
'';
};
# Configure Redshift for Oslo
services.redshift = {
enable = true;
latitude = "59.911491";
longitude = "10.757933";
};
# Configure fonts
fonts = {
fonts = with pkgs; [
corefonts
font-awesome-ttf
input-fonts
noto-fonts-cjk
noto-fonts-emoji
powerline-fonts
helvetica-neue-lt-std
];
};
# Configure random setting of wallpapers
systemd.user.services.feh-wp = {
description = "Randomly set wallpaper via feh";
serviceConfig = {
Type = "oneshot";
WorkingDirectory = "${pkgs.wallpapers}/share/wallpapers";
# Manually shuffle because feh's --randomize option can't be restricted to
# just certain file types.
ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.fd}/bin/fd -atf | shuf | head -n1 | ${pkgs.findutils}/bin/xargs ${pkgs.feh}/bin/feh --bg-fill'";
};
};
systemd.user.timers.feh-wp = {
description = "Set a random wallpaper every hour";
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session.target" ];
timerConfig = {
OnActiveSec = "1second";
OnUnitActiveSec = "1hour";
};
};
}

View file

@ -0,0 +1,27 @@
# Bundle configuration files into a derivation.
# I call this derivation dotfiles despite that not technically being true
# anymore ...
{ config, pkgs, ...}:
let dotfiles = pkgs.stdenv.mkDerivation {
name = "tazjins-dotfiles";
srcs = [
./dotfiles
];
installPhase = ''
mkdir -p $out
cp ./* $out/
'';
};
in {
# /etc/ is a special place in NixOS!
# Symlinks that need to be created there must be specified explicitly.
environment.etc = {
"alacritty.yml".source = "${dotfiles}/alacritty.yml";
"fish/config.fish".source = "${dotfiles}/config.fish";
"tmux.conf".source = "${dotfiles}/tmux.conf";
};
}

View file

@ -0,0 +1,203 @@
# Configuration for Alacritty, the GPU enhanced terminal emulator
# Any items in the `env` entry below will be added as
# environment variables. Some entries may override variables
# set by alacritty it self.
env:
TERM: xterm-256color
window:
# TODO
decorations: full
scrolling:
history: 10000
multiplier: 3
faux_multiplier: 3
auto_scroll: true # TODO
# Display tabs using this many cells (changes require restart)
tabspaces: 4
# When true, bold text is drawn using the bright variant of colors.
draw_bold_text_with_bright_colors: true
# Font configuration (changes require restart)
font:
# The normal (roman) font face to use.
normal:
family: Input Mono
bold:
family: Input Mono
italic:
family: Input Mono
# Point size of the font
size: 12.0
# Scale the font size based on the monitor's DPI.
scale_with_dpi: false
# Use custom cursor colors. If true, display the cursor in the cursor.foreground
# and cursor.background colors, otherwise invert the colors of the cursor.
custom_cursor_colors: false
# Colors (Gruber Darker)
colors:
# Default colors
primary:
background: '0x181818'
foreground: '0xe4e4ef'
# Colors the cursor will use if `custom_cursor_colors` is true
cursor:
text: '0x000000'
cursor: '0xf5f5f5'
# Normal colors
normal:
black: '0x282828'
red: '0xf43841'
green: '0x73c936'
yellow: '0xffdd33'
blue: '0x96a6c8'
magenta: '0x9e95c7'
cyan: '0x1fad83'
white: '0xf5f5f5'
# Bright colors
bright:
black: '0x484848'
red: '0xff4f58'
green: '0x73c936'
yellow: '0xffdd33'
blue: '0x5f627f'
magenta: '0x9e95c7'
cyan: '0x1fad83'
white: '0xffffff'
# Background opacity
# Key bindings
#
# Each binding is defined as an object with some properties. Most of the
# properties are optional. All of the alphabetical keys should have a letter for
# the `key` value such as `V`. Function keys are probably what you would expect
# as well (F1, F2, ..). The number keys above the main keyboard are encoded as
# `Key1`, `Key2`, etc. Keys on the number pad are encoded `Number1`, `Number2`,
# etc. These all match the glutin::VirtualKeyCode variants.
#
# Possible values for `mods`
# `Command`, `Super` refer to the super/command/windows key
# `Control` for the control key
# `Shift` for the Shift key
# `Alt` and `Option` refer to alt/option
#
# mods may be combined with a `|`. For example, requiring control and shift
# looks like:
#
# mods: Control|Shift
#
# The parser is currently quite sensitive to whitespace and capitalization -
# capitalization must match exactly, and piped items must not have whitespace
# around them.
#
# Either an `action`, `chars`, or `command` field must be present.
# `action` must be one of `Paste`, `PasteSelection`, `Copy`, or `Quit`.
# `chars` writes the specified string every time that binding is activated.
# These should generally be escape sequences, but they can be configured to
# send arbitrary strings of bytes.
# `command` must be a map containing a `program` string, and `args` array of
# strings. For example:
# - { ... , command: { program: "alacritty", args: ["-e", "vttest"] } }
#
# Want to add a binding (e.g. "PageUp") but are unsure what the X sequence
# (e.g. "\x1b[5~") is? Open another terminal (like xterm) without tmux,
# then run `showkey -a` to get the sequence associated to a key combination.
key_bindings:
- { key: V, mods: Control|Shift, action: Paste }
- { key: C, mods: Control|Shift, action: Copy }
- { key: Q, mods: Command, action: Quit }
- { key: W, mods: Command, action: Quit }
- { key: Insert, mods: Shift, action: PasteSelection }
- { key: Home, chars: "\x1bOH", mode: AppCursor }
- { key: Home, chars: "\x1b[H", mode: ~AppCursor }
- { key: End, chars: "\x1bOF", mode: AppCursor }
- { key: End, chars: "\x1b[F", mode: ~AppCursor }
- { key: PageUp, mods: Shift, chars: "\x1b[5;2~" }
- { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
- { key: PageUp, chars: "\x1b[5~" }
- { key: PageDown, mods: Shift, chars: "\x1b[6;2~" }
- { key: PageDown, mods: Control, chars: "\x1b[6;5~" }
- { key: PageDown, chars: "\x1b[6~" }
- { key: Left, mods: Shift, chars: "\x1b[1;2D" }
- { key: Left, mods: Control, chars: "\x1b[1;5D" }
- { key: Left, mods: Alt, chars: "\x1b[1;3D" }
- { key: Left, chars: "\x1b[D", mode: ~AppCursor }
- { key: Left, chars: "\x1bOD", mode: AppCursor }
- { key: Right, mods: Shift, chars: "\x1b[1;2C" }
- { key: Right, mods: Control, chars: "\x1b[1;5C" }
- { key: Right, mods: Alt, chars: "\x1b[1;3C" }
- { key: Right, chars: "\x1b[C", mode: ~AppCursor }
- { key: Right, chars: "\x1bOC", mode: AppCursor }
- { key: Up, mods: Shift, chars: "\x1b[1;2A" }
- { key: Up, mods: Control, chars: "\x1b[1;5A" }
- { key: Up, mods: Alt, chars: "\x1b[1;3A" }
- { key: Up, chars: "\x1b[A", mode: ~AppCursor }
- { key: Up, chars: "\x1bOA", mode: AppCursor }
- { key: Down, mods: Shift, chars: "\x1b[1;2B" }
- { key: Down, mods: Control, chars: "\x1b[1;5B" }
- { key: Down, mods: Alt, chars: "\x1b[1;3B" }
- { key: Down, chars: "\x1b[B", mode: ~AppCursor }
- { key: Down, chars: "\x1bOB", mode: AppCursor }
- { key: Tab, mods: Shift, chars: "\x1b[Z" }
- { key: F1, chars: "\x1bOP" }
- { key: F2, chars: "\x1bOQ" }
- { key: F3, chars: "\x1bOR" }
- { key: F4, chars: "\x1bOS" }
- { key: F5, chars: "\x1b[15~" }
- { key: F6, chars: "\x1b[17~" }
- { key: F7, chars: "\x1b[18~" }
- { key: F8, chars: "\x1b[19~" }
- { key: F9, chars: "\x1b[20~" }
- { key: F10, chars: "\x1b[21~" }
- { key: F11, chars: "\x1b[23~" }
- { key: F12, chars: "\x1b[24~" }
- { key: Back, chars: "\x7f" }
- { key: Back, mods: Alt, chars: "\x1b\x7f" }
- { key: Insert, chars: "\x1b[2~" }
- { key: Delete, chars: "\x1b[3~" }
# Mouse bindings
#
# Currently doesn't support modifiers. Both the `mouse` and `action` fields must
# be specified.
#
# Values for `mouse`:
# - Middle
# - Left
# - Right
# - Numeric identifier such as `5`
#
# Values for `action`:
# - Paste
# - PasteSelection
# - Copy (TODO)
mouse_bindings:
- { mouse: Middle, action: PasteSelection }
mouse:
double_click: { threshold: 300 }
triple_click: { threshold: 300 }
selection:
semantic_escape_chars: ",│`|:\"' ()[]{}<>"
background_opacity: 1.0
hide_cursor_when_typing: false
# Live config reload (changes require restart)
live_config_reload: true
# Disable visual bell
visual_bell:
duration: 0

View file

@ -0,0 +1,40 @@
# Configure classic prompt
set fish_color_user --bold blue
set fish_color_cwd --bold white
# Enable colour hints in VCS prompt:
set __fish_git_prompt_showcolorhints yes
set __fish_git_prompt_color_prefix purple
set __fish_git_prompt_color_suffix purple
# Fish configuration
set fish_greeting ""
set PATH $HOME/.local/bin $HOME/.cargo/bin $PATH
# Editor configuration
set -gx EDITOR "emacsclient"
set -gx ALTERNATE_EDITOR "emacs -q -nw"
set -gx VISUAL "emacsclient"
# Miscellaneous
eval (direnv hook fish)
# Useful command aliases
alias gpr 'git pull --rebase'
alias gco 'git checkout'
alias gf 'git fetch'
alias gap 'git add -p'
alias pbcopy 'xclip -selection clipboard'
alias edit 'emacsclient -n'
alias servedir 'nix-shell -p haskellPackages.wai-app-static --run warp'
# Old habits die hard (also ls is just easier to type):
alias ls 'exa'
# Fix up nix-env & friends for Nix 2.0
export NIX_REMOTE=daemon
# Fix display of fish in emacs' term-mode:
function fish_title
true
end

View file

@ -0,0 +1,16 @@
defaults
port 587
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
# Runbox mail
account runbox
from mail@tazj.in
host mail.runbox.com
auth on
user mail@tazj.in
passwordeval pass show general/runbox-tazjin
# Use Runbox as default
account default : runbox

View file

@ -0,0 +1,21 @@
# .notmuch-config - Configuration file for the notmuch mail system
#
# For more information about notmuch, see https://notmuchmail.org
[database]
path=/home/vincent/mail
[user]
name=Vincent Ambo
primary_email=mail@tazj.in
other_email=tazjin@gmail.com;
[new]
tags=unread;inbox;
ignore=
[search]
exclude_tags=deleted;spam;draft;
[maildir]
synchronize_flags=true

View file

@ -0,0 +1,39 @@
[general]
accounts = tazjin, gmail
[DEFAULT]
ssl = yes
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
# Private GMail account (old):
[Account gmail]
maxage = 90
localrepository = gmail-local
remoterepository = gmail-remote
synclabels = yes
[Repository gmail-local]
type = GmailMaildir
localfolders = ~/mail/gmail
[Repository gmail-remote]
type = Gmail
remoteuser = tazjin@gmail.com
remotepassfile = ~/.config/mail/gmail-pass
folderfilter = lambda folder: folder == 'INBOX'
# Main private account:
[Account tazjin]
localrepository = tazjin-local
remoterepository = tazjin-remote
[Repository tazjin-local]
type = Maildir
localfolders = ~/mail/tazjin
[Repository tazjin-remote]
type = IMAP
remotehost = mail.runbox.com
remoteuser = mail@tazj.in
remotepassfile = ~/.config/mail/tazjin-pass
auth_mechanisms = LOGIN

View file

@ -0,0 +1,14 @@
set -g status off
set -gw mode-keys emacs
setw -g mouse on
# Correctly set window titles
set -g set-titles on
set -g set-titles-string "#W (#T)"
# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-yank'
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'

75
ops/infra/nixos/home.nix Normal file
View file

@ -0,0 +1,75 @@
# home-manager configuration used on ChromeOS systems
{ config, pkgs, ... }:
{
# Allow non-free software (fonts, IDEA, etc.):
nixpkgs.config.allowUnfree = true;
# Install various useful packages:
home.packages = with pkgs; [
bat
exa
gnupg
google-cloud-sdk
htop
pass
ripgrep
tdesktop
transmission
tree
# Fonts to make available in X11 applications:
input-fonts
# Emacs configuration stays in the normal ~/.emacs.d location (for
# now), hence this package is not installed via `programs.emacs`.
(import ./emacs.nix { inherit pkgs; })
];
programs.git = {
enable = true;
userEmail = "mail@tazj.in";
userName = "Vincent Ambo";
};
services.gpg-agent = {
enable = true;
extraConfig = ''
pinentry-program ${pkgs.pinentry}/bin/pinentry-gtk-2
allow-emacs-pinentry
'';
};
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
manual.html.enable = true;
# Shell configuration
#
# There are some differences between the ChromeOS / NixOS
# configurations, so instead of fixing up the dotfile to support
# both I opted for keeping the configuration here.
programs.fish = {
enable = true;
interactiveShellInit = ''
# Configure classic prompt
set fish_color_user --bold blue
set fish_color_cwd --bold white
# Enable colour hints in VCS prompt:
set __fish_git_prompt_showcolorhints yes
set __fish_git_prompt_color_prefix purple
set __fish_git_prompt_color_suffix purple
# Fish configuration
set fish_greeting ""
# Fix up nix-env & friends for Nix 2.0
export NIX_REMOTE=daemon
'';
};
# Ensure fonts installed via Nix are picked up.
fonts.fontconfig.enableProfileFonts = true;
}

77
ops/infra/nixos/mail.nix Normal file
View file

@ -0,0 +1,77 @@
# This file configures offlineimap, notmuch and MSMTP.
#
# Some manual configuration is required the first time this is
# applied:
#
# 1. Credential setup.
# 2. Linking of MSMTP config (ln -s /etc/msmtprc ~/.msmtprc)
# 3. Linking of notmuch config (ln -s /etc/notmuch-config ~/.notmuch-config)
{ config, lib, pkgs, ... }:
let offlineImapConfig = pkgs.writeText "offlineimaprc"
(builtins.readFile ./dotfiles/offlineimaprc);
msmtpConfig = pkgs.writeText "msmtprc"
(builtins.readFile ./dotfiles/msmtprc);
notmuchConfig = pkgs.writeText "notmuch-config"
(builtins.readFile ./dotfiles/notmuch-config);
tagConfig = pkgs.writeText "notmuch-tags" ''
# Tag emacs-devel mailing list:
-inbox +emacs-devel -- to:emacs-devel@gnu.org OR cc:emacs-devel@gnu.org
# Tag nix-devel mailing list & discourse:
-inbox +nix-devel -- to:nix-devel@googlegroups.com OR from:nixos1@discoursemail.com
# Tag my own mail (from other devices) as sent:
-inbox +sent -- from:mail@tazj.in
# Drafts are always read, duh.
-unread -- tag:draft
'';
notmuchIndex = pkgs.writeShellScriptBin "notmuch-index" ''
echo "Indexing new mails in notmuch"
# Index new mail
${pkgs.notmuch}/bin/notmuch new
# Apply tags
cat ${tagConfig} | ${pkgs.notmuch}/bin/notmuch tag --batch
echo "Done indexing new mails"
'';
in {
# Enable OfflineIMAP timer & service:
systemd.user.timers.offlineimap = {
description = "OfflineIMAP timer";
wantedBy = [ "timers.target" ];
timerConfig = {
Unit = "offlineimap.service";
OnCalendar = "*:0/2"; # every 2 minutes
Persistent = "true"; # persist timer state after reboots
};
};
systemd.user.services.offlineimap = {
description = "OfflineIMAP service";
path = with pkgs; [ pass notmuch ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.offlineimap}/bin/offlineimap -u syslog -o -c ${offlineImapConfig}";
ExecStartPost = "${notmuchIndex}/bin/notmuch-index";
TimeoutStartSec = "2min";
};
};
# Link configuration files to /etc/ (from where they will be linked
# further):
environment.etc = {
"msmtprc".source = msmtpConfig;
"notmuch-config".source = notmuchConfig;
};
}

View file

@ -0,0 +1,132 @@
# This file contains configuration for packages to install.
# It does not contain configuration for software that is already covered
# by other NixOS options (e.g. emacs)
{ config, pkgs, ... }:
let
fetchChannel = { rev, sha256 }: import (fetchTarball {
inherit sha256;
url = "https://github.com/NixOS/nixpkgs-channels/archive/${rev}.tar.gz";
}) { config.allowUnfree = true; };
# Channels last updated: 2018-10-10
#
# Instead of relying on Nix channels and ending up with out-of-sync
# situations between machines, the commit for the stable Nix channel
# is pinned here.
stable = fetchChannel {
rev = "d96c7a356383302db4426a0d5a8383af921d964f";
sha256 = "0hlhczh3m077rwrhp4smf3zd2sfj38h2c126bycv66m0aff0gycn";
};
# Certain packages from unstable are hand-picked into the package
# set.
unstable = fetchChannel {
rev = "32bcd72bf28a971c9063a9cdcc32effe49f49331";
sha256 = "1f74m18r6xl9s55jbkj9bjhdxg2489kwjam4d96pf9rzq0i1f8li";
};
in {
# Configure the Nix package manager
nixpkgs = {
config.allowUnfree = true;
# To use the pinned channel, the original package set is thrown
# away in the overrides:
config.packageOverrides = oldPkgs: stable // {
# Store whole unstable channel in case that other modules need
# it (see emacs.nix for example):
inherit unstable;
# Backport Exa from unstable until a fix for the Rust builder is
# backported.
#
# https://github.com/NixOS/nixpkgs/pull/48020
exa = unstable.exa;
wallpapers = import ./pkgs/wallpapers.nix;
pulseaudio-ctl = import pkgs/pulseaudio-ctl.nix;
};
};
# ... and declare packages to be installed.
environment.systemPackages = with pkgs; [
# Default nixos.* packages:
alacritty
binutils-unwrapped
chromium
curl
direnv
dnsutils
dotnet-sdk
evince
exa
extremetuxracer
fd
file
firefox-unwrapped
fish
gcc
git
gnumake
gnupg
google-cloud-sdk
gopass
hicolor-icon-theme
htop
i3lock
iftop
jq
kontemplate
kubernetes
lispPackages.quicklisp
lxappearance-gtk3
manpages
maven
mono
mq-cli
msmtp
ngrok
notmuch
numix-cursor-theme
numix-gtk-theme
numix-icon-theme
offlineimap
openjdk
openssl
openssl.dev
pass
pavucontrol
pkgconfig
pulseaudio-ctl
pwgen
ripgrep
rustup
sbcl
screen
siege
spotify
stdmanpages
systemd.dev
tdesktop
terraform
tig
tmux
tokei
transmission
tree
units
unzip
vlc
xclip
xfce.xfce4-screenshooter
# Haskell packages:
cabal-install
ghc
hlint
stack
stack2nix
haskellPackages.stylish-haskell
haskellPackages.yesod-bin
];
}

View file

@ -0,0 +1,39 @@
# Local configuration for 'stallo' (Home desktop PC)
{ config, pkgs, ...}:
{
boot.initrd.luks.devices.stallo-luks.device = "/dev/disk/by-uuid/b484cf1e-a27b-4785-8bd6-fa85a004b073";
# Use proprietary nvidia driver
services.xserver.videoDrivers = [ "nvidia" ];
# Enable 32-bit compatibility for Steam:
hardware.opengl.driSupport32Bit = true;
hardware.pulseaudio.support32Bit = true;
# Wine for Blizzard stuff
environment.systemPackages = with pkgs.unstable; [ wineWowPackages.staging winetricks ];
networking = {
hostName = "stallo";
wireless.enable = true;
wireless.networks = {
# Welcome to roast club!
"How do I computer fast?" = {
psk = "washyourface";
# Prefer 5Ghz unless the card is acting up.
priority = 10;
};
"How do I computer?" = {
psk = "washyourface";
};
};
# IPv6 at home, of course:
nameservers = [
"2606:4700:4700::1111"
"2606:4700:4700::1001"
];
};
}

3
ops/journaldriver/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
result
/target
**/*.rs.bk

816
ops/journaldriver/Cargo.lock generated Normal file
View file

@ -0,0 +1,816 @@
[[package]]
name = "aho-corasick"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ascii"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chunked_transfer"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cookie"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-foundation"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-foundation-sys"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cstr-argument"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "humantime"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "idna"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "journaldriver"
version = "1.1.0"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"medallion 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
"systemd 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ureq 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libsystemd-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "medallion"
version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "native-tls"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)",
"schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.10.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-probe"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl-sys"
version = "0.9.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "percent-encoding"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pkg-config"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "qstring"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_syscall"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "remove_dir_all"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ryu"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "safemem"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "schannel"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "security-framework"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "security-framework-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "systemd"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cstr-argument 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libsystemd-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-cstr 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempfile"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-normalization"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ureq"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"qstring 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "url"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-cstr"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vcpkg"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wincolor"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
"checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
"checksum chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980"
"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa"
"checksum cstr-argument 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "514570a4b719329df37f93448a70df2baac553020d0eb43a8dfa9c1f5ba7b658"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum libsystemd-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e751b723417158e0949ba470bee4affd6f1dd6b67622b5240d79186631b6a0d9"
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum medallion 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b2e6f0713b388174fc3de9b63a0a63dfcee191a8abc8e06c0a9c6d80821c1891"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b"
"checksum native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0a7bd714e83db15676d31caf968ad7318e9cc35f93c85a90231c8f22867549"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2e79eede055813a3ac52fb3915caf8e1c9da2dec1587871aec9f6f7b48508d"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
"checksum openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)" = "409d77eeb492a1aebd6eb322b2ee72ff7c7496b4434d98b3bf8be038755de65e"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
"checksum qstring 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "545ec057a36a93e25fb5883baed912e4984af4e2543bbf0e3463d962e0408469"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341"
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56"
"checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0"
"checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf"
"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9"
"checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe"
"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum syn 0.15.8 (registry+https://github.com/rust-lang/crates.io-index)" = "356d1c5043597c40489e9af2d2498c7fefc33e99b7d75b43be336c8a59b3e45e"
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
"checksum systemd 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b62a732355787f960c25536210ae0a981aca2e5dae9dab8491bdae39613ce48"
"checksum tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "55c1195ef8513f3273d55ff59fe5da6940287a0d7a98331254397f464833675b"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum ureq 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f3f941c0434783c82e46d30508834be5f3c1f2c85dd1b98f0681984c7be8e03"
"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum utf8-cstr 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55bcbb425141152b10d5693095950b51c3745d019363fc2929ffd8f61449b628"
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"

View file

@ -0,0 +1,21 @@
[package]
name = "journaldriver"
version = "1.1.0"
authors = ["Vincent Ambo <mail@tazj.in>"]
license = "GPL-3.0-or-later"
[dependencies]
chrono = { version = "0.4", features = [ "serde" ]}
env_logger = "0.5"
failure = "0.1"
lazy_static = "1.0"
log = "0.4"
medallion = "2.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
systemd = "0.3"
ureq = { version = "0.6.2", features = [ "json" ]}
[build-dependencies]
pkg-config = "0.3"

152
ops/journaldriver/README.md Normal file
View file

@ -0,0 +1,152 @@
journaldriver
=============
This is a small daemon used to forward logs from `journald` (systemd's
logging service) to [Stackdriver Logging][].
Many existing log services are written in inefficient dynamic
languages with error-prone "cover every possible use-case"
configuration. `journaldriver` instead aims to fit a specific use-case
very well, instead of covering every possible logging setup.
`journaldriver` can be run on GCP-instances with no additional
configuration as authentication tokens are retrieved from the
[metadata server][].
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**
- [Features](#features)
- [Usage on Google Cloud Platform](#usage-on-google-cloud-platform)
- [Usage outside of Google Cloud Platform](#usage-outside-of-google-cloud-platform)
- [Log levels / severities / priorities](#log-levels--severities--priorities)
- [NixOS module](#nixos-module)
- [Stackdriver Error Reporting](#stackdriver-error-reporting)
<!-- markdown-toc end -->
# Features
* `journaldriver` persists the last forwarded position in the journal
and will resume forwarding at the same position after a restart
* `journaldriver` will recognise log entries in JSON format and
forward them appropriately to make structured log entries available
in Stackdriver
* `journaldriver` can be used outside of GCP by configuring static
credentials
* `journaldriver` will recognise journald's log priority levels and
convert them into equivalent Stackdriver log severity levels
# Usage on Google Cloud Platform
`journaldriver` does not require any configuration when running on GCP
instances.
1. Install `journaldriver` on the instance from which you wish to
forward logs.
2. Ensure that the instance has the appropriate permissions to write
to Stackdriver. Google continously changes how IAM is implemented
on GCP, so you will have to refer to [Google's documentation][].
By default instances have the required permissions if Stackdriver
Logging support is enabled in the project.
3. Start `journaldriver`, for example via `systemd`.
# Usage outside of Google Cloud Platform
When running outside of GCP, the following extra steps need to be
performed:
1. Create a Google Cloud Platform service account with the "Log
Writer" role and download its private key in JSON-format.
2. When starting `journaldriver`, configure the following environment
variables:
* `GOOGLE_CLOUD_PROJECT`: Name of the GCP project to which logs
should be written.
* `GOOGLE_APPLICATION_CREDENTIALS`: Filesystem path to the
JSON-file containing the service account's private key.
* `LOG_STREAM`: Name of the target log stream in Stackdriver Logging.
This will be automatically created if it does not yet exist.
* `LOG_NAME`: Name of the target log to write to. This defaults to
`journaldriver` if unset, but it is recommended to - for
example - set it to the machine hostname.
# Log levels / severities / priorities
`journaldriver` recognises [journald's priorities][] and converts them
into [equivalent severities][] in Stackdriver. Both sets of values
correspond to standard `syslog` priorities.
The easiest way to emit log messages with priorites from an
application is to use [priority prefixes][], which are compatible with
structured log messages.
For example, to emit a simple warning message (structured and
unstructured):
```
$ echo '<4>{"fnord":true, "msg":"structured log (warning)"}' | systemd-cat
$ echo '<4>unstructured log (warning)' | systemd-cat
```
# NixOS module
The NixOS package repository [contains a module][] for setting up
`journaldriver` on NixOS machines. NixOS by default uses `systemd` for
service management and `journald` for logging, which means that log
output from most services will be captured automatically.
On a GCP instance the only required option is this:
```nix
services.journaldriver.enable = true;
```
When running outside of GCP, the configuration looks as follows:
```nix
services.journaldriver = {
enable = true;
logStream = "prod-environment";
logName = "hostname";
googleCloudProject = "gcp-project-name";
applicationCredentials = keyFile;
};
```
**Note**: The `journaldriver`-module is included in stable releases of
NixOS since NixOS 18.09.
# Stackdriver Error Reporting
The [Stackdriver Error Reporting][] service of Google's monitoring
toolbox supports automatically detecting and correlating errors from
log entries.
To use this functionality log messages must be logged in the expected
[log format][].
*Note*: Reporting errors from non-GCP instances requires that the
`LOG_STREAM` environment variable is set to the special value
`global`.
This value changes the monitored resource descriptor from a log stream
to the project-global stream. Due to a limitation in Stackdriver Error
Reporting, this is the only way to correctly ingest errors from
non-GCP machines. Please see [issue #4][] for more information about
this.
[Stackdriver Logging]: https://cloud.google.com/logging/
[metadata server]: https://cloud.google.com/compute/docs/storing-retrieving-metadata
[Google's documentation]: https://cloud.google.com/logging/docs/access-control
[NixOS]: https://nixos.org/
[contains a module]: https://github.com/NixOS/nixpkgs/pull/42134
[journald's priorities]: http://0pointer.de/public/systemd-man/sd-daemon.html
[equivalent severities]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity
[priority prefixes]: http://0pointer.de/public/systemd-man/sd-daemon.html
[Stackdriver Error Reporting]: https://cloud.google.com/error-reporting/
[log format]: https://cloud.google.com/error-reporting/docs/formatting-error-messages
[issue #4]: https://github.com/tazjin/journaldriver/issues/4

View file

@ -0,0 +1,6 @@
extern crate pkg_config;
fn main() {
pkg_config::probe_library("libsystemd")
.expect("Could not probe libsystemd");
}

View file

@ -0,0 +1,9 @@
{ pkgs, ... }:
pkgs.third_party.naersk.buildPackage {
src = ./.;
buildInputs = with pkgs.third_party; [
pkgconfig openssl systemd.dev
];
}

View file

@ -0,0 +1,665 @@
// Copyright (C) 2018 Vincent Ambo <mail@tazj.in>
//
// journaldriver is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! This file implements journaldriver, a small application that
//! forwards logs from journald (systemd's log facility) to
//! Stackdriver Logging.
//!
//! Log entries are read continously from journald and are forwarded
//! to Stackdriver in batches.
//!
//! Stackdriver Logging has a concept of monitored resources. In the
//! simplest case this monitored resource will be the GCE instance on
//! which journaldriver is running.
//!
//! Information about the instance, the project and required security
//! credentials are retrieved from Google's metadata instance on GCP.
//!
//! To run journaldriver on non-GCP machines, users must specify the
//! `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_CLOUD_PROJECT` and
//! `LOG_NAME` environment variables.
#[macro_use] extern crate failure;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
#[macro_use] extern crate lazy_static;
extern crate chrono;
extern crate env_logger;
extern crate medallion;
extern crate serde;
extern crate systemd;
extern crate ureq;
use chrono::offset::LocalResult;
use chrono::prelude::*;
use failure::ResultExt;
use serde_json::{from_str, Value};
use std::env;
use std::fs::{self, File, rename};
use std::io::{self, Read, ErrorKind, Write};
use std::mem;
use std::path::PathBuf;
use std::process;
use std::time::{Duration, Instant};
use systemd::journal::*;
#[cfg(test)]
mod tests;
const LOGGING_SERVICE: &str = "https://logging.googleapis.com/google.logging.v2.LoggingServiceV2";
const ENTRIES_WRITE_URL: &str = "https://logging.googleapis.com/v2/entries:write";
const METADATA_TOKEN_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";
const METADATA_ID_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/id";
const METADATA_ZONE_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/zone";
const METADATA_PROJECT_URL: &str = "http://metadata.google.internal/computeMetadata/v1/project/project-id";
/// Convenience type alias for results using failure's `Error` type.
type Result<T> = std::result::Result<T, failure::Error>;
/// Representation of static service account credentials for GCP.
#[derive(Debug, Deserialize)]
struct Credentials {
/// PEM encoded private key
private_key: String,
/// `kid` of this private key
private_key_id: String,
/// "email" address of the service account
client_email: String,
}
lazy_static! {
/// ID of the GCP project to which to send logs.
static ref PROJECT_ID: String = get_project_id();
/// Name of the log to write to (this should only be manually
/// configured if not running on GCP):
static ref LOG_NAME: String = env::var("LOG_NAME")
.unwrap_or("journaldriver".into());
/// Service account credentials (if configured)
static ref SERVICE_ACCOUNT_CREDENTIALS: Option<Credentials> =
env::var("GOOGLE_APPLICATION_CREDENTIALS").ok()
.and_then(|path| File::open(path).ok())
.and_then(|file| serde_json::from_reader(file).ok());
/// Descriptor of the currently monitored instance. Refer to the
/// documentation of `determine_monitored_resource` for more
/// information.
static ref MONITORED_RESOURCE: Value = determine_monitored_resource();
/// Path to the directory in which journaldriver should persist
/// its cursor state.
static ref CURSOR_DIR: PathBuf = env::var("CURSOR_POSITION_DIR")
.unwrap_or("/var/lib/journaldriver".into())
.into();
/// Path to the cursor position file itself.
static ref CURSOR_FILE: PathBuf = {
let mut path = CURSOR_DIR.clone();
path.push("cursor.pos");
path
};
/// Path to the temporary file used for cursor position writes.
static ref CURSOR_TMP_FILE: PathBuf = {
let mut path = CURSOR_DIR.clone();
path.push("cursor.tmp");
path
};
}
/// Convenience helper for retrieving values from the metadata server.
fn get_metadata(url: &str) -> Result<String> {
let response = ureq::get(url)
.set("Metadata-Flavor", "Google")
.timeout_connect(5000)
.timeout_read(5000)
.call();
if response.ok() {
// Whitespace is trimmed to remove newlines from responses.
let body = response.into_string()
.context("Failed to decode metadata response")?
.trim().to_string();
Ok(body)
} else {
let status = response.status_line().to_string();
let body = response.into_string()
.unwrap_or_else(|e| format!("Metadata body error: {}", e));
bail!("Metadata failure: {} ({})", body, status)
}
}
/// Convenience helper for determining the project ID.
fn get_project_id() -> String {
env::var("GOOGLE_CLOUD_PROJECT")
.map_err(Into::into)
.or_else(|_: failure::Error| get_metadata(METADATA_PROJECT_URL))
.expect("Could not determine project ID")
}
/// Determines the monitored resource descriptor used in Stackdriver
/// logs. On GCP this will be set to the instance ID as returned by
/// the metadata server.
///
/// On non-GCP machines the value is determined by using the
/// `GOOGLE_CLOUD_PROJECT` and `LOG_STREAM` environment variables.
///
/// [issue #4]: https://github.com/tazjin/journaldriver/issues/4
fn determine_monitored_resource() -> Value {
if let Ok(log) = env::var("LOG_STREAM") {
// The special value `global` is recognised as a log stream name that
// results in a `global`-type resource descriptor. This is useful in
// cases where Stackdriver Error Reporting is intended to be used on
// a non-GCE instance. See [issue #4][] for details.
if log == "global" {
return json!({
"type": "global",
"labels": {
"project_id": PROJECT_ID.as_str(),
}
});
}
json!({
"type": "logging_log",
"labels": {
"project_id": PROJECT_ID.as_str(),
"name": log,
}
})
} else {
let instance_id = get_metadata(METADATA_ID_URL)
.expect("Could not determine instance ID");
let zone = get_metadata(METADATA_ZONE_URL)
.expect("Could not determine instance zone");
json!({
"type": "gce_instance",
"labels": {
"project_id": PROJECT_ID.as_str(),
"instance_id": instance_id,
"zone": zone,
}
})
}
}
/// Represents the response returned by the metadata server's token
/// endpoint. The token is normally valid for an hour.
#[derive(Deserialize)]
struct TokenResponse {
expires_in: u64,
access_token: String,
}
/// Struct used to store a token together with a sensible
/// representation of when it expires.
struct Token {
token: String,
fetched_at: Instant,
expires: Duration,
}
impl Token {
/// Does this token need to be renewed?
fn is_expired(&self) -> bool {
self.fetched_at.elapsed() > self.expires
}
}
/// Retrieves a token from the GCP metadata service. Retrieving these
/// tokens requires no additional authentication.
fn get_metadata_token() -> Result<Token> {
let body = get_metadata(METADATA_TOKEN_URL)?;
let token: TokenResponse = from_str(&body)?;
debug!("Fetched new token from metadata service");
Ok(Token {
fetched_at: Instant::now(),
expires: Duration::from_secs(token.expires_in / 2),
token: token.access_token,
})
}
/// Signs a token using static client credentials configured for a
/// service account. This service account must have been given the
/// `Log Writer` role in Google Cloud IAM.
///
/// The process for creating and signing these tokens is described
/// here:
///
/// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
fn sign_service_account_token(credentials: &Credentials) -> Result<Token> {
use medallion::{Algorithm, Header, Payload};
let iat = Utc::now();
let exp = iat.checked_add_signed(chrono::Duration::seconds(3600))
.ok_or_else(|| format_err!("Failed to calculate token expiry"))?;
let header = Header {
alg: Algorithm::RS256,
headers: Some(json!({
"kid": credentials.private_key_id,
})),
};
let payload: Payload<()> = Payload {
iss: Some(credentials.client_email.clone()),
sub: Some(credentials.client_email.clone()),
aud: Some(LOGGING_SERVICE.to_string()),
iat: Some(iat.timestamp() as u64),
exp: Some(exp.timestamp() as u64),
..Default::default()
};
let token = medallion::Token::new(header, payload)
.sign(credentials.private_key.as_bytes())
.context("Signing service account token failed")?;
debug!("Signed new service account token");
Ok(Token {
token,
fetched_at: Instant::now(),
expires: Duration::from_secs(3000),
})
}
/// Retrieve the authentication token either by using static client
/// credentials, or by talking to the metadata server.
///
/// Which behaviour is used is controlled by the environment variable
/// `GOOGLE_APPLICATION_CREDENTIALS`, which should be configured to
/// point at a JSON private key file if service account authentication
/// is to be used.
fn get_token() -> Result<Token> {
if let Some(credentials) = SERVICE_ACCOUNT_CREDENTIALS.as_ref() {
sign_service_account_token(credentials)
} else {
get_metadata_token()
}
}
/// This structure represents the different types of payloads
/// supported by journaldriver.
///
/// Currently log entries can either contain plain text messages or
/// structured payloads in JSON-format.
#[derive(Debug, Serialize, PartialEq)]
#[serde(untagged)]
enum Payload {
TextPayload {
#[serde(rename = "textPayload")]
text_payload: String,
},
JsonPayload {
#[serde(rename = "jsonPayload")]
json_payload: Value,
},
}
/// Attempt to parse a log message as JSON and return it as a
/// structured payload. If parsing fails, return the entry in plain
/// text format.
fn message_to_payload(message: Option<String>) -> Payload {
match message {
None => Payload::TextPayload { text_payload: "empty log entry".into() },
Some(text_payload) => {
// Attempt to deserialize the text payload as a generic
// JSON value.
if let Ok(json_payload) = serde_json::from_str::<Value>(&text_payload) {
// If JSON-parsing succeeded on the payload, check
// whether we parsed an object (Stackdriver does not
// expect other types of JSON payload) and return it
// in that case.
if json_payload.is_object() {
return Payload::JsonPayload { json_payload }
}
}
Payload::TextPayload { text_payload }
}
}
}
/// Attempt to parse journald's microsecond timestamps into a UTC
/// timestamp.
///
/// Parse errors are dismissed and returned as empty options: There
/// simply aren't any useful fallback mechanisms other than defaulting
/// to ingestion time for journaldriver's use-case.
fn parse_microseconds(input: String) -> Option<DateTime<Utc>> {
if input.len() != 16 {
return None;
}
let seconds: i64 = (&input[..10]).parse().ok()?;
let micros: u32 = (&input[10..]).parse().ok()?;
match Utc.timestamp_opt(seconds, micros * 1000) {
LocalResult::Single(time) => Some(time),
_ => None,
}
}
/// Converts a journald log message priority to a
/// Stackdriver-compatible severity number.
///
/// Both Stackdriver and journald specify equivalent
/// severities/priorities. Conveniently, the names are the same.
/// Inconveniently, the numbers are not.
///
/// For more information on the journald priorities, consult these
/// man-pages:
///
/// * systemd.journal-fields(7) (section 'PRIORITY')
/// * sd-daemon(3)
/// * systemd.exec(5) (section 'SyslogLevelPrefix')
///
/// Note that priorities can be logged by applications via the prefix
/// concept described in these man pages, without interfering with
/// structured JSON-payloads.
///
/// For more information on the Stackdriver severity levels, please
/// consult Google's documentation:
///
/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
///
/// Any unknown priority values result in no severity being set.
fn priority_to_severity(priority: String) -> Option<u32> {
match priority.as_ref() {
"0" => Some(800), // emerg
"1" => Some(700), // alert
"2" => Some(600), // crit
"3" => Some(500), // err
"4" => Some(400), // warning
"5" => Some(300), // notice
"6" => Some(200), // info
"7" => Some(100), // debug
_ => None,
}
}
/// This structure represents a log entry in the format expected by
/// the Stackdriver API.
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct LogEntry {
labels: Value,
#[serde(skip_serializing_if = "Option::is_none")]
timestamp: Option<DateTime<Utc>>,
#[serde(flatten)]
payload: Payload,
// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
#[serde(skip_serializing_if = "Option::is_none")]
severity: Option<u32>,
}
impl From<JournalRecord> for LogEntry {
// Converts from the fields contained in a journald record to the
// representation required by Stackdriver Logging.
//
// The fields are documented in systemd.journal-fields(7).
fn from(mut record: JournalRecord) -> LogEntry {
// The message field is technically just a convention, but
// journald seems to default to it when ingesting unit
// output.
let payload = message_to_payload(record.remove("MESSAGE"));
// Presumably this is always set, but who can be sure
// about anything in this world.
let hostname = record.remove("_HOSTNAME");
// The unit is seemingly missing on kernel entries, but
// present on all others.
let unit = record.remove("_SYSTEMD_UNIT");
// The source timestamp (if present) is specified in
// microseconds since epoch.
//
// If it is not present or can not be parsed, journaldriver
// will not send a timestamp for the log entry and it will
// default to the ingestion time.
let timestamp = record
.remove("_SOURCE_REALTIME_TIMESTAMP")
.and_then(parse_microseconds);
// Journald uses syslogd's concept of priority. No idea if this is
// always present, but it's optional in the Stackdriver API, so we just
// omit it if we can't find or parse it.
let severity = record
.remove("PRIORITY")
.and_then(priority_to_severity);
LogEntry {
payload,
timestamp,
labels: json!({
"host": hostname,
"unit": unit.unwrap_or_else(|| "syslog".into()),
}),
severity,
}
}
}
/// Attempt to read from the journal. If no new entry is present,
/// await the next one up to the specified timeout.
fn receive_next_record(timeout: Duration, journal: &mut Journal)
-> Result<Option<JournalRecord>> {
let next_record = journal.next_record()?;
if next_record.is_some() {
return Ok(next_record);
}
Ok(journal.await_next_record(Some(timeout))?)
}
/// This function starts a double-looped, blocking receiver. It will
/// buffer messages for half a second before flushing them to
/// Stackdriver.
fn receiver_loop(mut journal: Journal) -> Result<()> {
let mut token = get_token()?;
let mut buf: Vec<LogEntry> = Vec::new();
let iteration = Duration::from_millis(500);
loop {
trace!("Beginning outer iteration");
let now = Instant::now();
loop {
if now.elapsed() > iteration {
break;
}
if let Ok(Some(entry)) = receive_next_record(iteration, &mut journal) {
trace!("Received a new entry");
buf.push(entry.into());
}
}
if !buf.is_empty() {
let to_flush = mem::replace(&mut buf, Vec::new());
flush(&mut token, to_flush, journal.cursor()?)?;
}
trace!("Done outer iteration");
}
}
/// Writes the current cursor into `/var/journaldriver/cursor.pos`. To
/// avoid issues with journaldriver being terminated while the cursor
/// is still being written, this will first write the cursor into a
/// temporary file and then move it.
fn persist_cursor(cursor: String) -> Result<()> {
// This code exists to aid in tracking down if there are other
// causes of issue #2 than what has already been taken care of.
//
// One theory is that journald (or the Rust library to interface
// with it) may occasionally return empty cursor strings. If this
// is ever the case, we would like to know about it.
if cursor.is_empty() {
error!("Received empty journald cursor position, refusing to persist!");
error!("Please report this message at https://github.com/tazjin/journaldriver/issues/2");
return Ok(())
}
let mut file = File::create(&*CURSOR_TMP_FILE)
.context("Failed to create cursor file")?;
write!(file, "{}", cursor).context("Failed to write cursor file")?;
rename(&*CURSOR_TMP_FILE, &*CURSOR_FILE)
.context("Failed to move cursor file")
.map_err(Into::into)
}
/// Flushes all drained records to Stackdriver. Any Stackdriver
/// message can at most contain 1000 log entries which means they are
/// chunked up here.
///
/// In some cases large payloads seem to cause errors in Stackdriver -
/// the chunks are therefore made smaller here.
///
/// If flushing is successful the last cursor position will be
/// persisted to disk.
fn flush(token: &mut Token,
entries: Vec<LogEntry>,
cursor: String) -> Result<()> {
if token.is_expired() {
debug!("Refreshing Google metadata access token");
let new_token = get_token()?;
mem::replace(token, new_token);
}
for chunk in entries.chunks(750) {
let request = prepare_request(chunk);
if let Err(write_error) = write_entries(token, request) {
error!("Failed to write {} entries: {}", chunk.len(), write_error)
} else {
debug!("Wrote {} entries to Stackdriver", chunk.len())
}
}
persist_cursor(cursor)
}
/// Convert a slice of log entries into the format expected by
/// Stackdriver. This format is documented here:
///
/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write
fn prepare_request(entries: &[LogEntry]) -> Value {
json!({
"logName": format!("projects/{}/logs/{}", PROJECT_ID.as_str(), LOG_NAME.as_str()),
"resource": &*MONITORED_RESOURCE,
"entries": entries,
"partialSuccess": true
})
}
/// Perform the log entry insertion in Stackdriver Logging.
fn write_entries(token: &Token, request: Value) -> Result<()> {
let response = ureq::post(ENTRIES_WRITE_URL)
.set("Authorization", format!("Bearer {}", token.token).as_str())
// The timeout values are set relatively high, not because of
// an expectation of Stackdriver being slow but just to
// eventually hit an error case in case of network troubles.
// Presumably no request in a functioning environment will
// ever hit these limits.
.timeout_connect(2000)
.timeout_read(5000)
.send_json(request);
if response.ok() {
Ok(())
} else {
let status = response.status_line().to_string();
let body = response.into_string()
.unwrap_or_else(|_| "no response body".into());
bail!("Write failure: {} ({})", body, status)
}
}
/// Attempt to read the initial cursor position from the configured
/// file. If there is no initial cursor position set, read from the
/// tail of the log.
///
/// The only "acceptable" error when reading the cursor position is
/// the cursor position file not existing, other errors are fatal
/// because they indicate a misconfiguration of journaldriver.
fn initial_cursor() -> Result<JournalSeek> {
let read_result: io::Result<String> = (|| {
let mut contents = String::new();
let mut file = File::open(&*CURSOR_FILE)?;
file.read_to_string(&mut contents)?;
Ok(contents.trim().into())
})();
match read_result {
Ok(cursor) => Ok(JournalSeek::Cursor { cursor }),
Err(ref err) if err.kind() == ErrorKind::NotFound => {
info!("No previous cursor position, reading from journal tail");
Ok(JournalSeek::Tail)
},
Err(err) => {
(Err(err).context("Could not read cursor position"))?
}
}
}
fn main () {
env_logger::init();
// The directory in which cursor positions are persisted should
// have been created:
if !CURSOR_DIR.exists() {
error!("Cursor directory at '{:?}' does not exist", *CURSOR_DIR);
process::exit(1);
}
let cursor_position_dir = CURSOR_FILE.parent()
.expect("Invalid cursor position file path");
fs::create_dir_all(cursor_position_dir)
.expect("Could not create directory to store cursor position in");
let mut journal = Journal::open(JournalFiles::All, false, true)
.expect("Failed to open systemd journal");
let seek_position = initial_cursor()
.expect("Failed to determine initial cursor position");
match journal.seek(seek_position) {
Ok(cursor) => info!("Opened journal at cursor '{}'", cursor),
Err(err) => {
error!("Failed to set initial journal position: {}", err);
process::exit(1)
}
}
receiver_loop(journal).expect("log receiver encountered an unexpected error");
}

View file

@ -0,0 +1,95 @@
use super::*;
use serde_json::to_string;
#[test]
fn test_text_entry_serialization() {
let entry = LogEntry {
labels: Value::Null,
timestamp: None,
payload: Payload::TextPayload {
text_payload: "test entry".into(),
},
severity: None,
};
let expected = "{\"labels\":null,\"textPayload\":\"test entry\"}";
let result = to_string(&entry).expect("serialization failed");
assert_eq!(expected, result, "Plain text payload should serialize correctly")
}
#[test]
fn test_json_entry_serialization() {
let entry = LogEntry {
labels: Value::Null,
timestamp: None,
payload: Payload::JsonPayload {
json_payload: json!({
"message": "JSON test"
})
},
severity: None,
};
let expected = "{\"labels\":null,\"jsonPayload\":{\"message\":\"JSON test\"}}";
let result = to_string(&entry).expect("serialization failed");
assert_eq!(expected, result, "JSOn payload should serialize correctly")
}
#[test]
fn test_plain_text_payload() {
let message = "plain text payload".into();
let payload = message_to_payload(Some(message));
let expected = Payload::TextPayload {
text_payload: "plain text payload".into(),
};
assert_eq!(expected, payload, "Plain text payload should be detected correctly");
}
#[test]
fn test_empty_payload() {
let payload = message_to_payload(None);
let expected = Payload::TextPayload {
text_payload: "empty log entry".into(),
};
assert_eq!(expected, payload, "Empty payload should be handled correctly");
}
#[test]
fn test_json_payload() {
let message = "{\"someKey\":\"someValue\", \"otherKey\": 42}".into();
let payload = message_to_payload(Some(message));
let expected = Payload::JsonPayload {
json_payload: json!({
"someKey": "someValue",
"otherKey": 42
})
};
assert_eq!(expected, payload, "JSON payload should be detected correctly");
}
#[test]
fn test_json_no_object() {
// This message can be parsed as valid JSON, but it is not an
// object - it should be returned as a plain-text payload.
let message = "42".into();
let payload = message_to_payload(Some(message));
let expected = Payload::TextPayload {
text_payload: "42".into(),
};
assert_eq!(expected, payload, "Non-object JSON payload should be plain text");
}
#[test]
fn test_parse_microseconds() {
let input: String = "1529175149291187".into();
let expected: DateTime<Utc> = "2018-06-16T18:52:29.291187Z"
.to_string().parse().unwrap();
assert_eq!(Some(expected), parse_microseconds(input));
}

60
ops/kms_pass.nix Normal file
View file

@ -0,0 +1,60 @@
# This tool mimics a subset of the interface of 'pass', but uses
# Google Cloud KMS for encryption.
#
# It is intended to be compatible with how 'kontemplate' invokes
# 'pass.'
#
# Only the 'show' and 'insert' commands are supported.
{ pkgs, kms, ... }:
let inherit (pkgs.third_party) google-cloud-sdk tree writeShellScriptBin;
in (writeShellScriptBin "pass" ''
set -eo pipefail
CMD="$1"
readonly SECRET=$2
readonly SECRET_PATH="$SECRETS_DIR/$SECRET"
function secret_check {
if [[ -z $SECRET ]]; then
echo 'Secret must be specified'
exit 1
fi
}
if [[ -z $CMD ]]; then
CMD="ls"
fi
case "$CMD" in
ls)
${tree}/bin/tree $SECRETS_DIR
;;
show)
secret_check
${google-cloud-sdk}/bin/gcloud kms decrypt \
--project ${kms.project} \
--location ${kms.region} \
--keyring ${kms.keyring} \
--key ${kms.key} \
--ciphertext-file $SECRET_PATH \
--plaintext-file -
;;
insert)
secret_check
${google-cloud-sdk}/bin/gcloud kms encrypt \
--project ${kms.project} \
--location ${kms.region} \
--keyring ${kms.keyring} \
--key ${kms.key} \
--ciphertext-file $SECRET_PATH \
--plaintext-file -
echo "Inserted secret '$SECRET'"
;;
*)
echo "Usage: pass show/insert <secret>"
exit 1
;;
esac
'') // { meta.enableCI = true; }

Binary file not shown.

BIN
ops/secrets/nixery-gcs-json Normal file

Binary file not shown.

BIN
ops/secrets/nixery-gcs-pem Normal file

Binary file not shown.

Binary file not shown.

10
ops/sync-gcsr/default.nix Normal file
View file

@ -0,0 +1,10 @@
{ pkgs, ... }:
pkgs.buildGo.program {
name = "sync-gcsr";
srcs = [ ./main.go ];
deps = with pkgs.third_party; map (p: p.gopkg) [
gopkgs."gopkg.in".src-d.go-git
];
}

92
ops/sync-gcsr/main.go Normal file
View file

@ -0,0 +1,92 @@
// Copyright 2019 Google LLC.
// SPDX-License-Identifier: Apache-2.0
//
// sync-gcsr implements a small utility that periodically mirrors a
// remote Google Cloud Source Repository to a local file path.
package main
import (
"fmt"
"log"
"os"
"time"
git "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
)
func EnvOr(key, def string) string {
v := os.Getenv(key)
if v == "" {
return def
}
return v
}
func updateRepo(repo *git.Repository, tree *git.Worktree, opts *git.PullOptions) error {
err := tree.Pull(opts)
if err == git.NoErrAlreadyUpToDate {
// nothing to do ...
return nil
} else if err != nil {
return err
}
log.Println("Updated local repository mirror")
return nil
}
func main() {
var dest = EnvOr("SYNC_DEST", "/git/depot")
var project = EnvOr("SYNC_PROJECT", "tazjins-infrastructure")
var repo = EnvOr("SYNC_REPO", "depot")
var user = os.Getenv("SYNC_USER")
var pass = os.Getenv("SYNC_PASS")
log.Printf("Syncing repository '%s/%s' to destination '%s'", project, repo, dest)
var cloneOpts = git.CloneOptions{
URL: fmt.Sprintf("https://source.developers.google.com/p/%s/r/%s", project, repo),
}
if user != "" && pass != "" {
cloneOpts.Auth = &http.BasicAuth{
Username: user,
Password: pass,
}
log.Println("Enabling basic authentication as user", user)
}
action := "clone"
handle, err := git.PlainClone(dest, false, &cloneOpts)
if err == git.ErrRepositoryAlreadyExists {
log.Println("Repository has already been cloned!")
handle, err = git.PlainOpen(dest)
action = "open"
}
if err != nil {
log.Fatalf("Failed to %s repository: %s", action, err)
} else {
log.Println("Initiating update loop")
}
tree, err := handle.Worktree()
if err != nil {
log.Fatalln("Failed to open repository worktree:", err)
}
pullOpts := git.PullOptions{
Auth: cloneOpts.Auth,
Force: true,
}
for {
if err = updateRepo(handle, tree, &pullOpts); err != nil {
log.Fatalf("Failed to pull updated repository: %s", err)
}
time.Sleep(30 * time.Second) // TODO(tazjin): Config option for pull interval?
}
}