93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
|
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/cryptic-net-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)
|
||
|
}
|