github.com/grailbio/base@v0.0.11/cmd/ticket-server/config/load.go (about) 1 // Copyright 2018 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 package config 6 7 import ( 8 "fmt" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/grailbio/base/security/ticket" 14 "v.io/v23/naming" 15 "v.io/v23/security/access" 16 "v.io/x/lib/vlog" 17 "v.io/x/ref/lib/vdl/build" 18 "v.io/x/ref/lib/vdl/compile" 19 "v.io/x/ref/lib/vdl/vdlutil" 20 ) 21 22 const configSuffix = ".vdlconfig" 23 24 type ticketConfig struct { 25 Kind string 26 Ticket ticket.Ticket 27 Perms access.Permissions 28 Controls map[ticket.Control]bool 29 } 30 31 type Config map[string]ticketConfig 32 33 // Load returns a map with the tickets from a directory where the key is the 34 // path of the ticket. 35 func Load(dir string) (map[string]ticketConfig, error) { 36 all := Config{} 37 38 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 39 // The prefix we want for a path like 'config/docker/rwc.vdlconfig' is 40 // 'docker/rwc' where 'config' is the dir variable. For this example dirPart 41 // will be 'docker' and filePart will be 'rwc'. 42 dirPart := strings.TrimLeft(strings.TrimPrefix(filepath.Dir(path), dir), "/") 43 filePart := strings.TrimSuffix(filepath.Base(path), configSuffix) 44 prefix := naming.Join(dirPart, filePart) 45 vlog.VI(1).Infof("walk: %q prefix %q", path, prefix) 46 47 if !strings.HasSuffix(path, configSuffix) { 48 return nil 49 } 50 51 f, err := os.Open(path) 52 if err != nil { 53 return fmt.Errorf("bad path %q: %+v", path, err) 54 } 55 56 errors := vdlutil.Errors{} 57 warnings := vdlutil.Errors{} 58 packages := build.TransitivePackagesForConfig(path, f, build.Opts{}, &errors, &warnings) 59 env := compile.NewEnv(100) 60 for _, p := range packages { 61 vlog.VI(1).Infof("building package: %+v", p.Path) 62 build.BuildPackage(p, env) 63 if env.Errors.NumErrors() != 0 { 64 return fmt.Errorf("errors building %s:\n%+v", p.Path, env.Errors) 65 } 66 } 67 68 f.Seek(0, 0) 69 config := ticket.Config{} 70 build.BuildConfigValue(path, f, nil, env, &config) 71 72 if env.Errors != nil && env.Errors.NumErrors() > 0 { 73 return env.Errors.ToError() 74 } 75 76 for name, t := range config.Tickets { 77 perms := config.Permissions 78 if t.Permissions != nil { 79 perms = t.Permissions 80 } 81 // TODO(noah): Remove this check after PagerDutyId and TicketId controls are supported. 82 if _, ok := t.Controls[ticket.ControlRationale]; len(t.Controls) != 0 && (len(t.Controls) != 1 || !ok) { 83 return fmt.Errorf("only rationale control is supported: %+v", t.Controls) 84 } 85 all[naming.Join(prefix, name)] = ticketConfig{ 86 Ticket: t.Ticket, 87 Perms: perms, 88 Controls: t.Controls, 89 } 90 } 91 92 return nil 93 }) 94 95 return all, err 96 }