From f4ad22b247805fd8688192a09dea5870e0a30670 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 15 Sep 2020 15:20:49 -0400 Subject: [PATCH] Move default port to a TCP target attribute (#361) --- api/internal/genapi/input.go | 5 + api/targets/option.gen.go | 32 +++- api/targets/target.gen.go | 24 +-- api/targets/tcp_target_attributes.gen.go | 6 + internal/cmd/commands/targets/funcs.go | 33 ++++- internal/cmd/commands/targets/tcp.go | 4 +- internal/gen/controller.swagger.json | 7 +- .../api/resources/targets/target.pb.go | 138 +++++++++++++----- .../api/resources/targets/v1/target.proto | 8 +- .../storage/target/store/v1/target.proto | 2 +- .../controller/handlers/subtypes_test.go | 18 ++- .../handlers/targets/target_service.go | 75 +++++++--- .../handlers/targets/target_service_test.go | 57 +++++--- internal/target/store/target.pb.go | 22 +-- internal/target/subtype.go | 41 ++++++ 15 files changed, 358 insertions(+), 114 deletions(-) create mode 100644 api/targets/tcp_target_attributes.gen.go create mode 100644 internal/target/subtype.go diff --git a/api/internal/genapi/input.go b/api/internal/genapi/input.go index f81cfb388..298b9c047 100644 --- a/api/internal/genapi/input.go +++ b/api/internal/genapi/input.go @@ -342,4 +342,9 @@ var inputStructs = []*structInfo{ typeOnCreate: true, createResponseTypes: true, }, + { + inProto: &targets.TcpTargetAttributes{}, + outFile: "targets/tcp_target_attributes.gen.go", + subtypeName: "TcpTarget", + }, } diff --git a/api/targets/option.gen.go b/api/targets/option.gen.go index 460cc54a0..1733b7040 100644 --- a/api/targets/option.gen.go +++ b/api/targets/option.gen.go @@ -45,15 +45,39 @@ func WithAutomaticVersioning(enable bool) Option { } } -func WithDefaultPort(inDefaultPort uint32) Option { +func WithAttributes(inAttributes map[string]interface{}) Option { return func(o *options) { - o.postMap["default_port"] = inDefaultPort + o.postMap["attributes"] = inAttributes } } -func DefaultDefaultPort() Option { +func DefaultAttributes() Option { return func(o *options) { - o.postMap["default_port"] = nil + o.postMap["attributes"] = nil + } +} + +func WithTcpTargetDefaultPort(inDefaultPort uint32) Option { + return func(o *options) { + raw, ok := o.postMap["attributes"] + if !ok { + raw = interface{}(map[string]interface{}{}) + } + val := raw.(map[string]interface{}) + val["default_port"] = inDefaultPort + o.postMap["attributes"] = val + } +} + +func DefaultTcpTargetDefaultPort() Option { + return func(o *options) { + raw, ok := o.postMap["attributes"] + if !ok { + raw = interface{}(map[string]interface{}{}) + } + val := raw.(map[string]interface{}) + val["default_port"] = nil + o.postMap["attributes"] = val } } diff --git a/api/targets/target.gen.go b/api/targets/target.gen.go index f46510e87..840501072 100644 --- a/api/targets/target.gen.go +++ b/api/targets/target.gen.go @@ -16,18 +16,18 @@ import ( ) type Target struct { - Id string `json:"id,omitempty"` - ScopeId string `json:"scope_id,omitempty"` - Scope *scopes.ScopeInfo `json:"scope,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - CreatedTime time.Time `json:"created_time,omitempty"` - UpdatedTime time.Time `json:"updated_time,omitempty"` - Version uint32 `json:"version,omitempty"` - Type string `json:"type,omitempty"` - HostSetIds []string `json:"host_set_ids,omitempty"` - HostSets []*HostSet `json:"host_sets,omitempty"` - DefaultPort uint32 `json:"default_port,omitempty"` + Id string `json:"id,omitempty"` + ScopeId string `json:"scope_id,omitempty"` + Scope *scopes.ScopeInfo `json:"scope,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + CreatedTime time.Time `json:"created_time,omitempty"` + UpdatedTime time.Time `json:"updated_time,omitempty"` + Version uint32 `json:"version,omitempty"` + Type string `json:"type,omitempty"` + HostSetIds []string `json:"host_set_ids,omitempty"` + HostSets []*HostSet `json:"host_sets,omitempty"` + Attributes map[string]interface{} `json:"attributes,omitempty"` responseBody *bytes.Buffer responseMap map[string]interface{} diff --git a/api/targets/tcp_target_attributes.gen.go b/api/targets/tcp_target_attributes.gen.go new file mode 100644 index 000000000..f7918d6cc --- /dev/null +++ b/api/targets/tcp_target_attributes.gen.go @@ -0,0 +1,6 @@ +// Code generated by "make api"; DO NOT EDIT. +package targets + +type TcpTargetAttributes struct { + DefaultPort uint32 `json:"default_port,omitempty"` +} diff --git a/internal/cmd/commands/targets/funcs.go b/internal/cmd/commands/targets/funcs.go index 7c8e31070..888e00a2f 100644 --- a/internal/cmd/commands/targets/funcs.go +++ b/internal/cmd/commands/targets/funcs.go @@ -19,7 +19,6 @@ func generateTargetTableOutput(in *targets.Target) string { "Type": in.Type, "Created Time": in.CreatedTime.Local().Format(time.RFC3339), "Updated Time": in.UpdatedTime.Local().Format(time.RFC3339), - "Default Port": in.DefaultPort, } if in.Name != "" { @@ -35,6 +34,19 @@ func generateTargetTableOutput(in *targets.Target) string { maxLength = len(k) } } + if len(in.Attributes) > 0 { + for k, v := range in.Attributes { + if attributeMap[k] != "" { + in.Attributes[attributeMap[k]] = v + delete(in.Attributes, k) + } + } + for k := range in.Attributes { + if len(k) > maxLength { + maxLength = len(k) + } + } + } var hostSetMaps []map[string]interface{} if len(in.HostSets) > 0 { @@ -68,9 +80,24 @@ func generateTargetTableOutput(in *targets.Target) string { } } + if len(in.Attributes) > 0 { + if true { + ret = append(ret, + fmt.Sprintf(" Attributes: %s", ""), + ) + } + ret = append(ret, + base.WrapMap(4, maxLength, in.Attributes), + ) + } + return base.WrapForHelpText(ret) } +var attributeMap = map[string]string{ + "default_port": "Default Port", +} + func exampleOutput() string { in := &targets.Target{ Id: "ttcp_1234567890", @@ -95,7 +122,9 @@ func exampleOutput() string { HostCatalogId: "hcst_1234567890", }, }, - DefaultPort: 22, + Attributes: map[string]interface{}{ + "default_port": 22, + }, } return generateTargetTableOutput(in) } diff --git a/internal/cmd/commands/targets/tcp.go b/internal/cmd/commands/targets/tcp.go index 32afd87ad..e5c5985c2 100644 --- a/internal/cmd/commands/targets/tcp.go +++ b/internal/cmd/commands/targets/tcp.go @@ -138,14 +138,14 @@ func (c *TcpCommand) Run(args []string) int { switch c.flagDefaultPort { case "": case "null": - opts = append(opts, targets.DefaultDefaultPort()) + opts = append(opts, targets.DefaultTcpTargetDefaultPort()) default: port, err := strconv.ParseUint(c.flagDefaultPort, 10, 32) if err != nil { c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagDefaultPort, err)) return 1 } - opts = append(opts, targets.WithDefaultPort(uint32(port))) + opts = append(opts, targets.WithTcpTargetDefaultPort(uint32(port))) } targetClient := targets.NewClient(client) diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index 229c247f6..edba27f55 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -2931,10 +2931,9 @@ "description": "The host sets that make up this target.\nOutput only.", "readOnly": true }, - "default_port": { - "type": "integer", - "format": "int64", - "description": "The default port a target should use if present." + "attributes": { + "type": "object", + "description": "The attributes that are applied for the specific Target type." } }, "title": "Target contains all fields related to a Target resource" diff --git a/internal/gen/controller/api/resources/targets/target.pb.go b/internal/gen/controller/api/resources/targets/target.pb.go index 9c2a4692f..34a5c1008 100644 --- a/internal/gen/controller/api/resources/targets/target.pb.go +++ b/internal/gen/controller/api/resources/targets/target.pb.go @@ -8,7 +8,7 @@ package targets import ( proto "github.com/golang/protobuf/proto" - _ "github.com/golang/protobuf/ptypes/struct" + _struct "github.com/golang/protobuf/ptypes/struct" timestamp "github.com/golang/protobuf/ptypes/timestamp" wrappers "github.com/golang/protobuf/ptypes/wrappers" scopes "github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes" @@ -119,8 +119,8 @@ type Target struct { // The host sets that make up this target. // Output only. HostSets []*HostSet `protobuf:"bytes,110,rep,name=host_sets,json=hostSets,proto3" json:"host_sets,omitempty"` - // The default port a target should use if present. - DefaultPort *wrappers.UInt32Value `protobuf:"bytes,120,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty"` + // The attributes that are applied for the specific Target type. + Attributes *_struct.Struct `protobuf:"bytes,120,opt,name=attributes,proto3" json:"attributes,omitempty"` } func (x *Target) Reset() { @@ -232,7 +232,54 @@ func (x *Target) GetHostSets() []*HostSet { return nil } -func (x *Target) GetDefaultPort() *wrappers.UInt32Value { +func (x *Target) GetAttributes() *_struct.Struct { + if x != nil { + return x.Attributes + } + return nil +} + +type TcpTargetAttributes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DefaultPort *wrappers.UInt32Value `protobuf:"bytes,10,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty"` +} + +func (x *TcpTargetAttributes) Reset() { + *x = TcpTargetAttributes{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_targets_v1_target_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TcpTargetAttributes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TcpTargetAttributes) ProtoMessage() {} + +func (x *TcpTargetAttributes) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_targets_v1_target_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 TcpTargetAttributes.ProtoReflect.Descriptor instead. +func (*TcpTargetAttributes) Descriptor() ([]byte, []int) { + return file_controller_api_resources_targets_v1_target_proto_rawDescGZIP(), []int{2} +} + +func (x *TcpTargetAttributes) GetDefaultPort() *wrappers.UInt32Value { if x != nil { return x.DefaultPort } @@ -263,7 +310,7 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, - 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0xa6, 0x05, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x6c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0xff, 0x04, 0x0a, 0x06, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, @@ -299,19 +346,25 @@ var file_controller_api_resources_targets_v1_target_proto_rawDesc = []byte{ 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x52, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x64, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x23, 0xa0, 0xda, - 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1b, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, - 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x55, - 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x78, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x13, 0x54, 0x63, 0x70, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x6f, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0x2e, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x17, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, + 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x3b, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -326,28 +379,31 @@ func file_controller_api_resources_targets_v1_target_proto_rawDescGZIP() []byte return file_controller_api_resources_targets_v1_target_proto_rawDescData } -var file_controller_api_resources_targets_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_controller_api_resources_targets_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_controller_api_resources_targets_v1_target_proto_goTypes = []interface{}{ (*HostSet)(nil), // 0: controller.api.resources.targets.v1.HostSet (*Target)(nil), // 1: controller.api.resources.targets.v1.Target - (*scopes.ScopeInfo)(nil), // 2: controller.api.resources.scopes.v1.ScopeInfo - (*wrappers.StringValue)(nil), // 3: google.protobuf.StringValue - (*timestamp.Timestamp)(nil), // 4: google.protobuf.Timestamp - (*wrappers.UInt32Value)(nil), // 5: google.protobuf.UInt32Value + (*TcpTargetAttributes)(nil), // 2: controller.api.resources.targets.v1.TcpTargetAttributes + (*scopes.ScopeInfo)(nil), // 3: controller.api.resources.scopes.v1.ScopeInfo + (*wrappers.StringValue)(nil), // 4: google.protobuf.StringValue + (*timestamp.Timestamp)(nil), // 5: google.protobuf.Timestamp + (*_struct.Struct)(nil), // 6: google.protobuf.Struct + (*wrappers.UInt32Value)(nil), // 7: google.protobuf.UInt32Value } var file_controller_api_resources_targets_v1_target_proto_depIdxs = []int32{ - 2, // 0: controller.api.resources.targets.v1.Target.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 3, // 1: controller.api.resources.targets.v1.Target.name:type_name -> google.protobuf.StringValue - 3, // 2: controller.api.resources.targets.v1.Target.description:type_name -> google.protobuf.StringValue - 4, // 3: controller.api.resources.targets.v1.Target.created_time:type_name -> google.protobuf.Timestamp - 4, // 4: controller.api.resources.targets.v1.Target.updated_time:type_name -> google.protobuf.Timestamp + 3, // 0: controller.api.resources.targets.v1.Target.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 4, // 1: controller.api.resources.targets.v1.Target.name:type_name -> google.protobuf.StringValue + 4, // 2: controller.api.resources.targets.v1.Target.description:type_name -> google.protobuf.StringValue + 5, // 3: controller.api.resources.targets.v1.Target.created_time:type_name -> google.protobuf.Timestamp + 5, // 4: controller.api.resources.targets.v1.Target.updated_time:type_name -> google.protobuf.Timestamp 0, // 5: controller.api.resources.targets.v1.Target.host_sets:type_name -> controller.api.resources.targets.v1.HostSet - 5, // 6: controller.api.resources.targets.v1.Target.default_port:type_name -> google.protobuf.UInt32Value - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 6, // 6: controller.api.resources.targets.v1.Target.attributes:type_name -> google.protobuf.Struct + 7, // 7: controller.api.resources.targets.v1.TcpTargetAttributes.default_port:type_name -> google.protobuf.UInt32Value + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_controller_api_resources_targets_v1_target_proto_init() } @@ -380,6 +436,18 @@ func file_controller_api_resources_targets_v1_target_proto_init() { return nil } } + file_controller_api_resources_targets_v1_target_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TcpTargetAttributes); 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{ @@ -387,7 +455,7 @@ func file_controller_api_resources_targets_v1_target_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_api_resources_targets_v1_target_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 3, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/proto/local/controller/api/resources/targets/v1/target.proto b/internal/proto/local/controller/api/resources/targets/v1/target.proto index 01a87c3b7..022de406f 100644 --- a/internal/proto/local/controller/api/resources/targets/v1/target.proto +++ b/internal/proto/local/controller/api/resources/targets/v1/target.proto @@ -56,6 +56,10 @@ message Target { // Output only. repeated HostSet host_sets = 110; - // The default port a target should use if present. - google.protobuf.UInt32Value default_port = 120 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"default_port" that: "DefaultPort"}]; + // The attributes that are applied for the specific Target type. + google.protobuf.Struct attributes = 120 [(custom_options.v1.generate_sdk_option) = true]; } + +message TcpTargetAttributes { + google.protobuf.UInt32Value default_port = 10 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = {this:"attributes.default_port" that: "DefaultPort"}]; +} \ No newline at end of file diff --git a/internal/proto/local/controller/storage/target/store/v1/target.proto b/internal/proto/local/controller/storage/target/store/v1/target.proto index 5a92be31e..6332afcb0 100644 --- a/internal/proto/local/controller/storage/target/store/v1/target.proto +++ b/internal/proto/local/controller/storage/target/store/v1/target.proto @@ -100,6 +100,6 @@ message TcpTarget { // @inject_tag: `gorm:"default:null"` uint32 default_port = 80 [(custom_options.v1.mask_mapping) = { this: "DefaultPort" - that: "default_port" + that: "attributes.default_port" }]; } \ No newline at end of file diff --git a/internal/servers/controller/handlers/subtypes_test.go b/internal/servers/controller/handlers/subtypes_test.go index 593746096..d902d67c1 100644 --- a/internal/servers/controller/handlers/subtypes_test.go +++ b/internal/servers/controller/handlers/subtypes_test.go @@ -6,6 +6,8 @@ import ( structpb "github.com/golang/protobuf/ptypes/struct" "github.com/google/go-cmp/cmp" accountspb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/accounts" + hostspb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts" + targetspb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/targets" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/encoding/protojson" @@ -25,6 +27,16 @@ func TestStructToProtoToStruct(t *testing.T) { pb: &accountspb.PasswordAccountAttributes{LoginName: "testun", Password: &wrapperspb.StringValue{Value: "testpw"}}, wantJson: `{"login_name": "testun", "password": "testpw"}`, }, + { + name: "tcp", + pb: &targetspb.TcpTargetAttributes{DefaultPort: &wrapperspb.UInt32Value{Value: 22}}, + wantJson: `{"default_port": 22}`, + }, + { + name: "host", + pb: &hostspb.StaticHostAttributes{Address: &wrapperspb.StringValue{Value: "::1"}}, + wantJson: `{"address": "::1"}`, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -35,9 +47,9 @@ func TestStructToProtoToStruct(t *testing.T) { require.NoError(t, protojson.Unmarshal([]byte(tc.wantJson), wantStruct)) assert.Empty(t, cmp.Diff(wantStruct, st, protocmp.Transform())) - newPwAttr := tc.pb.ProtoReflect().New().Interface() - StructToProto(st, newPwAttr) - assert.Equal(t, tc.pb, newPwAttr) + newAttr := tc.pb.ProtoReflect().New().Interface() + StructToProto(st, newAttr) + assert.Equal(t, tc.pb, newAttr) }) } } diff --git a/internal/servers/controller/handlers/targets/target_service.go b/internal/servers/controller/handlers/targets/target_service.go index 264a0e41d..9bee5e0ee 100644 --- a/internal/servers/controller/handlers/targets/target_service.go +++ b/internal/servers/controller/handlers/targets/target_service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/golang/protobuf/ptypes/wrappers" "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/db" pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/targets" @@ -27,7 +28,7 @@ var ( func init() { var err error - if maskManager, err = handlers.NewMaskManager(&store.TcpTarget{}, &pb.Target{}); err != nil { + if maskManager, err = handlers.NewMaskManager(&store.TcpTarget{}, &pb.Target{}, &pb.TcpTargetAttributes{}); err != nil { panic(err) } } @@ -203,7 +204,7 @@ func (s Service) getFromRepo(ctx context.Context, id string) (*pb.Target, error) if u == nil { return nil, handlers.NotFoundErrorf("Target %q doesn't exist.", id) } - return toProto(u, m), nil + return toProto(u, m) } func (s Service) createInRepo(ctx context.Context, item *pb.Target) (*pb.Target, error) { @@ -211,8 +212,12 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (*pb.Target, if item.GetDescription() != nil { opts = append(opts, target.WithDescription(item.GetDescription().GetValue())) } - if item.GetDefaultPort().GetValue() != 0 { - opts = append(opts, target.WithDefaultPort(item.GetDefaultPort().GetValue())) + tcpAttrs := &pb.TcpTargetAttributes{} + if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Provided attributes don't match expected format.") + } + if tcpAttrs.GetDefaultPort().GetValue() != 0 { + opts = append(opts, target.WithDefaultPort(tcpAttrs.GetDefaultPort().GetValue())) } u, err := target.NewTcpTarget(item.GetScopeId(), opts...) if err != nil { @@ -229,7 +234,7 @@ func (s Service) createInRepo(ctx context.Context, item *pb.Target) (*pb.Target, if out == nil { return nil, status.Error(codes.Internal, "Unable to create target but no error returned from repository.") } - return toProto(out, m), nil + return toProto(out, m) } func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Target) (*pb.Target, error) { @@ -240,8 +245,13 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st if name := item.GetName(); name != nil { opts = append(opts, target.WithName(name.GetValue())) } - if item.GetDefaultPort().GetValue() != 0 { - opts = append(opts, target.WithDefaultPort(item.GetDefaultPort().GetValue())) + + tcpAttrs := &pb.TcpTargetAttributes{} + if err := handlers.StructToProto(item.GetAttributes(), tcpAttrs); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Provided attributes don't match expected format.") + } + if tcpAttrs.GetDefaultPort().GetValue() != 0 { + opts = append(opts, target.WithDefaultPort(tcpAttrs.GetDefaultPort().GetValue())) } version := item.GetVersion() u, err := target.NewTcpTarget(scopeId, opts...) @@ -264,7 +274,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st if rowsUpdated == 0 { return nil, handlers.NotFoundErrorf("Target %q doesn't exist.", id) } - return toProto(out, m), nil + return toProto(out, m) } func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { @@ -293,7 +303,11 @@ func (s Service) listFromRepo(ctx context.Context, scopeId string) ([]*pb.Target } var outUl []*pb.Target for _, u := range ul { - outUl = append(outUl, toProto(u, nil)) + o, err := toProto(u, nil) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to convert value to proto: %v.", err) + } + outUl = append(outUl, o) } return outUl, nil } @@ -310,7 +324,7 @@ func (s Service) addInRepo(ctx context.Context, targetId string, hostSetId []str if out == nil { return nil, status.Error(codes.Internal, "Unable to lookup target after adding host sets to it.") } - return toProto(out, m), nil + return toProto(out, m) } func (s Service) setInRepo(ctx context.Context, targetId string, hostSetIds []string, version uint32) (*pb.Target, error) { @@ -330,7 +344,7 @@ func (s Service) setInRepo(ctx context.Context, targetId string, hostSetIds []st if out == nil { return nil, status.Error(codes.Internal, "Unable to lookup target after setting host sets for it.") } - return toProto(out, m), nil + return toProto(out, m) } func (s Service) removeInRepo(ctx context.Context, targetId string, hostSetIds []string, version uint32) (*pb.Target, error) { @@ -349,7 +363,7 @@ func (s Service) removeInRepo(ctx context.Context, targetId string, hostSetIds [ if out == nil { return nil, status.Error(codes.Internal, "Unable to lookup target after removing host sets from it.") } - return toProto(out, m), nil + return toProto(out, m) } func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.VerifyResults { @@ -396,7 +410,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. return auth.Verify(ctx, opts...) } -func toProto(in target.Target, m []*target.TargetSet) *pb.Target { +func toProto(in target.Target, m []*target.TargetSet) (*pb.Target, error) { out := pb.Target{ Id: in.GetPublicId(), ScopeId: in.GetScopeId(), @@ -411,9 +425,15 @@ func toProto(in target.Target, m []*target.TargetSet) *pb.Target { if in.GetName() != "" { out.Name = wrapperspb.String(in.GetName()) } - if in.GetDefaultPort() != 0 { - out.DefaultPort = wrapperspb.UInt32(in.GetDefaultPort()) + attrs := &pb.TcpTargetAttributes{} + if in.GetDefaultPort() > 0 { + attrs.DefaultPort = &wrappers.UInt32Value{Value: in.GetDefaultPort()} } + st, err := handlers.ProtoToStruct(attrs) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed building password attribute struct: %v", err) + } + out.Attributes = st for _, hs := range m { out.HostSetIds = append(out.HostSetIds, hs.GetPublicId()) out.HostSets = append(out.HostSets, &pb.HostSet{ @@ -421,7 +441,7 @@ func toProto(in target.Target, m []*target.TargetSet) *pb.Target { HostCatalogId: hs.GetCatalogId(), }) } - return &out + return &out, nil } // A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce @@ -442,8 +462,15 @@ func validateCreateRequest(req *pbs.CreateTargetRequest) error { if req.GetItem().GetName() == nil || req.GetItem().GetName().GetValue() == "" { badFields["name"] = "This field is required." } - if req.GetItem().GetDefaultPort() != nil && req.GetItem().GetDefaultPort().GetValue() == 0 { - badFields["default_port"] = "This optional field cannot be set to 0." + switch target.SubtypeFromType(req.GetItem().GetType()) { + case target.TcpSubType: + tcpAttrs := &pb.TcpTargetAttributes{} + if err := handlers.StructToProto(req.GetItem().GetAttributes(), tcpAttrs); err != nil { + badFields["attributes"] = "Attribute fields do not match the expected format." + } + if tcpAttrs.GetDefaultPort() != nil && tcpAttrs.GetDefaultPort().GetValue() == 0 { + badFields["attributes.default_port"] = "This optional field cannot be set to 0." + } } switch req.GetItem().GetType() { case target.TcpTargetType.String(): @@ -462,8 +489,16 @@ func validateUpdateRequest(req *pbs.UpdateTargetRequest) error { if handlers.MaskContains(req.GetUpdateMask().GetPaths(), "name") && req.GetItem().GetName().GetValue() == "" { badFields["name"] = "This field cannot be set to empty." } - if req.GetItem().GetDefaultPort() != nil && req.GetItem().GetDefaultPort().GetValue() == 0 { - badFields["default_port"] = "This optional field cannot be set to 0." + switch target.SubtypeFromType(req.GetItem().GetType()) { + + case target.TcpSubType: + tcpAttrs := &pb.TcpTargetAttributes{} + if err := handlers.StructToProto(req.GetItem().GetAttributes(), tcpAttrs); err != nil { + badFields["attributes"] = "Attribute fields do not match the expected format." + } + if tcpAttrs.GetDefaultPort() != nil && tcpAttrs.GetDefaultPort().GetValue() == 0 { + badFields["attributes.default_port"] = "This optional field cannot be set to 0." + } } if req.GetItem().GetType() != "" { badFields["type"] = "This field cannot be updated." diff --git a/internal/servers/controller/handlers/targets/target_service_test.go b/internal/servers/controller/handlers/targets/target_service_test.go index dbbbc86f6..e9693b776 100644 --- a/internal/servers/controller/handlers/targets/target_service_test.go +++ b/internal/servers/controller/handlers/targets/target_service_test.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/wrapperspb" ) @@ -58,6 +59,7 @@ func TestGet(t *testing.T) { Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()}, Type: target.TcpTargetType.String(), HostSetIds: []string{hs[0].GetPublicId(), hs[1].GetPublicId()}, + Attributes: new(structpb.Struct), } for _, ihs := range hs { pTar.HostSets = append(pTar.HostSets, &pb.HostSet{Id: ihs.GetPublicId(), HostCatalogId: ihs.GetCatalogId()}) @@ -142,6 +144,7 @@ func TestList(t *testing.T) { UpdatedTime: tar.GetUpdateTime().GetTimestamp(), Version: tar.GetVersion(), Type: target.TcpTargetType.String(), + Attributes: new(structpb.Struct), }) } @@ -299,7 +302,9 @@ func TestCreate(t *testing.T) { Name: wrapperspb.String("name"), Description: wrapperspb.String("desc"), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, }}, res: &pbs.CreateTargetResponse{ Uri: fmt.Sprintf("targets/%s_", target.TcpTargetPrefix), @@ -309,7 +314,9 @@ func TestCreate(t *testing.T) { Name: wrapperspb.String("name"), Description: wrapperspb.String("desc"), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, }, }, errCode: codes.OK, @@ -320,7 +327,9 @@ func TestCreate(t *testing.T) { Name: wrapperspb.String("name"), Description: wrapperspb.String("desc"), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(0), + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(0), + }}, }}, errCode: codes.InvalidArgument, }, @@ -468,7 +477,9 @@ func TestUpdate(t *testing.T) { Name: wrapperspb.String("name"), Description: wrapperspb.String("desc"), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, CreatedTime: tar.GetCreateTime().GetTimestamp(), HostSetIds: hsIds, HostSets: hostSets, @@ -496,9 +507,11 @@ func TestUpdate(t *testing.T) { Description: wrapperspb.String("desc"), CreatedTime: tar.GetCreateTime().GetTimestamp(), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), - HostSetIds: hsIds, - HostSets: hostSets, + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, + HostSetIds: hsIds, + HostSets: hostSets, }, }, errCode: codes.OK, @@ -529,7 +542,9 @@ func TestUpdate(t *testing.T) { req: &pbs.UpdateTargetRequest{ UpdateMask: &field_mask.FieldMask{Paths: []string{"default_port"}}, Item: &pb.Target{ - DefaultPort: wrapperspb.UInt32(0), + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(0), + }}, }, }, errCode: codes.InvalidArgument, @@ -575,9 +590,11 @@ func TestUpdate(t *testing.T) { Name: wrapperspb.String("default"), CreatedTime: tar.GetCreateTime().GetTimestamp(), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), - HostSetIds: hsIds, - HostSets: hostSets, + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, + HostSetIds: hsIds, + HostSets: hostSets, }, }, errCode: codes.OK, @@ -602,9 +619,11 @@ func TestUpdate(t *testing.T) { Description: wrapperspb.String("default"), CreatedTime: tar.GetCreateTime().GetTimestamp(), Type: target.TcpTargetType.String(), - DefaultPort: wrapperspb.UInt32(2), - HostSetIds: hsIds, - HostSets: hostSets, + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, + HostSetIds: hsIds, + HostSets: hostSets, }, }, errCode: codes.OK, @@ -628,10 +647,12 @@ func TestUpdate(t *testing.T) { Name: wrapperspb.String("default"), Description: wrapperspb.String("notignored"), CreatedTime: tar.GetCreateTime().GetTimestamp(), - DefaultPort: wrapperspb.UInt32(2), - Type: target.TcpTargetType.String(), - HostSetIds: hsIds, - HostSets: hostSets, + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "default_port": structpb.NewNumberValue(2), + }}, + Type: target.TcpTargetType.String(), + HostSetIds: hsIds, + HostSets: hostSets, }, }, errCode: codes.OK, diff --git a/internal/target/store/target.pb.go b/internal/target/store/target.pb.go index ad3240b9d..ceb700e26 100644 --- a/internal/target/store/target.pb.go +++ b/internal/target/store/target.pb.go @@ -395,7 +395,7 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xa3, 0x03, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xae, 0x03, 0x0a, 0x09, 0x54, 0x63, 0x70, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, @@ -417,16 +417,16 @@ var file_controller_storage_target_store_v1_target_proto_rawDesc = []byte{ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x1f, - 0xc2, 0xdd, 0x29, 0x1b, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, - 0x74, 0x12, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, - 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x3b, 0x5a, 0x39, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, + 0xc2, 0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, + 0x74, 0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/target/subtype.go b/internal/target/subtype.go new file mode 100644 index 000000000..e95389d9a --- /dev/null +++ b/internal/target/subtype.go @@ -0,0 +1,41 @@ +package target + +import ( + "strings" +) + +type SubType int + +const ( + UnknownSubtype SubType = iota + TcpSubType +) + +func (t SubType) String() string { + switch t { + case TcpSubType: + return "tcp" + } + return "unknown" +} + +// SubtypeFromType converts a string to a SubType. +// returns UnknownSubtype if no SubType with that name is found. +func SubtypeFromType(t string) SubType { + switch { + case strings.EqualFold(strings.TrimSpace(t), TcpSubType.String()): + return TcpSubType + } + return UnknownSubtype +} + +// SubtypeFromId takes any public id in the target subsystem and uses the prefix to determine +// what subtype the id is for. +// Returns UnknownSubtype if no SubType with this id's prefix is found. +func SubtypeFromId(id string) SubType { + switch { + case strings.HasPrefix(strings.TrimSpace(id), TcpTargetPrefix): + return TcpSubType + } + return UnknownSubtype +}