package garage import ( crypticnet "cryptic-net" "cryptic-net/yamlutil" "errors" "fmt" "net" "strconv" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) // IsKeyNotFound returns true if the given error is the result of a key not // being found in a bucket. func IsKeyNotFound(err error) bool { var mErr minio.ErrorResponse return errors.As(err, &mErr) && mErr.Code == "NoSuchKey" } // APICredentials describe data fields necessary for authenticating with a // garage api endpoint. type APICredentials struct { ID string `yaml:"id"` Secret string `yaml:"secret"` } // GlobalBucketAPICredentials returns APICredentials for the global bucket. func GlobalBucketAPICredentials(env *crypticnet.Env) (APICredentials, error) { const path = "garage/priv/global-bucket-key.yml" var creds APICredentials if err := yamlutil.LoadYamlFSFile(&creds, env.BootstrapFS, path); err != nil { return APICredentials{}, fmt.Errorf("loading %q from bootstrap fs: %w", path, err) } return creds, nil } // APIAddr returns the network address of a garage api endpoint in the network. // It will prefer an endpoint on this particular host, if there is one, but will // otherwise return a random endpoint. func APIAddr(env *crypticnet.Env) string { if allocs := env.ThisDaemon().Storage.Allocations; len(allocs) > 0 { return net.JoinHostPort( env.ThisHost().Nebula.IP, strconv.Itoa(allocs[0].APIPort), ) } for _, host := range env.Hosts { if host.Garage == nil || len(host.Garage.Instances) == 0 { continue } return net.JoinHostPort( host.Nebula.IP, strconv.Itoa(host.Garage.Instances[0].APIPort), ) } panic("no garage instances configured") } // APIClient returns a minio client configured to use the given garage API // endpoint. func APIClient(addr string, creds APICredentials) (*minio.Client, error) { return minio.New(addr, &minio.Options{ Creds: credentials.NewStaticV4(creds.ID, creds.Secret, ""), Region: Region, }) } // GlobalBucketAPIClient returns a minio client pre-configured with access to // the global bucket. func GlobalBucketAPIClient(env *crypticnet.Env) (*minio.Client, error) { creds, err := GlobalBucketAPICredentials(env) if err != nil { return nil, fmt.Errorf("loading global bucket credentials: %w", err) } addr := APIAddr(env) return APIClient(addr, creds) }