Skip to content

Commit

Permalink
feat: namespace configuration (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
zepatrik authored Nov 26, 2020
1 parent 5a2fd1c commit b94f50d
Show file tree
Hide file tree
Showing 25 changed files with 675 additions and 51 deletions.
29 changes: 29 additions & 0 deletions .schema/namespace.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "The name of the namespace.",
"examples": [
"videos",
"groups",
"files"
]
},
"id": {
"type": "integer",
"title": "The unique ID of the namespace. Can not be changed once set.",
"minimum": 0
},
"config": {
"type": "object",
"title": "The configuration of the namespace.",
"description": "To be defined."
}
},
"required": [
"name",
"id"
]
}
79 changes: 79 additions & 0 deletions cmd/namespace/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package namespace

import (
"errors"
"fmt"

"github.com/ory/x/cmdx"
"github.com/ory/x/flagx"
"github.com/ory/x/logrusx"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/ory/keto/internal/driver"
"github.com/ory/keto/internal/persistence"
)

func NewMigrateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "migrate <namespaces.yml>",
Short: "Migrate a namespace up.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
d := driver.NewDefaultDriver(logrusx.New("keto", "master"), "master", "local", "today")

n, err := validateNamespaceFile(cmd, args[0])
if err != nil {
return err
}

status, err := d.Registry().NamespaceManager().NamespaceStatus(n)
if err != nil {
if !errors.Is(err, persistence.ErrNamespaceUnknown) {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not get status for namespace \"%s\": %+v\n", n.Name, err)
return cmdx.FailSilently(cmd)
}
} else {
if status.CurrentVersion == status.NextVersion {
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "The namespace is already migrated up to the most recent version, there is noting to do.")
return nil
}

cmdx.PrintRow(cmd, status)

if !flagx.MustGetBool(cmd, YesFlag) {
if !cmdx.AskForConfirmation("Are you sure that you want to apply this migration? Make sure to check the CHANGELOG and UPGRADE for breaking changes beforehand.", cmd.InOrStdin(), cmd.OutOrStdout()) {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Migration of namespace \"%s\" aborted.\n", n.Name)
return nil
}
}
}

if err := d.Registry().NamespaceManager().MigrateNamespaceUp(n); err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not apply namespace migration: %+v\n", err)
return cmdx.FailSilently(cmd)
}

status, err = d.Registry().NamespaceManager().NamespaceStatus(n)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not get status for namespace \"%s\": %+v\n", n.Name, err)
return cmdx.FailSilently(cmd)
}

cmdx.PrintRow(cmd, status)

return nil
},
}

registerYesFlag(cmd.Flags())
registerPackageFlags(cmd.Flags())

return cmd
}

const YesFlag = "yes"

func registerYesFlag(flags *pflag.FlagSet) {
flags.BoolP(YesFlag, YesFlag[:1], false, "answer all questions with yes")
}
27 changes: 27 additions & 0 deletions cmd/namespace/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package namespace

import (
"github.com/ory/x/cmdx"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/ory/keto/cmd/client"
)

func NewNamespaceCmd() *cobra.Command {
return &cobra.Command{
Use: "namespace",
}
}

func RegisterCommandsRecursive(parent *cobra.Command) {
rootCmd := NewNamespaceCmd()
rootCmd.AddCommand(NewMigrateCmd(), NewValidateCmd())

parent.AddCommand(rootCmd)
}

func registerPackageFlags(flags *pflag.FlagSet) {
client.RegisterRemoteURLFlag(flags)
cmdx.RegisterFormatFlags(flags)
}
88 changes: 88 additions & 0 deletions cmd/namespace/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package namespace

import (
"fmt"
"io/ioutil"

"github.com/markbates/pkger"
"github.com/ory/jsonschema/v3"
"github.com/ory/x/cmdx"
"github.com/ory/x/viperx"
"github.com/segmentio/objconv/yaml"
"github.com/spf13/cobra"

"github.com/ory/keto/internal/namespace"
)

const namespaceSchemaPath = "/.schema/namespace.schema.json"

func NewValidateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "validate <namespace.yml> [<namespace2.yml> ...]",
Args: cobra.MinimumNArgs(1),
Short: "Validate a namespace file.",
Long: "Validate a namespace file and get human readable errors.",
RunE: func(cmd *cobra.Command, args []string) error {
for _, fn := range args {
_, err := validateNamespaceFile(cmd, fn)
if err != nil {
return err
}
}

_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Congrats, all files are valid!")
return nil
},
}

return cmd
}

var namespaceSchema *jsonschema.Schema

func validateNamespaceFile(cmd *cobra.Command, fn string) (*namespace.Namespace, error) {
if namespaceSchema == nil {
sf, err := pkger.Open(namespaceSchemaPath)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not open the namespace schema file. This is an internal error that should be reported. Thanks ;)\n%+v\n", err)
return nil, cmdx.FailSilently(cmd)
}

c := jsonschema.NewCompiler()
if err := c.AddResource(namespaceSchemaPath, sf); err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not add the namespace schema file to the compiler. This is an internal error that should be reported. Thanks ;)\n%+v\n", err)
return nil, cmdx.FailSilently(cmd)
}

namespaceSchema, err = c.Compile(namespaceSchemaPath)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not compile the namespace schema file. This is an internal error that should be reported. Thanks ;)\n%+v\n", err)
return nil, cmdx.FailSilently(cmd)
}
}

fc, err := ioutil.ReadFile(fn)
if err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not read file \"%s\": %+v\n", fn, err)
return nil, cmdx.FailSilently(cmd)
}

var val map[string]interface{}
if err := yaml.Unmarshal(fc, &val); err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Encountered yaml unmarshal error for \"%s\": %+v\n", fn, err)
return nil, cmdx.FailSilently(cmd)
}

if err := namespaceSchema.ValidateInterface(val); err != nil {
viperx.PrintHumanReadableValidationErrors(cmd.ErrOrStderr(), err)
return nil, cmdx.FailSilently(cmd)
}

var n namespace.Namespace
if err := yaml.Unmarshal(fc, &n); err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Encountered yaml unmarshal error for \"%s\": %+v\n", fn, err)
return nil, cmdx.FailSilently(cmd)
}

return &n, nil
}
14 changes: 9 additions & 5 deletions cmd/relationtuple/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,29 @@ import (
)

const (
FlagSubject = "subject"
FlagRelation = "relation"
FlagObject = "object"
FlagSubject = "subject"
FlagRelation = "relation"
FlagObject = "object"
FlagNamespace = "namespace"
)

func registerRelationTupleFlags(flags *pflag.FlagSet) {
flags.String(FlagSubject, "", "Set the requested subject")
flags.String(FlagRelation, "", "Set the requested relation")
flags.String(FlagObject, "", "Set the requested object")
flags.String(FlagNamespace, "", "Set the requested namespace")
}

func readQueryFromFlags(cmd *cobra.Command) (*acl.ListRelationTuplesRequest_Query, error) {
subject := flagx.MustGetString(cmd, FlagSubject)
relation := flagx.MustGetString(cmd, FlagRelation)
object := flagx.MustGetString(cmd, FlagObject)
namespace := flagx.MustGetString(cmd, FlagNamespace)

query := &acl.ListRelationTuplesRequest_Query{
Relation: relation,
Object: object,
Relation: relation,
Object: object,
Namespace: namespace,
}

s, err := relationtuple.SubjectFromString(subject)
Expand Down
11 changes: 10 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@
package cmd

import (
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/ory/x/cmdx"

"github.com/ory/keto/cmd/namespace"

"github.com/ory/keto/cmd/relationtuple"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -49,7 +54,9 @@ var logger = new(logrusx.Logger)
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
if !errors.Is(err, cmdx.ErrNoPrintButFail) {
fmt.Println(err)
}
os.Exit(-1)
}
}
Expand All @@ -67,6 +74,8 @@ func init() {
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

relationtuple.RegisterCommandRecursive(RootCmd)

namespace.RegisterCommandsRecursive(RootCmd)
}

// initConfig reads in config file and ENV variables if set.
Expand Down
10 changes: 5 additions & 5 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ on configuration options, open the configuration documentation:
os.Exit(1)
}

