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