ea01cc3c6872a88adb341d953adbe75760b4f176
[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         MaxBlockEntries    int
67         MaxCollectionBytes int64
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                 MaxQueueTimeForLockRequests      Duration
106                 LogCreateRequestFraction         float64
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
154                 WebDAVCache WebDAVCacheConfig
155
156                 KeepproxyPermission UploadDownloadRolePermissions
157                 WebDAVPermission    UploadDownloadRolePermissions
158                 WebDAVLogEvents     bool
159         }
160         Git struct {
161                 GitCommand   string
162                 GitoliteHome string
163                 Repositories string
164         }
165         Login struct {
166                 LDAP struct {
167                         Enable             bool
168                         URL                URL
169                         StartTLS           bool
170                         InsecureTLS        bool
171                         MinTLSVersion      TLSVersion
172                         StripDomain        string
173                         AppendDomain       string
174                         SearchAttribute    string
175                         SearchBindUser     string
176                         SearchBindPassword string
177                         SearchBase         string
178                         SearchFilters      string
179                         EmailAttribute     string
180                         UsernameAttribute  string
181                 }
182                 Google struct {
183                         Enable                          bool
184                         ClientID                        string
185                         ClientSecret                    string
186                         AlternateEmailAddresses         bool
187                         AuthenticationRequestParameters map[string]string
188                 }
189                 OpenIDConnect struct {
190                         Enable                          bool
191                         Issuer                          string
192                         ClientID                        string
193                         ClientSecret                    string
194                         EmailClaim                      string
195                         EmailVerifiedClaim              string
196                         UsernameClaim                   string
197                         AcceptAccessToken               bool
198                         AcceptAccessTokenScope          string
199                         AuthenticationRequestParameters map[string]string
200                 }
201                 PAM struct {
202                         Enable             bool
203                         Service            string
204                         DefaultEmailDomain string
205                 }
206                 Test struct {
207                         Enable bool
208                         Users  map[string]TestUser
209                 }
210                 LoginCluster         string
211                 RemoteTokenRefresh   Duration
212                 TokenLifetime        Duration
213                 TrustedClients       map[URL]struct{}
214                 TrustPrivateNetworks bool
215                 IssueTrustedTokens   bool
216         }
217         Mail struct {
218                 MailchimpAPIKey                string
219                 MailchimpListID                string
220                 SendUserSetupNotificationEmail bool
221                 IssueReporterEmailFrom         string
222                 IssueReporterEmailTo           string
223                 SupportEmailAddress            string
224                 EmailFrom                      string
225         }
226         SystemLogs struct {
227                 LogLevel                  string
228                 Format                    string
229                 MaxRequestLogParamsSize   int
230                 RequestQueueDumpDirectory string
231         }
232         TLS struct {
233                 Certificate string
234                 Key         string
235                 Insecure    bool
236                 ACME        struct {
237                         Server string
238                 }
239         }
240         Users struct {
241                 ActivatedUsersAreVisibleToOthers      bool
242                 AnonymousUserToken                    string
243                 AdminNotifierEmailFrom                string
244                 AutoAdminFirstUser                    bool
245                 AutoAdminUserWithEmail                string
246                 AutoSetupNewUsers                     bool
247                 AutoSetupNewUsersWithRepository       bool
248                 AutoSetupNewUsersWithVmUUID           string
249                 AutoSetupUsernameBlacklist            StringSet
250                 EmailSubjectPrefix                    string
251                 NewInactiveUserNotificationRecipients StringSet
252                 NewUserNotificationRecipients         StringSet
253                 NewUsersAreActive                     bool
254                 UserNotifierEmailFrom                 string
255                 UserNotifierEmailBcc                  StringSet
256                 UserProfileNotificationAddress        string
257                 PreferDomainForUsername               string
258                 UserSetupMailText                     string
259                 RoleGroupsVisibleToAll                bool
260                 CanCreateRoleGroups                   bool
261                 ActivityLoggingPeriod                 Duration
262                 SyncIgnoredGroups                     []string
263                 SyncRequiredGroups                    []string
264                 SyncUserAccounts                      bool
265                 SyncUserAPITokens                     bool
266                 SyncUserGroups                        bool
267                 SyncUserSSHKeys                       bool
268         }
269         StorageClasses map[string]StorageClassConfig
270         Volumes        map[string]Volume
271         Workbench      struct {
272                 ActivationContactLink            string
273                 APIClientConnectTimeout          Duration
274                 APIClientReceiveTimeout          Duration
275                 APIResponseCompression           bool
276                 ApplicationMimetypesWithViewIcon StringSet
277                 ArvadosDocsite                   string
278                 ArvadosPublicDataDocURL          string
279                 DefaultOpenIdPrefix              string
280                 DisableSharingURLsUI             bool
281                 EnableGettingStartedPopup        bool
282                 EnablePublicProjectsPage         bool
283                 FileViewersConfigURL             string
284                 LogViewerMaxBytes                ByteSize
285                 MultiSiteSearch                  string
286                 ProfilingEnabled                 bool
287                 Repositories                     bool
288                 RepositoryCache                  string
289                 RunningJobLogRecordsToFetch      int
290                 SecretKeyBase                    string
291                 ShowRecentCollectionsOnDashboard bool
292                 ShowUserAgreementInline          bool
293                 ShowUserNotifications            bool
294                 SiteName                         string
295                 Theme                            string
296                 UserProfileFormFields            map[string]struct {
297                         Type                 string
298                         FormFieldTitle       string
299                         FormFieldDescription string
300                         Required             bool
301                         Position             int
302                         Options              map[string]struct{}
303                 }
304                 UserProfileFormMessage string
305                 WelcomePageHTML        string
306                 InactivePageHTML       string
307                 SSHHelpPageHTML        string
308                 SSHHelpHostSuffix      string
309                 IdleTimeout            Duration
310                 BannerUUID             string
311         }
312 }
313
314 type StorageClassConfig struct {
315         Default  bool
316         Priority int
317 }
318
319 type Volume struct {
320         AccessViaHosts         map[URL]VolumeAccess
321         ReadOnly               bool
322         AllowTrashWhenReadOnly bool
323         Replication            int
324         StorageClasses         map[string]bool
325         Driver                 string
326         DriverParameters       json.RawMessage
327 }
328
329 type S3VolumeDriverParameters struct {
330         IAMRole            string
331         AccessKeyID        string
332         SecretAccessKey    string
333         Endpoint           string
334         Region             string
335         Bucket             string
336         LocationConstraint bool
337         V2Signature        bool
338         IndexPageSize      int
339         ConnectTimeout     Duration
340         ReadTimeout        Duration
341         RaceWindow         Duration
342         UnsafeDelete       bool
343         PrefixLength       int
344 }
345
346 type AzureVolumeDriverParameters struct {
347         StorageAccountName   string
348         StorageAccountKey    string
349         StorageBaseURL       string
350         ContainerName        string
351         RequestTimeout       Duration
352         ListBlobsRetryDelay  Duration
353         ListBlobsMaxAttempts int
354 }
355
356 type DirectoryVolumeDriverParameters struct {
357         Root      string
358         Serialize bool
359 }
360
361 type VolumeAccess struct {
362         ReadOnly bool
363 }
364
365 type Services struct {
366         Composer       Service
367         Controller     Service
368         DispatchCloud  Service
369         DispatchLSF    Service
370         DispatchSLURM  Service
371         GitHTTP        Service
372         GitSSH         Service
373         Health         Service
374         Keepbalance    Service
375         Keepproxy      Service
376         Keepstore      Service
377         RailsAPI       Service
378         WebDAVDownload Service
379         WebDAV         Service
380         WebShell       Service
381         Websocket      Service
382         Workbench1     Service
383         Workbench2     Service
384 }
385
386 type Service struct {
387         InternalURLs map[URL]ServiceInstance
388         ExternalURL  URL
389 }
390
391 type TestUser struct {
392         Email    string
393         Password string
394 }
395
396 // URL is a url.URL that is also usable as a JSON key/value.
397 type URL url.URL
398
399 // UnmarshalText implements encoding.TextUnmarshaler so URL can be
400 // used as a JSON key/value.
401 func (su *URL) UnmarshalText(text []byte) error {
402         u, err := url.Parse(string(text))
403         if err == nil {
404                 *su = URL(*u)
405                 if su.Path == "" && su.Host != "" {
406                         // http://example really means http://example/
407                         su.Path = "/"
408                 }
409         }
410         return err
411 }
412
413 func (su URL) MarshalText() ([]byte, error) {
414         return []byte(su.String()), nil
415 }
416
417 func (su URL) String() string {
418         return (*url.URL)(&su).String()
419 }
420
421 type TLSVersion uint16
422
423 func (v TLSVersion) MarshalText() ([]byte, error) {
424         switch v {
425         case 0:
426                 return []byte{}, nil
427         case tls.VersionTLS10:
428                 return []byte("1.0"), nil
429         case tls.VersionTLS11:
430                 return []byte("1.1"), nil
431         case tls.VersionTLS12:
432                 return []byte("1.2"), nil
433         case tls.VersionTLS13:
434                 return []byte("1.3"), nil
435         default:
436                 return nil, fmt.Errorf("unsupported TLSVersion %x", v)
437         }
438 }
439
440 func (v *TLSVersion) UnmarshalJSON(text []byte) error {
441         if len(text) > 0 && text[0] == '"' {
442                 var s string
443                 err := json.Unmarshal(text, &s)
444                 if err != nil {
445                         return err
446                 }
447                 text = []byte(s)
448         }
449         switch string(text) {
450         case "":
451                 *v = 0
452         case "1.0":
453                 *v = tls.VersionTLS10
454         case "1.1":
455                 *v = tls.VersionTLS11
456         case "1.2":
457                 *v = tls.VersionTLS12
458         case "1.3":
459                 *v = tls.VersionTLS13
460         default:
461                 return fmt.Errorf("unsupported TLSVersion %q", text)
462         }
463         return nil
464 }
465
466 type ServiceInstance struct {
467         ListenURL  URL
468         Rendezvous string `json:",omitempty"`
469 }
470
471 type PostgreSQL struct {
472         Connection     PostgreSQLConnection
473         ConnectionPool int
474 }
475
476 type PostgreSQLConnection map[string]string
477
478 type RemoteCluster struct {
479         Host          string
480         Proxy         bool
481         Scheme        string
482         Insecure      bool
483         ActivateUsers bool
484 }
485
486 type CUDAFeatures struct {
487         DriverVersion      string
488         HardwareCapability string
489         DeviceCount        int
490 }
491
492 type InstanceType struct {
493         Name            string `json:"-"`
494         ProviderType    string
495         VCPUs           int
496         RAM             ByteSize
497         Scratch         ByteSize `json:"-"`
498         IncludedScratch ByteSize
499         AddedScratch    ByteSize
500         Price           float64
501         Preemptible     bool
502         CUDA            CUDAFeatures
503 }
504
505 type ContainersConfig struct {
506         CloudVMs                      CloudVMsConfig
507         CrunchRunCommand              string
508         CrunchRunArgumentsList        []string
509         DefaultKeepCacheRAM           ByteSize
510         DispatchPrivateKey            string
511         LogReuseDecisions             bool
512         MaxDispatchAttempts           int
513         MaxRetryAttempts              int
514         MinRetryPeriod                Duration
515         ReserveExtraRAM               ByteSize
516         StaleLockTimeout              Duration
517         SupportedDockerImageFormats   StringSet
518         AlwaysUsePreemptibleInstances bool
519         PreemptiblePriceFactor        float64
520         MaximumPriceFactor            float64
521         RuntimeEngine                 string
522         LocalKeepBlobBuffersPerVCPU   int
523         LocalKeepLogsToContainerLog   string
524
525         JobsAPI struct {
526                 Enable         string
527                 GitInternalDir string
528         }
529         Logging struct {
530                 MaxAge                       Duration
531                 SweepInterval                Duration
532                 LogBytesPerEvent             int
533                 LogSecondsBetweenEvents      Duration
534                 LogThrottlePeriod            Duration
535                 LogThrottleBytes             int
536                 LogThrottleLines             int
537                 LimitLogBytesPerJob          int
538                 LogPartialLineThrottlePeriod Duration
539                 LogUpdatePeriod              Duration
540                 LogUpdateSize                ByteSize
541         }
542         ShellAccess struct {
543                 Admin bool
544                 User  bool
545         }
546         SLURM struct {
547                 PrioritySpread             int64
548                 SbatchArgumentsList        []string
549                 SbatchEnvironmentVariables map[string]string
550                 Managed                    struct {
551                         DNSServerConfDir       string
552                         DNSServerConfTemplate  string
553                         DNSServerReloadCommand string
554                         DNSServerUpdateCommand string
555                         ComputeNodeDomain      string
556                         ComputeNodeNameservers StringSet
557                         AssignNodeHostname     string
558                 }
559         }
560         LSF struct {
561                 BsubSudoUser      string
562                 BsubArgumentsList []string
563                 BsubCUDAArguments []string
564         }
565 }
566
567 type CloudVMsConfig struct {
568         Enable bool
569
570         BootProbeCommand               string
571         InstanceInitCommand            string
572         DeployRunnerBinary             string
573         DeployPublicKey                bool
574         ImageID                        string
575         MaxCloudOpsPerSecond           int
576         MaxProbesPerSecond             int
577         MaxConcurrentInstanceCreateOps int
578         MaxInstances                   int
579         InitialQuotaEstimate           int
580         SupervisorFraction             float64
581         PollInterval                   Duration
582         ProbeInterval                  Duration
583         SSHPort                        string
584         SyncInterval                   Duration
585         TimeoutBooting                 Duration
586         TimeoutIdle                    Duration
587         TimeoutProbe                   Duration
588         TimeoutShutdown                Duration
589         TimeoutSignal                  Duration
590         TimeoutStaleRunLock            Duration
591         TimeoutTERM                    Duration
592         ResourceTags                   map[string]string
593         TagKeyPrefix                   string
594
595         Driver           string
596         DriverParameters json.RawMessage
597 }
598
599 type InstanceTypeMap map[string]InstanceType
600
601 var errDuplicateInstanceTypeName = errors.New("duplicate instance type name")
602
603 // UnmarshalJSON does special handling of InstanceTypes:
604 //
605 // - populate computed fields (Name and Scratch)
606 //
607 // - error out if InstancesTypes are populated as an array, which was
608 // deprecated in Arvados 1.2.0
609 func (it *InstanceTypeMap) UnmarshalJSON(data []byte) error {
610         fixup := func(t InstanceType) (InstanceType, error) {
611                 if t.ProviderType == "" {
612                         t.ProviderType = t.Name
613                 }
614                 // If t.Scratch is set in the configuration file, it will be ignored and overwritten.
615                 // It will also generate a "deprecated or unknown config entry" warning.
616                 t.Scratch = t.IncludedScratch + t.AddedScratch
617                 return t, nil
618         }
619
620         if len(data) > 0 && data[0] == '[' {
621                 return fmt.Errorf("InstanceTypes must be specified as a map, not an array, see https://doc.arvados.org/admin/config.html")
622         }
623         var hash map[string]InstanceType
624         err := json.Unmarshal(data, &hash)
625         if err != nil {
626                 return err
627         }
628         // Fill in Name field (and ProviderType field, if not
629         // specified) using hash key.
630         *it = InstanceTypeMap(hash)
631         for name, t := range *it {
632                 t.Name = name
633                 t, err := fixup(t)
634                 if err != nil {
635                         return err
636                 }
637                 (*it)[name] = t
638         }
639         return nil
640 }
641
642 type StringSet map[string]struct{}
643
644 // UnmarshalJSON handles old config files that provide an array of
645 // instance types instead of a hash.
646 func (ss *StringSet) UnmarshalJSON(data []byte) error {
647         if len(data) > 0 && data[0] == '[' {
648                 var arr []string
649                 err := json.Unmarshal(data, &arr)
650                 if err != nil {
651                         return err
652                 }
653                 if len(arr) == 0 {
654                         *ss = nil
655                         return nil
656                 }
657                 *ss = make(map[string]struct{}, len(arr))
658                 for _, t := range arr {
659                         (*ss)[t] = struct{}{}
660                 }
661                 return nil
662         }
663         var hash map[string]struct{}
664         err := json.Unmarshal(data, &hash)
665         if err != nil {
666                 return err
667         }
668         *ss = make(map[string]struct{}, len(hash))
669         for t := range hash {
670                 (*ss)[t] = struct{}{}
671         }
672
673         return nil
674 }
675
676 type ServiceName string
677
678 const (
679         ServiceNameController    ServiceName = "arvados-controller"
680         ServiceNameDispatchCloud ServiceName = "arvados-dispatch-cloud"
681         ServiceNameDispatchLSF   ServiceName = "arvados-dispatch-lsf"
682         ServiceNameDispatchSLURM ServiceName = "crunch-dispatch-slurm"
683         ServiceNameGitHTTP       ServiceName = "arvados-git-httpd"
684         ServiceNameHealth        ServiceName = "arvados-health"
685         ServiceNameKeepbalance   ServiceName = "keep-balance"
686         ServiceNameKeepproxy     ServiceName = "keepproxy"
687         ServiceNameKeepstore     ServiceName = "keepstore"
688         ServiceNameKeepweb       ServiceName = "keep-web"
689         ServiceNameRailsAPI      ServiceName = "arvados-api-server"
690         ServiceNameWebsocket     ServiceName = "arvados-ws"
691         ServiceNameWorkbench1    ServiceName = "arvados-workbench1"
692         ServiceNameWorkbench2    ServiceName = "arvados-workbench2"
693 )
694
695 // Map returns all services as a map, suitable for iterating over all
696 // services or looking up a service by name.
697 func (svcs Services) Map() map[ServiceName]Service {
698         return map[ServiceName]Service{
699                 ServiceNameController:    svcs.Controller,
700                 ServiceNameDispatchCloud: svcs.DispatchCloud,
701                 ServiceNameDispatchLSF:   svcs.DispatchLSF,
702                 ServiceNameDispatchSLURM: svcs.DispatchSLURM,
703                 ServiceNameGitHTTP:       svcs.GitHTTP,
704                 ServiceNameHealth:        svcs.Health,
705                 ServiceNameKeepbalance:   svcs.Keepbalance,
706                 ServiceNameKeepproxy:     svcs.Keepproxy,
707                 ServiceNameKeepstore:     svcs.Keepstore,
708                 ServiceNameKeepweb:       svcs.WebDAV,
709                 ServiceNameRailsAPI:      svcs.RailsAPI,
710                 ServiceNameWebsocket:     svcs.Websocket,
711                 ServiceNameWorkbench1:    svcs.Workbench1,
712                 ServiceNameWorkbench2:    svcs.Workbench2,
713         }
714 }