github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/provtarget/builddefaults/default.go (about) 1 // Copyright (c) 2021-2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package builddefaults 6 7 import ( 8 "context" 9 "fmt" 10 "io" 11 "net" 12 "os" 13 "strings" 14 "time" 15 16 "github.com/choria-io/go-choria/config" 17 "github.com/choria-io/go-choria/internal/util" 18 "github.com/choria-io/go-choria/srvcache" 19 "github.com/choria-io/tokens" 20 "github.com/sirupsen/logrus" 21 22 "github.com/choria-io/go-choria/backoff" 23 "github.com/choria-io/go-choria/build" 24 ) 25 26 // Provider creates an instance of the provider 27 func Provider() *Resolver { 28 return &Resolver{ 29 bi: &build.Info{}, 30 } 31 } 32 33 // Resolver resolve names against the compile time build properties 34 type Resolver struct { 35 identity string 36 bi *build.Info 37 } 38 39 // Name is te name of the resolver 40 func (b *Resolver) Name() string { 41 return "Choria JWT Resolver" 42 } 43 44 // Configure overrides build settings using the contents of the JWT 45 func (b *Resolver) Configure(ctx context.Context, cfg *config.Config, log *logrus.Entry) { 46 jwtf := b.bi.ProvisionJWTFile() 47 if jwtf == "" { 48 return 49 } 50 51 if !util.FileExist(jwtf) { 52 return 53 } 54 55 log.Infof("Setting build defaults to those found in %s", jwtf) 56 57 b.identity = cfg.Identity 58 59 jwtreader, err := os.Open(b.bi.ProvisionJWTFile()) 60 if err != nil { 61 log.Errorf("Configuration of the provisioner settings based on JWT file %s failed: %s", jwtf, err) 62 return 63 } 64 defer jwtreader.Close() 65 66 _, err = SetBuildBasedOnJWT(jwtreader, b.bi) 67 if err != nil { 68 log.Errorf("Configuration of the provisioner settings based on JWT file %s failed: %s", jwtf, err) 69 } 70 } 71 72 // Targets are the build time configured provisioners 73 func (b *Resolver) Targets(ctx context.Context, log *logrus.Entry) []string { 74 if b.bi.ProvisionBrokerURLs() != "" { 75 return strings.Split(b.bi.ProvisionBrokerURLs(), ",") 76 } 77 78 domain := b.bi.ProvisionBrokerSRVDomain() 79 if domain == "" { 80 log.Warnf("Neither provisioning broker url or provisioning SRV domain is set, cannot continue") 81 return []string{} 82 } 83 84 log.Infof("Performing provisioning broker resolution via SRV using domain %s", domain) 85 86 servers := srvcache.NewServers() 87 cache := srvcache.New(b.identity, 5*time.Second, net.LookupSRV, log) 88 var err error 89 try := 0 90 91 for { 92 try++ 93 94 for _, q := range []string{"_choria-provisioner._tcp"} { 95 if ctx.Err() != nil { 96 return []string{} 97 } 98 99 record := q + "." + domain 100 log.Infof("Attempting SRV lookup on %s", record) 101 102 servers, err = cache.LookupSrvServers("", "", record, "nats") 103 if err != nil { 104 log.Warnf("Failed to resolve %s: %s", record, err) 105 continue 106 } 107 108 log.Infof("Found %d SRV records for %s", servers.Count(), record) 109 break 110 } 111 112 if servers.Count() > 0 { 113 break 114 } 115 116 log.Warnf("Resolving provisioning brokers via SRV lookups in domain %s failed on try %d, will keep trying", domain, try) 117 118 backoff.TwentySec.TrySleep(ctx, try) 119 } 120 121 return servers.Strings() 122 } 123 124 // SetBuildBasedOnJWT sets build settings based on contents of a JWT file 125 func SetBuildBasedOnJWT(r io.Reader, bi *build.Info) (*tokens.ProvisioningClaims, error) { 126 jwt, err := io.ReadAll(r) 127 if err != nil { 128 return nil, err 129 } 130 131 claims, err := tokens.ParseProvisionTokenUnverified(string(jwt)) 132 if err != nil { 133 return nil, err 134 } 135 136 if claims.Token == "" { 137 return nil, fmt.Errorf("no auth token") 138 } 139 140 if claims.SRVDomain == "" && claims.URLs == "" { 141 return nil, fmt.Errorf("no srv domain or urls") 142 } 143 144 if claims.SRVDomain != "" && claims.URLs != "" { 145 return nil, fmt.Errorf("both srv domain and URLs supplied") 146 } 147 148 bi.SetProvisionBrokerURLs(claims.URLs) 149 bi.SetProvisionToken(claims.Token) 150 bi.SetProvisionBrokerSRVDomain(claims.SRVDomain) 151 bi.SetProvisionUsingVersion2(claims.ProtoV2) 152 bi.SetProvisionAllowServerUpdate(claims.AllowUpdate) 153 154 if claims.ProvDefault { 155 bi.EnableProvisionModeAsDefault() 156 } else { 157 bi.DisableProvisionModeAsDefault() 158 } 159 160 if claims.Secure { 161 bi.EnableProvisionModeSecurity() 162 } else { 163 bi.DisableProvisionModeSecurity() 164 } 165 166 if claims.ProvFacts != "" { 167 bi.SetProvisionFacts(claims.ProvFacts) 168 } 169 170 if claims.ProvRegData != "" { 171 bi.SetProvisionRegistrationData(claims.ProvRegData) 172 } 173 174 if claims.ProvNatsUser != "" { 175 bi.SetProvisioningBrokerUsername(claims.ProvNatsUser) 176 } 177 178 if claims.ProvNatsPass != "" { 179 bi.SetProvisioningBrokerPassword(claims.ProvNatsPass) 180 } 181 182 return claims, nil 183 }