Add active session count to the worker (#2145)
This commit is contained in:
9 files changed
+167
-79
No files matched your search
@@ -81,4 +81,5 @@ const (
|
||||
ConfigurationField = "configuration"
|
||||
WorkerAuthTokenField = "worker_auth_token"
|
||||
WorkerConfigField = "worker_config"
|
||||
ActiveConnectionCountField = "active_session_count"
|
||||
)
|
||||
@@ -462,6 +462,9 @@ func toProto(ctx context.Context, in *servers.Worker, opt ...handlers.Option) (*
|
||||
if outputFields.Has(globals.LastStatusTimeField) {
|
||||
out.LastStatusTime = in.GetLastStatusTime().GetTimestamp()
|
||||
}
|
||||
if outputFields.Has(globals.ActiveConnectionCountField) {
|
||||
out.ActiveConnectionCount = in.ActiveConnectionCount()
|
||||
}
|
||||
if outputFields.Has(globals.CanonicalTagsField) && len(in.CanonicalTags()) > 0 {
|
||||
var err error
|
||||
out.CanonicalTags, err = tagsToMapProto(in.CanonicalTags())
|
||||
|
||||
@@ -150,41 +150,6 @@ create table server_worker_tag (
|
||||
primary key(worker_id, key, value, source)
|
||||
);
|
||||
|
||||
-- worker_aggregate view allows the worker and configuration to be read at the
|
||||
-- same time.
|
||||
create view server_worker_aggregate as
|
||||
with worker_config_tags(worker_id, source, tags) as (
|
||||
select
|
||||
ct.worker_id,
|
||||
ct.source,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
string_agg(distinct concat_ws('Y', ct.key, ct.value), 'Z') as tags
|
||||
from server_worker_tag ct
|
||||
group by ct.worker_id, ct.source
|
||||
)
|
||||
select
|
||||
w.public_id,
|
||||
w.scope_id,
|
||||
w.description,
|
||||
w.name,
|
||||
w.address,
|
||||
w.create_time,
|
||||
w.update_time,
|
||||
w.version,
|
||||
w.worker_reported_name,
|
||||
w.worker_reported_address,
|
||||
w.last_status_time,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
wt.tags as api_tags,
|
||||
ct.tags as worker_config_tags
|
||||
from server_worker w
|
||||
left join worker_config_tags wt on
|
||||
w.public_id = wt.worker_id and wt.source = 'api'
|
||||
left join worker_config_tags ct on
|
||||
w.public_id = ct.worker_id and ct.source = 'configuration';
|
||||
comment on view server_worker_aggregate is
|
||||
'server_worker_aggregate contains the worker resource with its worker provided config values and its configuration and api provided tags.';
|
||||
|
||||
|
||||
-- Aaand drop server_tag
|
||||
drop table server_tag;
|
||||
@@ -245,26 +210,6 @@ set
|
||||
where
|
||||
status = 'running';
|
||||
|
||||
|
||||
-- Replaces the view created in 9/01.
|
||||
-- Remove the worker id from this view. In actuality this is almost a no-op
|
||||
-- because no server information was ever getting populated here due to a bug
|
||||
-- in the update mask when updating a session at the time we activate a session.
|
||||
create view session_list as
|
||||
select
|
||||
s.public_id, s.user_id, s.host_id, s.target_id,
|
||||
s.host_set_id, s.auth_token_id, s.scope_id, s.certificate,s.expiration_time,
|
||||
s.connection_limit, s.tofu_token, s.key_id, s.termination_reason, s.version,
|
||||
s.create_time, s.update_time, s.endpoint, s.worker_filter,
|
||||
ss.state, ss.previous_end_time, ss.start_time, ss.end_time, sc.public_id as connection_id,
|
||||
sc.client_tcp_address, sc.client_tcp_port, sc.endpoint_tcp_address, sc.endpoint_tcp_port,
|
||||
sc.bytes_up, sc.bytes_down, sc.closed_reason
|
||||
from session s
|
||||
join session_state ss on
|
||||
s.public_id = ss.session_id
|
||||
left join session_connection sc on
|
||||
s.public_id = sc.session_id;
|
||||
|
||||
-- Drop the server and server_type_enm tables
|
||||
drop table server;
|
||||
drop table server_type_enm;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
begin;
|
||||
|
||||
-- worker_aggregate view allows the worker and configuration to be read at the
|
||||
-- same time.
|
||||
create view server_worker_aggregate as
|
||||
with worker_config_tags(worker_id, source, tags) as (
|
||||
select
|
||||
ct.worker_id,
|
||||
ct.source,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
string_agg(distinct concat_ws('Y', ct.key, ct.value), 'Z') as tags
|
||||
from server_worker_tag ct
|
||||
group by ct.worker_id, ct.source
|
||||
),
|
||||
connection_count (worker_id, count) as (
|
||||
select
|
||||
worker_id,
|
||||
count(1) as count
|
||||
from session_connection
|
||||
where closed_reason is null
|
||||
group by worker_id
|
||||
)
|
||||
select
|
||||
w.public_id,
|
||||
w.scope_id,
|
||||
w.description,
|
||||
w.name,
|
||||
w.address,
|
||||
w.create_time,
|
||||
w.update_time,
|
||||
w.version,
|
||||
w.worker_reported_name,
|
||||
w.worker_reported_address,
|
||||
w.last_status_time,
|
||||
cc.count as active_connection_count,
|
||||
-- keys and tags can be any lowercase printable character so use uppercase characters as delimitors.
|
||||
wt.tags as api_tags,
|
||||
ct.tags as worker_config_tags
|
||||
from server_worker w
|
||||
left join worker_config_tags wt on
|
||||
w.public_id = wt.worker_id and wt.source = 'api'
|
||||
left join worker_config_tags ct on
|
||||
w.public_id = ct.worker_id and ct.source = 'configuration'
|
||||
left join connection_count as cc on
|
||||
w.public_id = cc.worker_id;
|
||||
comment on view server_worker_aggregate is
|
||||
'server_worker_aggregate contains the worker resource with its worker provided config values and its configuration and api provided tags.';
|
||||
|
||||
|
||||
-- Replaces the view created in 9/01.
|
||||
-- Remove the worker id from this view. In actuality this is almost a no-op
|
||||
-- because no server information was ever getting populated here due to a bug
|
||||
-- in the update mask when updating a session at the time we activate a session.
|
||||
create view session_list as
|
||||
select
|
||||
s.public_id, s.user_id, s.host_id, s.target_id,
|
||||
s.host_set_id, s.auth_token_id, s.scope_id, s.certificate,s.expiration_time,
|
||||
s.connection_limit, s.tofu_token, s.key_id, s.termination_reason, s.version,
|
||||
s.create_time, s.update_time, s.endpoint, s.worker_filter,
|
||||
ss.state, ss.previous_end_time, ss.start_time, ss.end_time, sc.public_id as connection_id,
|
||||
sc.client_tcp_address, sc.client_tcp_port, sc.endpoint_tcp_address, sc.endpoint_tcp_port,
|
||||
sc.bytes_up, sc.bytes_down, sc.closed_reason
|
||||
from session s
|
||||
join session_state ss on
|
||||
s.public_id = ss.session_id
|
||||
left join session_connection sc on
|
||||
s.public_id = sc.session_id;
|
||||
|
||||
commit;
|
||||
@@ -5586,6 +5586,12 @@
|
||||
"type": "string",
|
||||
"title": "worker_auth_token is input only. Supports the worker led node\nenrollment flow where this credentials token is produced by a worker. This\ntoken is a base58 encoded types.FetchNodeCredentialsRequest from\nhttps://github.com/hashicorp/nodeenrollment"
|
||||
},
|
||||
"active_connection_count": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Output only. The number of connections that this worker is currently handling.",
|
||||
"readOnly": true
|
||||
},
|
||||
"authorized_actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -96,6 +96,9 @@ message Worker {
|
||||
// https://github.com/hashicorp/nodeenrollment
|
||||
google.protobuf.StringValue worker_auth_token = 150 [json_name = "worker_auth_token"]; // @gotags: `class:"public"`
|
||||
|
||||
// Output only. The number of connections that this worker is currently handling.
|
||||
uint32 active_connection_count = 160 [json_name = "active_connection_count"]; // @gotags: `class:"public"`
|
||||
|
||||
// Output only. The available actions on this resource for the requester.
|
||||
repeated string authorized_actions = 300 [json_name = "authorized_actions"]; // @gotags: `class:"public"`
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers"
|
||||
"github.com/hashicorp/boundary/internal/servers/store"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/go-dbw"
|
||||
"github.com/hashicorp/go-kms-wrapping/extras/kms/v2/migrations"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestDeleteWorker(t *testing.T) {
|
||||
@@ -162,10 +164,43 @@ func TestLookupWorker(t *testing.T) {
|
||||
servers.WithPublicId(w.GetPublicId()))
|
||||
require.NoError(t, err)
|
||||
|
||||
sessRepo, err := session.NewRepository(rw, rw, kms)
|
||||
require.NoError(t, err)
|
||||
connRepo, err := session.NewConnectionRepository(ctx, rw, rw, kms, session.WithWorkerStateDelay(0))
|
||||
require.NoError(t, err)
|
||||
// 1 session with 2 connections
|
||||
{
|
||||
composedOf := session.TestSessionParams(t, conn, wrapper, iam.TestRepo(t, conn, wrapper))
|
||||
future := timestamppb.New(time.Now().Add(time.Hour))
|
||||
exp := ×tamp.Timestamp{Timestamp: future}
|
||||
composedOf.ConnectionLimit = -1
|
||||
sess := session.TestSession(t, conn, wrapper, composedOf, session.WithDbOpts(db.WithSkipVetForWrite(true)), session.WithExpirationTime(exp))
|
||||
sess, _, err = sessRepo.ActivateSession(ctx, sess.GetPublicId(), sess.Version, []byte("foo"))
|
||||
require.NoError(t, err)
|
||||
c, _, err := connRepo.AuthorizeConnection(ctx, sess.GetPublicId(), w.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
c, _, err = connRepo.AuthorizeConnection(ctx, sess.GetPublicId(), w.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
}
|
||||
|
||||
// 1 session with 1 connection
|
||||
{
|
||||
sess2 := session.TestDefaultSession(t, conn, wrapper, iam.TestRepo(t, conn, wrapper),
|
||||
session.WithDbOpts(db.WithSkipVetForWrite(true)))
|
||||
sess2, _, err = sessRepo.ActivateSession(ctx, sess2.GetPublicId(), sess2.Version, []byte("foo"))
|
||||
require.NoError(t, err)
|
||||
c, _, err := connRepo.AuthorizeConnection(ctx, sess2.GetPublicId(), w.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
}
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
got, err := repo.LookupWorker(ctx, w.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cmp.Diff(w, got, protocmp.Transform()))
|
||||
assert.Equal(t, uint32(3), got.ActiveConnectionCount())
|
||||
assert.Equal(t, map[string][]string{"key": {"val"}}, got.GetApiTags())
|
||||
assert.Equal(t, map[string][]string{"config": {"test"}}, got.GetConfigTags())
|
||||
assert.Equal(t, map[string][]string{
|
||||
|
||||
@@ -36,8 +36,9 @@ func AttachWorkerIdToState(ctx context.Context, workerId string) (*structpb.Stru
|
||||
type Worker struct {
|
||||
*store.Worker
|
||||
|
||||
apiTags []*Tag `gorm:"-"`
|
||||
configTags []*Tag `gorm:"-"`
|
||||
activeConnectionCount uint32 `gorm:"-"`
|
||||
apiTags []*Tag `gorm:"-"`
|
||||
configTags []*Tag `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewWorker returns a new Worker. Valid options are WithName, WithDescription
|
||||
@@ -112,6 +113,12 @@ func (w *Worker) CanonicalAddress() string {
|
||||
return w.GetWorkerReportedAddress()
|
||||
}
|
||||
|
||||
// ActiveConnectionCount is the current number of sessions this worker is handling
|
||||
// according to the controllers.
|
||||
func (w *Worker) ActiveConnectionCount() uint32 {
|
||||
return w.activeConnectionCount
|
||||
}
|
||||
|
||||
// CanonicalTags is the deduplicated set of tags contained on both the resource
|
||||
// set over the API as well as the tags reported by the worker itself.
|
||||
func (w *Worker) CanonicalTags() map[string][]string {
|
||||
@@ -129,6 +136,7 @@ func (w *Worker) CanonicalTags() map[string][]string {
|
||||
return tags
|
||||
}
|
||||
|
||||
// GetApiTags returns the tags for this worker which has been set by the api.
|
||||
func (w *Worker) GetApiTags() map[string][]string {
|
||||
tags := make(map[string][]string)
|
||||
for _, t := range w.apiTags {
|
||||
@@ -137,6 +145,8 @@ func (w *Worker) GetApiTags() map[string][]string {
|
||||
return tags
|
||||
}
|
||||
|
||||
// GetConfigTags returns the tags for this worker which has been set through
|
||||
// the worker daemon's configuration file.
|
||||
func (w *Worker) GetConfigTags() map[string][]string {
|
||||
tags := make(map[string][]string)
|
||||
for _, t := range w.configTags {
|
||||
@@ -172,6 +182,8 @@ type workerAggregate struct {
|
||||
Address string
|
||||
Version uint32
|
||||
ApiTags string
|
||||
ActiveConnectionCount uint32
|
||||
// Config Fields
|
||||
WorkerReportedName string
|
||||
WorkerReportedAddress string
|
||||
LastStatusTime *timestamp.Timestamp
|
||||
@@ -194,6 +206,7 @@ func (a *workerAggregate) toWorker(ctx context.Context) (*Worker, error) {
|
||||
WorkerReportedName: a.WorkerReportedName,
|
||||
LastStatusTime: a.LastStatusTime,
|
||||
},
|
||||
activeConnectionCount: a.ActiveConnectionCount,
|
||||
}
|
||||
tags, err := tagsFromAggregatedTagString(ctx, a.ApiTags)
|
||||
if err != nil {
|
||||
|
||||
@@ -137,6 +137,8 @@ type Worker struct {
|
||||
// token is a base58 encoded types.FetchNodeCredentialsRequest from
|
||||
// https://github.com/hashicorp/nodeenrollment
|
||||
WorkerAuthToken *wrapperspb.StringValue `protobuf:"bytes,150,opt,name=worker_auth_token,proto3" json:"worker_auth_token,omitempty"` // @gotags: `class:"public"`
|
||||
// Output only. The number of connections that this worker is currently handling.
|
||||
ActiveConnectionCount uint32 `protobuf:"varint,160,opt,name=active_connection_count,proto3" json:"active_connection_count,omitempty"` // @gotags: `class:"public"`
|
||||
// Output only. The available actions on this resource for the requester.
|
||||
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty"` // @gotags: `class:"public"`
|
||||
}
|
||||
@@ -278,6 +280,13 @@ func (x *Worker) GetWorkerAuthToken() *wrapperspb.StringValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Worker) GetActiveConnectionCount() uint32 {
|
||||
if x != nil {
|
||||
return x.ActiveConnectionCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Worker) GetAuthorizedActions() []string {
|
||||
if x != nil {
|
||||
return x.AuthorizedActions
|
||||
@@ -319,7 +328,7 @@ var file_controller_api_resources_workers_v1_worker_proto_rawDesc = []byte{
|
||||
0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc6, 0x09, 0x0a, 0x06, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x81, 0x0a, 0x0a, 0x06, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 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,
|
||||
@@ -381,27 +390,31 @@ var file_controller_api_resources_workers_v1_worker_proto_rawDesc = []byte{
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x96, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2f, 0x0a, 0x12,
|
||||
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f,
|
||||
0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x53, 0x0a,
|
||||
0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
||||
0x38, 0x01, 0x1a, 0x5c, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x54,
|
||||
0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
||||
0x42, 0x50, 0x5a, 0x4e, 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, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 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, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x3b, 0x77, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x72, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x17,
|
||||
0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0xa0, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17,
|
||||
0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f,
|
||||
0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,
|
||||
0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x53, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5c, 0x0a,
|
||||
0x12, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x50, 0x5a, 0x4e, 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, 0x73, 0x64, 0x6b,
|
||||
0x2f, 0x70, 0x62, 0x73, 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, 0x77, 0x6f,
|
||||
0x72, 0x6b, 0x65, 0x72, 0x73, 0x3b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
Reference in new issue
Block a user