From 7be5a49faa0567790cbd52ff9f5020f8908e9a5e Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Fri, 2 Apr 2021 13:36:36 +0200 Subject: [PATCH 1/7] config store wip --- cmd/config_store-client/main.go | 86 +++ cmd/config_store/internal/server/server.go | 134 +++++ cmd/config_store/internal/storage/sqlite.go | 210 +++++++ cmd/config_store/internal/storage/storage.go | 11 + cmd/config_store/main.go | 38 ++ config_store/client.go | 156 +++++ config_store/config.go | 276 +++++++++ config_store/config.pb.go | 565 +++++++++++++++++++ config_store/config_grpc.pb.go | 196 +++++++ signal18/config_store/v1/config.proto | 56 ++ signal18/config_store/v1/notes.md | 18 + 11 files changed, 1746 insertions(+) create mode 100644 cmd/config_store-client/main.go create mode 100644 cmd/config_store/internal/server/server.go create mode 100644 cmd/config_store/internal/storage/sqlite.go create mode 100644 cmd/config_store/internal/storage/storage.go create mode 100644 cmd/config_store/main.go create mode 100644 config_store/client.go create mode 100644 config_store/config.go create mode 100644 config_store/config.pb.go create mode 100644 config_store/config_grpc.pb.go create mode 100644 signal18/config_store/v1/config.proto create mode 100644 signal18/config_store/v1/notes.md diff --git a/cmd/config_store-client/main.go b/cmd/config_store-client/main.go new file mode 100644 index 000000000..1884319b7 --- /dev/null +++ b/cmd/config_store-client/main.go @@ -0,0 +1,86 @@ +package main + +import ( + "context" + "log" + + cs "github.com/signal18/replication-manager/config_store" +) + +func main() { + // connect to the locally available config_store server + + csc := cs.NewConfigStore("127.0.0.1:7777", cs.Environment_NONE) + + err := csc.ImportTOML("/etc/replication-manager/") + if err != nil { + log.Fatalf("Could not import TOML config: %s", err) + } + + props := make([]*cs.Property, 0) + props = append(props, csc.NewStringProperty([]string{"foo", "baz"}, "client-test", "foo", "foo-2")) + props = append(props, csc.NewStringProperty([]string{}, "client-test", "bar", "bar")) + + // for checking the error on the server + // props = append(props, &cs.Property{ + // Value: "foo-2", + // Store: "client-test", + // }) + + ctx := context.Background() + responses, err := csc.Store(ctx, props) + if err != nil { + log.Fatalf("Error storing: %s", err) + } + + for _, r := range responses { + log.Printf("Store response data: %v", r) + } + + // list the available properties + available, err := csc.Search(ctx, &cs.Query{}) + if err != nil { + log.Printf("Error retrieving data: %s", err) + } + for _, r := range available { + log.Printf("List response data: %v", r) + } + + specificKey, err := csc.Search(ctx, &cs.Query{ + Property: &cs.Property{ + Key: "foo", + Namespace: "client-test", + }, + }) + if err != nil { + log.Printf("Error retrieving data: %s", err) + } + for _, r := range specificKey { + log.Printf("List specificKey data: %v", r) + } + + specificNamespace, err := csc.Search(ctx, &cs.Query{ + Property: &cs.Property{ + Namespace: "client-test", + }, + }) + if err != nil { + log.Printf("Error retrieving data: %s", err) + } + for _, r := range specificNamespace { + log.Printf("List specificNamespace data: %v", r) + } + + specificUnavailableNamespace, err := csc.Search(ctx, &cs.Query{ + Property: &cs.Property{ + Namespace: "foo", + }, + }) + if err != nil { + log.Printf("Error retrieving data: %s", err) + } + for _, r := range specificUnavailableNamespace { + log.Printf("List foo data: %v", r) + } + +} diff --git a/cmd/config_store/internal/server/server.go b/cmd/config_store/internal/server/server.go new file mode 100644 index 000000000..59ede0a7b --- /dev/null +++ b/cmd/config_store/internal/server/server.go @@ -0,0 +1,134 @@ +package server + +import ( + "fmt" + "io" + "log" + "net" + + "github.com/signal18/replication-manager/cmd/config_store/internal/storage" + cs "github.com/signal18/replication-manager/config_store" + "google.golang.org/grpc" +) + +type Server struct { + cs.ConfigStoreServer + + st storage.ConfigStorage + + grpcServer *grpc.Server + conf Config + Up chan bool +} + +type Config struct { + ListenAddressForgRPC string +} + +func NewServer(conf Config, storage storage.ConfigStorage) *Server { + s := Server{ + conf: conf, + st: storage, + } + + s.Up = make(chan bool) + return &s +} + +func (s *Server) StartGRPCServer() error { + lis, err := net.Listen("tcp", s.conf.ListenAddressForgRPC) + if err != nil { + return err + } + + // create a gRPC server object + s.grpcServer = grpc.NewServer() + + cs.RegisterConfigStoreServer(s.grpcServer, s) + + s.Up <- true + log.Printf("starting HTTP/2 gRPC server, listening on: %s", lis.Addr().String()) + if err := s.grpcServer.Serve(lis); err != nil { + return err + } + + return nil +} + +func (s *Server) Store(stream cs.ConfigStore_StoreServer) error { + for { + in, err := stream.Recv() + if err == io.EOF { + return nil + } + + if in == nil { + return fmt.Errorf("empty object sent") + } + + log.Printf("Received property: %v", in) + + err = in.Validate() + if err != nil { + log.Printf("Error on validation: %s", err) + return err + } + + // check if the Store is set, if not set to default + if in.Namespace == "" { + in.Namespace = "default" + } + + find, err := s.st.Search(&cs.Query{ + Property: in, + Limit: 1, + IgnoreValue: true, + }) + + if err != nil && err != storage.ErrNoRowsFound { + log.Printf("Error on searching for existing property: %s", err) + return err + } + + if len(find) == 1 { + found := find[0] + if found.Key == in.Key && found.Namespace == in.Namespace && found.Environment == in.Environment { + + if found.DatabaseValue() == in.DatabaseValue() { + log.Printf("Property did not change: %v", in) + stream.Send(found) + continue + } + log.Printf("Updating existing property: %v with %v", found, in) + found.Values = in.Values + found.Revision++ + in = found + } + } + + out, err := s.st.Store(in) + if err != nil { + log.Printf("Error on storing: %s", err) + return err + } + + stream.Send(out) + } +} + +func (s *Server) Search(query *cs.Query, stream cs.ConfigStore_SearchServer) error { + properties, err := s.st.Search(query) + if err != nil { + return err + } + + for _, p := range properties { + err := stream.Send(p) + if err != nil { + log.Printf("Error sending: %s", err) + return err + } + } + + return nil +} diff --git a/cmd/config_store/internal/storage/sqlite.go b/cmd/config_store/internal/storage/sqlite.go new file mode 100644 index 000000000..2c5568df3 --- /dev/null +++ b/cmd/config_store/internal/storage/sqlite.go @@ -0,0 +1,210 @@ +package storage + +import ( + "errors" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" + cs "github.com/signal18/replication-manager/config_store" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type SQLiteStorage struct { + path string + db *sqlx.DB +} + +func NewSQLiteStorage(path string) (*SQLiteStorage, error) { + st := &SQLiteStorage{ + path: path, + } + + if err := st.open(); err != nil { + return nil, err + } + + return st, nil +} + +func (st *SQLiteStorage) Close() error { + return st.db.Close() +} + +func (st *SQLiteStorage) open() error { + var err error + + create := false + if _, err := os.Stat(st.path); os.IsNotExist(err) { + create = true + } + + st.db, err = sqlx.Open("sqlite3", st.path) + if err != nil { + return err + } + + if create { + if err := st.db.Ping(); err != nil { + return err + } + + if err := st.create(); err != nil { + return err + } + } + + return st.db.Ping() +} + +func (st *SQLiteStorage) create() error { + schema := `CREATE TABLE properties ( + key text, + value text null, + section text null, + namespace text default "default", + environment int default 0, + revision int default 0, + version string null, + created TEXT default CURRENT_TIMESTAMP, + deleted TEXT null + );` + + result, err := st.db.Exec(schema) + if err != nil { + return err + } + + log.Printf("Create result: %v", result) + return nil +} + +var ( + storeProperty = "INSERT INTO properties (" + + "key, value, section, namespace, " + + "environment, revision, version, " + + "created" + + ") VALUES (" + + "?, ?, ?, ?, " + + "?, ?, ?, " + + "?" + + ")" +) + +func (st *SQLiteStorage) Store(property *cs.Property) (*cs.Property, error) { + log.Printf("Query: \n%s", storeProperty) + + property.Created = timestamppb.Now() + + _, err := st.db.Exec(storeProperty, + property.Key, + property.DatabaseValue(), + strings.Join(property.Section, cs.RecordSeperator), + property.Namespace, + property.Environment, + property.Revision, + property.Version, + property.Created.AsTime().Format(time.RFC3339Nano), + ) + + if err != nil { + return nil, err + } + + return property, nil +} + +var ( + ErrNoRowsFound = errors.New("no results") +) + +func (st *SQLiteStorage) Search(query *cs.Query) (results []*cs.Property, err error) { + results = make([]*cs.Property, 0) + + sql, values := st.getSQLQuery(query) + log.Printf("SQL Query: %s\nQuery: %v", sql, query) + rows, err := st.db.Queryx(sql, values...) + if err != nil { + return + } + + if rows == nil { + return results, ErrNoRowsFound + } + + for rows.Next() { + buf := make(map[string]interface{}) + err = rows.MapScan(buf) + if err != nil { + return + } + + p := &cs.Property{} + err = p.Scan(buf) + if err != nil { + return + } + + results = append(results, p) + } + + return +} + +func (st *SQLiteStorage) getSQLQuery(q *cs.Query) (query string, values []interface{}) { + basequery := "SELECT * FROM properties" + + if q.Property == nil { + query = basequery + return + } + + basequery += " WHERE " + queries := make([]string, 0) + + if q.Property.Key != "" { + queries = append(queries, "key = ?") + values = append(values, q.Property.Key) + } + + if !q.IgnoreValue { + if q.Property.DatabaseValue() != "" { + queries = append(queries, "value = ?") + values = append(values, q.Property.DatabaseValue()) + } + } + + if q.Property.Namespace != "" { + queries = append(queries, "namespace = ?") + values = append(values, q.Property.Namespace) + } + + if q.Property.Environment != 0 { + queries = append(queries, "environment = ?") + values = append(values, q.Property.Environment) + } + + if q.Property.Revision != 0 { + queries = append(queries, "revision = ?") + values = append(values, q.Property.Revision) + } + + if q.Property.Version != "" { + queries = append(queries, "version = ?") + values = append(values, q.Property.Version) + } + + query = basequery + strings.Join(queries, " AND ") + + query += " ORDER BY revision DESC" + + if q.Limit != 0 { + query += fmt.Sprintf(" LIMIT %d", q.Limit) + } + + return query, values +} diff --git a/cmd/config_store/internal/storage/storage.go b/cmd/config_store/internal/storage/storage.go new file mode 100644 index 000000000..2518fee33 --- /dev/null +++ b/cmd/config_store/internal/storage/storage.go @@ -0,0 +1,11 @@ +package storage + +import ( + cs "github.com/signal18/replication-manager/config_store" +) + +type ConfigStorage interface { + Close() error + Store(property *cs.Property) (*cs.Property, error) + Search(query *cs.Query) ([]*cs.Property, error) +} diff --git a/cmd/config_store/main.go b/cmd/config_store/main.go new file mode 100644 index 000000000..a9fe93412 --- /dev/null +++ b/cmd/config_store/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "log" + + "github.com/signal18/replication-manager/cmd/config_store/internal/server" + "github.com/signal18/replication-manager/cmd/config_store/internal/storage" +) + +func main() { + sconf := server.Config{ + ListenAddressForgRPC: "127.0.0.1:7777", + } + + st, err := storage.NewSQLiteStorage("/tmp/test.sqlite") + if err != nil { + log.Fatalf("Error creating SQLite Storage: %s", err) + } + defer st.Close() + + s := server.NewServer(sconf, st) + + go func(s *server.Server) { + err := s.StartGRPCServer() + if err != nil { + log.Fatalf("Failed to start gRPC server: %s", err) + } + }(s) + + // the gRPC server is up and running + if <-s.Up { + log.Println("We are up and running") + + // enter an infinite loop as else the program would exit since our only + // blocking call is inside a Go routine + select {} + } +} diff --git a/config_store/client.go b/config_store/client.go new file mode 100644 index 000000000..ddf09e7ef --- /dev/null +++ b/config_store/client.go @@ -0,0 +1,156 @@ +package config_store + +import ( + context "context" + "io" + "log" + "strings" + "time" + + "github.com/spf13/viper" + grpc "google.golang.org/grpc" +) + +type ConfigStore struct { + conn *grpc.ClientConn + env Environment +} + +func NewConfigStore(address string, env Environment) *ConfigStore { + csc := &ConfigStore{ + env: env, + } + + ctx := context.Background() + var opts []grpc.DialOption + opts = append(opts, grpc.WithInsecure()) + + var err error + csc.conn, err = grpc.DialContext(ctx, + address, + opts..., + ) + if err != nil { + log.Fatalf("Failed to dial: %v", err) + } + + return csc +} + +func (csc *ConfigStore) NewStringProperty(section []string, namespace string, key string, value string) *Property { + return NewStringProperty(section, namespace, csc.env, key, value) +} + +func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*Property, error) { + client := NewConfigStoreClient(csc.conn) + clientDeadline := time.Now().Add(time.Duration(30) * time.Second) + ctx, _ = context.WithDeadline(ctx, clientDeadline) + storeClient, err := client.Store(ctx) + if err != nil { + log.Printf("Cannot connect error: %v", err) + return nil, err + } + + var responses []*Property + + for _, p := range properties { + if err := storeClient.Send(p); err != nil { + log.Printf("Error sending: %v", err) + return nil, err + } + resp, err := storeClient.Recv() + if err != nil { + log.Printf("Error returned: %v", err) + return nil, err + } + responses = append(responses, resp) + } + + err = storeClient.CloseSend() + if err != nil { + log.Fatalf("Error returned: %v", err) + return nil, err + } + + return responses, nil +} + +func (csc *ConfigStore) Search(ctx context.Context, query *Query) ([]*Property, error) { + client := NewConfigStoreClient(csc.conn) + listClient, err := client.Search(ctx, query) + if err != nil { + return nil, err + } + + var responses []*Property + + for { + in, err := listClient.Recv() + if err == io.EOF { + break + } + + if err != nil { + log.Printf("Could not list: %s", err) + return nil, err + } + + responses = append(responses, in) + } + + return responses, nil +} + +func (csc *ConfigStore) ImportTOML(path string) error { + v := viper.New() + v.SetConfigName("config") + v.SetConfigType("toml") + v.AddConfigPath(path) + err := v.ReadInConfig() + if err != nil { + log.Fatalf("Could not read config: %s", err) + return err + } + + var props []*Property + + keys := v.AllKeys() + for _, rawkey := range keys { + log.Printf("key: %s", rawkey) + + var key string + var section []string + buf := strings.Split(rawkey, ".") + if len(buf) == 2 { + key = buf[len(buf)-1] + section = buf[:len(buf)-1] + } + + value := v.Get(rawkey) + + p := &Property{ + Key: key, + Section: section, + } + + p.SetValue(value) + + log.Printf("p: %v", p) + props = append(props, p) + } + + log.Printf("found %d props", len(props)) + + // push da tempo + ctx := context.Background() + stored, err := csc.Store(ctx, props) + + log.Printf("stored %d props", len(props)) + for _, p := range stored { + log.Printf("stored: %v", p) + } + + // TODO: we need to process the included files too + + return nil +} diff --git a/config_store/config.go b/config_store/config.go new file mode 100644 index 000000000..566845583 --- /dev/null +++ b/config_store/config.go @@ -0,0 +1,276 @@ +package config_store + +import ( + "errors" + "fmt" + "log" + "strconv" + "strings" + "time" + + timestamppb "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + ErrPropertyKeyMissing = errors.New("property key is not set") +) + +const ( + RecordSeperator = "\u241E" +) + +func NewProperty(section []string, namespace string, env Environment, key string, values []*Value) *Property { + p := &Property{ + Key: key, + Values: values, + Section: section, + Namespace: namespace, + Environment: env, + } + return p +} + +func NewStringProperty(section []string, namespace string, env Environment, key string, value string) *Property { + v := &Value{ + Type: Type_STRING, + ValueString: value, + } + + values := make([]*Value, 0) + values = append(values, v) + return NewProperty(section, namespace, env, key, values) +} + +func (p *Property) Validate() error { + if p.Key == "" { + return ErrPropertyKeyMissing + } + + return nil +} + +func (p *Property) SetStringValue(v string) { + p.Values = make([]*Value, 0) + p.Values = append(p.Values, &Value{ + ValueString: v, + }) +} + +func (p *Property) SetValue(value interface{}) { + p.Values = make([]*Value, 0) + if v, ok := value.(string); ok { + p.Values = append(p.Values, &Value{ + Type: Type_STRING, + ValueString: v, + }) + return + } + + if v, ok := value.(int); ok { + p.Values = append(p.Values, &Value{ + Type: Type_INT, + ValueInt: int64(v), + }) + + return + } + + if v, ok := value.(int64); ok { + p.Values = append(p.Values, &Value{ + Type: Type_INT, + ValueInt: v, + }) + + return + } + + if v, ok := value.(float32); ok { + p.Values = append(p.Values, &Value{ + Type: Type_FLOAT, + ValueFloat: v, + }) + + return + } + + if v, ok := value.(bool); ok { + p.Values = append(p.Values, &Value{ + Type: Type_BOOL, + ValueBool: v, + }) + + return + } +} + +// DatabaseValue returns a string representation of the possible repeated Value +// property as a string. +// SQLite stores data natively as TEXT anyway +func (p *Property) DatabaseValue() string { + buf := make([]string, 0) + for _, v := range p.Values { + buf = append(buf, v.DatabaseValue()) + } + + return strings.Join(buf, RecordSeperator) +} + +// DatabaseValue returns a string representation where the first digit signifies +// the type for the Value. +func (v *Value) DatabaseValue() string { + var s strings.Builder + s.WriteString(strconv.FormatInt(int64(v.Type), 10)) + s.WriteString(v.GetStringValue()) + return s.String() +} + +func ValueFromDatabaseValue(db string) *Value { + t := db[0:1] + v := db[1:] + log.Printf("t: %v, v: %v", t, v) + + var value *Value + + if n, err := strconv.Atoi(t); err == nil { + value = &Value{ + Type: Type(n), + } + + switch value.Type { + case Type_STRING: + value.ValueString = v + case Type_INT: + if iv, err := strconv.Atoi(v); err == nil { + value.ValueInt = int64(iv) + } else { + panic("stored value is not an integer") + } + case Type_FLOAT: + if f, err := strconv.ParseFloat(v, 32); err == nil { + value.ValueFloat = float32(f) + } else { + panic("stored value is not a float") + } + case Type_BOOL: + if v == "true" { + value.ValueBool = true + } else { + value.ValueBool = false + } + } + + } else { + panic("first character of value is not an integer") + } + + return value +} + +func (v *Value) GetStringValue() string { + switch v.Type { + case Type_STRING: + return v.ValueString + case Type_INT: + return strconv.FormatInt(v.ValueInt, 10) + case Type_FLOAT: + return fmt.Sprintf("%f", v.ValueFloat) + case Type_BOOL: + if v.ValueBool { + return "true" + } else { + return "false" + } + } + + return "" +} + +func (v *Value) GetValue() interface{} { + switch v.Type { + case Type_STRING: + return v.ValueString + case Type_INT: + return v.ValueInt + case Type_FLOAT: + return v.ValueFloat + case Type_BOOL: + return v.ValueBool + } + + return nil +} + +func (p *Property) Scan(results map[string]interface{}) error { + if buf, ok := results["key"]; ok { + if buf != nil { + p.Key = buf.(string) + } + } + + if buf, ok := results["value"]; ok { + if buf != nil { + values := make([]*Value, 0) + vs := strings.Split(buf.(string), RecordSeperator) + for _, v := range vs { + values = append(values, ValueFromDatabaseValue(v)) + } + + p.Values = values + } + } + + if buf, ok := results["namespace"]; ok { + if buf != nil { + p.Namespace = buf.(string) + } + } + + if buf, ok := results["section"]; ok { + if buf != nil { + s := buf.(string) + if s != "" { + p.Section = strings.Split(s, "|") + } + } + } + + if buf, ok := results["environment"]; ok { + if buf != nil { + p.Environment = Environment(buf.(int64)) + } + } + + if buf, ok := results["revision"]; ok { + if buf != nil { + p.Revision = buf.(int64) + } + } + + if buf, ok := results["version"]; ok { + if buf != nil { + p.Version = buf.(string) + } + } + + if buf, ok := results["created"]; ok { + if buf != nil { + t, err := time.Parse(time.RFC3339Nano, buf.(string)) + if err != nil { + return err + } + p.Created = timestamppb.New(t) + } + } + + if buf, ok := results["deleted"]; ok { + if buf != nil { + t, err := time.Parse(time.RFC3339Nano, buf.(string)) + if err != nil { + return err + } + p.Deleted = timestamppb.New(t) + } + } + + return nil +} diff --git a/config_store/config.pb.go b/config_store/config.pb.go new file mode 100644 index 000000000..4f6af2483 --- /dev/null +++ b/config_store/config.pb.go @@ -0,0 +1,565 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.15.6 +// source: config.proto + +package config_store + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Environment int32 + +const ( + Environment_NONE Environment = 0 + Environment_PRODUCTION Environment = 1 + Environment_STAGING Environment = 2 + Environment_TESTING Environment = 3 + Environment_DEVELOPMENT Environment = 4 +) + +// Enum value maps for Environment. +var ( + Environment_name = map[int32]string{ + 0: "NONE", + 1: "PRODUCTION", + 2: "STAGING", + 3: "TESTING", + 4: "DEVELOPMENT", + } + Environment_value = map[string]int32{ + "NONE": 0, + "PRODUCTION": 1, + "STAGING": 2, + "TESTING": 3, + "DEVELOPMENT": 4, + } +) + +func (x Environment) Enum() *Environment { + p := new(Environment) + *p = x + return p +} + +func (x Environment) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Environment) Descriptor() protoreflect.EnumDescriptor { + return file_config_proto_enumTypes[0].Descriptor() +} + +func (Environment) Type() protoreflect.EnumType { + return &file_config_proto_enumTypes[0] +} + +func (x Environment) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Environment.Descriptor instead. +func (Environment) EnumDescriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{0} +} + +type Type int32 + +const ( + Type_STRING Type = 0 + Type_INT Type = 1 + Type_FLOAT Type = 2 + Type_BOOL Type = 3 +) + +// Enum value maps for Type. +var ( + Type_name = map[int32]string{ + 0: "STRING", + 1: "INT", + 2: "FLOAT", + 3: "BOOL", + } + Type_value = map[string]int32{ + "STRING": 0, + "INT": 1, + "FLOAT": 2, + "BOOL": 3, + } +) + +func (x Type) Enum() *Type { + p := new(Type) + *p = x + return p +} + +func (x Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Type) Descriptor() protoreflect.EnumDescriptor { + return file_config_proto_enumTypes[1].Descriptor() +} + +func (Type) Type() protoreflect.EnumType { + return &file_config_proto_enumTypes[1] +} + +func (x Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Type.Descriptor instead. +func (Type) EnumDescriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{1} +} + +type Property struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Values []*Value `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + Environment Environment `protobuf:"varint,4,opt,name=environment,proto3,enum=signal18.config_store.v1.Environment" json:"environment,omitempty"` + Section []string `protobuf:"bytes,5,rep,name=section,proto3" json:"section,omitempty"` + Revision int64 `protobuf:"varint,10,opt,name=revision,proto3" json:"revision,omitempty"` + Version string `protobuf:"bytes,11,opt,name=version,proto3" json:"version,omitempty"` + // either created or modified can be dropped as they are the same value + Created *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created,proto3" json:"created,omitempty"` + Deleted *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=deleted,proto3" json:"deleted,omitempty"` +} + +func (x *Property) Reset() { + *x = Property{} + if protoimpl.UnsafeEnabled { + mi := &file_config_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Property) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Property) ProtoMessage() {} + +func (x *Property) ProtoReflect() protoreflect.Message { + mi := &file_config_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Property.ProtoReflect.Descriptor instead. +func (*Property) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{0} +} + +func (x *Property) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Property) GetValues() []*Value { + if x != nil { + return x.Values + } + return nil +} + +func (x *Property) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *Property) GetEnvironment() Environment { + if x != nil { + return x.Environment + } + return Environment_NONE +} + +func (x *Property) GetSection() []string { + if x != nil { + return x.Section + } + return nil +} + +func (x *Property) GetRevision() int64 { + if x != nil { + return x.Revision + } + return 0 +} + +func (x *Property) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Property) GetCreated() *timestamppb.Timestamp { + if x != nil { + return x.Created + } + return nil +} + +func (x *Property) GetDeleted() *timestamppb.Timestamp { + if x != nil { + return x.Deleted + } + return nil +} + +type Value struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ValueString string `protobuf:"bytes,1,opt,name=value_string,json=valueString,proto3" json:"value_string,omitempty"` + ValueInt int64 `protobuf:"varint,2,opt,name=value_int,json=valueInt,proto3" json:"value_int,omitempty"` + ValueFloat float32 `protobuf:"fixed32,3,opt,name=value_float,json=valueFloat,proto3" json:"value_float,omitempty"` + ValueBool bool `protobuf:"varint,4,opt,name=value_bool,json=valueBool,proto3" json:"value_bool,omitempty"` + Type Type `protobuf:"varint,6,opt,name=type,proto3,enum=signal18.config_store.v1.Type" json:"type,omitempty"` +} + +func (x *Value) Reset() { + *x = Value{} + if protoimpl.UnsafeEnabled { + mi := &file_config_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Value) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Value) ProtoMessage() {} + +func (x *Value) ProtoReflect() protoreflect.Message { + mi := &file_config_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Value.ProtoReflect.Descriptor instead. +func (*Value) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{1} +} + +func (x *Value) GetValueString() string { + if x != nil { + return x.ValueString + } + return "" +} + +func (x *Value) GetValueInt() int64 { + if x != nil { + return x.ValueInt + } + return 0 +} + +func (x *Value) GetValueFloat() float32 { + if x != nil { + return x.ValueFloat + } + return 0 +} + +func (x *Value) GetValueBool() bool { + if x != nil { + return x.ValueBool + } + return false +} + +func (x *Value) GetType() Type { + if x != nil { + return x.Type + } + return Type_STRING +} + +type Query struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Property *Property `protobuf:"bytes,1,opt,name=property,proto3" json:"property,omitempty"` + Limit int64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + IgnoreValue bool `protobuf:"varint,3,opt,name=ignore_value,json=ignoreValue,proto3" json:"ignore_value,omitempty"` +} + +func (x *Query) Reset() { + *x = Query{} + if protoimpl.UnsafeEnabled { + mi := &file_config_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Query) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Query) ProtoMessage() {} + +func (x *Query) ProtoReflect() protoreflect.Message { + mi := &file_config_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Query.ProtoReflect.Descriptor instead. +func (*Query) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{2} +} + +func (x *Query) GetProperty() *Property { + if x != nil { + return x.Property + } + return nil +} + +func (x *Query) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *Query) GetIgnoreValue() bool { + if x != nil { + return x.IgnoreValue + } + return false +} + +var File_config_proto protoreflect.FileDescriptor + +var file_config_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf8, 0x02, 0x0a, 0x08, 0x50, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x47, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x34, + 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x64, 0x22, 0xbb, 0x01, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x32, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x08, + 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x52, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0e, + 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x53, 0x54, 0x41, 0x47, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x54, + 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x45, 0x56, 0x45, + 0x4c, 0x4f, 0x50, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x30, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, + 0x03, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, + 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x03, 0x32, 0xb7, 0x01, 0x0a, 0x0b, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x55, 0x0a, 0x05, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, + 0x30, 0x01, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x22, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2f, 0x72, 0x65, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_config_proto_rawDescOnce sync.Once + file_config_proto_rawDescData = file_config_proto_rawDesc +) + +func file_config_proto_rawDescGZIP() []byte { + file_config_proto_rawDescOnce.Do(func() { + file_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_config_proto_rawDescData) + }) + return file_config_proto_rawDescData +} + +var file_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_config_proto_goTypes = []interface{}{ + (Environment)(0), // 0: signal18.config_store.v1.Environment + (Type)(0), // 1: signal18.config_store.v1.Type + (*Property)(nil), // 2: signal18.config_store.v1.Property + (*Value)(nil), // 3: signal18.config_store.v1.Value + (*Query)(nil), // 4: signal18.config_store.v1.Query + (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp +} +var file_config_proto_depIdxs = []int32{ + 3, // 0: signal18.config_store.v1.Property.values:type_name -> signal18.config_store.v1.Value + 0, // 1: signal18.config_store.v1.Property.environment:type_name -> signal18.config_store.v1.Environment + 5, // 2: signal18.config_store.v1.Property.created:type_name -> google.protobuf.Timestamp + 5, // 3: signal18.config_store.v1.Property.deleted:type_name -> google.protobuf.Timestamp + 1, // 4: signal18.config_store.v1.Value.type:type_name -> signal18.config_store.v1.Type + 2, // 5: signal18.config_store.v1.Query.property:type_name -> signal18.config_store.v1.Property + 2, // 6: signal18.config_store.v1.ConfigStore.Store:input_type -> signal18.config_store.v1.Property + 4, // 7: signal18.config_store.v1.ConfigStore.Search:input_type -> signal18.config_store.v1.Query + 2, // 8: signal18.config_store.v1.ConfigStore.Store:output_type -> signal18.config_store.v1.Property + 2, // 9: signal18.config_store.v1.ConfigStore.Search:output_type -> signal18.config_store.v1.Property + 8, // [8:10] is the sub-list for method output_type + 6, // [6:8] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_config_proto_init() } +func file_config_proto_init() { + if File_config_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Property); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Value); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Query); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_config_proto_rawDesc, + NumEnums: 2, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_config_proto_goTypes, + DependencyIndexes: file_config_proto_depIdxs, + EnumInfos: file_config_proto_enumTypes, + MessageInfos: file_config_proto_msgTypes, + }.Build() + File_config_proto = out.File + file_config_proto_rawDesc = nil + file_config_proto_goTypes = nil + file_config_proto_depIdxs = nil +} diff --git a/config_store/config_grpc.pb.go b/config_store/config_grpc.pb.go new file mode 100644 index 000000000..592737f71 --- /dev/null +++ b/config_store/config_grpc.pb.go @@ -0,0 +1,196 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package config_store + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ConfigStoreClient is the client API for ConfigStore service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ConfigStoreClient interface { + Store(ctx context.Context, opts ...grpc.CallOption) (ConfigStore_StoreClient, error) + Search(ctx context.Context, in *Query, opts ...grpc.CallOption) (ConfigStore_SearchClient, error) +} + +type configStoreClient struct { + cc grpc.ClientConnInterface +} + +func NewConfigStoreClient(cc grpc.ClientConnInterface) ConfigStoreClient { + return &configStoreClient{cc} +} + +func (c *configStoreClient) Store(ctx context.Context, opts ...grpc.CallOption) (ConfigStore_StoreClient, error) { + stream, err := c.cc.NewStream(ctx, &ConfigStore_ServiceDesc.Streams[0], "/signal18.config_store.v1.ConfigStore/Store", opts...) + if err != nil { + return nil, err + } + x := &configStoreStoreClient{stream} + return x, nil +} + +type ConfigStore_StoreClient interface { + Send(*Property) error + Recv() (*Property, error) + grpc.ClientStream +} + +type configStoreStoreClient struct { + grpc.ClientStream +} + +func (x *configStoreStoreClient) Send(m *Property) error { + return x.ClientStream.SendMsg(m) +} + +func (x *configStoreStoreClient) Recv() (*Property, error) { + m := new(Property) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *configStoreClient) Search(ctx context.Context, in *Query, opts ...grpc.CallOption) (ConfigStore_SearchClient, error) { + stream, err := c.cc.NewStream(ctx, &ConfigStore_ServiceDesc.Streams[1], "/signal18.config_store.v1.ConfigStore/Search", opts...) + if err != nil { + return nil, err + } + x := &configStoreSearchClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type ConfigStore_SearchClient interface { + Recv() (*Property, error) + grpc.ClientStream +} + +type configStoreSearchClient struct { + grpc.ClientStream +} + +func (x *configStoreSearchClient) Recv() (*Property, error) { + m := new(Property) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// ConfigStoreServer is the server API for ConfigStore service. +// All implementations must embed UnimplementedConfigStoreServer +// for forward compatibility +type ConfigStoreServer interface { + Store(ConfigStore_StoreServer) error + Search(*Query, ConfigStore_SearchServer) error + mustEmbedUnimplementedConfigStoreServer() +} + +// UnimplementedConfigStoreServer must be embedded to have forward compatible implementations. +type UnimplementedConfigStoreServer struct { +} + +func (UnimplementedConfigStoreServer) Store(ConfigStore_StoreServer) error { + return status.Errorf(codes.Unimplemented, "method Store not implemented") +} +func (UnimplementedConfigStoreServer) Search(*Query, ConfigStore_SearchServer) error { + return status.Errorf(codes.Unimplemented, "method Search not implemented") +} +func (UnimplementedConfigStoreServer) mustEmbedUnimplementedConfigStoreServer() {} + +// UnsafeConfigStoreServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ConfigStoreServer will +// result in compilation errors. +type UnsafeConfigStoreServer interface { + mustEmbedUnimplementedConfigStoreServer() +} + +func RegisterConfigStoreServer(s grpc.ServiceRegistrar, srv ConfigStoreServer) { + s.RegisterService(&ConfigStore_ServiceDesc, srv) +} + +func _ConfigStore_Store_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(ConfigStoreServer).Store(&configStoreStoreServer{stream}) +} + +type ConfigStore_StoreServer interface { + Send(*Property) error + Recv() (*Property, error) + grpc.ServerStream +} + +type configStoreStoreServer struct { + grpc.ServerStream +} + +func (x *configStoreStoreServer) Send(m *Property) error { + return x.ServerStream.SendMsg(m) +} + +func (x *configStoreStoreServer) Recv() (*Property, error) { + m := new(Property) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _ConfigStore_Search_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(Query) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(ConfigStoreServer).Search(m, &configStoreSearchServer{stream}) +} + +type ConfigStore_SearchServer interface { + Send(*Property) error + grpc.ServerStream +} + +type configStoreSearchServer struct { + grpc.ServerStream +} + +func (x *configStoreSearchServer) Send(m *Property) error { + return x.ServerStream.SendMsg(m) +} + +// ConfigStore_ServiceDesc is the grpc.ServiceDesc for ConfigStore service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ConfigStore_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "signal18.config_store.v1.ConfigStore", + HandlerType: (*ConfigStoreServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Store", + Handler: _ConfigStore_Store_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "Search", + Handler: _ConfigStore_Search_Handler, + ServerStreams: true, + }, + }, + Metadata: "config.proto", +} diff --git a/signal18/config_store/v1/config.proto b/signal18/config_store/v1/config.proto new file mode 100644 index 000000000..7a58936d8 --- /dev/null +++ b/signal18/config_store/v1/config.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; + +package signal18.config_store.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/signal18/replication-manager/config_store"; + +enum Environment { + NONE = 0; + PRODUCTION = 1; + STAGING = 2; + TESTING = 3; + DEVELOPMENT = 4; +} + +enum Type { + STRING = 0; + INT = 1; + FLOAT = 2; + BOOL = 3; +} + +message Property { + string key = 1; + repeated Value values = 2; + string namespace = 3; + Environment environment = 4; + repeated string section = 5; + + int64 revision = 10; + string version = 11; + + // either created or modified can be dropped as they are the same value + google.protobuf.Timestamp created = 12; + google.protobuf.Timestamp deleted = 14; +} + +message Value { + string value_string = 1; + int64 value_int = 2; + float value_float = 3; + bool value_bool = 4; + Type type = 6; +} + +message Query { + Property property = 1; + int64 limit = 2; + bool ignore_value = 3; +} + +service ConfigStore { + rpc Store(stream Property) returns (stream Property) {} + rpc Search(Query) returns (stream Property) {} +} \ No newline at end of file diff --git a/signal18/config_store/v1/notes.md b/signal18/config_store/v1/notes.md new file mode 100644 index 000000000..3c67a8034 --- /dev/null +++ b/signal18/config_store/v1/notes.md @@ -0,0 +1,18 @@ +## Install notes + +Requires some setup, download protoc: https://github.com/protocolbuffers/protobuf/releases and copy the bin to `/usr/local/bin` and put the include in `/usr/local/include`. + +Then we need some generators for the Protobuffer compiler to generate Go output + +``` +go install google.golang.org/protobuf/cmd/protoc-gen-go +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc +``` + +Then we can compile it. + +NB: the paths=source_relative for go and grpc are important else it'll end up with the entire package name again inside the path directory! + +``` +protoc -I=/usr/local/include/google/protobuf -I signal18/config_store/v1/ --go_opt=paths=source_relative --go_out=./config_store --go-grpc_opt=paths=source_relative --go-grpc_out=./config_store signal18/config_store/v1/config.proto +``` \ No newline at end of file From 468e73f81d2f2a2a7388811133217ce0092102a3 Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Thu, 22 Apr 2021 02:00:39 +0200 Subject: [PATCH 2/7] Cleaner key/value store for arrays --- cmd/config_store-client/main.go | 14 +- cmd/config_store/internal/server/server.go | 2 +- cmd/config_store/internal/storage/sqlite.go | 91 +++++-- config_store/client.go | 6 +- config_store/config.go | 278 +++++++++----------- config_store/config.pb.go | 119 ++++----- signal18/config_store/v1/config.proto | 7 +- 7 files changed, 243 insertions(+), 274 deletions(-) diff --git a/cmd/config_store-client/main.go b/cmd/config_store-client/main.go index 1884319b7..70dba8587 100644 --- a/cmd/config_store-client/main.go +++ b/cmd/config_store-client/main.go @@ -18,14 +18,8 @@ func main() { } props := make([]*cs.Property, 0) - props = append(props, csc.NewStringProperty([]string{"foo", "baz"}, "client-test", "foo", "foo-2")) - props = append(props, csc.NewStringProperty([]string{}, "client-test", "bar", "bar")) - - // for checking the error on the server - // props = append(props, &cs.Property{ - // Value: "foo-2", - // Store: "client-test", - // }) + props = append(props, csc.NewProperty([]string{"foo", "baz"}, "client-test", "foo", "foo-2")) + props = append(props, csc.NewProperty([]string{"bar-section"}, "client-test", "bar", "value1", "value2")) ctx := context.Background() responses, err := csc.Store(ctx, props) @@ -73,14 +67,14 @@ func main() { specificUnavailableNamespace, err := csc.Search(ctx, &cs.Query{ Property: &cs.Property{ - Namespace: "foo", + Namespace: "bar-section", }, }) if err != nil { log.Printf("Error retrieving data: %s", err) } for _, r := range specificUnavailableNamespace { - log.Printf("List foo data: %v", r) + log.Printf("List bar-section data: %v", r) } } diff --git a/cmd/config_store/internal/server/server.go b/cmd/config_store/internal/server/server.go index 59ede0a7b..67a995ef6 100644 --- a/cmd/config_store/internal/server/server.go +++ b/cmd/config_store/internal/server/server.go @@ -94,7 +94,7 @@ func (s *Server) Store(stream cs.ConfigStore_StoreServer) error { found := find[0] if found.Key == in.Key && found.Namespace == in.Namespace && found.Environment == in.Environment { - if found.DatabaseValue() == in.DatabaseValue() { + if cs.ValuesEqual(found.Values, in.Values) { log.Printf("Property did not change: %v", in) stream.Send(found) continue diff --git a/cmd/config_store/internal/storage/sqlite.go b/cmd/config_store/internal/storage/sqlite.go index 2c5568df3..e70c8b08c 100644 --- a/cmd/config_store/internal/storage/sqlite.go +++ b/cmd/config_store/internal/storage/sqlite.go @@ -2,7 +2,6 @@ package storage import ( "errors" - "fmt" "log" "os" "strings" @@ -65,6 +64,8 @@ func (st *SQLiteStorage) create() error { schema := `CREATE TABLE properties ( key text, value text null, + value_order int default 0, + value_type int default 0, section text null, namespace text default "default", environment int default 0, @@ -85,13 +86,19 @@ func (st *SQLiteStorage) create() error { var ( storeProperty = "INSERT INTO properties (" + - "key, value, section, namespace, " + - "environment, revision, version, " + + "key, " + + "value, " + + "value_order, " + + "value_type, " + + "section, " + + "namespace, " + + "environment, " + + "revision, " + + "version, " + "created" + ") VALUES (" + - "?, ?, ?, ?, " + - "?, ?, ?, " + - "?" + + "?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?" + ")" ) @@ -100,19 +107,22 @@ func (st *SQLiteStorage) Store(property *cs.Property) (*cs.Property, error) { property.Created = timestamppb.Now() - _, err := st.db.Exec(storeProperty, - property.Key, - property.DatabaseValue(), - strings.Join(property.Section, cs.RecordSeperator), - property.Namespace, - property.Environment, - property.Revision, - property.Version, - property.Created.AsTime().Format(time.RFC3339Nano), - ) - - if err != nil { - return nil, err + for order, value := range property.Values { + _, err := st.db.Exec(storeProperty, + property.Key, + value.Data, + order, + value.Type, + strings.Join(property.Section, cs.RecordSeperator), + property.Namespace, + property.Environment, + property.Revision, + property.Version, + property.Created.AsTime().Format(time.RFC3339Nano), + ) + if err != nil { + return nil, err + } } return property, nil @@ -136,6 +146,9 @@ func (st *SQLiteStorage) Search(query *cs.Query) (results []*cs.Property, err er return results, ErrNoRowsFound } + var lastKey string + var p *cs.Property + for rows.Next() { buf := make(map[string]interface{}) err = rows.MapScan(buf) @@ -143,15 +156,36 @@ func (st *SQLiteStorage) Search(query *cs.Query) (results []*cs.Property, err er return } - p := &cs.Property{} + // if the lastKey doesn't match the incoming key + // reset the Property as it doesn't have additional Values + if key, ok := buf["key"]; ok { + if key != nil { + if lastKey != key.(string) { + if lastKey != "" { + results = append(results, p) + } + p = &cs.Property{} + } + } + } err = p.Scan(buf) if err != nil { return } + lastKey = p.Key + } + + // because of the way we loop over the set we have to add the final one + // to the actual results + if p != nil { results = append(results, p) } + if len(results) > int(query.Limit) { + return results[:query.Limit], nil + } + return } @@ -171,12 +205,13 @@ func (st *SQLiteStorage) getSQLQuery(q *cs.Query) (query string, values []interf values = append(values, q.Property.Key) } - if !q.IgnoreValue { - if q.Property.DatabaseValue() != "" { - queries = append(queries, "value = ?") - values = append(values, q.Property.DatabaseValue()) - } - } + // TODO: reimplement + // if !q.IgnoreValue { + // if q.Property.DatabaseValue() != "" { + // queries = append(queries, "value = ?") + // values = append(values, q.Property.DatabaseValue()) + // } + // } if q.Property.Namespace != "" { queries = append(queries, "namespace = ?") @@ -202,9 +237,7 @@ func (st *SQLiteStorage) getSQLQuery(q *cs.Query) (query string, values []interf query += " ORDER BY revision DESC" - if q.Limit != 0 { - query += fmt.Sprintf(" LIMIT %d", q.Limit) - } + // normally we'd do a LIMIT here but we do that inside the search :) return query, values } diff --git a/config_store/client.go b/config_store/client.go index ddf09e7ef..c5c79ef0e 100644 --- a/config_store/client.go +++ b/config_store/client.go @@ -37,8 +37,8 @@ func NewConfigStore(address string, env Environment) *ConfigStore { return csc } -func (csc *ConfigStore) NewStringProperty(section []string, namespace string, key string, value string) *Property { - return NewStringProperty(section, namespace, csc.env, key, value) +func (csc *ConfigStore) NewProperty(section []string, namespace string, key string, values ...interface{}) *Property { + return NewProperty(section, namespace, csc.env, key, values...) } func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*Property, error) { @@ -133,7 +133,7 @@ func (csc *ConfigStore) ImportTOML(path string) error { Section: section, } - p.SetValue(value) + p.SetValues(value) log.Printf("p: %v", p) props = append(props, p) diff --git a/config_store/config.go b/config_store/config.go index 566845583..e8181cc46 100644 --- a/config_store/config.go +++ b/config_store/config.go @@ -3,7 +3,6 @@ package config_store import ( "errors" "fmt" - "log" "strconv" "strings" "time" @@ -19,26 +18,29 @@ const ( RecordSeperator = "\u241E" ) -func NewProperty(section []string, namespace string, env Environment, key string, values []*Value) *Property { +func NewProperty(section []string, namespace string, env Environment, key string, values ...interface{}) *Property { p := &Property{ Key: key, - Values: values, Section: section, Namespace: namespace, Environment: env, } + p.SetValues(values...) return p } -func NewStringProperty(section []string, namespace string, env Environment, key string, value string) *Property { - v := &Value{ - Type: Type_STRING, - ValueString: value, +func ValuesEqual(a []*Value, b []*Value) bool { + if len(a) != len(b) { + return false } - values := make([]*Value, 0) - values = append(values, v) - return NewProperty(section, namespace, env, key, values) + for i := range a { + if a[i].Data != b[i].Data { + return false + } + } + + return true } func (p *Property) Validate() error { @@ -49,133 +51,75 @@ func (p *Property) Validate() error { return nil } -func (p *Property) SetStringValue(v string) { - p.Values = make([]*Value, 0) - p.Values = append(p.Values, &Value{ - ValueString: v, - }) -} - -func (p *Property) SetValue(value interface{}) { - p.Values = make([]*Value, 0) +func NewValue(value interface{}) *Value { if v, ok := value.(string); ok { - p.Values = append(p.Values, &Value{ - Type: Type_STRING, - ValueString: v, - }) - return + // TODO: maybe add functionality to check if it's an int/bool/float + return &Value{ + Type: Type_STRING, + Data: v, + } } if v, ok := value.(int); ok { - p.Values = append(p.Values, &Value{ - Type: Type_INT, - ValueInt: int64(v), - }) - - return + return &Value{ + Type: Type_INT, + Data: fmt.Sprintf("%d", v), + } } if v, ok := value.(int64); ok { - p.Values = append(p.Values, &Value{ - Type: Type_INT, - ValueInt: v, - }) - - return + return &Value{ + Type: Type_INT, + Data: fmt.Sprintf("%d", v), + } } if v, ok := value.(float32); ok { - p.Values = append(p.Values, &Value{ - Type: Type_FLOAT, - ValueFloat: v, - }) - - return + return &Value{ + Type: Type_FLOAT, + Data: fmt.Sprintf("%f", v), + } } - if v, ok := value.(bool); ok { - p.Values = append(p.Values, &Value{ - Type: Type_BOOL, - ValueBool: v, - }) - - return + if v, ok := value.(float64); ok { + return &Value{ + Type: Type_FLOAT, + Data: fmt.Sprintf("%f", v), + } } -} -// DatabaseValue returns a string representation of the possible repeated Value -// property as a string. -// SQLite stores data natively as TEXT anyway -func (p *Property) DatabaseValue() string { - buf := make([]string, 0) - for _, v := range p.Values { - buf = append(buf, v.DatabaseValue()) + if v, ok := value.(bool); ok { + val := "true" + if v == false { + val = "false" + } + return &Value{ + Type: Type_BOOL, + Data: val, + } } - return strings.Join(buf, RecordSeperator) -} - -// DatabaseValue returns a string representation where the first digit signifies -// the type for the Value. -func (v *Value) DatabaseValue() string { - var s strings.Builder - s.WriteString(strconv.FormatInt(int64(v.Type), 10)) - s.WriteString(v.GetStringValue()) - return s.String() + return nil } -func ValueFromDatabaseValue(db string) *Value { - t := db[0:1] - v := db[1:] - log.Printf("t: %v, v: %v", t, v) - - var value *Value - - if n, err := strconv.Atoi(t); err == nil { - value = &Value{ - Type: Type(n), - } - - switch value.Type { - case Type_STRING: - value.ValueString = v - case Type_INT: - if iv, err := strconv.Atoi(v); err == nil { - value.ValueInt = int64(iv) - } else { - panic("stored value is not an integer") - } - case Type_FLOAT: - if f, err := strconv.ParseFloat(v, 32); err == nil { - value.ValueFloat = float32(f) - } else { - panic("stored value is not a float") - } - case Type_BOOL: - if v == "true" { - value.ValueBool = true - } else { - value.ValueBool = false - } - } - - } else { - panic("first character of value is not an integer") +func (p *Property) SetValues(values ...interface{}) { + p.Values = make([]*Value, 0) + for _, value := range values { + p.Values = append(p.Values, NewValue(value)) } - - return value } func (v *Value) GetStringValue() string { + buf := v.GetValue() switch v.Type { case Type_STRING: - return v.ValueString + return buf.(string) case Type_INT: - return strconv.FormatInt(v.ValueInt, 10) + return strconv.FormatInt(buf.(int64), 10) case Type_FLOAT: - return fmt.Sprintf("%f", v.ValueFloat) + return fmt.Sprintf("%f", buf.(float64)) case Type_BOOL: - if v.ValueBool { + if buf.(bool) { return "true" } else { return "false" @@ -188,13 +132,25 @@ func (v *Value) GetStringValue() string { func (v *Value) GetValue() interface{} { switch v.Type { case Type_STRING: - return v.ValueString + return v case Type_INT: - return v.ValueInt + if iv, err := strconv.Atoi(v.Data); err == nil { + return int64(iv) + } else { + panic("stored value is not an integer") + } case Type_FLOAT: - return v.ValueFloat + if f, err := strconv.ParseFloat(v.Data, 32); err == nil { + return float32(f) + } else { + panic("stored value is not a float") + } case Type_BOOL: - return v.ValueBool + if v.Data == "true" { + return true + } else { + return false + } } return nil @@ -207,68 +163,84 @@ func (p *Property) Scan(results map[string]interface{}) error { } } - if buf, ok := results["value"]; ok { + var order int64 + if buf, ok := results["val_order"]; ok { if buf != nil { - values := make([]*Value, 0) - vs := strings.Split(buf.(string), RecordSeperator) - for _, v := range vs { - values = append(values, ValueFromDatabaseValue(v)) - } - - p.Values = values + order = buf.(int64) } } - if buf, ok := results["namespace"]; ok { + var valueType Type + + if buf, ok := results["type"]; ok { if buf != nil { - p.Namespace = buf.(string) + valueType = Type(buf.(int64)) } } - if buf, ok := results["section"]; ok { + if buf, ok := results["value"]; ok { if buf != nil { - s := buf.(string) - if s != "" { - p.Section = strings.Split(s, "|") + value := &Value{ + Data: buf.(string), + Type: valueType, } + + p.Values = append(p.Values, value) } } - if buf, ok := results["environment"]; ok { - if buf != nil { - p.Environment = Environment(buf.(int64)) + if order == 0 { + if buf, ok := results["namespace"]; ok { + if buf != nil { + p.Namespace = buf.(string) + } } - } - if buf, ok := results["revision"]; ok { - if buf != nil { - p.Revision = buf.(int64) + if buf, ok := results["section"]; ok { + if buf != nil { + s := buf.(string) + if s != "" { + p.Section = strings.Split(s, "|") + } + } } - } - if buf, ok := results["version"]; ok { - if buf != nil { - p.Version = buf.(string) + if buf, ok := results["environment"]; ok { + if buf != nil { + p.Environment = Environment(buf.(int64)) + } } - } - if buf, ok := results["created"]; ok { - if buf != nil { - t, err := time.Parse(time.RFC3339Nano, buf.(string)) - if err != nil { - return err + if buf, ok := results["revision"]; ok { + if buf != nil { + p.Revision = buf.(int64) } - p.Created = timestamppb.New(t) } - } - if buf, ok := results["deleted"]; ok { - if buf != nil { - t, err := time.Parse(time.RFC3339Nano, buf.(string)) - if err != nil { - return err + if buf, ok := results["version"]; ok { + if buf != nil { + p.Version = buf.(string) + } + } + + if buf, ok := results["created"]; ok { + if buf != nil { + t, err := time.Parse(time.RFC3339Nano, buf.(string)) + if err != nil { + return err + } + p.Created = timestamppb.New(t) + } + } + + if buf, ok := results["deleted"]; ok { + if buf != nil { + t, err := time.Parse(time.RFC3339Nano, buf.(string)) + if err != nil { + return err + } + p.Deleted = timestamppb.New(t) } - p.Deleted = timestamppb.New(t) } } diff --git a/config_store/config.pb.go b/config_store/config.pb.go index 4f6af2483..5406ff724 100644 --- a/config_store/config.pb.go +++ b/config_store/config.pb.go @@ -245,11 +245,12 @@ type Value struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ValueString string `protobuf:"bytes,1,opt,name=value_string,json=valueString,proto3" json:"value_string,omitempty"` - ValueInt int64 `protobuf:"varint,2,opt,name=value_int,json=valueInt,proto3" json:"value_int,omitempty"` - ValueFloat float32 `protobuf:"fixed32,3,opt,name=value_float,json=valueFloat,proto3" json:"value_float,omitempty"` - ValueBool bool `protobuf:"varint,4,opt,name=value_bool,json=valueBool,proto3" json:"value_bool,omitempty"` - Type Type `protobuf:"varint,6,opt,name=type,proto3,enum=signal18.config_store.v1.Type" json:"type,omitempty"` + // string value_string = 1; + // int64 value_int = 2; + // float value_float = 3; + // bool value_bool = 4; + Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Type Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal18.config_store.v1.Type" json:"type,omitempty"` } func (x *Value) Reset() { @@ -284,34 +285,13 @@ func (*Value) Descriptor() ([]byte, []int) { return file_config_proto_rawDescGZIP(), []int{1} } -func (x *Value) GetValueString() string { +func (x *Value) GetData() string { if x != nil { - return x.ValueString + return x.Data } return "" } -func (x *Value) GetValueInt() int64 { - if x != nil { - return x.ValueInt - } - return 0 -} - -func (x *Value) GetValueFloat() float32 { - if x != nil { - return x.ValueFloat - } - return 0 -} - -func (x *Value) GetValueBool() bool { - if x != nil { - return x.ValueBool - } - return false -} - func (x *Value) GetType() Type { if x != nil { return x.Type @@ -413,51 +393,44 @@ var file_config_proto_rawDesc = []byte{ 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x22, 0xbb, 0x01, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, - 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x49, 0x6e, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x02, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x32, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x08, - 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x52, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0e, - 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x53, 0x54, 0x41, 0x47, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x54, - 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x45, 0x56, 0x45, - 0x4c, 0x4f, 0x50, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x30, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, - 0x03, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, - 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x03, 0x32, 0xb7, 0x01, 0x0a, 0x0b, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x55, 0x0a, 0x05, 0x53, - 0x74, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, - 0x30, 0x01, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x22, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, - 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2f, 0x72, 0x65, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x74, 0x65, 0x64, 0x22, 0x4f, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x3e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x52, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x69, + 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, + 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, + 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x47, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, + 0x0a, 0x07, 0x54, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x44, + 0x45, 0x56, 0x45, 0x4c, 0x4f, 0x50, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x30, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, + 0x41, 0x54, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x03, 0x32, 0xb7, + 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x55, + 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x22, + 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, + 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x1a, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2f, + 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/signal18/config_store/v1/config.proto b/signal18/config_store/v1/config.proto index 7a58936d8..97fc2abb9 100644 --- a/signal18/config_store/v1/config.proto +++ b/signal18/config_store/v1/config.proto @@ -37,11 +37,8 @@ message Property { } message Value { - string value_string = 1; - int64 value_int = 2; - float value_float = 3; - bool value_bool = 4; - Type type = 6; + string data = 1; + Type type = 2; } message Query { From 10a143368578a229f4e9997d337961a546f49102 Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Thu, 22 Apr 2021 02:59:33 +0200 Subject: [PATCH 3/7] Support for updating the latest revision for multi-value properties --- cmd/config_store/internal/storage/sqlite.go | 9 +++++++++ go.mod | 10 +++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cmd/config_store/internal/storage/sqlite.go b/cmd/config_store/internal/storage/sqlite.go index e70c8b08c..a8b3628ba 100644 --- a/cmd/config_store/internal/storage/sqlite.go +++ b/cmd/config_store/internal/storage/sqlite.go @@ -223,9 +223,12 @@ func (st *SQLiteStorage) getSQLQuery(q *cs.Query) (query string, values []interf values = append(values, q.Property.Environment) } + revisionless := false if q.Property.Revision != 0 { queries = append(queries, "revision = ?") values = append(values, q.Property.Revision) + } else { + revisionless = true } if q.Property.Version != "" { @@ -233,6 +236,12 @@ func (st *SQLiteStorage) getSQLQuery(q *cs.Query) (query string, values []interf values = append(values, q.Property.Version) } + if revisionless { + inQuery := "revision IN (SELECT revision FROM properties WHERE " + strings.Join(queries, " AND ") + " ORDER BY revision DESC LIMIT 1)" + queries = append(queries, inQuery) + values = append(values, values...) + } + query = basequery + strings.Join(queries, " AND ") query += " ORDER BY revision DESC" diff --git a/go.mod b/go.mod index 2b1b029a5..f6e2aa0f0 100644 --- a/go.mod +++ b/go.mod @@ -47,12 +47,13 @@ require ( github.com/fsnotify/fsnotify v1.4.7 github.com/go-sql-driver/mysql v1.5.0 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d + github.com/golang/protobuf v1.5.0 github.com/gonum/blas v0.0.0-20180125090452-e7c5890b24cf github.com/gonum/floats v0.0.0-20180125090339-7de1f4ea7ab5 github.com/gonum/internal v0.0.0-20180125090855-fda53f8d2571 github.com/gonum/lapack v0.0.0-20180125091020-f0b8b25edece github.com/gonum/matrix v0.0.0-20180124231301-a41cc49d4c29 - github.com/google/uuid v1.1.1 + github.com/google/uuid v1.1.2 github.com/googleapis/gnostic v0.3.1 // indirect github.com/gorilla/context v1.1.1 github.com/gorilla/handlers v1.3.0 @@ -86,7 +87,7 @@ require ( github.com/magiconair/properties v1.8.0 github.com/magneticio/vamp-router v0.0.0-20151116102511-29379b621548 github.com/mattn/go-runewidth v0.0.0-20170510074858-97311d9f7767 - github.com/mattn/go-sqlite3 v1.9.0 + github.com/mattn/go-sqlite3 v1.14.6 github.com/micro/go-log v0.1.0 // indirect github.com/micro/go-micro v0.1.4 github.com/micro/misc v0.1.0 // indirect @@ -118,7 +119,7 @@ require ( github.com/spf13/jwalterweatherman v1.0.0 github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.4.0 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/urfave/cli v1.22.3 github.com/walle/lll v1.0.1 // indirect github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f @@ -128,6 +129,9 @@ require ( golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f golang.org/x/text v0.3.2 google.golang.org/appengine v1.5.0 + google.golang.org/grpc v1.36.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect + google.golang.org/protobuf v1.26.0 gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 gopkg.in/fsnotify/fsnotify.v1 v1.4.7 From 77f1cfffd2846b74fb9d05d34b66a28d49b866fa Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Mon, 26 Apr 2021 23:49:48 +0200 Subject: [PATCH 4/7] Add encryption for secrets on the client side, server side is unaware --- .vscode/launch.json | 18 +++ cmd/config_store-client/main.go | 23 +++- cmd/config_store/internal/storage/sqlite.go | 12 +- config_store/client.go | 67 +++++++++++ config_store/config.go | 124 +++++++++++++++++++- config_store/config.pb.go | 121 ++++++++++--------- go.mod | 3 +- go.sum | 61 ++++++++++ signal18/config_store/v1/config.proto | 2 + 9 files changed, 370 insertions(+), 61 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 379d98d36..01e62f603 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,6 +12,24 @@ "program": "${workspaceFolder}/main.go", "env": {}, "args": ["monitor", "--config", "/etc/replication-manager/config.toml", "--log-file", "/var/lib/replication-manager/data/replication-manager.log"], + }, + { + "name": "config_store", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/config_store/main.go", + "env": {}, + "args": [], + }, + { + "name": "config_store client", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/config_store-client/main.go", + "env": {}, + "args": [], } ] } \ No newline at end of file diff --git a/cmd/config_store-client/main.go b/cmd/config_store-client/main.go index 70dba8587..2284c77c5 100644 --- a/cmd/config_store-client/main.go +++ b/cmd/config_store-client/main.go @@ -8,9 +8,17 @@ import ( ) func main() { - // connect to the locally available config_store server + // generate a key one time to use for the secrets + // key, err := cs.GenerateHexKey() + // if err != nil { + // log.Fatalf("Could not generate hex key: %s", err) + // } + key := "b00a4909fe6b7113c20ad8443cfe40075b817fe4351c4e287b44f1d69336edc7" + log.Printf("Key: %s", key) + // connect to the locally available config_store server csc := cs.NewConfigStore("127.0.0.1:7777", cs.Environment_NONE) + csc.SetKeyFromHex(key) err := csc.ImportTOML("/etc/replication-manager/") if err != nil { @@ -19,7 +27,15 @@ func main() { props := make([]*cs.Property, 0) props = append(props, csc.NewProperty([]string{"foo", "baz"}, "client-test", "foo", "foo-2")) - props = append(props, csc.NewProperty([]string{"bar-section"}, "client-test", "bar", "value1", "value2")) + props = append(props, csc.NewProperty([]string{"bar-section"}, "client-test", "bar", "value1", "value20")) + + password, err := csc.NewSecret([]string{"secrets"}, "cluster", "rootpassword", "somesecretpassword") + if err != nil { + log.Fatalf("Could not create secret") + } + props = append(props, password) + + log.Printf("password property: %v", password) ctx := context.Background() responses, err := csc.Store(ctx, props) @@ -29,6 +45,9 @@ func main() { for _, r := range responses { log.Printf("Store response data: %v", r) + if r.Secret { + log.Printf("Property is secret: %s", r.GetValues()) + } } // list the available properties diff --git a/cmd/config_store/internal/storage/sqlite.go b/cmd/config_store/internal/storage/sqlite.go index a8b3628ba..1d1f67c85 100644 --- a/cmd/config_store/internal/storage/sqlite.go +++ b/cmd/config_store/internal/storage/sqlite.go @@ -70,7 +70,9 @@ func (st *SQLiteStorage) create() error { namespace text default "default", environment int default 0, revision int default 0, - version string null, + version text null, + secret int default 0, + checksum text null, created TEXT default CURRENT_TIMESTAMP, deleted TEXT null );` @@ -95,10 +97,12 @@ var ( "environment, " + "revision, " + "version, " + + "secret, " + + "checksum, " + "created" + ") VALUES (" + - "?, ?, ?, ?, ?, " + - "?, ?, ?, ?, ?" + + "?, ?, ?, ?, ?, ?," + + "?, ?, ?, ?, ?, ?" + ")" ) @@ -118,6 +122,8 @@ func (st *SQLiteStorage) Store(property *cs.Property) (*cs.Property, error) { property.Environment, property.Revision, property.Version, + property.Secret, + value.Checksum, property.Created.AsTime().Format(time.RFC3339Nano), ) if err != nil { diff --git a/config_store/client.go b/config_store/client.go index c5c79ef0e..6dd19ab32 100644 --- a/config_store/client.go +++ b/config_store/client.go @@ -2,6 +2,9 @@ package config_store import ( context "context" + "crypto/rand" + "encoding/hex" + "fmt" "io" "log" "strings" @@ -14,6 +17,7 @@ import ( type ConfigStore struct { conn *grpc.ClientConn env Environment + key []byte } func NewConfigStore(address string, env Environment) *ConfigStore { @@ -37,10 +41,51 @@ func NewConfigStore(address string, env Environment) *ConfigStore { return csc } +func GenerateKey() ([]byte, error) { + key := make([]byte, 32) + _, err := rand.Read(key) + if err != nil { + return nil, err + } + return key, nil +} + +func GenerateHexKey() (string, error) { + key, err := GenerateKey() + if err != nil { + return "", err + } + + return hex.EncodeToString(key), nil +} + +func (csc *ConfigStore) SetKey(key []byte) { + csc.key = key +} + +func (csc *ConfigStore) SetKeyFromHex(key string) error { + binaryKey, err := hex.DecodeString(key) + if err != nil { + return err + } + csc.key = binaryKey + return nil +} + func (csc *ConfigStore) NewProperty(section []string, namespace string, key string, values ...interface{}) *Property { return NewProperty(section, namespace, csc.env, key, values...) } +func (csc *ConfigStore) NewSecret(section []string, namespace string, key string, values ...interface{}) (*Property, error) { + if csc.key == nil { + return nil, fmt.Errorf("config store key cannot be nil when using secrets") + } + + p := NewSecret(section, namespace, csc.env, key, values...) + + return p, nil +} + func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*Property, error) { client := NewConfigStoreClient(csc.conn) clientDeadline := time.Now().Add(time.Duration(30) * time.Second) @@ -54,6 +99,13 @@ func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*P var responses []*Property for _, p := range properties { + if p.Secret { + err := p.Encrypt(csc.key) + if err != nil { + log.Printf("Cannot encrypt: %s", err) + return nil, err + } + } if err := storeClient.Send(p); err != nil { log.Printf("Error sending: %v", err) return nil, err @@ -63,6 +115,13 @@ func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*P log.Printf("Error returned: %v", err) return nil, err } + if resp.Secret { + resp.Decrypt(csc.key) + if err != nil { + log.Printf("Cannot decrypt: %s", err) + return nil, err + } + } responses = append(responses, resp) } @@ -95,6 +154,14 @@ func (csc *ConfigStore) Search(ctx context.Context, query *Query) ([]*Property, return nil, err } + if in.Secret { + err = in.Decrypt(csc.key) + if err != nil { + log.Printf("Could not decrypt: %s", err) + return nil, err + } + } + responses = append(responses, in) } diff --git a/config_store/config.go b/config_store/config.go index e8181cc46..a9da8df04 100644 --- a/config_store/config.go +++ b/config_store/config.go @@ -1,12 +1,17 @@ package config_store import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" "errors" "fmt" "strconv" "strings" "time" + "github.com/zeebo/blake3" timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) @@ -29,6 +34,13 @@ func NewProperty(section []string, namespace string, env Environment, key string return p } +func NewSecret(section []string, namespace string, env Environment, key string, values ...interface{}) *Property { + p := NewProperty(section, namespace, env, key, values...) + p.SetSecret(true) + + return p +} + func ValuesEqual(a []*Value, b []*Value) bool { if len(a) != len(b) { return false @@ -36,6 +48,9 @@ func ValuesEqual(a []*Value, b []*Value) bool { for i := range a { if a[i].Data != b[i].Data { + if a[i].Checksum == b[i].Checksum { + continue + } return false } } @@ -43,6 +58,93 @@ func ValuesEqual(a []*Value, b []*Value) bool { return true } +func (p *Property) SetSecret(b bool) { + p.Secret = b +} + +func (p *Property) Encrypt(key []byte) error { + for _, v := range p.Values { + err := v.Encrypt(key) + if err != nil { + return err + } + } + + return nil +} + +func (p *Property) Decrypt(key []byte) error { + for _, v := range p.Values { + err := v.Decrypt(key) + if err != nil { + return err + } + } + + return nil +} + +func (v *Value) checksum() { + data := []byte(v.Data) + chk := blake3.Sum256(data) + v.Checksum = string(hex.EncodeToString(chk[:])) +} + +// Encrypt takes the Data inside the Value and encrypts it with the supplied key +// it is encoded in hex to be able to store it as a string +func (v *Value) Encrypt(key []byte) error { + data := []byte(v.Data) + v.checksum() + + blockCipher, err := aes.NewCipher(key) + if err != nil { + return err + } + + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err = rand.Read(nonce); err != nil { + return err + } + + ciphertext := gcm.Seal(nonce, nonce, data, nil) + v.Data = hex.EncodeToString(ciphertext) + + return nil +} + +func (v *Value) Decrypt(key []byte) error { + // we must first convert from hex to bytes + data, err := hex.DecodeString(v.Data) + if err != nil { + return err + } + + blockCipher, err := aes.NewCipher(key) + if err != nil { + return err + } + + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return err + } + + nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return err + } + + v.Data = string(plaintext) + + return nil +} + func (p *Property) Validate() error { if p.Key == "" { return ErrPropertyKeyMissing @@ -171,6 +273,7 @@ func (p *Property) Scan(results map[string]interface{}) error { } var valueType Type + var checksum string if buf, ok := results["type"]; ok { if buf != nil { @@ -178,11 +281,18 @@ func (p *Property) Scan(results map[string]interface{}) error { } } + if buf, ok := results["checksum"]; ok { + if buf != nil { + checksum = buf.(string) + } + } + if buf, ok := results["value"]; ok { if buf != nil { value := &Value{ - Data: buf.(string), - Type: valueType, + Data: buf.(string), + Type: valueType, + Checksum: checksum, } p.Values = append(p.Values, value) @@ -242,6 +352,16 @@ func (p *Property) Scan(results map[string]interface{}) error { p.Deleted = timestamppb.New(t) } } + + if buf, ok := results["secret"]; ok { + if buf != nil { + if buf.(int64) == 0 { + p.Secret = false + } else { + p.Secret = true + } + } + } } return nil diff --git a/config_store/config.pb.go b/config_store/config.pb.go index 5406ff724..7c0dc9807 100644 --- a/config_store/config.pb.go +++ b/config_store/config.pb.go @@ -138,6 +138,7 @@ type Property struct { Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` Environment Environment `protobuf:"varint,4,opt,name=environment,proto3,enum=signal18.config_store.v1.Environment" json:"environment,omitempty"` Section []string `protobuf:"bytes,5,rep,name=section,proto3" json:"section,omitempty"` + Secret bool `protobuf:"varint,6,opt,name=secret,proto3" json:"secret,omitempty"` Revision int64 `protobuf:"varint,10,opt,name=revision,proto3" json:"revision,omitempty"` Version string `protobuf:"bytes,11,opt,name=version,proto3" json:"version,omitempty"` // either created or modified can be dropped as they are the same value @@ -212,6 +213,13 @@ func (x *Property) GetSection() []string { return nil } +func (x *Property) GetSecret() bool { + if x != nil { + return x.Secret + } + return false +} + func (x *Property) GetRevision() int64 { if x != nil { return x.Revision @@ -245,12 +253,9 @@ type Value struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // string value_string = 1; - // int64 value_int = 2; - // float value_float = 3; - // bool value_bool = 4; - Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - Type Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal18.config_store.v1.Type" json:"type,omitempty"` + Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Type Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal18.config_store.v1.Type" json:"type,omitempty"` + Checksum string `protobuf:"bytes,3,opt,name=checksum,proto3" json:"checksum,omitempty"` // used to prevent restoring encrypted values } func (x *Value) Reset() { @@ -299,6 +304,13 @@ func (x *Value) GetType() Type { return Type_STRING } +func (x *Value) GetChecksum() string { + if x != nil { + return x.Checksum + } + return "" +} + type Query struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -369,7 +381,7 @@ var file_config_proto_rawDesc = []byte{ 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf8, 0x02, 0x0a, 0x08, 0x50, 0x72, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x90, 0x03, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, @@ -383,54 +395,57 @@ var file_config_proto_rawDesc = []byte{ 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x34, - 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x22, 0x4f, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, - 0x3e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x67, 0x6e, - 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x52, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, - 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, - 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x47, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, - 0x0a, 0x07, 0x54, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x44, - 0x45, 0x56, 0x45, 0x4c, 0x4f, 0x50, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x30, 0x0a, 0x04, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x00, - 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x4c, 0x4f, - 0x41, 0x54, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x03, 0x32, 0xb7, - 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x55, - 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x6b, 0x0a, 0x05, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x73, 0x69, + 0x76, 0x31, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, 0x80, 0x01, 0x0a, 0x05, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, + 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x52, 0x0a, 0x0b, + 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x4e, + 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, + 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x47, 0x49, 0x4e, 0x47, + 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, + 0x0f, 0x0a, 0x0b, 0x44, 0x45, 0x56, 0x45, 0x4c, 0x4f, 0x50, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x04, + 0x2a, 0x30, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, + 0x4e, 0x47, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, + 0x10, 0x03, 0x32, 0xb7, 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x6f, + 0x72, 0x65, 0x12, 0x55, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x22, - 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, - 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x1a, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, - 0x65, 0x72, 0x74, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2f, - 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x1a, + 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x51, 0x0a, 0x06, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x1a, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x31, 0x38, 0x2e, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x22, 0x00, 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x31, 0x38, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/go.mod b/go.mod index f6e2aa0f0..48e457a88 100644 --- a/go.mod +++ b/go.mod @@ -124,9 +124,10 @@ require ( github.com/walle/lll v1.0.1 // indirect github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f github.com/xwb1989/sqlparser v0.0.0-20171128062118-da747e0c62c4 + github.com/zeebo/blake3 v0.1.1 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 golang.org/x/net v0.0.0-20200202094626-16171245cfb2 - golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f + golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc golang.org/x/text v0.3.2 google.golang.org/appengine v1.5.0 google.golang.org/grpc v1.36.0 diff --git a/go.sum b/go.sum index fd701e0e2..b85e7cdbb 100644 --- a/go.sum +++ b/go.sum @@ -72,9 +72,11 @@ github.com/bluele/slack v0.0.0-20180528010058-b4b4d354a079 h1:dm7wU6Dyf+rVGryOAB github.com/bluele/slack v0.0.0-20180528010058-b4b4d354a079/go.mod h1:W679Ri2W93VLD8cVpEY/zLH1ow4zhJcCyjzrKxfM3QM= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d h1:7IjN4QP3c38xhg6wz8R3YjoU+6S9e7xBc0DAVLLIpHE= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/codegangsta/negroni v0.3.0 h1:ByBtJaE0u71x6Ebli7lm95c8oCkrmF88+s5qB2o6j8I= github.com/codegangsta/negroni v0.3.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -116,6 +118,10 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05w github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evmar/gocairo v0.0.0-20160222165215-ddd30f837497/go.mod h1:YXKUYPSqs+jDG8mvexHN2uTik4PKwg2B0WK9itQ0VrE= @@ -170,6 +176,15 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/gonum/blas v0.0.0-20180125090452-e7c5890b24cf h1:ukIp7SJ4RNEkyqdn8EZDzUTOsqWUbHnwPGU3d8pc7ok= github.com/gonum/blas v0.0.0-20180125090452-e7c5890b24cf/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= github.com/gonum/floats v0.0.0-20180125090339-7de1f4ea7ab5 h1:YEwYZI2QOW/49JC7hb5X5irk1J4BJc6Q37OnahdSuek= @@ -185,6 +200,10 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -194,6 +213,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= @@ -312,6 +332,8 @@ github.com/mattn/go-runewidth v0.0.0-20170510074858-97311d9f7767 h1:Nk2R0tWpD2Rd github.com/mattn/go-runewidth v0.0.0-20170510074858-97311d9f7767/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/micro/go-log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= github.com/micro/go-log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= @@ -387,6 +409,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -461,6 +484,7 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU= @@ -473,6 +497,10 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xwb1989/sqlparser v0.0.0-20171128062118-da747e0c62c4 h1:w96oitIHwAbUymu2zUSla/82gOKNzpJYkFdwCHE/UOA= github.com/xwb1989/sqlparser v0.0.0-20171128062118-da747e0c62c4/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.1.1 h1:Nbsts7DdKThRHHd+YNlqiGlRqGEF2bE2eXN+xQ1hsEs= +github.com/zeebo/blake3 v0.1.1/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4= +github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -497,7 +525,9 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -511,6 +541,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -544,6 +575,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc h1:HVFDs9bKvTxP6bh1Rj9MCSo+UmafQtI8ZWDPVwVk9g4= +golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54 h1:a5WocgxWTnjG0C4hZblDx+yonFbQMMbv8yJGhHMz/nY= golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -561,18 +594,45 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -608,6 +668,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= diff --git a/signal18/config_store/v1/config.proto b/signal18/config_store/v1/config.proto index 97fc2abb9..c102237c9 100644 --- a/signal18/config_store/v1/config.proto +++ b/signal18/config_store/v1/config.proto @@ -27,6 +27,7 @@ message Property { string namespace = 3; Environment environment = 4; repeated string section = 5; + bool secret = 6; int64 revision = 10; string version = 11; @@ -39,6 +40,7 @@ message Property { message Value { string data = 1; Type type = 2; + string checksum = 3; // used to prevent restoring encrypted values } message Query { From 908d5a1255569128d8ce56caa45e0f8512d587cb Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Tue, 27 Apr 2021 00:03:05 +0200 Subject: [PATCH 5/7] Double hash to prevent rainbow table attack, also store only 8 bytes of the hash as more is not needed for a checksum. We want to prevent unneeded revisions, not increased security there. --- config_store/config.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config_store/config.go b/config_store/config.go index a9da8df04..8d3dc730c 100644 --- a/config_store/config.go +++ b/config_store/config.go @@ -87,7 +87,8 @@ func (p *Property) Decrypt(key []byte) error { func (v *Value) checksum() { data := []byte(v.Data) chk := blake3.Sum256(data) - v.Checksum = string(hex.EncodeToString(chk[:])) + double := blake3.Sum256(chk[:]) + v.Checksum = string(hex.EncodeToString(double[:8])) } // Encrypt takes the Data inside the Value and encrypts it with the supplied key From 38ad2ec3126b1946102fffe01136f57c2c8911a6 Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Tue, 27 Apr 2021 00:54:02 +0200 Subject: [PATCH 6/7] Replace blake3 hash with argon2 password func --- config_store/config.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/config_store/config.go b/config_store/config.go index 8d3dc730c..52199b13f 100644 --- a/config_store/config.go +++ b/config_store/config.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/zeebo/blake3" + "golang.org/x/crypto/argon2" timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) @@ -84,18 +84,17 @@ func (p *Property) Decrypt(key []byte) error { return nil } -func (v *Value) checksum() { +func (v *Value) argon2(salt []byte) { data := []byte(v.Data) - chk := blake3.Sum256(data) - double := blake3.Sum256(chk[:]) - v.Checksum = string(hex.EncodeToString(double[:8])) + hash := argon2.IDKey(data, salt, 1, 64*1024, 1, 32) + v.Checksum = hex.EncodeToString(hash) } // Encrypt takes the Data inside the Value and encrypts it with the supplied key // it is encoded in hex to be able to store it as a string func (v *Value) Encrypt(key []byte) error { data := []byte(v.Data) - v.checksum() + v.argon2(key) blockCipher, err := aes.NewCipher(key) if err != nil { From 9dfd121ca22801056de48f5658a05941342931c9 Mon Sep 17 00:00:00 2001 From: Yorick Terweijden Date: Sat, 5 Jun 2021 17:39:04 +0200 Subject: [PATCH 7/7] Updates --- .vscode/launch.json | 2 +- cmd/config_store-client/main.go | 8 +++++--- config_store/client.go | 28 ++++++++++++++++++++++++++++ config_store/config.go | 4 ++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 01e62f603..cf23c199b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "args": ["monitor", "--config", "/etc/replication-manager/config.toml", "--log-file", "/var/lib/replication-manager/data/replication-manager.log"], }, { - "name": "config_store", + "name": "config_store server", "type": "go", "request": "launch", "mode": "auto", diff --git a/cmd/config_store-client/main.go b/cmd/config_store-client/main.go index 2284c77c5..82940ed7f 100644 --- a/cmd/config_store-client/main.go +++ b/cmd/config_store-client/main.go @@ -25,11 +25,13 @@ func main() { log.Fatalf("Could not import TOML config: %s", err) } + mySQLSection := csc.Section("mysql") + props := make([]*cs.Property, 0) - props = append(props, csc.NewProperty([]string{"foo", "baz"}, "client-test", "foo", "foo-2")) - props = append(props, csc.NewProperty([]string{"bar-section"}, "client-test", "bar", "value1", "value20")) + props = append(props, mySQLSection.NewProperty("client-test", "foo", "foo-2")) + props = append(props, mySQLSection.NewProperty("client-test", "bar", "value1", "value20")) - password, err := csc.NewSecret([]string{"secrets"}, "cluster", "rootpassword", "somesecretpassword") + password, err := mySQLSection.NewSecret("cluster", "rootpassword", "somesecretpassword") if err != nil { log.Fatalf("Could not create secret") } diff --git a/config_store/client.go b/config_store/client.go index 6dd19ab32..d267a0789 100644 --- a/config_store/client.go +++ b/config_store/client.go @@ -41,6 +41,20 @@ func NewConfigStore(address string, env Environment) *ConfigStore { return csc } +type ConfigSection struct { + csc *ConfigStore + section []string +} + +func (csc *ConfigStore) Section(name ...string) *ConfigSection { + cs := &ConfigSection{ + csc: csc, + section: name, + } + + return cs +} + func GenerateKey() ([]byte, error) { key := make([]byte, 32) _, err := rand.Read(key) @@ -86,6 +100,14 @@ func (csc *ConfigStore) NewSecret(section []string, namespace string, key string return p, nil } +func (cs *ConfigSection) NewProperty(namespace string, key string, values ...interface{}) *Property { + return cs.csc.NewProperty(cs.section, namespace, key, values...) +} + +func (cs *ConfigSection) NewSecret(namespace string, key string, values ...interface{}) (*Property, error) { + return cs.csc.NewSecret(cs.section, namespace, key, values...) +} + func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*Property, error) { client := NewConfigStoreClient(csc.conn) clientDeadline := time.Now().Add(time.Duration(30) * time.Second) @@ -134,6 +156,12 @@ func (csc *ConfigStore) Store(ctx context.Context, properties []*Property) ([]*P return responses, nil } +func (cs *ConfigSection) Search(ctx context.Context, query *Query) ([]*Property, error) { + query.Property.Section = cs.section + + return cs.csc.Search(ctx, query) +} + func (csc *ConfigStore) Search(ctx context.Context, query *Query) ([]*Property, error) { client := NewConfigStoreClient(csc.conn) listClient, err := client.Search(ctx, query) diff --git a/config_store/config.go b/config_store/config.go index 52199b13f..059470fde 100644 --- a/config_store/config.go +++ b/config_store/config.go @@ -58,6 +58,10 @@ func ValuesEqual(a []*Value, b []*Value) bool { return true } +func (p *Property) SetNamespace(namespace string) { + p.Namespace = namespace +} + func (p *Property) SetSecret(b bool) { p.Secret = b }