Skip to content

Commit

Permalink
wip: feat: support secrets for password
Browse files Browse the repository at this point in the history
Signed-off-by: Brooks Townsend <[email protected]>
  • Loading branch information
brooksmtownsend committed Jul 23, 2024
1 parent 8d6ccb9 commit ce023f4
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 157 deletions.
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,30 @@ wash build

## Run

Prerequisites:
### Prerequisites

- [wash 0.29](https://wasmcloud.com/docs/installation) or later
- A built couchbase capability provider, see [#build](#build)
- Setup Couchbase server with the required configuration for testing using docker-compose.yaml in the repo.
```
docker-compose up -d
```
Alternatively, you can use [Quick Install](https://docs.couchbase.com/server/current/getting-started/do-a-quick-install.html) guide with a bucket named **test** created.


```bash
docker-compose up -d
```

Alternatively, you can use [Quick Install](https://docs.couchbase.com/server/current/getting-started/do-a-quick-install.html) guide with a bucket named **test** created.

### Running

```shell
wash up -d
# TODO: provide encryption key setup
secret-nats-kv run &
# Put the password in the NATS KV secrets backend
provider_key=$(wash inspect ./build/wasmcloud-provider-couchbase.par.gz -o json | jq -r '.service')
secrets-nats-kv put password --string password
secrets-nats-kv add-mapping $provider_key --secret password
# Create the secret reference, instructing wasmCloud how to pull the secret
wash config put SECRET_couchbase_password backend=nats-kv key=password
wash app deploy ./wadm.yaml
```

Expand All @@ -42,7 +53,7 @@ curl localhost:8080/couchbase

## Test

To test the WIT bindings, download [`wit-bindgen`][wit-bindgen] and run the following:
To test the WIT bindings, download [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen) and run the following:

```console
wit-deps && wit-bindgen rust --out-dir /tmp/wit wit/
Expand Down
37 changes: 11 additions & 26 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
)

type CouchbaseConnectionArgs struct {
Username string
Password string
BucketName string
Host string
Username string
Password string
BucketName string
// Host string
ConnectionString string
ScopeName string
CollectionName string
Expand All @@ -20,39 +20,24 @@ type CouchbaseConnectionArgs struct {
func validateCouchbaseConfig(config map[string]string, secrets map[string]provider.SecretValue) (CouchbaseConnectionArgs, error) {
connectionArgs := CouchbaseConnectionArgs{}
if username, ok := config["username"]; !ok || username == "" {
return connectionArgs, errors.New("username is required")
return connectionArgs, errors.New("username config is required")
} else {
connectionArgs.Username = username
}
if bucketName, ok := config["bucket_name"]; !ok || bucketName == "" {
return connectionArgs, errors.New("bucket_name is required")
if bucketName, ok := config["bucketName"]; !ok || bucketName == "" {
return connectionArgs, errors.New("bucketName config is required")
} else {
connectionArgs.BucketName = bucketName
}
if host, ok := config["host"]; !ok || host == "" {
return connectionArgs, errors.New("host is required")
} else {
connectionArgs.Host = host
}
if connectionString, ok := config["connection_string"]; !ok || connectionString == "" {
return connectionArgs, errors.New("connection_string is required")
if connectionString, ok := config["connectionString"]; !ok || connectionString == "" {
return connectionArgs, errors.New("connectionString config is required")
} else {
connectionArgs.ConnectionString = connectionString
}
if scopeName, ok := config["scope_name"]; !ok || scopeName == "" {
return connectionArgs, errors.New("scope_name is required")
} else {
connectionArgs.ScopeName = scopeName
}
if collectionName, ok := config["collection_name"]; !ok || collectionName == "" {
return connectionArgs, errors.New("collection_name is required")
} else {
connectionArgs.CollectionName = collectionName
}

password := secrets["password"].StringValue()
password := secrets["password"].String.Reveal()
if password == "" {
return connectionArgs, errors.New("password is required")
return connectionArgs, errors.New("password secret is required")
} else {
connectionArgs.Password = password
}
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ require (

require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
Expand All @@ -31,12 +30,11 @@ require (
github.com/nats-io/nats.go v1.36.0 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0
go.opentelemetry.io/otel v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
Expand All @@ -47,3 +45,5 @@ require (
google.golang.org/grpc v1.64.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)

replace github.com/wasmCloud/provider-sdk-go => ../../wasmCloud/provider-sdk-go
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -87,14 +85,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/wasmCloud/provider-sdk-go v0.0.0-20240626135506-00b1fb3dec9e h1:UIK1VDU1hwvGTd4S9pokw/IoY0ChIhYldWB44JnWuD8=
github.com/wasmCloud/provider-sdk-go v0.0.0-20240626135506-00b1fb3dec9e/go.mod h1:DZRTpRkX3YluIs+FKcx157XbQa1q4rFRDpxbamZZBc0=
github.com/wrpc/wrpc/go v0.0.0-20240619071643-b830439e40d6 h1:P2X0Tsw8o45TmBZbST5vRguBjK80e7QJ9TX/fh/8l2U=
github.com/wrpc/wrpc/go v0.0.0-20240619071643-b830439e40d6/go.mod h1:xbr40Iv8kVVnQHnHzmdbtaxOvyRZLb7y3c90vrGGcxo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
Expand Down
125 changes: 28 additions & 97 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"os/signal"
Expand All @@ -14,14 +15,6 @@ import (
server "github.com/couchbase-examples/wasmcloud-provider-couchbase/bindings"
"github.com/couchbase/gocb/v2"
"github.com/wasmCloud/provider-sdk-go"
"go.opentelemetry.io/otel"

"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func main() {
Expand Down Expand Up @@ -72,6 +65,8 @@ func run() error {
// Store the provider for use in the handlers
providerHandler.WasmcloudProvider = p

fmt.Println("host data: %v", providerHandler.WasmcloudProvider.HostData())

// Setup two channels to await RPC and control interface operations
providerCh := make(chan error, 1)
signalCh := make(chan os.Signal, 1)
Expand Down Expand Up @@ -104,32 +99,43 @@ func run() error {
return nil
}

// Provider handler functions
func handleNewTargetLink(handler *Handler, link provider.InterfaceLinkDefinition) error {
handler.Logger.Info("Handling new target link", "link", link)
handler.linkedFrom[link.SourceID] = link.TargetConfig
err := ValidateCouchbaseConfig(link.TargetConfig)
couchbaseConnectionArgs, err := validateCouchbaseConfig(link.TargetConfig, link.TargetSecrets)
if err != nil {
handler.Logger.Error("Invalid couchbase target config", "error", err)
return err
}
handler.updateCouchbaseCluster(handler, link.SourceID, link.TargetConfig)
handler.updateCouchbaseCluster(handler, link.SourceID, couchbaseConnectionArgs)
return nil
}

func ValidateCouchbaseConfig(config map[string]string) error {
if config["username"] == "" {
return errors.New("username is required")
}
if config["password"] == "" {
return errors.New("password is required")
func (h *Handler) updateCouchbaseCluster(handler *Handler, sourceId string, connectionArgs CouchbaseConnectionArgs) {
// Connect to the cluster
cluster, err := gocb.Connect(connectionArgs.ConnectionString, gocb.ClusterOptions{
Username: connectionArgs.Username,
Password: connectionArgs.Password,
})
if err != nil {
handler.Logger.Error("unable to connect to couchbase cluster", "error", err)
return
}
if config["bucket"] == "" {
return errors.New("bucket is required")
var collection *gocb.Collection
if connectionArgs.CollectionName != "" && connectionArgs.ScopeName != "" {
collection = cluster.Bucket(connectionArgs.BucketName).Scope(connectionArgs.ScopeName).Collection(connectionArgs.CollectionName)
} else {
collection = cluster.Bucket(connectionArgs.BucketName).DefaultCollection()
}
if config["host"] == "" {
return errors.New("host is required")

bucket := cluster.Bucket(connectionArgs.BucketName)
if err = bucket.WaitUntilReady(5*time.Second, nil); err != nil {
handler.Logger.Error("unable to connect to couchbase bucket", "error", err)
}
return nil

// Store the connection
handler.clusterConnections[sourceId] = collection
}

func handleDelTargetLink(handler *Handler, link provider.InterfaceLinkDefinition) error {
Expand All @@ -139,7 +145,7 @@ func handleDelTargetLink(handler *Handler, link provider.InterfaceLinkDefinition
}

func handleHealthCheck(handler *Handler) string {
handler.Logger.Info("Handling health check")
handler.Logger.Debug("Handling health check")
return "provider healthy"
}

Expand All @@ -148,78 +154,3 @@ func handleShutdown(handler *Handler) error {
// clear(handler.linkedFrom)
return nil
}

func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) {
var shutdownFuncs []func(context.Context) error

// shutdown calls cleanup functions registered via shutdownFuncs.
// The errors from the calls are joined.
// Each registered cleanup will be invoked once.
shutdown = func(ctx context.Context) error {
var err error
for _, fn := range shutdownFuncs {
err = errors.Join(err, fn(ctx))
}
shutdownFuncs = nil
return err
}

// handleErr calls shutdown for cleanup and makes sure that all errors are returned.
handleErr := func(inErr error) {
err = errors.Join(inErr, shutdown(ctx))
}

// Set up propagator.
prop := newPropagator()
otel.SetTextMapPropagator(prop)

// Set up trace provider.
tracerProvider, err := newTraceProvider()
if err != nil {
handleErr(err)
return
}
shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown)
otel.SetTracerProvider(tracerProvider)
traceProvider := otel.GetTracerProvider()
tracer = traceProvider.Tracer(TRACER_NAME)

return
}

func newExporter(ctx context.Context) (*otlptrace.Exporter, error) {

exporter, err := otlptrace.New(
context.Background(),
otlptracehttp.NewClient(
otlptracehttp.WithEndpoint("localhost:4318"),

otlptracehttp.WithInsecure(),
),
)
return exporter, err
}

func newTraceProvider() (*trace.TracerProvider, error) {
traceExporter, err := newExporter(context.Background())
if err != nil {
return nil, err
}

traceProvider := trace.NewTracerProvider(
trace.WithBatcher(traceExporter,
// Default is 5s. Set to 1s for demonstrative purposes.
trace.WithBatchTimeout(time.Second)),
trace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("couchbase-provider"),
)))
return traceProvider, nil
}

func newPropagator() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
)
}
8 changes: 1 addition & 7 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ host_data='
"lattice_rpc_url": "0.0.0.0:4222",
"lattice_rpc_prefix": "default",
"provider_key": "couchbase",
"link_name": "default",
"config": {
"username": "Administrator",
"password": "password",
"bucketName": "test",
"connectionString": "localhost"
}
"link_name": "default"
}'
echo $host_data | base64 | go run ./
14 changes: 3 additions & 11 deletions wadm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ spec:
traits:
- type: spreadscaler
properties:
replicas: 1
replicas: 100
# Link the component to the provider on wasi-keyvalue
- type: link
properties:
Expand All @@ -23,30 +23,22 @@ spec:
package: keyvalue
interfaces: [atomics, store]
target_config:
- name: SECRET_couchbase_password
- name: provider-config
properties:
username: 'Administrator'
password: 'password'
bucketName: 'test'
connectionString: 'localhost'
scopeName: 'test'
- name: couchbase
type: capability
properties:
image: file://./build/wasmcloud-provider-couchbase.par.gz
id: couchbase
config:
- name: provider-config
properties:
username: 'Administrator'
password: 'password'
bucketName: 'test'
connectionString: 'localhost'
# Add a capability provider that enables HTTP access
- name: httpserver
type: capability
properties:
image: ghcr.io/wasmcloud/http-server:0.20.0
image: ghcr.io/wasmcloud/http-server:0.21.0
traits:
# Link the httpserver to the component, and configure the HTTP server
# to listen on port 8080 for incoming requests
Expand Down

0 comments on commit ce023f4

Please sign in to comment.