14324: Use logrus in Azure driver. Fix Sirupsen->sirupsen in imports
[arvados.git] / lib / service / cmd.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 // package service provides a cmd.Handler that brings up a system service.
6 package service
7
8 import (
9         "flag"
10         "fmt"
11         "io"
12         "net/http"
13         "os"
14
15         "git.curoverse.com/arvados.git/lib/cmd"
16         "git.curoverse.com/arvados.git/sdk/go/arvados"
17         "git.curoverse.com/arvados.git/sdk/go/httpserver"
18         "github.com/coreos/go-systemd/daemon"
19         "github.com/sirupsen/logrus"
20 )
21
22 type Handler interface {
23         http.Handler
24         CheckHealth() error
25 }
26
27 type NewHandlerFunc func(*arvados.Cluster, *arvados.NodeProfile) Handler
28
29 type command struct {
30         newHandler NewHandlerFunc
31         svcName    arvados.ServiceName
32 }
33
34 // Command returns a cmd.Handler that loads site config, calls
35 // newHandler with the current cluster and node configs, and brings up
36 // an http server with the returned handler.
37 //
38 // The handler is wrapped with server middleware (adding X-Request-ID
39 // headers, logging requests/responses, etc).
40 func Command(svcName arvados.ServiceName, newHandler NewHandlerFunc) cmd.Handler {
41         return &command{
42                 newHandler: newHandler,
43                 svcName:    svcName,
44         }
45 }
46
47 func (c *command) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
48         log := logrus.New()
49         log.Formatter = &logrus.JSONFormatter{
50                 TimestampFormat: rfc3339NanoFixed,
51         }
52         log.Out = stderr
53
54         var err error
55         defer func() {
56                 if err != nil {
57                         log.WithError(err).Info("exiting")
58                 }
59         }()
60         flags := flag.NewFlagSet("", flag.ContinueOnError)
61         flags.SetOutput(stderr)
62         configFile := flags.String("config", arvados.DefaultConfigFile, "Site configuration `file`")
63         nodeProfile := flags.String("node-profile", "", "`Name` of NodeProfiles config entry to use (if blank, use $ARVADOS_NODE_PROFILE or hostname reported by OS)")
64         err = flags.Parse(args)
65         if err == flag.ErrHelp {
66                 err = nil
67                 return 0
68         } else if err != nil {
69                 return 2
70         }
71         cfg, err := arvados.GetConfig(*configFile)
72         if err != nil {
73                 return 1
74         }
75         cluster, err := cfg.GetCluster("")
76         if err != nil {
77                 return 1
78         }
79         profileName := *nodeProfile
80         if profileName == "" {
81                 profileName = os.Getenv("ARVADOS_NODE_PROFILE")
82         }
83         profile, err := cluster.GetNodeProfile(profileName)
84         if err != nil {
85                 return 1
86         }
87         listen := profile.ServicePorts()[c.svcName]
88         if listen == "" {
89                 err = fmt.Errorf("configuration does not enable the %s service on this host", c.svcName)
90                 return 1
91         }
92         handler := c.newHandler(cluster, profile)
93         if err = handler.CheckHealth(); err != nil {
94                 return 1
95         }
96         srv := &httpserver.Server{
97                 Server: http.Server{
98                         Handler: httpserver.AddRequestIDs(httpserver.LogRequests(log, handler)),
99                 },
100                 Addr: listen,
101         }
102         err = srv.Start()
103         if err != nil {
104                 return 1
105         }
106         log.WithFields(logrus.Fields{
107                 "Listen":  srv.Addr,
108                 "Service": c.svcName,
109         }).Info("listening")
110         if _, err := daemon.SdNotify(false, "READY=1"); err != nil {
111                 log.WithError(err).Errorf("error notifying init daemon")
112         }
113         err = srv.Wait()
114         if err != nil {
115                 return 1
116         }
117         return 0
118 }
119
120 const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"