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