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