in registry/storage/driver/gcs/common.go [197:323]
func parseParameters(parameters map[string]any, useNext bool) (*driverParameters, error) {
bucket, ok := parameters["bucket"]
if !ok || fmt.Sprint(bucket) == "" {
return nil, fmt.Errorf("no bucket parameter provided")
}
rootDirectory, ok := parameters["rootdirectory"]
if !ok {
rootDirectory = ""
}
chunkSize := defaultChunkSize
chunkSizeParam, ok := parameters["chunksize"]
if ok {
switch v := chunkSizeParam.(type) {
case string:
vv, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return nil, fmt.Errorf("chunksize parameter must be an integer, %v invalid", chunkSizeParam)
}
chunkSize = vv
case int, uint, int32, uint32, uint64, int64:
chunkSize = reflect.ValueOf(v).Convert(reflect.TypeOf(chunkSize)).Int()
default:
return nil, fmt.Errorf("invalid valud for chunksize: %#v", chunkSizeParam)
}
if chunkSize < minChunkSize {
return nil, fmt.Errorf("the chunksize %#v parameter should be a number that is larger than or equal to %d", chunkSize, minChunkSize)
}
if chunkSize%minChunkSize != 0 {
return nil, fmt.Errorf("chunksize should be a multiple of %d", minChunkSize)
}
}
var ts oauth2.TokenSource
jwtConf := new(jwt.Config)
if keyfile, ok := parameters["keyfile"]; ok {
jsonKey, err := os.ReadFile(fmt.Sprint(keyfile))
if err != nil {
return nil, err
}
jwtConf, err = google.JWTConfigFromJSON(jsonKey, storage.ScopeFullControl)
if err != nil {
return nil, err
}
ts = jwtConf.TokenSource(context.Background())
} else if credentials, ok := parameters["credentials"]; ok {
credentialMap, ok := credentials.(map[any]any)
if !ok {
return nil, fmt.Errorf("the credentials were not specified in the correct format")
}
stringMap := make(map[string]any, 0)
for k, v := range credentialMap {
key, ok := k.(string)
if !ok {
return nil, fmt.Errorf("one of the credential keys was not a string: %s", fmt.Sprint(k))
}
stringMap[key] = v
}
data, err := json.Marshal(stringMap)
if err != nil {
return nil, fmt.Errorf("failed to marshal gcs credentials to json")
}
jwtConf, err = google.JWTConfigFromJSON(data, storage.ScopeFullControl)
if err != nil {
return nil, err
}
ts = jwtConf.TokenSource(context.Background())
} else {
var err error
ts, err = google.DefaultTokenSource(context.Background(), storage.ScopeFullControl)
if err != nil {
return nil, err
}
}
maxConcurrency, err := base.GetLimitFromParameter(parameters["maxconcurrency"], minConcurrency, defaultMaxConcurrency)
if err != nil {
return nil, fmt.Errorf("maxconcurrency config error: %s", err)
}
opts := []option.ClientOption{option.WithTokenSource(ts)}
if useNext {
// NOTE(prozlach): By default, reads are made using the Cloud Storage XML
// API. GCS SDK recommends using the JSON API instead, which is done
// here by setting WithJSONReads. This ensures consistency with other
// client operations, which all use JSON. JSON will become the default
// in a future release of GCS SDK. We only enable it for GCS next.
// https://cloud.google.com/go/docs/reference/cloud.google.com/go/storage/latest#cloud_google_com_go_storage_WithJSONReads
opts = append(opts, storage.WithJSONReads())
if userAgent, ok := parameters["useragent"]; ok {
if ua, ok := userAgent.(string); ok && ua != "" {
opts = append(opts, option.WithUserAgent(ua))
} else {
userAgent := fmt.Sprintf("container-registry %s (%s)", version.Version, runtime.Version())
opts = append(opts, option.WithUserAgent(userAgent))
}
}
}
storageClient, err := storage.NewClient(context.Background(), opts...)
if err != nil {
return nil, fmt.Errorf("storage client error: %s", err)
}
parallelWalkBool, err := parse.Bool(parameters, "parallelwalk", false)
if err != nil {
return nil, err
}
return &driverParameters{
bucket: fmt.Sprint(bucket),
rootDirectory: fmt.Sprint(rootDirectory),
email: jwtConf.Email,
privateKey: jwtConf.PrivateKey,
client: oauth2.NewClient(context.Background(), ts),
storageClient: storageClient,
chunkSize: chunkSize,
maxConcurrency: maxConcurrency,
parallelWalk: parallelWalkBool,
}, nil
}