11 "git.curoverse.com/arvados.git/sdk/go/arvados"
12 log "github.com/Sirupsen/logrus"
26 BlobSignatureTTL arvados.Duration
27 BlobSigningKeyFile string
28 RequireSignatures bool
29 SystemAuthTokenFile string
31 TrashLifetime arvados.Duration
32 TrashCheckInterval arvados.Duration
37 systemAuthToken string
38 debugLogf func(string, ...interface{})
41 var theConfig = DefaultConfig()
43 const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
45 // DefaultConfig returns the default configuration.
46 func DefaultConfig() *Config {
51 RequireSignatures: true,
52 BlobSignatureTTL: arvados.Duration(14 * 24 * time.Hour),
53 TrashLifetime: arvados.Duration(14 * 24 * time.Hour),
54 TrashCheckInterval: arvados.Duration(24 * time.Hour),
59 // Start should be called exactly once: after setting all public
60 // fields, and before using the config.
61 func (cfg *Config) Start() error {
63 log.SetLevel(log.DebugLevel)
64 cfg.debugLogf = log.Printf
65 cfg.debugLogf("debugging enabled")
67 cfg.debugLogf = func(string, ...interface{}) {}
70 switch strings.ToLower(cfg.LogFormat) {
72 log.SetFormatter(&log.TextFormatter{
74 TimestampFormat: rfc3339NanoFixed,
77 log.SetFormatter(&log.JSONFormatter{
78 TimestampFormat: rfc3339NanoFixed,
81 return fmt.Errorf(`unsupported log format %q (try "text" or "json")`, cfg.LogFormat)
84 if cfg.MaxBuffers < 0 {
85 return fmt.Errorf("MaxBuffers must be greater than zero")
87 bufs = newBufferPool(cfg.MaxBuffers, BlockSize)
89 if cfg.MaxRequests < 1 {
90 cfg.MaxRequests = cfg.MaxBuffers * 2
91 log.Printf("MaxRequests <1 or not specified; defaulting to MaxBuffers * 2 == %d", cfg.MaxRequests)
94 if cfg.BlobSigningKeyFile != "" {
95 buf, err := ioutil.ReadFile(cfg.BlobSigningKeyFile)
97 return fmt.Errorf("reading blob signing key file: %s", err)
99 cfg.blobSigningKey = bytes.TrimSpace(buf)
100 if len(cfg.blobSigningKey) == 0 {
101 return fmt.Errorf("blob signing key file %q is empty", cfg.BlobSigningKeyFile)
103 } else if cfg.RequireSignatures {
104 return fmt.Errorf("cannot enable RequireSignatures (-enforce-permissions) without a blob signing key")
106 log.Println("Running without a blob signing key. Block locators " +
107 "returned by this server will not be signed, and will be rejected " +
108 "by a server that enforces permissions.")
109 log.Println("To fix this, use the BlobSigningKeyFile config entry.")
112 if fn := cfg.SystemAuthTokenFile; fn != "" {
113 buf, err := ioutil.ReadFile(fn)
115 return fmt.Errorf("cannot read system auth token file %q: %s", fn, err)
117 cfg.systemAuthToken = strings.TrimSpace(string(buf))
120 if cfg.EnableDelete {
121 log.Print("Trash/delete features are enabled. WARNING: this has not " +
122 "been extensively tested. You should disable this unless you can afford to lose data.")
125 if len(cfg.Volumes) == 0 {
126 if (&unixVolumeAdder{cfg}).Discover() == 0 {
127 return fmt.Errorf("no volumes found")
130 for _, v := range cfg.Volumes {
131 if err := v.Start(); err != nil {
132 return fmt.Errorf("volume %s: %s", v, err)
134 log.Printf("Using volume %v (writable=%v)", v, v.Writable())
139 // VolumeTypes is built up by init() funcs in the source files that
140 // define the volume types.
141 var VolumeTypes = []func() VolumeWithExamples{}
143 type VolumeList []Volume
145 // UnmarshalJSON, given an array of objects, deserializes each object
146 // as the volume type indicated by the object's Type field.
147 func (vols *VolumeList) UnmarshalJSON(data []byte) error {
148 typeMap := map[string]func() VolumeWithExamples{}
149 for _, factory := range VolumeTypes {
150 t := factory().Type()
151 if _, ok := typeMap[t]; ok {
152 log.Fatal("volume type %+q is claimed by multiple VolumeTypes")
157 var mapList []map[string]interface{}
158 err := json.Unmarshal(data, &mapList)
162 for _, mapIn := range mapList {
163 typeIn, ok := mapIn["Type"].(string)
165 return fmt.Errorf("invalid volume type %+v", mapIn["Type"])
167 factory, ok := typeMap[typeIn]
169 return fmt.Errorf("unsupported volume type %+q", typeIn)
171 data, err := json.Marshal(mapIn)
176 err = json.Unmarshal(data, vol)
180 *vols = append(*vols, vol)
185 // MarshalJSON adds a "Type" field to each volume corresponding to its
187 func (vl *VolumeList) MarshalJSON() ([]byte, error) {
189 for _, vs := range *vl {
190 j, err := json.Marshal(vs)
195 data = append(data, byte(','))
197 t, err := json.Marshal(vs.Type())
201 data = append(data, j[0])
202 data = append(data, []byte(`"Type":`)...)
203 data = append(data, t...)
204 data = append(data, byte(','))
205 data = append(data, j[1:]...)
207 return append(data, byte(']')), nil