2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
package couchdb
|
2017-06-17 15:22:10 +00:00
|
|
|
|
|
|
|
import (
|
2020-09-15 14:01:26 +00:00
|
|
|
"context"
|
2017-06-17 15:22:10 +00:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2020-09-15 14:01:26 +00:00
|
|
|
"net/url"
|
2017-06-17 15:22:10 +00:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2018-04-03 00:46:59 +00:00
|
|
|
log "github.com/hashicorp/go-hclog"
|
2023-04-24 18:25:50 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/docker"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
|
|
|
"github.com/hashicorp/vault/sdk/physical"
|
2017-06-17 15:22:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestCouchDBBackend(t *testing.T) {
|
2020-09-15 14:01:26 +00:00
|
|
|
cleanup, config := prepareCouchdbDBTestContainer(t)
|
2017-06-17 15:22:10 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
2018-04-03 00:46:59 +00:00
|
|
|
logger := logging.NewVaultLogger(log.Debug)
|
2017-06-17 15:22:10 +00:00
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
b, err := NewCouchDBBackend(map[string]string{
|
2020-09-15 14:01:26 +00:00
|
|
|
"endpoint": config.URL().String(),
|
|
|
|
"username": config.username,
|
|
|
|
"password": config.password,
|
2017-08-03 17:24:27 +00:00
|
|
|
}, logger)
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
physical.ExerciseBackend(t, b)
|
|
|
|
physical.ExerciseBackend_ListPrefix(t, b)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTransactionalCouchDBBackend(t *testing.T) {
|
2020-09-15 14:01:26 +00:00
|
|
|
cleanup, config := prepareCouchdbDBTestContainer(t)
|
2017-06-17 15:22:10 +00:00
|
|
|
defer cleanup()
|
|
|
|
|
2018-04-03 00:46:59 +00:00
|
|
|
logger := logging.NewVaultLogger(log.Debug)
|
2017-06-17 15:22:10 +00:00
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
b, err := NewTransactionalCouchDBBackend(map[string]string{
|
2020-09-15 14:01:26 +00:00
|
|
|
"endpoint": config.URL().String(),
|
|
|
|
"username": config.username,
|
|
|
|
"password": config.password,
|
2017-08-03 17:24:27 +00:00
|
|
|
}, logger)
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2017-08-03 17:24:27 +00:00
|
|
|
physical.ExerciseBackend(t, b)
|
|
|
|
physical.ExerciseBackend_ListPrefix(t, b)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
type couchDB struct {
|
|
|
|
baseURL url.URL
|
|
|
|
dbname string
|
|
|
|
username string
|
|
|
|
password string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c couchDB) Address() string {
|
|
|
|
return c.baseURL.Host
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c couchDB) URL() *url.URL {
|
|
|
|
u := c.baseURL
|
|
|
|
u.Path = c.dbname
|
|
|
|
return &u
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ docker.ServiceConfig = &couchDB{}
|
|
|
|
|
|
|
|
func prepareCouchdbDBTestContainer(t *testing.T) (func(), *couchDB) {
|
2017-06-17 15:22:10 +00:00
|
|
|
// If environment variable is set, assume caller wants to target a real
|
|
|
|
// DynamoDB.
|
|
|
|
if os.Getenv("COUCHDB_ENDPOINT") != "" {
|
2020-09-15 14:01:26 +00:00
|
|
|
return func() {}, &couchDB{
|
|
|
|
baseURL: url.URL{Host: os.Getenv("COUCHDB_ENDPOINT")},
|
|
|
|
username: os.Getenv("COUCHDB_USERNAME"),
|
|
|
|
password: os.Getenv("COUCHDB_PASSWORD"),
|
|
|
|
}
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
runner, err := docker.NewServiceRunner(docker.RunOptions{
|
2022-11-02 17:33:17 +00:00
|
|
|
ContainerName: "couchdb",
|
|
|
|
ImageRepo: "docker.mirror.hashicorp.services/library/couchdb",
|
2020-09-15 14:01:26 +00:00
|
|
|
ImageTag: "1.6",
|
|
|
|
Ports: []string{"5984/tcp"},
|
|
|
|
DoNotAutoRemove: true,
|
|
|
|
})
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
t.Fatalf("Could not start local CouchDB: %s", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
svc, err := runner.StartService(context.Background(), setupCouchDB)
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
t.Fatalf("Could not start local CouchDB: %s", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
return svc.Cleanup, svc.Config.(*couchDB)
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupCouchDB(ctx context.Context, host string, port int) (docker.ServiceConfig, error) {
|
|
|
|
c := &couchDB{
|
|
|
|
baseURL: url.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", host, port)},
|
|
|
|
dbname: fmt.Sprintf("vault-test-%d", time.Now().Unix()),
|
|
|
|
username: "admin",
|
|
|
|
password: "admin",
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
{
|
|
|
|
resp, err := http.Get(c.baseURL.String())
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, err
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("expected couchdb to return status code 200, got (%s) instead", resp.Status)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-09-15 14:01:26 +00:00
|
|
|
req, err := http.NewRequest("PUT", c.URL().String(), nil)
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("could not create create database request: %q", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("could not create database: %q", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusCreated {
|
|
|
|
bs, _ := ioutil.ReadAll(resp.Body)
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("failed to create database: %s %s\n", resp.Status, string(bs))
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-15 14:01:26 +00:00
|
|
|
|
2017-06-17 15:22:10 +00:00
|
|
|
{
|
2020-09-15 14:01:26 +00:00
|
|
|
u := c.baseURL
|
|
|
|
u.Path = fmt.Sprintf("_config/admins/%s", c.username)
|
|
|
|
req, err := http.NewRequest("PUT", u.String(), strings.NewReader(fmt.Sprintf(`"%s"`, c.password)))
|
2017-06-17 15:22:10 +00:00
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("Could not create admin user request: %q", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
|
|
if err != nil {
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("Could not create admin user: %q", err)
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
bs, _ := ioutil.ReadAll(resp.Body)
|
2020-09-15 14:01:26 +00:00
|
|
|
return nil, fmt.Errorf("Failed to create admin user: %s %s\n", resp.Status, string(bs))
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 14:01:26 +00:00
|
|
|
return c, nil
|
2017-06-17 15:22:10 +00:00
|
|
|
}
|