21842: set suggestions to stay open on select
[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 }
319
320 type AzureVolumeDriverParameters struct {
321         StorageAccountName   string
322         StorageAccountKey    string
323         StorageBaseURL       string
324         ContainerName        string
325         RequestTimeout       Duration
326         ListBlobsRetryDelay  Duration
327         ListBlobsMaxAttempts int
328 }
329
330 type DirectoryVolumeDriverParameters struct {
331         Root      string
332         Serialize bool
333 }
334
335 type VolumeAccess struct {
336         ReadOnly bool
337 }
338
339 type Services struct {
340         Composer       Service
341         Controller     Service
342         DispatchCloud  Service
343         DispatchLSF    Service
344         DispatchSLURM  Service
345         Health         Service
346         Keepbalance    Service
347         Keepproxy      Service
348         Keepstore      Service
349         RailsAPI       Service
350         WebDAVDownload Service
351         WebDAV         Service
352         WebShell       Service
353         Websocket      Service
354         Workbench1     Service
355         Workbench2     Service
356 }
357
358 type Service struct {
359         InternalURLs map[URL]ServiceInstance
360         ExternalURL  URL
361 }
362
363 type TestUser struct {
364         Email    string
365         Password string
366 }
367
368 // URL is a url.URL that is also usable as a JSON key/value.
369 type URL url.URL
370
371 // UnmarshalText implements encoding.TextUnmarshaler so URL can be
372 // used as a JSON key/value.
373 func (su *URL) UnmarshalText(text []byte) error {
374         u, err := url.Parse(string(text))
375         if err == nil {
376                 *su = URL(*u)
377                 if su.Path == "" && su.Host != "" {
378                         // http://example really means http://example/
379                         su.Path = "/"
380                 }
381         }
382         return err
383 }
384
385 func (su URL) MarshalText() ([]byte, error) {
386         return []byte(su.String()), nil
387 }
388
389 func (su URL) String() string {
390         return (*url.URL)(&su).String()
391 }
392
393 type TLSVersion uint16
394
395 func (v TLSVersion) MarshalText() ([]byte, error) {
396         switch v {
397         case 0:
398                 return []byte{}, nil
399         case tls.VersionTLS10:
400                 return []byte("1.0"), nil
401         case tls.VersionTLS11:
402                 return []byte("1.1"), nil
403         case tls.VersionTLS12:
404                 return []byte("1.2"), nil
405         case tls.VersionTLS13:
406                 return []byte("1.3"), nil
407         default:
408                 return nil, fmt.Errorf("unsupported TLSVersion %x", v)
409         }
410 }
411
412 func (v *TLSVersion) UnmarshalJSON(text []byte) error {
413         if len(text) > 0 && text[0] == '"' {
414                 var s string
415                 err := json.Unmarshal(text, &s)
416                 if err != nil {
417                         return err
418                 }
419                 text = []byte(s)
420         }
421         switch string(text) {
422         case "":
423                 *v = 0
424         case "1.0":
425                 *v = tls.VersionTLS10
426         case "1.1":
427                 *v = tls.VersionTLS11
428         case "1.2":
429                 *v = tls.VersionTLS12
430         case "1.3":
431                 *v = tls.VersionTLS13
432         default:
433                 return fmt.Errorf("unsupported TLSVersion %q", text)
434         }
435         return nil
436 }
437
438 type ServiceInstance struct {
439         ListenURL  URL
440         Rendezvous string `json:",omitempty"`
441 }
442
443 type PostgreSQL struct {
444         Connection     PostgreSQLConnection
445         ConnectionPool int
446 }
447
448 type PostgreSQLConnection map[string]string
449
450 type RemoteCluster struct {
451         Host          string
452         Proxy         bool
453         Scheme        string
454         Insecure      bool
455         ActivateUsers bool
456 }
457
458 type CUDAFeatures struct {
459         DriverVersion      string
460         HardwareCapability string
461         DeviceCount        int
462 }
463
464 type InstanceType struct {
465         Name            string `json:"-"`
466         ProviderType    string
467         VCPUs           int
468         RAM             ByteSize
469         Scratch         ByteSize `json:"-"`
470         IncludedScratch ByteSize
471         AddedScratch    ByteSize
472         Price           float64
473         Preemptible     bool
474         CUDA            CUDAFeatures
475 }
476
477 type ContainersConfig struct {
478         CloudVMs                      CloudVMsConfig
479         CrunchRunCommand              string
480         CrunchRunArgumentsList        []string
481         DefaultKeepCacheRAM           ByteSize
482         DispatchPrivateKey            string
483         LogReuseDecisions             bool
484         MaxDispatchAttempts           int
485         MaxRetryAttempts              int
486         MinRetryPeriod                Duration
487         ReserveExtraRAM               ByteSize
488         StaleLockTimeout              Duration
489         SupportedDockerImageFormats   StringSet
490         AlwaysUsePreemptibleInstances bool
491         PreemptiblePriceFactor        float64
492         MaximumPriceFactor            float64
493         RuntimeEngine                 string
494         LocalKeepBlobBuffersPerVCPU   int
495         LocalKeepLogsToContainerLog   string
496
497         Logging struct {
498                 LogUpdatePeriod Duration
499                 LogUpdateSize   ByteSize
500         }
501         ShellAccess struct {
502                 Admin bool
503                 User  bool
504         }
505         SLURM struct {
506                 PrioritySpread             int64
507                 SbatchArgumentsList        []string
508                 SbatchEnvironmentVariables map[string]string
509         }
510         LSF struct {
511                 BsubSudoUser       string
512                 BsubArgumentsList  []string
513                 BsubCUDAArguments  []string
514                 MaxRunTimeOverhead Duration
515                 MaxRunTimeDefault  Duration
516         }
517 }
518
519 type CloudVMsConfig struct {
520         Enable bool
521
522         BootProbeCommand               string
523         InstanceInitCommand            string
524         DeployRunnerBinary             string
525         DeployPublicKey                bool
526         ImageID                        string
527         MaxCloudOpsPerSecond           int
528         MaxProbesPerSecond             int
529         MaxConcurrentInstanceCreateOps int
530         MaxInstances                   int
531         InitialQuotaEstimate           int
532         SupervisorFraction             float64
533         PollInterval                   Duration
534         ProbeInterval                  Duration
535         SSHPort                        string
536         SyncInterval                   Duration
537         TimeoutBooting                 Duration
538         TimeoutIdle                    Duration
539         TimeoutProbe                   Duration
540         TimeoutShutdown                Duration
541         TimeoutSignal                  Duration
542         TimeoutStaleRunLock            Duration
543         TimeoutTERM                    Duration
544         ResourceTags                   map[string]string
545         TagKeyPrefix                   string
546
547         Driver           string
548         DriverParameters json.RawMessage
549 }
550
551 type InstanceTypeMap map[string]InstanceType
552
553 var errDuplicateInstanceTypeName = errors.New("duplicate instance type name")
554
555 // UnmarshalJSON does special handling of InstanceTypes:
556 //
557 // - populate computed fields (Name and Scratch)
558 //
559 // - error out if InstancesTypes are populated as an array, which was
560 // deprecated in Arvados 1.2.0
561 func (it *InstanceTypeMap) UnmarshalJSON(data []byte) error {
562         fixup := func(t InstanceType) (InstanceType, error) {
563                 if t.ProviderType == "" {
564                         t.ProviderType = t.Name
565                 }
566                 // If t.Scratch is set in the configuration file, it will be ignored and overwritten.
567                 // It will also generate a "deprecated or unknown config entry" warning.
568                 t.Scratch = t.IncludedScratch + t.AddedScratch
569                 return t, nil
570         }
571
572         if len(data) > 0 && data[0] == '[' {
573                 return fmt.Errorf("InstanceTypes must be specified as a map, not an array, see https://doc.arvados.org/admin/config.html")
574         }
575         var hash map[string]InstanceType
576         err := json.Unmarshal(data, &hash)
577         if err != nil {
578                 return err
579         }
580         // Fill in Name field (and ProviderType field, if not
581         // specified) using hash key.
582         *it = InstanceTypeMap(hash)
583         for name, t := range *it {
584                 t.Name = name
585                 t, err := fixup(t)
586                 if err != nil {
587                         return err
588                 }
589                 (*it)[name] = t
590         }
591         return nil
592 }
593
594 type StringSet map[string]struct{}
595
596 // UnmarshalJSON handles old config files that provide an array of
597 // instance types instead of a hash.
598 func (ss *StringSet) UnmarshalJSON(data []byte) error {
599         if len(data) > 0 && data[0] == '[' {
600                 var arr []string
601                 err := json.Unmarshal(data, &arr)
602                 if err != nil {
603                         return err
604                 }
605                 if len(arr) == 0 {
606                         *ss = nil
607                         return nil
608                 }
609                 *ss = make(map[string]struct{}, len(arr))
610                 for _, t := range arr {
611                         (*ss)[t] = struct{}{}
612                 }
613                 return nil
614         }
615         var hash map[string]struct{}
616         err := json.Unmarshal(data, &hash)
617         if err != nil {
618                 return err
619         }
620         *ss = make(map[string]struct{}, len(hash))
621         for t := range hash {
622                 (*ss)[t] = struct{}{}
623         }
624
625         return nil
626 }
627
628 type ServiceName string
629
630 const (
631         ServiceNameController    ServiceName = "arvados-controller"
632         ServiceNameDispatchCloud ServiceName = "arvados-dispatch-cloud"
633         ServiceNameDispatchLSF   ServiceName = "arvados-dispatch-lsf"
634         ServiceNameDispatchSLURM ServiceName = "crunch-dispatch-slurm"
635         ServiceNameHealth        ServiceName = "arvados-health"
636         ServiceNameKeepbalance   ServiceName = "keep-balance"
637         ServiceNameKeepproxy     ServiceName = "keepproxy"
638         ServiceNameKeepstore     ServiceName = "keepstore"
639         ServiceNameKeepweb       ServiceName = "keep-web"
640         ServiceNameRailsAPI      ServiceName = "arvados-api-server"
641         ServiceNameWebsocket     ServiceName = "arvados-ws"
642         ServiceNameWorkbench1    ServiceName = "arvados-workbench1"
643         ServiceNameWorkbench2    ServiceName = "arvados-workbench2"
644 )
645
646 // Map returns all services as a map, suitable for iterating over all
647 // services or looking up a service by name.
648 func (svcs Services) Map() map[ServiceName]Service {
649         return map[ServiceName]Service{
650                 ServiceNameController:    svcs.Controller,
651                 ServiceNameDispatchCloud: svcs.DispatchCloud,
652                 ServiceNameDispatchLSF:   svcs.DispatchLSF,
653                 ServiceNameDispatchSLURM: svcs.DispatchSLURM,
654                 ServiceNameHealth:        svcs.Health,
655                 ServiceNameKeepbalance:   svcs.Keepbalance,
656                 ServiceNameKeepproxy:     svcs.Keepproxy,
657                 ServiceNameKeepstore:     svcs.Keepstore,
658                 ServiceNameKeepweb:       svcs.WebDAV,
659                 ServiceNameRailsAPI:      svcs.RailsAPI,
660                 ServiceNameWebsocket:     svcs.Websocket,
661                 ServiceNameWorkbench1:    svcs.Workbench1,
662                 ServiceNameWorkbench2:    svcs.Workbench2,
663         }
664 }