Skip to content

Commit

Permalink
feat(datastore): Added GCP Datastore backend
Browse files Browse the repository at this point in the history
* Cleaned up linting
* Added context to all store inteface methods
  • Loading branch information
micahhausler committed Dec 4, 2017
1 parent b289af6 commit 99aa936
Show file tree
Hide file tree
Showing 17 changed files with 399 additions and 88 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ _test
# Coverage
coverage.out

sa.json

# Build artifacts
helm-value-store

Expand Down
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ go:
- 1.9

before_install:
- go get -u golang.org/x/tools/cmd/cover
- make setup

script:
- make lint
- make test
- make test-cover
- make build
- make docker

Expand Down
15 changes: 6 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
REPO=helm-value-store
SHA = $(shell git rev-parse --short HEAD)
GO_PKGS=$$(go list ./... | grep -v vendor)

.PHONY: setup fmt test test-cover vendored clean
.PHONY: setup fmt test vendored clean

all: test build

setup:
go get golang.org/x/tools/cmd/cover
go get -u github.com/kardianos/govendor
go get -u github.com/golang/lint/golint

fmt:
go fmt $(GO_PKGS)
go fmt ./...

lint:
for pkg in $(GO_PKGS); do golint $$pkg; done
for pkg in $$(go list ./...); do golint $$pkg; done

build: fmt
go build

test: fmt
go test -race $(GO_PKGS)

test-cover: fmt
go test -cover $(GO_PKGS)
go vet ./...
go test -cover ./...
go test -race ./...

vendored:
# Check if any dependencies are missing
Expand Down
53 changes: 32 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# helm-value-store

