WIP: HTTP-01 solver that stores challenge tokens in FrostFS #4

Draft
potyarkin wants to merge 9 commits from potyarkin/lego:feature/http-01-frostfs-solver into tcl/http-01-frostfs-solver
2 changed files with 29 additions and 31 deletions
Showing only changes of commit 254983fbe2 - Show all commits

View file

@ -8,19 +8,18 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
status "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" status "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
containerid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" containerid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
objectid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" objectid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
) )
// Barebones API client for a single FrostFS container // Storage provides barebones API client for a single FrostFS container.
type Storage struct { type Storage struct {
endpoint string endpoint string
container containerid.ID container containerid.ID
@ -30,7 +29,7 @@ type Storage struct {
const storageRequestTimeout = 10 * time.Second const storageRequestTimeout = 10 * time.Second
// Create FrostFS client for working with a single storage container // Open FrostFS client for working with a single storage container.
func Open(endpoint, containerID string, key *ecdsa.PrivateKey) (*Storage, error) { func Open(endpoint, containerID string, key *ecdsa.PrivateKey) (*Storage, error) {
var container containerid.ID var container containerid.ID
err := container.DecodeString(containerID) err := container.DecodeString(containerID)
@ -95,10 +94,10 @@ func (s *Storage) Save(ctx context.Context, data []byte, attr ...string) (oid st
return "", fmt.Errorf("saving object to storage: %w", stat.(error)) return "", fmt.Errorf("saving object to storage: %w", stat.(error))
} }
id, _ := obj.ID() id, _ := obj.ID()
return fmt.Sprint(id), nil return id.String(), nil
} }
// Delete object from container // Delete object from container.
func (s *Storage) Delete(ctx context.Context, oid string) error { func (s *Storage) Delete(ctx context.Context, oid string) error {
var obj objectid.ID var obj objectid.ID
err := obj.DecodeString(oid) err := obj.DecodeString(oid)
@ -126,13 +125,13 @@ func (s *Storage) Delete(ctx context.Context, oid string) error {
return nil return nil
} }
// Open new connection to FrostFS storage node // Open new connection to FrostFS storage node.
func (s *Storage) dial(ctx context.Context) (*client.Client, error) { func (s *Storage) dial(ctx context.Context) (*client.Client, error) {
var wallet client.PrmInit var w client.PrmInit
wallet.Key = *s.key w.Key = *s.key
var c client.Client var c client.Client
c.Init(wallet) c.Init(w)
var endpoint client.PrmDial var endpoint client.PrmDial
endpoint.Endpoint = s.endpoint endpoint.Endpoint = s.endpoint
@ -144,7 +143,7 @@ func (s *Storage) dial(ctx context.Context) (*client.Client, error) {
return &c, nil return &c, nil
} }
// Compose object attributes slice // Compose object attributes slice.
func keyval2attrs(attr ...string) ([]object.Attribute, error) { func keyval2attrs(attr ...string) ([]object.Attribute, error) {
if len(attr)%2 != 0 { if len(attr)%2 != 0 {
return nil, fmt.Errorf("odd number of key-value strings: %d (must be even)", len(attr)) return nil, fmt.Errorf("odd number of key-value strings: %d (must be even)", len(attr))
@ -163,9 +162,8 @@ func keyval2attrs(attr ...string) ([]object.Attribute, error) {
return attributes, nil return attributes, nil
} }
// Load private key from wallet file // Load private key from wallet file.
func getKey(walletPath, walletAccount, walletPassword string) (*ecdsa.PrivateKey, error) { func getKey(walletPath, walletAccount, walletPassword string) (*ecdsa.PrivateKey, error) {
var err error
if walletPath == "" { if walletPath == "" {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // TODO: using ephemeral keys for now, later read from env vars key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // TODO: using ephemeral keys for now, later read from env vars
if err != nil { if err != nil {
@ -183,7 +181,7 @@ func getKey(walletPath, walletAccount, walletPassword string) (*ecdsa.PrivateKey
} }
account := w.Accounts[0] account := w.Accounts[0]
if walletAccount != "" { if walletAccount != "" {
decode, err := base58.CheckDecode(walletAccount) decode, err := base58.CheckDecode(walletAccount) //nolint:govet // err shadow declaration
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid account address: %w", err) return nil, fmt.Errorf("invalid account address: %w", err)
} }

View file

@ -3,8 +3,6 @@ package frostfs
// Tests for our FrostFS client code // Tests for our FrostFS client code
import ( import (
"testing"
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
@ -12,14 +10,16 @@ import (
"fmt" "fmt"
"os" "os"
"sync" "sync"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
) )
// Initialize storage backend for tests // Initialize storage backend for tests.
func openStorage(t *testing.T) *Storage { func openStorage(t *testing.T) *Storage {
cid := os.Getenv("FROSTFS_CID") // example: 348WWfBKbS79Wbmm38MRE3oBoEDM5Ga1XXbGKGNyisDM t.Helper()
endpoint := os.Getenv("FROSTFS_ENDPOINT") // example: grpc://localhost:8802 cid := os.Getenv("FROSTFS_CID") // sample: "348WWfBKbS79Wbmm38MRE3oBoEDM5Ga1XXbGKGNyisDM"
endpoint := os.Getenv("FROSTFS_ENDPOINT") // sample: "grpc://localhost:8802"
if cid == "" || endpoint == "" { if cid == "" || endpoint == "" {
t.Skipf("one or more environment variables not set: FROSTFS_ENDPOINT, FROSTFS_CID") t.Skipf("one or more environment variables not set: FROSTFS_ENDPOINT, FROSTFS_CID")
} }
@ -34,9 +34,9 @@ func openStorage(t *testing.T) *Storage {
return storage return storage
} }
// Save some bytes to FrostFS and clean up after // Save some bytes to FrostFS and clean up after.
func TestObjectPutDelete(t *testing.T) { func TestObjectPutDelete(t *testing.T) {
var payload = []byte("Hello FrostFS!\n") payload := []byte("Hello FrostFS!\n")
storage := openStorage(t) storage := openStorage(t)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel) t.Cleanup(cancel)
@ -52,9 +52,9 @@ func TestObjectPutDelete(t *testing.T) {
t.Logf("deleted object: %s", oid) t.Logf("deleted object: %s", oid)
} }
// Check that FrostFS is in fact a content addressable storage // Check that FrostFS is in fact a content addressable storage.
func TestMulipleObjects(t *testing.T) { func TestMulipleObjects(t *testing.T) {
var payload = []byte("Multiple objects with same content should get the same object ID") payload := []byte("Multiple objects with same content should get the same object ID")
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel) t.Cleanup(cancel)
@ -76,7 +76,7 @@ func TestMulipleObjects(t *testing.T) {
continue continue
} }
if obj != baseline { if obj != baseline {
t.Fatalf("non-identical object id: %s != %s", baseline, obj) panic(fmt.Errorf("non-identical object id: %s != %s", baseline, obj))
} }
} }
} }
@ -84,17 +84,17 @@ func TestMulipleObjects(t *testing.T) {
const testCount = 5 const testCount = 5
storage := openStorage(t) storage := openStorage(t)
for i := 0; i < testCount; i++ { for i := 0; i < testCount; i++ { //nolint:intrange
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
oid, err := storage.Save(ctx, payload, "FileName", "CAS.txt", "Tag", "test") oid, err := storage.Save(ctx, payload, "FileName", "CAS.txt", "Tag", "test")
if err != nil { if err != nil {
t.Fatal(err) panic(err)
} }
err = storage.Delete(ctx, oid) err = storage.Delete(ctx, oid)
if err != nil { if err != nil {
t.Fatal(err) panic(err)
} }
t.Log(oid) t.Log(oid)
}() }()
@ -102,7 +102,7 @@ func TestMulipleObjects(t *testing.T) {
wg.Wait() wg.Wait()
} }
// Check opening wallet from file system // Check opening wallet from file system.
func TestLoadWallet(t *testing.T) { func TestLoadWallet(t *testing.T) {
const ( const (
walletPath = "client_test_wallet.json" walletPath = "client_test_wallet.json"
@ -127,5 +127,5 @@ func TestLoadWallet(t *testing.T) {
func key2addr(k *ecdsa.PrivateKey) string { func key2addr(k *ecdsa.PrivateKey) string {
var owner user.ID var owner user.ID
user.IDFromKey(&owner, k.PublicKey) user.IDFromKey(&owner, k.PublicKey)
return fmt.Sprint(owner) return owner.String()
} }