From 7f3133299cdf00498f5f12227afcf9ce470761ae Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 1 Jun 2023 00:41:41 +0200 Subject: [PATCH] fully migrate DNS to proto --- pkg/roles/dns/record.go | 10 +- pkg/roles/dns/role.go | 2 +- pkg/roles/dns/role_config.go | 23 ++-- pkg/roles/dns/role_config_test.go | 3 +- pkg/roles/dns/role_test.go | 3 +- pkg/roles/dns/types/role_dns_config.pb.go | 143 ++++++++++++++++++++++ pkg/roles/dns/zone.go | 10 +- pkg/storage/utils.go | 23 ++++ protobuf/role_dns_config.proto | 7 ++ 9 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 pkg/roles/dns/types/role_dns_config.pb.go create mode 100644 pkg/storage/utils.go create mode 100644 protobuf/role_dns_config.proto diff --git a/pkg/roles/dns/record.go b/pkg/roles/dns/record.go index a4a79c138..2895ab4dc 100644 --- a/pkg/roles/dns/record.go +++ b/pkg/roles/dns/record.go @@ -2,12 +2,12 @@ package dns import ( "context" - "encoding/json" "net" "strings" "beryju.io/gravity/pkg/roles" "beryju.io/gravity/pkg/roles/dns/types" + "beryju.io/gravity/pkg/storage" "github.com/miekg/dns" "go.etcd.io/etcd/api/v3/mvccpb" clientv3 "go.etcd.io/etcd/client/v3" @@ -43,13 +43,7 @@ func (z *ZoneContext) recordFromKV(kv *mvccpb.KeyValue) (*RecordContext, error) } rec.recordKey = strings.TrimSuffix(fullRecordKey, "/"+rec.uid) - // Try loading protobuf first - err := proto.Unmarshal(kv.Value, rec.Record) - if err == nil { - return rec, nil - } - // Otherwise try json - err = json.Unmarshal(kv.Value, &rec) + _, err := storage.Parse(kv.Value, rec.Record) if err != nil { return rec, err } diff --git a/pkg/roles/dns/role.go b/pkg/roles/dns/role.go index 091e020c4..807459a55 100644 --- a/pkg/roles/dns/role.go +++ b/pkg/roles/dns/role.go @@ -24,7 +24,7 @@ type Role struct { ctx context.Context zones map[string]*ZoneContext - cfg *RoleConfig + cfg *types.RoleConfig log *zap.Logger servers []*dns.Server zonesM sync.RWMutex diff --git a/pkg/roles/dns/role_config.go b/pkg/roles/dns/role_config.go index bbf9e7f4a..65de2e409 100644 --- a/pkg/roles/dns/role_config.go +++ b/pkg/roles/dns/role_config.go @@ -2,41 +2,38 @@ package dns import ( "context" - "encoding/json" instanceTypes "beryju.io/gravity/pkg/instance/types" + "beryju.io/gravity/pkg/storage" "go.uber.org/zap" + "google.golang.org/protobuf/proto" "beryju.io/gravity/pkg/roles/dns/types" "github.com/swaggest/usecase" "github.com/swaggest/usecase/status" ) -type RoleConfig struct { - Port int32 `json:"port"` -} - -func (r *Role) decodeRoleConfig(raw []byte) *RoleConfig { - def := RoleConfig{ +func (r *Role) decodeRoleConfig(raw []byte) *types.RoleConfig { + def := types.RoleConfig{ Port: 53, } if len(raw) < 1 { return &def } - err := json.Unmarshal(raw, &def) + conf, err := storage.Parse(raw, &def) if err != nil { r.log.Warn("failed to decode role config", zap.Error(err)) } - return &def + return conf } type APIRoleConfigOutput struct { - Config RoleConfig `json:"config" required:"true"` + Config *types.RoleConfig `json:"config" required:"true"` } func (r *Role) APIRoleConfigGet() usecase.Interactor { u := usecase.NewInteractor(func(ctx context.Context, input struct{}, output *APIRoleConfigOutput) error { - output.Config = *r.cfg + output.Config = r.cfg return nil }) u.SetName("dns.get_role_config") @@ -46,12 +43,12 @@ func (r *Role) APIRoleConfigGet() usecase.Interactor { } type APIRoleConfigInput struct { - Config RoleConfig `json:"config" required:"true"` + Config *types.RoleConfig `json:"config" required:"true"` } func (r *Role) APIRoleConfigPut() usecase.Interactor { u := usecase.NewInteractor(func(ctx context.Context, input APIRoleConfigInput, output *struct{}) error { - jc, err := json.Marshal(input.Config) + jc, err := proto.Marshal(input.Config) if err != nil { return status.Wrap(err, status.InvalidArgument) } diff --git a/pkg/roles/dns/role_config_test.go b/pkg/roles/dns/role_config_test.go index 6a20a4c77..dad7ba02b 100644 --- a/pkg/roles/dns/role_config_test.go +++ b/pkg/roles/dns/role_config_test.go @@ -5,6 +5,7 @@ import ( "beryju.io/gravity/pkg/instance" "beryju.io/gravity/pkg/roles/dns" + "beryju.io/gravity/pkg/roles/dns/types" "beryju.io/gravity/pkg/tests" "github.com/stretchr/testify/assert" ) @@ -31,7 +32,7 @@ func TestAPIRoleConfigPut(t *testing.T) { defer role.Stop() assert.NoError(t, role.APIRoleConfigPut().Interact(ctx, dns.APIRoleConfigInput{ - Config: dns.RoleConfig{ + Config: &types.RoleConfig{ Port: 1054, }, }, &struct{}{})) diff --git a/pkg/roles/dns/role_test.go b/pkg/roles/dns/role_test.go index 70b3ae867..9bdba03b4 100644 --- a/pkg/roles/dns/role_test.go +++ b/pkg/roles/dns/role_test.go @@ -5,12 +5,13 @@ import ( "beryju.io/gravity/pkg/instance" "beryju.io/gravity/pkg/roles/dns" + "beryju.io/gravity/pkg/roles/dns/types" "beryju.io/gravity/pkg/tests" "github.com/stretchr/testify/assert" ) func RoleConfig() []byte { - return []byte(tests.MustJSON(dns.RoleConfig{ + return []byte(tests.MustPB(&types.RoleConfig{ Port: 1054, })) } diff --git a/pkg/roles/dns/types/role_dns_config.pb.go b/pkg/roles/dns/types/role_dns_config.pb.go new file mode 100644 index 000000000..63f66a76e --- /dev/null +++ b/pkg/roles/dns/types/role_dns_config.pb.go @@ -0,0 +1,143 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: protobuf/role_dns_config.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 RoleConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Port int32 `protobuf:"varint,1,opt,name=port,proto3" json:"port,omitempty"` +} + +func (x *RoleConfig) Reset() { + *x = RoleConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_protobuf_role_dns_config_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoleConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoleConfig) ProtoMessage() {} + +func (x *RoleConfig) ProtoReflect() protoreflect.Message { + mi := &file_protobuf_role_dns_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 RoleConfig.ProtoReflect.Descriptor instead. +func (*RoleConfig) Descriptor() ([]byte, []int) { + return file_protobuf_role_dns_config_proto_rawDescGZIP(), []int{0} +} + +func (x *RoleConfig) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +var File_protobuf_role_dns_config_proto protoreflect.FileDescriptor + +var file_protobuf_role_dns_config_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, + 0x64, 0x6e, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0x20, 0x0a, 0x0a, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x42, 0x15, 0x5a, 0x13, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x2f, + 0x64, 0x6e, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_protobuf_role_dns_config_proto_rawDescOnce sync.Once + file_protobuf_role_dns_config_proto_rawDescData = file_protobuf_role_dns_config_proto_rawDesc +) + +func file_protobuf_role_dns_config_proto_rawDescGZIP() []byte { + file_protobuf_role_dns_config_proto_rawDescOnce.Do(func() { + file_protobuf_role_dns_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_protobuf_role_dns_config_proto_rawDescData) + }) + return file_protobuf_role_dns_config_proto_rawDescData +} + +var file_protobuf_role_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_protobuf_role_dns_config_proto_goTypes = []interface{}{ + (*RoleConfig)(nil), // 0: RoleConfig +} +var file_protobuf_role_dns_config_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_protobuf_role_dns_config_proto_init() } +func file_protobuf_role_dns_config_proto_init() { + if File_protobuf_role_dns_config_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_protobuf_role_dns_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RoleConfig); 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_protobuf_role_dns_config_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_protobuf_role_dns_config_proto_goTypes, + DependencyIndexes: file_protobuf_role_dns_config_proto_depIdxs, + MessageInfos: file_protobuf_role_dns_config_proto_msgTypes, + }.Build() + File_protobuf_role_dns_config_proto = out.File + file_protobuf_role_dns_config_proto_rawDesc = nil + file_protobuf_role_dns_config_proto_goTypes = nil + file_protobuf_role_dns_config_proto_depIdxs = nil +} diff --git a/pkg/roles/dns/zone.go b/pkg/roles/dns/zone.go index bc38f37d2..7494ce120 100644 --- a/pkg/roles/dns/zone.go +++ b/pkg/roles/dns/zone.go @@ -2,7 +2,6 @@ package dns import ( "context" - "encoding/json" "fmt" "strings" "sync" @@ -12,6 +11,7 @@ import ( "beryju.io/gravity/pkg/roles/dns/types" "beryju.io/gravity/pkg/roles/dns/utils" tsdbTypes "beryju.io/gravity/pkg/roles/tsdb/types" + "beryju.io/gravity/pkg/storage" "github.com/getsentry/sentry-go" "github.com/miekg/dns" "go.etcd.io/etcd/api/v3/mvccpb" @@ -139,13 +139,7 @@ func (r *Role) zoneFromKV(raw *mvccpb.KeyValue) (*ZoneContext, error) { z.log = r.log.With(zap.String("zone", name)) z.etcdKey = string(raw.Key) - // Try loading protobuf first - err := proto.Unmarshal(raw.Value, z.Zone) - if err == nil { - return z, nil - } - // Otherwise try json - err = json.Unmarshal(raw.Value, &z) + _, err := storage.Parse(raw.Value, z.Zone) if err != nil { return nil, err } diff --git a/pkg/storage/utils.go b/pkg/storage/utils.go new file mode 100644 index 000000000..4dc00be44 --- /dev/null +++ b/pkg/storage/utils.go @@ -0,0 +1,23 @@ +package storage + +import ( + "encoding/json" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +// Parse Attempt to parse data as protobuf first, otherwise try json +func Parse[T protoreflect.ProtoMessage](raw []byte, v T) (T, error) { + // Try loading protobuf first + err := proto.Unmarshal(raw, v) + if err == nil { + return v, nil + } + // Otherwise try json + err = json.Unmarshal(raw, &v) + if err == nil { + return v, nil + } + return v, err +} diff --git a/protobuf/role_dns_config.proto b/protobuf/role_dns_config.proto new file mode 100644 index 000000000..0196fdab8 --- /dev/null +++ b/protobuf/role_dns_config.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +option go_package = "pkg/roles/dns/types"; + +message RoleConfig { + int32 port = 1; +}