reg := &driver.RegistryDefault{}
d := driver.NewDefaultDriver(logrusx.New("keto", "master"), "master", "local", "today")

wg := &sync.WaitGroup{}
wg.Add(2)
Expand All @@ -70,7 +70,7 @@ on configuration options, open the configuration documentation:
defer wg.Done()

s := grpc.NewServer()
relS := relationtuple.NewGRPCServer(reg)
relS := relationtuple.NewGRPCServer(d.Registry())
acl.RegisterReadServiceServer(s, relS)
fmt.Println("going to serve GRPC on", lis.Addr().String())
if err := s.Serve(lis); err != nil {
Expand All @@ -82,11 +82,11 @@ on configuration options, open the configuration documentation:
defer wg.Done()

router := httprouter.New()
rh := relationtuple.NewHandler(reg)
rh := relationtuple.NewHandler(d.Registry())
rh.RegisterPublicRoutes(router)
ch := check.NewHandler(reg)
ch := check.NewHandler(d.Registry())
ch.RegisterPublicRoutes(router)
eh := expand.NewHandler(reg)
eh := expand.NewHandler(d.Registry())
eh.RegisterPublicRoutes(router)

server := graceful.WithDefaults(&http.Server{
Expand Down
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,32 @@ require (
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
github.com/bufbuild/buf v0.31.1
github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect
github.com/ghodss/yaml v1.0.0
github.com/go-openapi/errors v0.19.4
github.com/go-openapi/runtime v0.19.5
github.com/go-openapi/strfmt v0.19.5
github.com/go-openapi/swag v0.19.5
github.com/go-openapi/validate v0.19.3
github.com/go-swagger/go-swagger v0.21.1-0.20200107003254-1c98855b472d
github.com/gobuffalo/packr v1.24.1
github.com/gobuffalo/packr v1.24.1 // indirect
github.com/golang/protobuf v1.4.3
github.com/gorilla/sessions v1.1.3
github.com/gorilla/websocket v1.4.2
github.com/julienschmidt/httprouter v1.2.0
github.com/markbates/pkger v0.17.0
github.com/ory/cli v0.0.11
github.com/ory/go-acc v0.2.3
github.com/ory/graceful v0.1.1
github.com/ory/herodot v0.9.1
github.com/ory/jsonschema/v3 v3.0.1
github.com/ory/viper v1.7.5
github.com/ory/x v0.0.154
github.com/pkg/errors v0.9.1
github.com/rs/cors v1.6.0
github.com/rubenv/sql-migrate v0.0.0-20190327083759-54bad0a9b051 // indirect
github.com/segmentio/objconv v1.0.1
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.6.0
github.com/spf13/cobra v1.0.1-0.20201006035406-b97b5ead31f7
github.com/spf13/pflag v1.0.5
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,7 @@ github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 h1:ZuhckGJ10ula
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc=
github.com/segmentio/conf v1.2.0/go.mod h1:Y3B9O/PqqWqjyxyWWseyj/quPEtMu1zDp/kVbSWWaB0=
github.com/segmentio/go-snakecase v1.1.0/go.mod h1:jk1miR5MS7Na32PZUykG89Arm+1BUSYhuGR6b7+hJto=
github.com/segmentio/objconv v1.0.1 h1:QjfLzwriJj40JibCV3MGSEiAoXixbp4ybhwfTB8RXOM=
github.com/segmentio/objconv v1.0.1/go.mod h1:auayaH5k3137Cl4SoXTgrzQcuQDmvuVtZgS0fb1Ahys=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
Expand Down
2 changes: 1 addition & 1 deletion go_mod_indirect_pins.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package main

import (
_ "github.com/go-swagger/go-swagger/cmd/swagger"
_ "github.com/gobuffalo/packr/packr"
_ "github.com/markbates/pkger"
_ "github.com/sqs/goreturns"
_ "golang.org/x/tools/cmd/cover"
_ "golang.org/x/tools/cmd/goimports"
Expand Down
Loading

0 comments on commit b94f50d

Please sign in to comment.