17574: Add BalanceUpdateLimit config, fix tests.
[arvados.git] / sdk / go / arvados / config.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvados
6
7 import (
8         "encoding/json"
9         "errors"
10         "fmt"
11         "net/url"
12         "os"
13
14         "git.arvados.org/arvados.git/sdk/go/config"
15 )
16
17 var DefaultConfigFile = func() string {
18         if path := os.Getenv("ARVADOS_CONFIG"); path != "" {
19                 return path
20         }
21         return "/etc/arvados/config.yml"
22 }()
23
24 type Config struct {
25         Clusters         map[string]Cluster
26         AutoReloadConfig bool
27 }
28
29 // GetConfig returns the current system config, loading it from
30 // configFile if needed.
31 func GetConfig(configFile string) (*Config, error) {
32         var cfg Config
33         err := config.LoadFile(&cfg, configFile)
34         return &cfg, err
35 }
36
37 // GetCluster returns the cluster ID and config for the given
38 // cluster, or the default/only configured cluster if clusterID is "".
39 func (sc *Config) GetCluster(clusterID string) (*Cluster, error) {
40         if clusterID == "" {
41                 if len(sc.Clusters) == 0 {
42                         return nil, fmt.Errorf("no clusters configured")
43                 } else if len(sc.Clusters) > 1 {
44                         return nil, fmt.Errorf("multiple clusters configured, cannot choose")
45                 } else {
46                         for id, cc := range sc.Clusters {
47                                 cc.ClusterID = id
48                                 return &cc, nil
49                         }
50                 }
51         }
52         cc, ok := sc.Clusters[clusterID]
53         if !ok {
54                 return nil, fmt.Errorf("cluster %q is not configured", clusterID)
55         }
56         cc.ClusterID = clusterID
57         return &cc, nil
58 }
59
60 type WebDAVCacheConfig struct {
61         TTL                  Duration
62         UUIDTTL              Duration
63         MaxBlockEntries      int
64         MaxCollectionEntries int
65         MaxCollectionBytes   int64
66         MaxPermissionEntries int
67         MaxUUIDEntries       int
68         MaxSessions          int
69 }
70
71 type UploadDownloadPermission struct {
72         Upload   bool
73         Download bool
74 }
75
76 type UploadDownloadRolePermissions struct {
77         User  UploadDownloadPermission
78         Admin UploadDownloadPermission
79 }
80
81 type Cluster struct {
82         ClusterID       string `json:"-"`
83         ManagementToken string
84         SystemRootToken string
85         Services        Services
86         InstanceTypes   InstanceTypeMap
87         Containers      ContainersConfig
88         RemoteClusters  map[string]RemoteCluster
89         PostgreSQL      PostgreSQL
90
91         API struct {
92                 AsyncPermissionsUpdateInterval Duration
93                 DisabledAPIs                   StringSet
94                 MaxIndexDatabaseRead           int
95                 MaxItemsPerResponse            int
96                 MaxConcurrentRequests          int
97                 MaxKeepBlobBuffers             int
98                 MaxRequestAmplification        int
99                 MaxRequestSize                 int
100                 MaxTokenLifetime               Duration
101                 RequestTimeout                 Duration
102                 SendTimeout                    Duration
103                 WebsocketClientEventQueue      int
104                 WebsocketServerEventQueue      int
105                 KeepServiceRequestTimeout      Duration
106         }
107         AuditLogs struct {
108                 MaxAge             Duration
109                 MaxDeleteBatch     int
110                 UnloggedAttributes StringSet
111         }
112         Collections struct {
113                 BlobSigning              bool
114                 BlobSigningKey           string
115                 BlobSigningTTL           Duration
116                 BlobTrash                bool
117                 BlobTrashLifetime        Duration
118                 BlobTrashCheckInterval   Duration
119                 BlobTrashConcurrency     int
120                 BlobDeleteConcurrency    int
121                 BlobReplicateConcurrency int
122                 CollectionVersioning     bool
123                 DefaultTrashLifetime     Duration
124                 DefaultReplication       int
125                 ManagedProperties        map[string]struct {
126                         Value     interface{}
127                         Function  string
128                         Protected bool
129                 }
130                 PreserveVersionIfIdle        Duration
131                 TrashSweepInterval           Duration
132                 TrustAllContent              bool
133                 ForwardSlashNameSubstitution string
134                 S3FolderObjects              bool
135
136                 BlobMissingReport        string
137                 BalancePeriod            Duration
138                 BalanceCollectionBatch   int
139                 BalanceCollectionBuffers int
140                 BalanceTimeout           Duration
141                 BalanceUpdateLimit       int
142
143                 WebDAVCache WebDAVCacheConfig
144
145                 KeepproxyPermission UploadDownloadRolePermissions
146                 WebDAVPermission    UploadDownloadRolePermissions
147                 WebDAVLogEvents     bool
148         }
149         Git struct {
150                 GitCommand   string
151                 GitoliteHome string
152                 Repositories string
153         }
154         Login struct {
155                 LDAP struct {
156                         Enable             bool
157                         URL                URL
158                         StartTLS           bool
159                         InsecureTLS        bool
160                         StripDomain        string
161                         AppendDomain       string
162                         SearchAttribute    string
163                         SearchBindUser     string
164                         SearchBindPassword string
165                         SearchBase         string
166                         SearchFilters      string
167                         EmailAttribute     string
168                         UsernameAttribute  string
169                 }
170                 Google struct {
171                         Enable                          bool
172                         ClientID                        string
173                         ClientSecret                    string
174                         AlternateEmailAddresses         bool
175                         AuthenticationRequestParameters map[string]string
176                 }
177                 OpenIDConnect struct {
178                         Enable                          bool
179                         Issuer                          string
180                         ClientID                        string
181                         ClientSecret                    string
182                         EmailClaim                      string
183                         EmailVerifiedClaim              string
184                         UsernameClaim                   string
185                         AcceptAccessToken               bool
186                         AcceptAccessTokenScope          string
187                         AuthenticationRequestParameters map[string]string
188                 }
189                 PAM struct {
190                         Enable             bool
191                         Service            string
192                         DefaultEmailDomain string
193                 }
194                 Test struct {
195                         Enable bool
196                         Users  map[string]TestUser
197                 }
198                 LoginCluster       string
199                 RemoteTokenRefresh Duration
200                 TokenLifetime      Duration
201                 TrustedClients     map[string]struct{}
202                 IssueTrustedTokens bool
203         }
204         Mail struct {
205                 MailchimpAPIKey                string
206                 MailchimpListID                string
207                 SendUserSetupNotificationEmail bool
208                 IssueReporterEmailFrom         string
209                 IssueReporterEmailTo           string
210                 SupportEmailAddress            string
211                 EmailFrom                      string
212         }
213         SystemLogs struct {
214                 LogLevel                string
215                 Format                  string
216                 MaxRequestLogParamsSize int
217         }
218         TLS struct {
219                 Certificate string
220                 Key         string
221                 Insecure    bool
222         }
223         Users struct {
224                 AnonymousUserToken                    string
225                 AdminNotifierEmailFrom                string
226                 AutoAdminFirstUser                    bool
227                 AutoAdminUserWithEmail                string
228                 AutoSetupNewUsers                     bool
229                 AutoSetupNewUsersWithRepository       bool
230                 AutoSetupNewUsersWithVmUUID           string
231                 AutoSetupUsernameBlacklist            StringSet
232                 EmailSubjectPrefix                    string
233                 NewInactiveUserNotificationRecipients StringSet
234                 NewUserNotificationRecipients         StringSet
235                 NewUsersAreActive                     bool
236                 UserNotifierEmailFrom                 string
237                 UserProfileNotificationAddress        string
238                 PreferDomainForUsername               string
239                 UserSetupMailText                     string
240         }
241         Volumes   map[string]Volume
242         Workbench struct {
243                 ActivationContactLink            string
244                 APIClientConnectTimeout          Duration
245                 APIClientReceiveTimeout          Duration
246                 APIResponseCompression           bool
247                 ApplicationMimetypesWithViewIcon StringSet
248                 ArvadosDocsite                   string
249                 ArvadosPublicDataDocURL          string
250                 DefaultOpenIdPrefix              string
251                 EnableGettingStartedPopup        bool
252                 EnablePublicProjectsPage         bool
253                 FileViewersConfigURL             string
254                 LogViewerMaxBytes                ByteSize
255                 MultiSiteSearch                  string
256                 ProfilingEnabled                 bool
257                 Repositories                     bool
258                 RepositoryCache                  string
259                 RunningJobLogRecordsToFetch      int
260                 SecretKeyBase                    string
261                 ShowRecentCollectionsOnDashboard bool
262                 ShowUserAgreementInline          bool
263                 ShowUserNotifications            bool
264                 SiteName                         string
265                 Theme                            string
266                 UserProfileFormFields            map[string]struct {
267                         Type                 string
268                         FormFieldTitle       string
269                         FormFieldDescription string
270                         Required             bool
271                         Position             int
272                         Options              map[string]struct{}
273                 }
274                 UserProfileFormMessage string
275                 VocabularyURL          string
276                 WelcomePageHTML        string
277                 InactivePageHTML       string
278                 SSHHelpPageHTML        string
279                 SSHHelpHostSuffix      string
280                 IdleTimeout            Duration
281         }
282 }
283
284 type Volume struct {
285         AccessViaHosts   map[URL]VolumeAccess
286         ReadOnly         bool
287         Replication      int
288         StorageClasses   map[string]bool
289         Driver           string
290         DriverParameters json.RawMessage
291 }
292
293 type S3VolumeDriverParameters struct {
294         IAMRole            string
295         AccessKeyID        string
296         SecretAccessKey    string
297         Endpoint           string
298         Region             string
299         Bucket             string
300         LocationConstraint bool
301         V2Signature        bool
302         UseAWSS3v2Driver   bool
303         IndexPageSize      int
304         ConnectTimeout     Duration
305         ReadTimeout        Duration
306         RaceWindow         Duration
307         UnsafeDelete       bool
308 }
309
310 type AzureVolumeDriverParameters struct {
311         StorageAccountName   string
312         StorageAccountKey    string
313         StorageBaseURL       string
314         ContainerName        string
315         RequestTimeout       Duration
316         ListBlobsRetryDelay  Duration
317         ListBlobsMaxAttempts int
318 }
319
320 type DirectoryVolumeDriverParameters struct {
321         Root      string
322         Serialize bool
323 }
324
325 type VolumeAccess struct {
326         ReadOnly bool
327 }
328
329 type Services struct {
330         Composer       Service
331         Controller     Service
332         DispatchCloud  Service
333         GitHTTP        Service
334         GitSSH         Service
335         Health         Service
336         Keepbalance    Service
337         Keepproxy      Service
338         Keepstore      Service
339         RailsAPI       Service
340         WebDAVDownload Service
341         WebDAV         Service
342         WebShell       Service
343         Websocket      Service
344         Workbench1     Service
345         Workbench2     Service
346 }
347
348 type Service struct {
349         InternalURLs map[URL]ServiceInstance
350         ExternalURL  URL
351 }
352
353 type TestUser struct {
354         Email    string
355         Password string
356 }
357
358 // URL is a url.URL that is also usable as a JSON key/value.
359 type URL url.URL
360
361 // UnmarshalText implements encoding.TextUnmarshaler so URL can be
362 // used as a JSON key/value.
363 func (su *URL) UnmarshalText(text []byte) error {
364         u, err := url.Parse(string(text))
365         if err == nil {
366                 *su = URL(*u)
367                 if su.Path == "" && su.Host != "" {
368                         // http://example really means http://example/
369                         su.Path = "/"
370                 }
371         }
372         return err
373 }
374
375 func (su URL) MarshalText() ([]byte, error) {
376         return []byte(fmt.Sprintf("%s", (*url.URL)(&su).String())), nil
377 }
378
379 func (su URL) String() string {
380         return (*url.URL)(&su).String()
381 }
382
383 type ServiceInstance struct {
384         Rendezvous string `json:",omitempty"`
385 }
386
387 type PostgreSQL struct {
388         Connection     PostgreSQLConnection
389         ConnectionPool int
390 }
391
392 type PostgreSQLConnection map[string]string
393
394 type RemoteCluster struct {
395         Host          string
396         Proxy         bool
397         Scheme        string
398         Insecure      bool
399         ActivateUsers bool
400 }
401
402 type InstanceType struct {
403         Name            string
404         ProviderType    string
405         VCPUs           int
406         RAM             ByteSize
407         Scratch         ByteSize
408         IncludedScratch ByteSize
409         AddedScratch    ByteSize
410         Price           float64
411         Preemptible     bool
412 }
413
414 type ContainersConfig struct {
415         CloudVMs                    CloudVMsConfig
416         CrunchRunCommand            string
417         CrunchRunArgumentsList      []string
418         DefaultKeepCacheRAM         ByteSize
419         DispatchPrivateKey          string
420         LogReuseDecisions           bool
421         MaxComputeVMs               int
422         MaxDispatchAttempts         int
423         MaxRetryAttempts            int
424         MinRetryPeriod              Duration
425         ReserveExtraRAM             ByteSize
426         StaleLockTimeout            Duration
427         SupportedDockerImageFormats StringSet
428         UsePreemptibleInstances     bool
429         RuntimeEngine               string
430
431         JobsAPI struct {
432                 Enable         string
433                 GitInternalDir string
434         }
435         Logging struct {
436                 MaxAge                       Duration
437                 LogBytesPerEvent             int
438                 LogSecondsBetweenEvents      Duration
439                 LogThrottlePeriod            Duration
440                 LogThrottleBytes             int
441                 LogThrottleLines             int
442                 LimitLogBytesPerJob          int
443                 LogPartialLineThrottlePeriod Duration
444                 LogUpdatePeriod              Duration
445                 LogUpdateSize                ByteSize
446         }
447         ShellAccess struct {
448                 Admin bool
449                 User  bool
450         }
451         SLURM struct {
452                 PrioritySpread             int64
453                 SbatchArgumentsList        []string
454                 SbatchEnvironmentVariables map[string]string
455                 Managed                    struct {
456                         DNSServerConfDir       string
457                         DNSServerConfTemplate  string
458                         DNSServerReloadCommand string
459                         DNSServerUpdateCommand string
460                         ComputeNodeDomain      string
461                         ComputeNodeNameservers StringSet
462                         AssignNodeHostname     string
463                 }
464         }
465 }
466
467 type CloudVMsConfig struct {
468         Enable bool
469
470         BootProbeCommand               string
471         DeployRunnerBinary             string
472         ImageID                        string
473         MaxCloudOpsPerSecond           int
474         MaxProbesPerSecond             int
475         MaxConcurrentInstanceCreateOps int
476         PollInterval                   Duration
477         ProbeInterval                  Duration
478         SSHPort                        string
479         SyncInterval                   Duration
480         TimeoutBooting                 Duration
481         TimeoutIdle                    Duration
482         TimeoutProbe                   Duration
483         TimeoutShutdown                Duration
484         TimeoutSignal                  Duration
485         TimeoutStaleRunLock            Duration
486         TimeoutTERM                    Duration
487         ResourceTags                   map[string]string
488         TagKeyPrefix                   string
489
490         Driver           string
491         DriverParameters json.RawMessage
492 }
493
494 type InstanceTypeMap map[string]InstanceType
495
496 var errDuplicateInstanceTypeName = errors.New("duplicate instance type name")
497
498 // UnmarshalJSON handles old config files that provide an array of
499 // instance types instead of a hash.
500 func (it *InstanceTypeMap) UnmarshalJSON(data []byte) error {
501         fixup := func(t InstanceType) (InstanceType, error) {
502                 if t.ProviderType == "" {
503                         t.ProviderType = t.Name
504                 }
505                 if t.Scratch == 0 {
506                         t.Scratch = t.IncludedScratch + t.AddedScratch
507                 } else if t.AddedScratch == 0 {
508                         t.AddedScratch = t.Scratch - t.IncludedScratch
509                 } else if t.IncludedScratch == 0 {
510                         t.IncludedScratch = t.Scratch - t.AddedScratch
511                 }
512
513                 if t.Scratch != (t.IncludedScratch + t.AddedScratch) {
514                         return t, fmt.Errorf("InstanceType %q: Scratch != (IncludedScratch + AddedScratch)", t.Name)
515                 }
516                 return t, nil
517         }
518
519         if len(data) > 0 && data[0] == '[' {
520                 var arr []InstanceType
521                 err := json.Unmarshal(data, &arr)
522                 if err != nil {
523                         return err
524                 }
525                 if len(arr) == 0 {
526                         *it = nil
527                         return nil
528                 }
529                 *it = make(map[string]InstanceType, len(arr))
530                 for _, t := range arr {
531                         if _, ok := (*it)[t.Name]; ok {
532                                 return errDuplicateInstanceTypeName
533                         }
534                         t, err := fixup(t)
535                         if err != nil {
536                                 return err
537                         }
538                         (*it)[t.Name] = t
539                 }
540                 return nil
541         }
542         var hash map[string]InstanceType
543         err := json.Unmarshal(data, &hash)
544         if err != nil {
545                 return err
546         }
547         // Fill in Name field (and ProviderType field, if not
548         // specified) using hash key.
549         *it = InstanceTypeMap(hash)
550         for name, t := range *it {
551                 t.Name = name
552                 t, err := fixup(t)
553                 if err != nil {
554                         return err
555                 }
556                 (*it)[name] = t
557         }
558         return nil
559 }
560
561 type StringSet map[string]struct{}
562
563 // UnmarshalJSON handles old config files that provide an array of
564 // instance types instead of a hash.
565 func (ss *StringSet) UnmarshalJSON(data []byte) error {
566         if len(data) > 0 && data[0] == '[' {
567                 var arr []string
568                 err := json.Unmarshal(data, &arr)
569                 if err != nil {
570                         return err
571                 }
572                 if len(arr) == 0 {
573                         *ss = nil
574                         return nil
575                 }
576                 *ss = make(map[string]struct{}, len(arr))
577                 for _, t := range arr {
578                         (*ss)[t] = struct{}{}
579                 }
580                 return nil
581         }
582         var hash map[string]struct{}
583         err := json.Unmarshal(data, &hash)
584         if err != nil {
585                 return err
586         }
587         *ss = make(map[string]struct{}, len(hash))
588         for t := range hash {
589                 (*ss)[t] = struct{}{}
590         }
591
592         return nil
593 }
594
595 type ServiceName string
596
597 const (
598         ServiceNameRailsAPI      ServiceName = "arvados-api-server"
599         ServiceNameController    ServiceName = "arvados-controller"
600         ServiceNameDispatchCloud ServiceName = "arvados-dispatch-cloud"
601         ServiceNameHealth        ServiceName = "arvados-health"
602         ServiceNameWorkbench1    ServiceName = "arvados-workbench1"
603         ServiceNameWorkbench2    ServiceName = "arvados-workbench2"
604         ServiceNameWebsocket     ServiceName = "arvados-ws"
605         ServiceNameKeepbalance   ServiceName = "keep-balance"
606         ServiceNameKeepweb       ServiceName = "keep-web"
607         ServiceNameKeepproxy     ServiceName = "keepproxy"
608         ServiceNameKeepstore     ServiceName = "keepstore"
609 )
610
611 // Map returns all services as a map, suitable for iterating over all
612 // services or looking up a service by name.
613 func (svcs Services) Map() map[ServiceName]Service {
614         return map[ServiceName]Service{
615                 ServiceNameRailsAPI:      svcs.RailsAPI,
616                 ServiceNameController:    svcs.Controller,
617                 ServiceNameDispatchCloud: svcs.DispatchCloud,
618                 ServiceNameHealth:        svcs.Health,
619                 ServiceNameWorkbench1:    svcs.Workbench1,
620                 ServiceNameWorkbench2:    svcs.Workbench2,
621                 ServiceNameWebsocket:     svcs.Websocket,
622                 ServiceNameKeepbalance:   svcs.Keepbalance,
623                 ServiceNameKeepweb:       svcs.WebDAV,
624                 ServiceNameKeepproxy:     svcs.Keepproxy,
625                 ServiceNameKeepstore:     svcs.Keepstore,
626         }
627 }