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