[![Build Status](https://travis-ci.org/skuid/helm-value-store.svg?branch=master)](https://travis-ci.org/skuid/helm-value-store)
[![https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/skuid/helm-value-store/)

[![godoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/skuid/helm-value-store/)
[![Docker Repository on Quay](https://quay.io/repository/skuid/helm-value-store/status "Docker Repository on Quay")](https://quay.io/repository/skuid/helm-value-store)

A helm plugin for working with helm deployment values.

Expand All @@ -12,9 +12,8 @@ you might have slightly different values files that need to be stored somewhere.
This project is an attempt to manage working with multiple `values.yaml` files for
nearly identitcal deployments.

The only backing store is currently DynamoDB, but other backends such as etcd, consul,
or Vault could easily be implemented.

Currently supported backing stores are AWS DynamoDB and GCP Datastore, but other
backends such as etcd, consul, or Vault could easily be implemented.

## Example

Expand Down Expand Up @@ -101,14 +100,6 @@ echo 'export GOPATH=~/go' | tee -a ~/.profile
echo 'export PATH="$PATH:~/go/bin"' | tee -a ~/.profile
```

### AWS Prerequisite

You must have the ability to create, read, and write to a DynamoDB table.

Set the proper access key environment variables, or use the
`$HOME/.aws/{config/credentials}` and set the appropriate
`AWS_DEFAULT_PROFILE` environment variable.

### Install helm-value-store

```bash
Expand All @@ -123,14 +114,35 @@ mkdir -p "$HELM_HOME/plugins/value-store"
cat <<EOF > "$HELM_HOME/plugins/value-store/plugin.yaml"
name: "value-store"
version: "0.1.0"
usage: "Store values in DynamoDB"
usage: "Store values in a database"
ignoreFlags: false
useTunnel: true
command: "helm-value-store"
EOF
```

### Create DynamoDB table
### GCP Setup (backend: datastore)

1. Go to the [GCP dashboard](https://console.cloud.google.com) and create a new project
1. Go to the [credentials page](https://console.cloud.google.com/apis/credentials) and create a new Service Account
1. Give the service account a name, and add it to the role: Datastore > Cloud Datastore Owner
* Be sure to select the "JSON" Key type, and click "Create"
1. Set the following environment variables

```
export HELM_VALUE_STORE_BACKEND=datastore
export HELM_VALUE_STORE_SERVICE_ACCOUNT="/path/to/sa.json"
```

### AWS Prerequisite (backend: dynamodb)

You must have the ability to create, read, and write to a DynamoDB table.

Set the proper access key environment variables, or use the
`$HOME/.aws/{config/credentials}` and set the appropriate
`AWS_DEFAULT_PROFILE` environment variable.

### Create DynamoDB table (backend: dynamodb)

If this is your first time using helm-value-store, you will need to create a DynamoDB table for storing values:

Expand All @@ -141,11 +153,9 @@ helm-value-store load --setup --file <(echo "[]")
## Usage

```
$ helm-value-store
A helm plugin for working with Helm Release data
Usage:
helm-value-store [flags]
helm-value-store [command]
Available Commands:
Expand All @@ -162,12 +172,13 @@ Available Commands:
version print the version number
Flags:
--backend string The backend for the value store (default "dynamodb")
--dynamodb-table string Name of the dynamodb table (default "helm-charts")
-h, --help help for helm-value-store
--backend string The backend for the value store. Must be one of [dynamodb datastore] (default "dynamodb")
--dynamodb-table string Name of the dynamodb table (default "helm-charts")
-h, --help help for helm-value-store
--service-account string The Google Service Account JSON file (default "sa.json")
--timeout duration The timeout for a given command (default 30s)
Use "helm-value-store [command] --help" for more information about a command.
```

## License
Expand Down
8 changes: 6 additions & 2 deletions cmd/create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"errors"
"fmt"
"io/ioutil"
Expand All @@ -9,6 +10,7 @@ import (
"github.com/skuid/helm-value-store/store"
"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type createCmdArgs struct {
Expand Down Expand Up @@ -67,9 +69,11 @@ func create(cmd *cobra.Command, args []string) {
r.Values = string(values)
}
if len(createArgs.chart) == 0 {
exitOnErr(errors.New("No chart provided!"))
exitOnErr(errors.New("No chart provided"))
}
err := releaseStore.Put(r)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
err := releaseStore.Put(ctx, r)
exitOnErr(err)
fmt.Println("Created release in release store!")
}
8 changes: 6 additions & 2 deletions cmd/delete.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type deleteCmdArgs struct {
Expand Down Expand Up @@ -36,10 +38,12 @@ func init() {

func delete(cmd *cobra.Command, args []string) {
if len(deleteArgs.uuid) == 0 {
exitOnErr(errors.New("Must supply a UUID!"))
exitOnErr(errors.New("Must supply a UUID"))
}

err := releaseStore.Delete(deleteArgs.uuid)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
err := releaseStore.Delete(ctx, deleteArgs.uuid)
exitOnErr(err)

fmt.Printf("Deleted release %s in release store.\n", deleteArgs.uuid)
Expand Down
6 changes: 5 additions & 1 deletion cmd/dump.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"context"
"encoding/json"
"os"

"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type dumpCmdArgs struct {
Expand All @@ -32,7 +34,9 @@ func init() {
}

func dump(cmd *cobra.Command, args []string) {
releases, err := releaseStore.List(dumpArgs.label.ToMap())
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
releases, err := releaseStore.List(ctx, dumpArgs.label.ToMap())
exitOnErr(err)

encoder := json.NewEncoder(os.Stdout)
Expand Down
13 changes: 9 additions & 4 deletions cmd/get.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/skuid/helm-value-store/store"
"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type getCmdArgs struct {
Expand Down Expand Up @@ -42,24 +44,27 @@ func get(cmd *cobra.Command, args []string) {
var err error
releases := store.Releases{}

ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()

if len(getArgs.uuid) > 0 {
release, err := releaseStore.Get(getArgs.uuid)
release, err := releaseStore.Get(ctx, getArgs.uuid)
exitOnErr(err)
releases = append(releases, *release)

} else if len(getArgs.name) > 0 || len(getArgs.labels) > 0 {
releases, err = releaseStore.List(getArgs.labels.ToMap())
releases, err = releaseStore.List(ctx, getArgs.labels.ToMap())
exitOnErr(err)

hasReleases(releases, "No releases match those labels!")

if len(getArgs.name) > 0 {
releases = filterByName(releases, getArgs.name)
}
hasReleases(releases, "No releases match that name and those labels!")
hasReleases(releases, "No releases match that name and those labels")

} else {
exitOnErr(errors.New("Must supply a UUID, release name, or labels!"))
exitOnErr(errors.New("Must supply a UUID, release name, or labels"))
}

for i, release := range releases {
Expand Down
9 changes: 7 additions & 2 deletions cmd/install.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package cmd

import (
"context"
"fmt"
"strings"

"github.com/skuid/helm-value-store/store"
"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type installCmdArgs struct {
Expand Down Expand Up @@ -55,11 +57,14 @@ func install(cmd *cobra.Command, args []string) {
var err error
release := &store.Release{}

ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()

if len(installArgs.uuid) > 0 {
release, err = releaseStore.Get(installArgs.uuid)
release, err = releaseStore.Get(ctx, installArgs.uuid)
exitOnErr(err)
} else if len(installArgs.name) > 0 {
releases, err := releaseStore.List(installArgs.labels.ToMap())
releases, err := releaseStore.List(ctx, installArgs.labels.ToMap())
exitOnErr(err)

matches := releasesByName(installArgs.name, releases)
Expand Down
6 changes: 5 additions & 1 deletion cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"fmt"
"os"
"strings"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/skuid/helm-value-store/store"
"github.com/skuid/spec"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type listCmdArgs struct {
Expand Down Expand Up @@ -44,7 +46,9 @@ func filterByName(releases store.Releases, name string) store.Releases {
}

func list(cmd *cobra.Command, args []string) {
releases, err := releaseStore.List(listArgs.labels.ToMap())
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
releases, err := releaseStore.List(ctx, listArgs.labels.ToMap())
exitOnErr(err)

if len(listArgs.name) > 0 {
Expand Down
13 changes: 9 additions & 4 deletions cmd/load.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package cmd

import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/skuid/helm-value-store/store"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type loadCmdArgs struct {
Expand All @@ -25,7 +27,7 @@ var loadCmd = &cobra.Command{
func init() {
RootCmd.AddCommand(loadCmd)
f := loadCmd.Flags()
f.StringVar(&loadArgs.file, "file", "dynamoReleases.json", "Name of file to ingest")
f.StringVar(&loadArgs.file, "file", "", "Name of file to ingest")
f.BoolVar(&loadArgs.setup, "setup", false, "Setup the value store (may create resources).")

loadCmd.MarkFlagRequired("file")
Expand All @@ -46,11 +48,14 @@ func load(cmd *cobra.Command, args []string) {
err = json.NewDecoder(f).Decode(&releases)
exitOnErr(err)

ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
if loadArgs.setup {
releaseStore.Setup()
err = releaseStore.Setup(ctx)
exitOnErr(err)
}

err = releaseStore.Load(releases)
err = releaseStore.Load(ctx, releases)
exitOnErr(err)
fmt.Println("Loaded resources into dynamo!")
fmt.Printf("Loaded %d resources into %s\n", len(releases), viper.GetString("backend"))
}
Loading

0 comments on commit 99aa936

Please sign in to comment.