Digging into the reva "Hello World!" example.md

Before I can start writing about the s3 storage provider implementation, I should probably document how to run and configure reva, so that you can better understand how it works. Let’s dive right into it:

$ git clone git@github.com:cernbox/reva && cd reva
$ make
$ ./cmd/revad/revad -c cmd/revad/basic-revad.toml -p revad.pid &> revad.log &
[1] 4003
$ curl localhost:9998
Hello World!%
$ kill %1
[1] + 4003 terminated ./cmd/revad/revad -c cmd/revad/basic-revad.toml -p revad.pid &> revad.log

Ok, so let me unpack the above:

  1. cernbox/reva is the upstream project. Our changes live in owncloud/reva so we can keep track of our builds and PRs independently. How we collaborate exactly is probably worth another post. For this example I am going to use upstream directly.
  2. Why make? It will fill some environment variables and bake the version and git commit into the binary that can later be used to properly identify which code was running. You can of course just run go build ./cmd/revad to produce a binary without that magic.
  3. Reva ships with a minimal configuration that we use to get a service up and running:
    $ cat cmd/revad/basic-revad.toml
    [http]
    enabled_services = ["helloworldsvc"]
    
    I also redirected all output to a logfile and gave revad the path to a pidfile. Let’s ignore those for now and focus on the HTTP service.
  4. As you probably guessed, the helloworldsvc does nothing else but render Hello World!.
  5. kill %1, if you are unfamiliar with job control, kills the job number 1, whereas kill 1 kills the process with the pid 1. Two very different things.

Grepping the code

So, where does the service live in the codebase?

$ grep -r -A1 -B1 Hello cmd/revad
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go- }
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go: if conf.HelloMessage == "" {
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go: conf.HelloMessage = "Hello World!"
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go- }
--
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go- Prefix string `mapstructure:"prefix"`
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go: HelloMessage string `mapstructure:"hello_message"`
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go-}
--
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go: w.Write([]byte(s.conf.HelloMessage))
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go- })
Übereinstimmungen in Binärdatei cmd/revad/revad

Interesting, there seems to be a config option for the s.conf.HelloMessage.

Configuring services

How do we configure that helloworldsvc?

$ cp cmd/revad/basic-revad.toml myrevad.toml
$ echo "\n[http.services.helloworldsvc]\nhello_message='Hi reva!'" >> myrevad.toml
$ ./cmd/revad/revad -c myrevad.toml -p revad.pid &> revad.log &
[1] 14395
$ curl localhost:9998
Hi reva!%
$ kill %1

The TOML file contains ini like sections. Every service that is registered can be configured in a dedicated section that contains his name.

Registering a service

How is reva made aware of the service? If you look at the codebase you will find several loader.go files. They all contain a list of packages to make reva aware of them. Finally, a service needs to register itself with either the httpserver or grpcserver. For the helloworldsvc this looks like this:

$ grep -rn helloworldsvc cmd/revad/svcs
cmd/revad/svcs/httpsvcs/loader/loader.go:24: _ "github.com/cernbox/reva/cmd/revad/svcs/httpsvcs/helloworldsvc"
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go:19:package helloworldsvc
cmd/revad/svcs/httpsvcs/helloworldsvc/helloworldsvc.go:31: httpserver.Register("helloworldsvc", New)

httpserver.Register("helloworldsvc", New) is what makes reva aware of the helloworldsvc.

Reva is an opinionated framework

The above should give you pointers to the different pieces of a reva service. Putting it all together, you can think of reva as a framework to implement, configure and execute HTTP and GRPC services. It comes with zerolog for logging, a TOML based configuration, prometheus metrics, and provides several go packages that make implementing CS3 services easier. Adding opentracing is planned as well.

Putting config changes into effect

One last thing: do we really have to kill revad to change the config? In theory not:

$ ./cmd/revad/revad -p revad.pid -s reload
signaling master process

That should spawn a new process, test the new config and switch over to the new instance without dropping a request. However that did not work for me … might be a bug.

¯\_(ツ)_/¯

PR welcome!

Cheers!

Next up: how to implement a storage provider for reva.

1 Like