Deploying Gerrit Code Review
Deploying Gerrit Code Review
Deploying Gerrit Code Review
Project Lineage
Google Mondrian ⇉ Rietveld ⇉ Gerrit 1.x ⇉ Gerrit 2.x
Contributors
Google, Qualcomm, SAP, Sony Mobile, Wikimedia,
GerritForge, CollabNet, Spotify, Garmin, Kitware, ...
Deployment Options
Database
H2 (built-in), PostgreSQL, MySQL
Servlet Container
Jetty (built-in), Tomcat (war deployment)
Authentication
LDAP, OpenID, Container
For this tutorial we will use H2 and Jetty
Exercise 1 – Install Gerrit
(optional) Create a non-privileged user to run Gerrit
$ sudo adduser gerrit2
$ sudo su gerrit2
http://code.google.com/p/gerrit/downloads/detail?name=gerrit-2.6-rc0.war
Exercise 1 – Configure
Gerrit
Edit settings in '~/gerrit_testsite/etc/gerrit.config'
Change
[auth]
type = OPENID
into
[auth]
type = DEVELOPMENT_BECOME_ANY_ACCOUNT
2.
3.
4.
5.
Exercise 2 – Admin User
Add public ssh key (content of ~/.ssh/id_rsa.pub)
Exercise 3 – Developer User
The first user created is granted admin rights automatically.
Additional users are ordinary users with no special powers.
Web alternative
http://localhost:8080/ Projects > Create New Project
- type ls ~/gerrit_testsite/git
Reviewing Code
Push to the "magic" refs/for/<branch_name>
Gerrit creates a special ref for the commit
Gerrit creates a Change with a Patch-Set
Create a change
$ echo "Hello Gerrit" > hello.txt
$ git add hello.txt
$ git commit -m "My first change"
Click on hello.txt, double click on the content and enter some text
Click on "Review"
Exercise 5 – Reviewing Code
By default every logged-in user can review
Default workflow:
A change can be submitted if it:
- has highest vote in every label category
- has no lowest vote in any label category
- Log in as admin
- People > Create New Group
- Name "myproject-committers"
- Add developer user
Exercise – Grant Access
Projects > List > myproject
Projects > Access
Add permissions:
Exercise – Submit Change
Log in as developer again, click Review button
Addressing Review Issues
- A version of a Change is called a Patch Set
- A Patch Set is represented by a Git commit
- A new Patch Set "replaces" an older one
Default groups:
Administrators -- granted all capabilities
Non-Interactive Users -- assigned to
Inheritance
ACL
● "Registered users" can
read all branches.
Project ACL of ● "Super users" can
A approve changes.
inherit from
Project
B
ACL
● "Registered users" can
read all branches.
ACL of ● "Super users" can approve
changes.
● "CI system user" can mark
changes as verified.
An ACL Entry
An ACL Entry
Reference pattern (what branches the grants impact)
Permission or capability
Group (of users or nested groups) that can use this power.
Read refs/heads/*
Push refs/for/refs/heads/*
Label Code-Review refs/heads/master
Label Verify ^refs/heads/release-[0-9]\.[0-9]$
Exclusive Flag
ALLOW Push
Example: Maintainer
refs/heads/*
− Can reject a change
Label Code-Review −2..+2 + Can accept a change
git
refs/heads/master
Main.java
MyClass.java
refs/meta/config
groups
project.config
project.config
[project]
description = Rights inherited by all other projects
state = active
[access "refs/*"]
read = group Administrators
read = group Anonymous Users
forgeAuthor = group Registered Users
[access "refs/for/refs/*"]
push = group Registered Users
[access "refs/heads/*"]
label-Code-Review = -1..+1 group Registered Users
Exercise – Propose ACL
Mortal users that can't change the permissions directly can
propose changes in the web UI and have them reviewed
like any other code change.
What existing tool can you use to batch edit these files?
Advanced Workflows
Default Rules
Define default rules in Prolog:
$ git init rules ; cd rules
$ git remote add origin ssh://adminalex@localhost:29418/myproject
$ git pull origin refs/meta/config
$ vi rules.pl
submit_rule(submit(CR, V)) :-
gerrit:max_with_block(-1, 1, 'Verified', V),
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
submit_rule(submit(CR, V)) :-
gerrit:max_with_block(-1, 1, 'Verified', V),
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
submit_rule(submit(CR, V)) :-
base(CR, V).
base(CR, V) :-
gerrit:max_with_block(-1, 1, 'Verified', V),
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
No Self Approvals
Replace rules.pl to ignore self-approved Code-Review +2
submit_rule(submit(CR, V, N)) :-
gerrit:commit_author(A),
gerrit:max_with_block(-2, 2, 'Code-Review', label(_, ok(A))),
N = label('Non-Author Code-Review', need(_)),
base(CR, V),
!.
submit_rule(submit(CR, V)) :-
base(CR, V).
base(CR, V) :-
gerrit:max_with_block(-1, 1, 'Verified', V),
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
Thanks! Other Cool Stuff
Plugins/Extensions External group systems; User avatars; External accounts (future)
stream-events Monitor server activity in real time, react to events (e.g. CI)
Workflow by file Add (or simplify) review flow for Documentation, etc.
code.google.com/p/gerrit
Scaling Gerrit (continued)
Memory Usage
Gerrit Loves Memory
Git data
Paged into Java heap on demand
Custom block cache implementation
Works around Java mmap() limitations
container.javaOptions
Additional flags to pass to JVM, e.g. -d64 -server
core.packedGitOpenFiles
Defines open files ulimit. Gerrit sets process ulimit to MAX(1024, packedGitOpenFiles * 2)
Minimum ulimit selected by gerrit.sh is 1024.
JGit Cache Settings
core.packedGitLimit (10 MiB)
Max. bytes to load and cache in memory from pack files.
core.packedGitOpenFiles (128)
Max. number of pack files to have open at once.
core.packedGitWindowSize (8 kiB)
Bytes of a pack file to load into memory in a single read operation.
database.poolMinIdle (4)
Minimum number of connections to keep idle in the pool.
database.poolMaxIdle (4)
Maximum number of connections to keep idle in the pool.
database.poolMaxWait (30sec)
Max. time request processing thread will wait to acquire a database connection.
Jetty HTTP Daemon
httpd.acceptorThreads (2)
Worker threads dedicated to accepting new incoming TCP connections.
httpd.maxQueued (50)
Maximum number of connections which can enter the queue waiting for a worker thread.
httpd.maxWait (5min)
Maximum time for a project clone, fetch or push request over smart HTTP.
SSH Daemon
sshd.threads (1.5xCPUs)
Number of threads to execute SSH command requests.
sshd.batchThreads (0)
Number of threads for SSH command requests from Non-Interactive Users.
sshd.streamThreads (1+CPUs)
Number of threads for formatting events to asynchronous streaming clients.
sshd.commandStartThreads (2)
Number of threads used to start new SSH commands.
sshd.maxConnectionsPerUser (64)
Maximum number of concurrent SSH sessions for a user account.
receive-pack (git push)
receive.maxObjectSizeLimit (0)
Maximum Git object size that receive-pack will accept.
Use this to prevent pushing objects which are too large to Gerrit.
receive.changeUpdateThreads (disabled)
Number of threads to perform database metadata updates.
Slower databases can benefit from parallel updates if users frequently push multiple changes.
receive.timeout (2min)
Upper bound on time taken to process change data received from client.
Exercise – Inspect State
Display active client SSH connections
$ ssh -p 29418 localhost gerrit show-connections
GC configuration:
defined in ~/.gitconfig of the system user that runs the Gerrit server
or in specific <project>.git/config
Exercise:
- type $ git help config and explore the gc configuration options
- run gc on a project (if it's new you may need to tweak the gc configuration)
- find the gc log and check gc statistics
Speed Up git clone
Make our project history larger:
$ for a in {1..99};do echo $a >a;git add a;git commit -m $a;done
$ git push ~/gerrit_testsite/git/myproject.git master
Make it faster:
$ ssh -p 29418 alexadmin@localhost gerrit gc myproject
$ git clone ssh://alexadmin@localhost:29418/myproject t3
Cloning into 't3'...
remote: Total 300 (delta 0), reused 300 (delta 0)
Distribute Load
Replicate to other servers
Enable replication plugin
Configure remotes in site_path/etc/replication.config
Gerrit Slaves
Only serve Git over SSH
Enforce same Read access permissions, using same user and groups.
container.slave = true
database.database = ... same address as master ...
cache.<name>.maxAge = 15min # or some other low value