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