diff --git a/controller/handler_edge_ctrl/common.go b/controller/handler_edge_ctrl/common.go index 8ce5742dc..43e46a46e 100644 --- a/controller/handler_edge_ctrl/common.go +++ b/controller/handler_edge_ctrl/common.go @@ -71,6 +71,22 @@ func (self *baseRequestHandler) returnError(ctx requestContext, err error) { } } +func (self *baseRequestHandler) logResult(ctx requestContext, err error) { + logger := logrus. + WithField("router", ctx.GetHandler().getChannel().Id().Token). + WithField("operation", ctx.GetHandler().Label()) + + if sessionCtx, ok := ctx.(sessionRequestContext); ok { + logger = logger.WithField("token", sessionCtx.GetSessionToken()) + } + + if err != nil { + logger.WithError(err).Error("operation failed") + } else { + logger.Debug("operation success") + } +} + type requestContext interface { GetHandler() requestHandler GetMessage() *channel2.Message diff --git a/controller/handler_edge_ctrl/common_tunnel.go b/controller/handler_edge_ctrl/common_tunnel.go index e5516615f..3476f37e9 100644 --- a/controller/handler_edge_ctrl/common_tunnel.go +++ b/controller/handler_edge_ctrl/common_tunnel.go @@ -191,8 +191,8 @@ func (self *baseTunnelRequestContext) getCreateApiSessionResponse() *edge_ctrl_p func (self *baseTunnelRequestContext) getCreateSessionResponse() *edge_ctrl_pb.CreateSessionResponse { return &edge_ctrl_pb.CreateSessionResponse{ - SessionId: self.apiSession.Id, - Token: self.apiSession.Token, + SessionId: self.session.Id, + Token: self.session.Token, } } diff --git a/controller/handler_edge_ctrl/create_tunnel_terminator.go b/controller/handler_edge_ctrl/create_tunnel_terminator.go index 940e0c727..858c0ed55 100644 --- a/controller/handler_edge_ctrl/create_tunnel_terminator.go +++ b/controller/handler_edge_ctrl/create_tunnel_terminator.go @@ -121,7 +121,7 @@ func (self *createTunnelTerminatorHandler) CreateTerminator(ctx *CreateTunnelTer response := &edge_ctrl_pb.CreateTunnelTerminatorResponse{ Session: ctx.getCreateSessionResponse(), - TerminatorId: "", + TerminatorId: id, } if newApiSession { diff --git a/controller/handler_edge_ctrl/health_event.go b/controller/handler_edge_ctrl/health_event.go new file mode 100644 index 000000000..433f65088 --- /dev/null +++ b/controller/handler_edge_ctrl/health_event.go @@ -0,0 +1,98 @@ +/* + Copyright NetFoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package handler_edge_ctrl + +import ( + "github.com/golang/protobuf/proto" + "github.com/michaelquigley/pfxlog" + "github.com/openziti/edge/controller/env" + "github.com/openziti/edge/controller/persistence" + "github.com/openziti/edge/pb/edge_ctrl_pb" + "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/metrics" + "time" +) + +type healthEventHandler struct { + baseRequestHandler + serviceHealthCheckPassedCounter metrics.IntervalCounter + serviceHealthCheckFailedCounter metrics.IntervalCounter +} + +func NewHealthEventHandler(appEnv *env.AppEnv, ch channel2.Channel) channel2.ReceiveHandler { + serviceEventMetrics := appEnv.GetHostController().GetNetwork().GetServiceEventsMetricsRegistry() + return &healthEventHandler{ + baseRequestHandler: baseRequestHandler{ + ch: ch, + appEnv: appEnv, + }, + serviceHealthCheckPassedCounter: serviceEventMetrics.IntervalCounter("service.health_check.passed", time.Minute), + serviceHealthCheckFailedCounter: serviceEventMetrics.IntervalCounter("service.health_check.failed", time.Minute), + } +} + +func (self *healthEventHandler) ContentType() int32 { + return int32(edge_ctrl_pb.ContentType_HealthEventType) +} + +func (self *healthEventHandler) Label() string { + return "health.event" +} + +func (self *healthEventHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) { + req := &edge_ctrl_pb.HealthEventRequest{} + if err := proto.Unmarshal(msg.Body, req); err != nil { + pfxlog.ContextLogger(ch.Label()).WithError(err).Error("could not unmarshal health event") + return + } + + ctx := &HealthEventRequestContext{ + baseSessionRequestContext: baseSessionRequestContext{handler: self, msg: msg}, + req: req, + } + + go self.handleHealthEvent(ctx) +} + +func (self *healthEventHandler) handleHealthEvent(ctx *HealthEventRequestContext) { + if !ctx.loadRouter() { + return + } + + ctx.loadSession(ctx.req.SessionToken) + ctx.checkSessionType(persistence.SessionTypeBind) + ctx.checkSessionFingerprints(ctx.req.Fingerprints) + + if ctx.err == nil { + if ctx.req.CheckPassed { + self.serviceHealthCheckPassedCounter.Update(ctx.session.ServiceId, time.Now(), 1) + } else { + self.serviceHealthCheckFailedCounter.Update(ctx.session.ServiceId, time.Now(), 1) + } + } + + self.logResult(ctx, ctx.err) +} + +type HealthEventRequestContext struct { + baseSessionRequestContext + req *edge_ctrl_pb.HealthEventRequest +} + +func (self *HealthEventRequestContext) GetSessionToken() string { + return self.req.SessionToken +} diff --git a/controller/handler_edge_ctrl/tunnel_health_event.go b/controller/handler_edge_ctrl/tunnel_health_event.go new file mode 100644 index 000000000..1dd57e38e --- /dev/null +++ b/controller/handler_edge_ctrl/tunnel_health_event.go @@ -0,0 +1,88 @@ +/* + Copyright NetFoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package handler_edge_ctrl + +import ( + "github.com/openziti/edge/controller/env" + "github.com/openziti/edge/edge_common" + "github.com/openziti/edge/pb/edge_ctrl_pb" + "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/metrics" + "time" +) + +type tunnelHealthEventHandler struct { + baseRequestHandler + serviceHealthCheckPassedCounter metrics.IntervalCounter + serviceHealthCheckFailedCounter metrics.IntervalCounter +} + +func NewTunnelHealthEventHandler(appEnv *env.AppEnv, ch channel2.Channel) channel2.ReceiveHandler { + serviceEventMetrics := appEnv.GetHostController().GetNetwork().GetServiceEventsMetricsRegistry() + return &tunnelHealthEventHandler{ + baseRequestHandler: baseRequestHandler{ + ch: ch, + appEnv: appEnv, + }, + serviceHealthCheckPassedCounter: serviceEventMetrics.IntervalCounter("service.health_check.passed", time.Minute), + serviceHealthCheckFailedCounter: serviceEventMetrics.IntervalCounter("service.health_check.failed", time.Minute), + } +} + +func (self *tunnelHealthEventHandler) ContentType() int32 { + return int32(edge_ctrl_pb.ContentType_TunnelHealthEventType) +} + +func (self *tunnelHealthEventHandler) Label() string { + return "tunnel.health.event" +} + +func (self *tunnelHealthEventHandler) HandleReceive(msg *channel2.Message, _ channel2.Channel) { + terminatorId, _ := msg.GetStringHeader(int32(edge_ctrl_pb.Header_TerminatorId)) + checkPassed, _ := msg.GetBoolHeader(int32(edge_ctrl_pb.Header_CheckPassed)) + + ctx := &TunnelHealthEventRequestContext{ + baseSessionRequestContext: baseSessionRequestContext{handler: self, msg: msg}, + terminatorId: terminatorId, + checkPassed: checkPassed, + } + + go self.handleHealthEvent(ctx) +} + +func (self *tunnelHealthEventHandler) handleHealthEvent(ctx *TunnelHealthEventRequestContext) { + if !ctx.loadRouter() { + return + } + + terminator := ctx.verifyTerminator(ctx.terminatorId, edge_common.TunnelBinding) + if terminator != nil && ctx.err == nil { + if ctx.checkPassed { + self.serviceHealthCheckPassedCounter.Update(terminator.Service, time.Now(), 1) + } else { + self.serviceHealthCheckFailedCounter.Update(terminator.Service, time.Now(), 1) + } + } + + self.logResult(ctx, ctx.err) +} + +type TunnelHealthEventRequestContext struct { + baseSessionRequestContext + terminatorId string + checkPassed bool +} diff --git a/controller/model/api_session_certificate_handlers.go b/controller/model/api_session_certificate_handlers.go index e075aedc7..3b7ff1e9d 100644 --- a/controller/model/api_session_certificate_handlers.go +++ b/controller/model/api_session_certificate_handlers.go @@ -119,17 +119,17 @@ func (handler *ApiSessionCertificateHandler) Delete(id string) error { return handler.deleteEntity(id) } -func (handler *ApiSessionCertificateHandler) Query(query string) (*ApiSessionCertificateListResult, error) { +func (handler *ApiSessionCertificateHandler) Query(tx *bbolt.Tx, query string) (*ApiSessionCertificateListResult, error) { result := &ApiSessionCertificateListResult{handler: handler} - err := handler.list(query, result.collect) + err := handler.ListWithTx(tx, query, result.collect) if err != nil { return nil, err } return result, nil } -func (handler *ApiSessionCertificateHandler) ReadByApiSessionId(apiSessionId string) ([]*ApiSessionCertificate, error) { - result, err := handler.Query(fmt.Sprintf(`apiSession = "%s"`, apiSessionId)) +func (handler *ApiSessionCertificateHandler) ReadByApiSessionId(tx *bbolt.Tx, apiSessionId string) ([]*ApiSessionCertificate, error) { + result, err := handler.Query(tx, fmt.Sprintf(`apiSession = "%s"`, apiSessionId)) if err != nil { return nil, err diff --git a/controller/model/api_session_handlers.go b/controller/model/api_session_handlers.go index 792a83b8b..683059299 100644 --- a/controller/model/api_session_handlers.go +++ b/controller/model/api_session_handlers.go @@ -138,7 +138,7 @@ func (handler *ApiSessionHandler) heartbeatFlush(beats []*Heartbeat) { for _, beat := range beats { err := store.Update(mutCtx, &persistence.ApiSession{ BaseExtEntity: boltz.BaseExtEntity{ - Id: beat.ApiSessionId, + Id: beat.ApiSessionId, }, LastActivityAt: beat.LastActivityAt, }, persistence.UpdateLastActivityAtChecker{}) @@ -204,21 +204,22 @@ func (handler *ApiSessionHandler) Query(query string) (*ApiSessionListResult, er } func (handler *ApiSessionHandler) VisitFingerprintsForApiSessionId(apiSessionId string, visitor func(fingerprint string) bool) error { - apiSession, err := handler.Read(apiSessionId) + return handler.GetDb().View(func(tx *bbolt.Tx) error { + apiSession, err := handler.readInTx(tx, apiSessionId) + if err != nil { + return errors.Wrapf(err, "could not query fingerprints by api session id [%s]", apiSessionId) + } - if err != nil { - return errors.Wrapf(err, "could not query fingerprints by api session id [%s]", apiSessionId) - } - - return handler.VisitFingerprintsForApiSession(apiSession.IdentityId, apiSessionId, visitor) + return handler.VisitFingerprintsForApiSession(tx, apiSession.IdentityId, apiSessionId, visitor) + }) } -func (handler *ApiSessionHandler) VisitFingerprintsForApiSession(identityId, apiSessionId string, visitor func(fingerprint string) bool) error { - if stopVisiting, err := handler.env.GetHandlers().Identity.VisitIdentityAuthenticatorFingerprints(identityId, visitor); stopVisiting || err != nil { +func (handler *ApiSessionHandler) VisitFingerprintsForApiSession(tx *bbolt.Tx, identityId, apiSessionId string, visitor func(fingerprint string) bool) error { + if stopVisiting, err := handler.env.GetHandlers().Identity.VisitIdentityAuthenticatorFingerprints(tx, identityId, visitor); stopVisiting || err != nil { return err } - apiSessionCerts, err := handler.env.GetHandlers().ApiSessionCertificate.ReadByApiSessionId(apiSessionId) + apiSessionCerts, err := handler.env.GetHandlers().ApiSessionCertificate.ReadByApiSessionId(tx, apiSessionId) if err != nil { return err } diff --git a/controller/model/identity_handlers.go b/controller/model/identity_handlers.go index 64d0dd206..d05f2ca93 100644 --- a/controller/model/identity_handlers.go +++ b/controller/model/identity_handlers.go @@ -318,24 +318,23 @@ func (handler *IdentityHandler) CollectAuthenticators(id string, collector func( }) } -func (handler *IdentityHandler) visitAuthenticators(id string, visitor func(entity *Authenticator) bool) error { - return handler.GetDb().View(func(tx *bbolt.Tx) error { - _, err := handler.readInTx(tx, id) - if err != nil { +func (handler *IdentityHandler) visitAuthenticators(tx *bbolt.Tx, id string, visitor func(entity *Authenticator) bool) error { + _, err := handler.readInTx(tx, id) + if err != nil { + return err + } + authenticatorIds := handler.GetStore().GetRelatedEntitiesIdList(tx, id, persistence.FieldIdentityAuthenticators) + for _, authenticatorId := range authenticatorIds { + authenticator := &Authenticator{} + if err := handler.env.GetHandlers().Authenticator.readEntityInTx(tx, authenticatorId, authenticator); err != nil { return err } - authenticatorIds := handler.GetStore().GetRelatedEntitiesIdList(tx, id, persistence.FieldIdentityAuthenticators) - for _, authenticatorId := range authenticatorIds { - authenticator := &Authenticator{} - if err := handler.env.GetHandlers().Authenticator.readEntityInTx(tx, authenticatorId, authenticator); err != nil { - return err - } - if visitor(authenticator) { - return nil - } + if visitor(authenticator) { + return nil } - return nil - }) + } + return nil + } func (handler *IdentityHandler) CollectEnrollments(id string, collector func(entity *Enrollment) error) error { @@ -496,9 +495,9 @@ func (handler *IdentityHandler) IsActive(id string) bool { return handler.identityStatusMap.IsActive(id) } -func (handler *IdentityHandler) VisitIdentityAuthenticatorFingerprints(identityId string, visitor func(string) bool) (bool, error) { +func (handler *IdentityHandler) VisitIdentityAuthenticatorFingerprints(tx *bbolt.Tx, identityId string, visitor func(string) bool) (bool, error) { stopVisit := false - err := handler.visitAuthenticators(identityId, func(authenticator *Authenticator) bool { + err := handler.visitAuthenticators(tx, identityId, func(authenticator *Authenticator) bool { for _, authPrint := range authenticator.Fingerprints() { if visitor(authPrint) { stopVisit = true diff --git a/controller/persistence/migration_initialize.go b/controller/persistence/migration_initialize.go index 87826efa2..056e00916 100644 --- a/controller/persistence/migration_initialize.go +++ b/controller/persistence/migration_initialize.go @@ -39,6 +39,7 @@ func (m *Migrations) initialize(step *boltz.MigrationStep) int { m.addPostureCheckTypes(step) m.createInterceptV1ConfigType(step) m.createHostV1ConfigType(step) + step.SetError(m.stores.ConfigType.Create(step.Ctx, hostV2ConfigType)) return CurrentDbVersion } @@ -125,6 +126,7 @@ var serverConfigTypeV1 = &ConfigType{ "enum": []interface{}{ "fail", "pass", + "change", }, }, "consecutiveEvents": map[string]interface{}{ @@ -137,7 +139,7 @@ var serverConfigTypeV1 = &ConfigType{ }, "action": map[string]interface{}{ "type": "string", - "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+)", + "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+|send event)", }, }, }, @@ -233,6 +235,474 @@ var serverConfigTypeV1 = &ConfigType{ }, } +var hostV1ConfigTypeId = "NH5p4FpGR" +var hostV1ConfigType = &ConfigType{ + BaseExtEntity: boltz.BaseExtEntity{Id: hostV1ConfigTypeId}, + Name: "host.v1", + Schema: map[string]interface{}{ + "$id": "http://ziti-edge.netfoundry.io/schemas/host-v1.schema.json", + "definitions": map[string]interface{}{ + "duration": map[string]interface{}{ + "type": "string", + "pattern": "[0-9]+(h|m|s|ms)", + }, + "method": map[string]interface{}{ + "type": "string", + "enum": []interface{}{ + "GET", + "POST", + "PUT", + "PATCH", + }, + }, + "action": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "trigger", + "action", + }, + "properties": map[string]interface{}{ + "trigger": map[string]interface{}{ + "type": "string", + "enum": []interface{}{ + "fail", + "pass", + "change", + }, + }, + "consecutiveEvents": map[string]interface{}{ + "type": "integer", + "minimum": float64(0), + "maximum": float64(math.MaxUint16), + }, + "duration": map[string]interface{}{ + "$ref": "#/definitions/duration", + }, + "action": map[string]interface{}{ + "type": "string", + "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+|send event)", + }, + }, + }, + "actionList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/action", + }, + "minItems": 1, + "maxItems": 20, + }, + "portCheck": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "interval", + "timeout", + "address", + }, + "properties": map[string]interface{}{ + "interval": map[string]interface{}{"$ref": "#/definitions/duration"}, + "timeout": map[string]interface{}{"$ref": "#/definitions/duration"}, + "address": map[string]interface{}{"type": "string"}, + "actions": map[string]interface{}{"$ref": "#/definitions/actionList"}, + }, + }, + "httpCheck": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "interval", + "timeout", + "url", + }, + "properties": map[string]interface{}{ + "url": map[string]interface{}{"type": "string"}, + "method": map[string]interface{}{"$ref": "#/definitions/method"}, + "body": map[string]interface{}{"type": "string"}, + "interval": map[string]interface{}{"$ref": "#/definitions/duration"}, + "timeout": map[string]interface{}{"$ref": "#/definitions/duration"}, + "actions": map[string]interface{}{"$ref": "#/definitions/actionList"}, + "expectStatus": map[string]interface{}{ + "type": "integer", + "minimum": float64(100), + "maximum": float64(599), + }, + "expectInBody": map[string]interface{}{"type": "string"}, + }, + }, + "portCheckList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/portCheck", + }, + }, + "httpCheckList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/httpCheck", + }, + }, + "ipAddressFormat": map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"format": "ipv4"}, + map[string]interface{}{"format": "ipv6"}, + }, + }, + "ipAddress": map[string]interface{}{ + "type": "string", + "$ref": "#/definitions/ipAddressFormat", + }, + "hostname": map[string]interface{}{ + "type": "string", + "format": "hostname", + "not": map[string]interface{}{"$ref": "#/definitions/ipAddressFormat"}, + }, + "address": map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"$ref": "#/definitions/ipAddress"}, + map[string]interface{}{"$ref": "#/definitions/hostname"}, + }, + }, + }, + "type": "object", + "properties": map[string]interface{}{ + "protocol": map[string]interface{}{ + "type": "string", + "enum": []interface{}{"tcp", "udp", "sctp"}, + "description": "Dial the specified protocol when a ziti client connects to the service.", + }, + "dialInterceptedProtocol": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same protocol that was intercepted at the client tunneler. 'protocol' and 'dialInterceptedProtocol' are mutually exclusive.", + }, + "address": map[string]interface{}{ + "$ref": "#/definitions/address", + "description": "Dial the specified ip address or hostname when a ziti client connects to the service.", + }, + "dialInterceptedAddress": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same ip address that was intercepted at the client tunneler. 'address' and 'dialInterceptedAddress' are mutually exclusive.", + }, + "port": map[string]interface{}{ + "type": "integer", + "minimum": 0, + "maximum": 65535, + "description": "Dial the specified port when a ziti client connects to the service.", + }, + "dialInterceptedPort": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same port that was intercepted at the client tunneler. 'port' and 'dialInterceptedPort' are mutually exclusive.", + }, + "portChecks": map[string]interface{}{ + "$ref": "#/definitions/portCheckList", + }, + "httpChecks": map[string]interface{}{ + "$ref": "#/definitions/httpCheckList", + }, + "listenOptions": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "properties": map[string]interface{}{ + "cost": map[string]interface{}{ + "type": "integer", + "minimum": 0, + "maximum": 65535, + "description": "defaults to 0", + }, + "precedence": map[string]interface{}{ + "type": "string", + "enum": []interface{}{"default", "required", "failed"}, + "description": "defaults to 'default'", + }, + "connectTimeoutSeconds": map[string]interface{}{ + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "description": "defaults to 5", + }, + "maxConnections": map[string]interface{}{ + "type": "integer", + "minimum": 1, + "description": "defaults to 3", + }, + "identity": map[string]interface{}{ + "type": "string", + "description": "Associate the hosting terminator with the specified identity. '$tunneler_id.name' resolves to the name of the hosting tunneler's identity. '$tunneler_id.tag[tagName]' resolves to the value of the 'tagName' tag on the hosting tunneler's identity.", + }, + "bindUsingEdgeIdentity": map[string]interface{}{ + "type": "boolean", + "description": "Associate the hosting terminator with the name of the hosting tunneler's identity. Setting this to 'true' is equivalent to setting 'identiy=$tunneler_id.name'", + }, + }, + }, + }, + "additionalProperties": false, + "allOf": []interface{}{ + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"protocol"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedProtocol"}}, + }, + }, + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"address"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedAddress"}}, + }, + }, + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"port"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedPort"}}, + }, + }, + }, + }, +} + +var hostV2ConfigTypeId = "host.v2" +var hostV2ConfigType = &ConfigType{ + BaseExtEntity: boltz.BaseExtEntity{Id: hostV2ConfigTypeId}, + Name: "host.v2", + Schema: map[string]interface{}{ + "$id": "http://ziti-edge.netfoundry.io/schemas/host-v2.schema.json", + "definitions": map[string]interface{}{ + "duration": map[string]interface{}{ + "type": "string", + "pattern": "[0-9]+(h|m|s|ms)", + }, + "method": map[string]interface{}{ + "type": "string", + "enum": []interface{}{ + "GET", + "POST", + "PUT", + "PATCH", + }, + }, + "action": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "trigger", + "action", + }, + "properties": map[string]interface{}{ + "trigger": map[string]interface{}{ + "type": "string", + "enum": []interface{}{ + "fail", + "pass", + "change", + }, + }, + "consecutiveEvents": map[string]interface{}{ + "type": "integer", + "minimum": float64(0), + "maximum": float64(math.MaxUint16), + }, + "duration": map[string]interface{}{ + "$ref": "#/definitions/duration", + }, + "action": map[string]interface{}{ + "type": "string", + "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+|send event)", + }, + }, + }, + "actionList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/action", + }, + "minItems": 1, + "maxItems": 20, + }, + "portCheck": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "interval", + "timeout", + "address", + }, + "properties": map[string]interface{}{ + "interval": map[string]interface{}{"$ref": "#/definitions/duration"}, + "timeout": map[string]interface{}{"$ref": "#/definitions/duration"}, + "address": map[string]interface{}{"type": "string"}, + "actions": map[string]interface{}{"$ref": "#/definitions/actionList"}, + }, + }, + "httpCheck": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "required": []interface{}{ + "interval", + "timeout", + "url", + }, + "properties": map[string]interface{}{ + "url": map[string]interface{}{"type": "string"}, + "method": map[string]interface{}{"$ref": "#/definitions/method"}, + "body": map[string]interface{}{"type": "string"}, + "interval": map[string]interface{}{"$ref": "#/definitions/duration"}, + "timeout": map[string]interface{}{"$ref": "#/definitions/duration"}, + "actions": map[string]interface{}{"$ref": "#/definitions/actionList"}, + "expectStatus": map[string]interface{}{ + "type": "integer", + "minimum": float64(100), + "maximum": float64(599), + }, + "expectInBody": map[string]interface{}{"type": "string"}, + }, + }, + "portCheckList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/portCheck", + }, + }, + "httpCheckList": map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "$ref": "#/definitions/httpCheck", + }, + }, + "ipAddressFormat": map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"format": "ipv4"}, + map[string]interface{}{"format": "ipv6"}, + }, + }, + "ipAddress": map[string]interface{}{ + "type": "string", + "$ref": "#/definitions/ipAddressFormat", + }, + "hostname": map[string]interface{}{ + "type": "string", + "format": "hostname", + "not": map[string]interface{}{"$ref": "#/definitions/ipAddressFormat"}, + }, + "address": map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"$ref": "#/definitions/ipAddress"}, + map[string]interface{}{"$ref": "#/definitions/hostname"}, + }, + }, + "terminator": map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "protocol": map[string]interface{}{ + "type": "string", + "enum": []interface{}{"tcp", "udp", "sctp"}, + "description": "Dial the specified protocol when a ziti client connects to the service.", + }, + "dialInterceptedProtocol": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same protocol that was intercepted at the client tunneler. 'protocol' and 'dialInterceptedProtocol' are mutually exclusive.", + }, + "address": map[string]interface{}{ + "$ref": "#/definitions/address", + "description": "Dial the specified ip address or hostname when a ziti client connects to the service.", + }, + "dialInterceptedAddress": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same ip address that was intercepted at the client tunneler. 'address' and 'dialInterceptedAddress' are mutually exclusive.", + }, + "port": map[string]interface{}{ + "type": "integer", + "minimum": 0, + "maximum": 65535, + "description": "Dial the specified port when a ziti client connects to the service.", + }, + "dialInterceptedPort": map[string]interface{}{ + "type": "boolean", + "enum": []interface{}{true}, + "description": "Dial the same port that was intercepted at the client tunneler. 'port' and 'dialInterceptedPort' are mutually exclusive.", + }, + "portChecks": map[string]interface{}{ + "$ref": "#/definitions/portCheckList", + }, + "httpChecks": map[string]interface{}{ + "$ref": "#/definitions/httpCheckList", + }, + "listenOptions": map[string]interface{}{ + "type": "object", + "additionalProperties": false, + "properties": map[string]interface{}{ + "cost": map[string]interface{}{ + "type": "integer", + "minimum": 0, + "maximum": 65535, + "description": "defaults to 0", + }, + "precedence": map[string]interface{}{ + "type": "string", + "enum": []interface{}{"default", "required", "failed"}, + "description": "defaults to 'default'", + }, + "connectTimeout": map[string]interface{}{"$ref": "#/definitions/duration"}, + "maxConnections": map[string]interface{}{ + "type": "integer", + "minimum": 1, + "description": "defaults to 3", + }, + "identity": map[string]interface{}{ + "type": "string", + "description": "Associate the hosting terminator with the specified identity. '$tunneler_id.name' resolves to the name of the hosting tunneler's identity. '$tunneler_id.tag[tagName]' resolves to the value of the 'tagName' tag on the hosting tunneler's identity.", + }, + "bindUsingEdgeIdentity": map[string]interface{}{ + "type": "boolean", + "description": "Associate the hosting terminator with the name of the hosting tunneler's identity. Setting this to 'true' is equivalent to setting 'identiy=$tunneler_id.name'", + }, + }, + }, + }, + "additionalProperties": false, + "allOf": []interface{}{ + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"protocol"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedProtocol"}}, + }, + }, + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"address"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedAddress"}}, + }, + }, + map[string]interface{}{ + "oneOf": []interface{}{ + map[string]interface{}{"required": []interface{}{"port"}}, + map[string]interface{}{"required": []interface{}{"dialInterceptedPort"}}, + }, + }, + }, + }, + "terminatorList": map[string]interface{}{ + "type": "array", + "minItems": 1, + "items": map[string]interface{}{ + "$ref": "#/definitions/terminator", + }, + }, + }, + "type": "object", + "properties": map[string]interface{}{ + "terminators": map[string]interface{}{ + "$ref": "#/definitions/terminatorList", + }, + }, + }, +} + func (m *Migrations) createInitialTunnelerConfigTypes(step *boltz.MigrationStep) { clientConfigTypeV1 := &ConfigType{ BaseExtEntity: boltz.BaseExtEntity{Id: clientConfigV1TypeId}, diff --git a/controller/persistence/migration_v14.go b/controller/persistence/migration_v14.go index e28f389d6..ef317ab74 100644 --- a/controller/persistence/migration_v14.go +++ b/controller/persistence/migration_v14.go @@ -133,133 +133,10 @@ func (m *Migrations) createInterceptV1ConfigType(step *boltz.MigrationStep) { } func (m *Migrations) createHostV1ConfigType(step *boltz.MigrationStep) { - configTypeName := "host.v1" - configTypeId := "NH5p4FpGR" - configType := &ConfigType{ - BaseExtEntity: boltz.BaseExtEntity{Id: configTypeId}, - Name: configTypeName, - Schema: map[string]interface{}{ - "$id": "http://ziti-edge.netfoundry.io/schemas/host-v1.schema.json", - "$defs": map[string]interface{}{ - "ipAddressFormat": map[string]interface{}{ - "oneOf": []interface{}{ - map[string]interface{}{"format": "ipv4"}, - map[string]interface{}{"format": "ipv6"}, - }, - }, - "ipAddress": map[string]interface{}{ - "type": "string", - "$ref": "#/$defs/ipAddressFormat", - }, - "hostname": map[string]interface{}{ - "type": "string", - "format": "hostname", - "not": map[string]interface{}{"$ref": "#/$defs/ipAddressFormat"}, - }, - "address": map[string]interface{}{ - "oneOf": []interface{}{ - map[string]interface{}{"$ref": "#/$defs/ipAddress"}, - map[string]interface{}{"$ref": "#/$defs/hostname"}, - }, - }, - }, - "type": "object", - "properties": map[string]interface{}{ - "protocol": map[string]interface{}{ - "type": "string", - "enum": []interface{}{"tcp", "udp", "sctp"}, - "description": "Dial the specified protocol when a ziti client connects to the service.", - }, - "dialInterceptedProtocol": map[string]interface{}{ - "type": "boolean", - "enum": []interface{}{true}, - "description": "Dial the same protocol that was intercepted at the client tunneler. 'protocol' and 'dialInterceptedProtocol' are mutually exclusive.", - }, - "address": map[string]interface{}{ - "$ref": "#/$defs/address", - "description": "Dial the specified ip address or hostname when a ziti client connects to the service.", - }, - "dialInterceptedAddress": map[string]interface{}{ - "type": "boolean", - "enum": []interface{}{true}, - "description": "Dial the same ip address that was intercepted at the client tunneler. 'address' and 'dialInterceptedAddress' are mutually exclusive.", - }, - "port": map[string]interface{}{ - "type": "integer", - "minimum": 0, - "maximum": 65535, - "description": "Dial the specified port when a ziti client connects to the service.", - }, - "dialInterceptedPort": map[string]interface{}{ - "type": "boolean", - "enum": []interface{}{true}, - "description": "Dial the same port that was intercepted at the client tunneler. 'port' and 'dialInterceptedPort' are mutually exclusive.", - }, - "listenOptions": map[string]interface{}{ - "type": "object", - "additionalProperties": false, - "properties": map[string]interface{}{ - "cost": map[string]interface{}{ - "type": "integer", - "minimum": 0, - "maximum": 65535, - "description": "defaults to 0", - }, - "precedence": map[string]interface{}{ - "type": "string", - "enum": []interface{}{"default", "required", "failed"}, - "description": "defaults to 'default'", - }, - "connectTimeoutSeconds": map[string]interface{}{ - "type": "integer", - "minimum": 0, - "maximum": 2147483647, - "description": "defaults to 5", - }, - "maxConnections": map[string]interface{}{ - "type": "integer", - "minimum": 1, - "description": "defaults to 3", - }, - "identity": map[string]interface{}{ - "type": "string", - "description": "Associate the hosting terminator with the specified identity. '$tunneler_id.name' resolves to the name of the hosting tunneler's identity. '$tunneler_id.tag[tagName]' resolves to the value of the 'tagName' tag on the hosting tunneler's identity.", - }, - "bindUsingEdgeIdentity": map[string]interface{}{ - "type": "boolean", - "description": "Associate the hosting terminator with the name of the hosting tunneler's identity. Setting this to 'true' is equivalent to setting 'identiy=$tunneler_id.name'", - }, - }, - }, - }, - "additionalProperties": false, - "allOf": []interface{}{ - map[string]interface{}{ - "oneOf": []interface{}{ - map[string]interface{}{"required": []interface{}{"protocol"}}, - map[string]interface{}{"required": []interface{}{"dialInterceptedProtocol"}}, - }, - }, - map[string]interface{}{ - "oneOf": []interface{}{ - map[string]interface{}{"required": []interface{}{"address"}}, - map[string]interface{}{"required": []interface{}{"dialInterceptedAddress"}}, - }, - }, - map[string]interface{}{ - "oneOf": []interface{}{ - map[string]interface{}{"required": []interface{}{"port"}}, - map[string]interface{}{"required": []interface{}{"dialInterceptedPort"}}, - }, - }, - }, - }, - } - - cfg, _ := m.stores.ConfigType.LoadOneByName(step.Ctx.Tx(), configTypeName) + cfg, _ := m.stores.ConfigType.LoadOneByName(step.Ctx.Tx(), hostV1ConfigType.Name) if cfg == nil { - step.SetError(m.stores.ConfigType.Create(step.Ctx, configType)) + step.SetError(m.stores.ConfigType.Create(step.Ctx, hostV1ConfigType)) } else { - log.Debugf("'%s' config type already exists. not creating.", configTypeName) + log.Debugf("'%s' config type already exists. not creating.", hostV1ConfigType.Name) } } diff --git a/controller/persistence/migrations.go b/controller/persistence/migrations.go index 4c1fb2478..a627b2ee4 100644 --- a/controller/persistence/migrations.go +++ b/controller/persistence/migrations.go @@ -22,7 +22,7 @@ import ( ) const ( - CurrentDbVersion = 19 + CurrentDbVersion = 20 FieldVersion = "version" ) @@ -79,6 +79,12 @@ func (m *Migrations) migrate(step *boltz.MigrationStep) int { m.updateIdentityTypes(step) } + if step.CurrentVersion < 20 { + step.SetError(m.stores.ConfigType.Update(step.Ctx, serverConfigTypeV1, nil)) + step.SetError(m.stores.ConfigType.Update(step.Ctx, hostV1ConfigType, nil)) + step.SetError(m.stores.ConfigType.Create(step.Ctx, hostV2ConfigType)) + } + // current version if step.CurrentVersion <= CurrentDbVersion { return CurrentDbVersion diff --git a/controller/server/controller.go b/controller/server/controller.go index 79392c7cb..fa485360c 100644 --- a/controller/server/controller.go +++ b/controller/server/controller.go @@ -140,12 +140,15 @@ func (c *Controller) GetCtrlHandlers(ch channel2.Channel) []channel2.ReceiveHand handler_edge_ctrl.NewUpdateTerminatorHandler(c.AppEnv, ch), handler_edge_ctrl.NewRemoveTerminatorHandler(c.AppEnv, ch), handler_edge_ctrl.NewValidateSessionsHandler(c.AppEnv, ch), + handler_edge_ctrl.NewHealthEventHandler(c.AppEnv, ch), + handler_edge_ctrl.NewCreateApiSessionHandler(c.AppEnv, ch, tunnelState), handler_edge_ctrl.NewCreateCircuitForTunnelHandler(c.AppEnv, ch, tunnelState), handler_edge_ctrl.NewCreateTunnelTerminatorHandler(c.AppEnv, ch, tunnelState), handler_edge_ctrl.NewUpdateTunnelTerminatorHandler(c.AppEnv, ch), handler_edge_ctrl.NewRemoveTunnelTerminatorHandler(c.AppEnv, ch), handler_edge_ctrl.NewListTunnelServicesHandler(c.AppEnv, ch, tunnelState), + handler_edge_ctrl.NewTunnelHealthEventHandler(c.AppEnv, ch), } } diff --git a/controller/sync_strats/marshal.go b/controller/sync_strats/marshal.go index 2d4d23453..58167eb10 100644 --- a/controller/sync_strats/marshal.go +++ b/controller/sync_strats/marshal.go @@ -17,13 +17,23 @@ package sync_strats import ( - "fmt" "github.com/openziti/edge/controller/env" "github.com/openziti/edge/pb/edge_ctrl_pb" + "go.etcd.io/bbolt" ) func apiSessionToProto(ae *env.AppEnv, token, identityId, apiSessionId string) (*edge_ctrl_pb.ApiSession, error) { - fingerprints, err := getFingerprints(ae, identityId, apiSessionId) + var result *edge_ctrl_pb.ApiSession + err := ae.GetDbProvider().GetDb().View(func(tx *bbolt.Tx) error { + var err error + result, err = apiSessionToProtoWithTx(tx, ae, token, identityId, apiSessionId) + return err + }) + return result, err +} + +func apiSessionToProtoWithTx(tx *bbolt.Tx, ae *env.AppEnv, token, identityId, apiSessionId string) (*edge_ctrl_pb.ApiSession, error) { + fingerprints, err := getFingerprints(tx, ae, identityId, apiSessionId) if err != nil { return nil, err } @@ -35,19 +45,9 @@ func apiSessionToProto(ae *env.AppEnv, token, identityId, apiSessionId string) ( }, nil } -func GetFingerprintsByApiSessionId(ae *env.AppEnv, apiSessionId string) ([]string, error) { - apiSession, err := ae.GetHandlers().ApiSession.Read(apiSessionId) - - if err != nil { - return nil, fmt.Errorf("could not query fingerprints by api session id [%s]: %s", apiSessionId, err) - } - - return getFingerprints(ae, apiSession.IdentityId, apiSessionId) -} - -func getFingerprints(ae *env.AppEnv, identityId, apiSessionId string) ([]string, error) { +func getFingerprints(tx *bbolt.Tx, ae *env.AppEnv, identityId, apiSessionId string) ([]string, error) { prints := map[string]struct{}{} - err := ae.Handlers.ApiSession.VisitFingerprintsForApiSession(identityId, apiSessionId, func(fingerprint string) bool { + err := ae.Handlers.ApiSession.VisitFingerprintsForApiSession(tx, identityId, apiSessionId, func(fingerprint string) bool { prints[fingerprint] = struct{}{} return false }) diff --git a/controller/sync_strats/sync_instant.go b/controller/sync_strats/sync_instant.go index 1a4e2301b..b3c262140 100644 --- a/controller/sync_strats/sync_instant.go +++ b/controller/sync_strats/sync_instant.go @@ -436,7 +436,7 @@ func (strategy *InstantStrategy) synchronize(rtx *RouterSender) { continue } - apiSessionProto, err := apiSessionToProto(strategy.ae, apiSession.Token, apiSession.IdentityId, apiSession.Id) + apiSessionProto, err := apiSessionToProtoWithTx(tx, strategy.ae, apiSession.Token, apiSession.IdentityId, apiSession.Id) if err != nil { logger.WithError(err).WithField("apiSessionId", string(current)).Errorf("error turning apiSession [%s] into proto: %v", string(current), err) diff --git a/go.mod b/go.mod index 3055be0f3..7266e072c 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ go 1.16 replace go.etcd.io/bbolt => github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e require ( - github.com/AppsFlyer/go-sundheit v0.2.0 + github.com/AppsFlyer/go-sundheit v0.3.1 github.com/Jeffail/gabs v1.4.0 github.com/achanda/go-sysctl v0.0.0-20160222034550-6be7678c45d2 github.com/blang/semver v3.5.1+incompatible @@ -23,7 +23,7 @@ require ( github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa github.com/go-openapi/errors v0.20.0 github.com/go-openapi/loads v0.20.2 - github.com/go-openapi/runtime v0.19.26 + github.com/go-openapi/runtime v0.19.27 github.com/go-openapi/spec v0.20.3 github.com/go-openapi/strfmt v0.20.0 github.com/go-openapi/swag v0.19.14 @@ -38,12 +38,12 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/netlink v1.4.0 github.com/michaelquigley/pfxlog v0.3.7 - github.com/miekg/dns v1.1.40 + github.com/miekg/dns v1.1.41 github.com/mitchellh/mapstructure v1.4.1 github.com/netfoundry/secretstream v0.1.2 github.com/openziti/fabric v0.16.44 github.com/openziti/foundation v0.15.44 - github.com/openziti/sdk-golang v0.15.27 + github.com/openziti/sdk-golang v0.15.31 github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 github.com/pkg/errors v0.9.1 github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 @@ -55,9 +55,9 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a - golang.org/x/net v0.0.0-20210226101413-39120d07d75e - golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 - golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 google.golang.org/protobuf v1.25.0 gopkg.in/resty.v1 v1.12.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 0c8d38b22..4f6f7db1f 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AppsFlyer/go-sundheit v0.2.0 h1:FArqX+HbqZ6U32RC3giEAWRUpkggqxHj91KIvxNgwjU= github.com/AppsFlyer/go-sundheit v0.2.0/go.mod h1:rCRkVTMQo7/krF7xQ9X0XEF1an68viFR6/Gy02q+4ds= +github.com/AppsFlyer/go-sundheit v0.3.1 h1:Zqnr3wV3WQmXonc234k9XZAoV2KHUHw3osR5k2iHQZE= +github.com/AppsFlyer/go-sundheit v0.3.1/go.mod h1:iZ8zWMS7idcvmqewf5mEymWWgoOiG/0WD4+aeh+heX4= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -174,8 +176,8 @@ github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29g github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/runtime v0.19.26 h1:K/6PoVNj5WJXUnMk+VEbELeXjtBkCS1UxTDa04tdXE0= -github.com/go-openapi/runtime v0.19.26/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= +github.com/go-openapi/runtime v0.19.27 h1:4zrQCJoP7rqNCUaApDv1MdPkaa5TuPfO05Lq5WLhX9I= +github.com/go-openapi/runtime v0.19.27/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= @@ -438,8 +440,8 @@ github.com/michaelquigley/pfxlog v0.3.7 h1:itV+da+Kek0GwApI2vOcGhLdMk6eCNfjXoR6/ github.com/michaelquigley/pfxlog v0.3.7/go.mod h1:s4uqqB54PDLSU6JvpizMBJ2VU4cpG3bXsXJvFHqHDLU= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA= -github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -487,12 +489,10 @@ github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e/go.mod h1:G5EMThw github.com/openziti/dilithium v0.3.3/go.mod h1:vsCjI2AU/hon9e+dLhUFbCNGesJDj2ASgkySOcpmvjo= github.com/openziti/fabric v0.16.44 h1:pMEXl8uSdgd/Dj7d4F0qK5TnlLuse5uCpZs3Ah6fPbM= github.com/openziti/fabric v0.16.44/go.mod h1:soU2ImwCdNOnLDM5JUqpk5wAvrN9LaslZL02oThJQUM= -github.com/openziti/foundation v0.15.40 h1:3xbBIARO16x5JgRHhzMMQQrkigWv7DpnuH5yP3railM= -github.com/openziti/foundation v0.15.40/go.mod h1:kYCUttsGO/GjoD7BSNhVOeyYDXHYMAfz59YeLoEyhHY= github.com/openziti/foundation v0.15.44 h1:+XMOMaog+ABBvxgmDhk70H0buhw2RtpeDClxk+TJ3qQ= github.com/openziti/foundation v0.15.44/go.mod h1:kYCUttsGO/GjoD7BSNhVOeyYDXHYMAfz59YeLoEyhHY= -github.com/openziti/sdk-golang v0.15.27 h1:mMyQqbkUlvq6NY7+bXt3LQRMTwTCtDOZZIwxgFWNdLY= -github.com/openziti/sdk-golang v0.15.27/go.mod h1:pGaUSyl0WRgeJ70evLKPlSwOt1rJoEPDORUFO/WSE8M= +github.com/openziti/sdk-golang v0.15.31 h1:vo+/wRbNtYBvkxHrAo9Is32SAJQjlhIS+9gHoajB1g0= +github.com/openziti/sdk-golang v0.15.31/go.mod h1:jrvkpxP7U1ejSKEj4J9/UTNWlt6nJaofUGKkTx7afvM= github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 h1:fa50YL1pzKW+1SsBnJDOHppJN9stOEwS+CRWyUtyYGU= github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= @@ -654,7 +654,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -680,7 +679,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -703,7 +701,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -718,8 +715,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226101413-39120d07d75e h1:jIQURUJ9mlLvYwTBtRHm9h58rYhSonLvRvgAnP8Nr7I= -golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -733,8 +730,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -762,7 +759,6 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -782,8 +778,9 @@ golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 h1:pTMjDVnP5eVRRlWO76rEWJ8JoC6Lf1CmyjPZXRiy2Sw= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 h1:cEhElsAv9LUt9ZUUocxzWe05oFLVd+AA2nstydTeI8g= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -825,9 +822,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/health/checks.go b/health/checks.go index 706b737d7..df113303c 100644 --- a/health/checks.go +++ b/health/checks.go @@ -48,6 +48,10 @@ func (self *ActionDefinition) CreateAction() (Action, error) { result.actionImpl = func(state *ServiceState) { state.nextPrecedence = edge.PrecedenceFailed } + } else if self.Action == "send event" { + result.actionImpl = func(state *ServiceState) { + state.sendEvent = true + } } else { increase := true var costStr string @@ -120,10 +124,12 @@ func (self *actionImpl) Matches(result *health.Result) bool { if self.Trigger == "fail" && result.IsHealthy() { return false } - if self.Trigger == "pass" && !result.IsHealthy() { return false } + if self.Trigger == "change" && self.consectivePasses != 1 && result.ContiguousFailures != 1 { + return false + } if self.ConsecutiveEvents != nil { if result.IsHealthy() && self.consectivePasses < int64(*self.ConsecutiveEvents) { diff --git a/health/health.go b/health/health.go index 7a63ccc72..aa2ffed31 100644 --- a/health/health.go +++ b/health/health.go @@ -7,6 +7,7 @@ import ( "github.com/openziti/foundation/util/concurrenz" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" + "github.com/sirupsen/logrus" "reflect" "sync" "time" @@ -18,6 +19,7 @@ const ( type ServiceUpdater interface { UpdateCostAndPrecedence(cost uint16, precedence edge.Precedence) error + SendHealthEvent(pass bool) error } type Check interface { @@ -32,8 +34,13 @@ type Action interface { } func NewServiceState(service string, precedence ziti.Precedence, cost uint16, updater ServiceUpdater) *ServiceState { + return NewServiceStateWithContext("0", service, precedence, cost, updater) +} + +func NewServiceStateWithContext(service, hostContext string, precedence ziti.Precedence, cost uint16, updater ServiceUpdater) *ServiceState { return &ServiceState{ Service: service, + HostContext: hostContext, BaselinePrecedence: edge.Precedence(precedence), currentPrecedence: edge.Precedence(precedence), nextPrecedence: edge.Precedence(precedence), @@ -45,11 +52,13 @@ func NewServiceState(service string, precedence ziti.Precedence, cost uint16, up } type ServiceState struct { - Service string + Service string + HostContext string BaselinePrecedence edge.Precedence currentPrecedence edge.Precedence nextPrecedence edge.Precedence + sendEvent bool BaselineCost uint16 Updater ServiceUpdater @@ -61,16 +70,26 @@ func (self *ServiceState) IsChanged() bool { return self.nextPrecedence != self.currentPrecedence || self.nextCost != self.currentCost } -func (self *ServiceState) Update() { +func (self *ServiceState) HandleActionResults(healthy bool) { + if self.sendEvent { + if err := self.Updater.SendHealthEvent(healthy); err != nil { + logrus.WithError(err). + WithField("service", self.Service). + WithField("hostContext", self.HostContext). + WithField("isHealth", healthy). + Error("error sending health event") + } + self.sendEvent = false + } + if !self.IsChanged() { return } - log := pfxlog.Logger() - if err := self.Updater.UpdateCostAndPrecedence(self.nextCost, self.nextPrecedence); err != nil { - log.WithError(err). + logrus.WithError(err). WithField("service", self.Service). + WithField("hostContext", self.HostContext). WithField("nextCost", self.nextCost). WithField("nextPrecedence", self.nextPrecedence). Error("error updating cost/precedence on service") @@ -89,11 +108,10 @@ type checkContext struct { func NewManager() Manager { result := &manager{ - health: health.New(), results: make(chan *result, 16), } + result.health = health.New(health.WithCheckListeners(result)) - result.health.WithCheckListener(result) go result.handleResults() return result @@ -102,6 +120,7 @@ func NewManager() Manager { type Manager interface { RegisterServiceChecks(service *ServiceState, checkDefinitions []CheckDefinition) error UnregisterServiceChecks(service string) + UnregisterServiceContextChecks(service, context string) Shutdown() } @@ -137,12 +156,12 @@ func (self *manager) handleResult(result *result) { action.Invoke(check.serviceState) } } - check.serviceState.Update() + check.serviceState.HandleActionResults(result.IsHealthy()) } else { - pfxlog.Logger().Errorf("coding error, check was of incorrect type: %v", reflect.TypeOf(val)) + logrus.Errorf("coding error, check was of incorrect type: %v", reflect.TypeOf(val)) } } else { - pfxlog.Logger().Warnf("no health check context found for %v", result.name) + logrus.Warnf("no health check context found for %v", result.name) } } @@ -157,15 +176,30 @@ func (self *manager) UnregisterServiceChecks(service string) { }) } +func (self *manager) UnregisterServiceContextChecks(service, hostContext string) { + log := logrus.WithField("service", service).WithField("hostContext", hostContext) + log.Debug("removing health checks") + + self.checks.Range(func(key, val interface{}) bool { + check := val.(*checkContext) + if check.serviceState.Service == service && check.serviceState.HostContext == hostContext { + log.WithField("check", check.id).Debug("removing check") + self.checks.Delete(check.id) + self.health.Deregister(check.id) + } + return true + }) +} + func (self *manager) RegisterServiceChecks(service *ServiceState, checkDefinitions []CheckDefinition) error { logger := pfxlog.Logger() for idx, checkDefinition := range checkDefinitions { - id := fmt.Sprintf("%v_%v", service.Service, idx) + id := fmt.Sprintf("%v_%v_%v", service.Service, service.HostContext, idx) _, found := self.checks.Load(id) counter := 0 for found { counter++ - id := fmt.Sprintf("%v_%v_%v", service.Service, idx, counter) + id := fmt.Sprintf("%v_%v_%v_%v", service.Service, service.HostContext, idx, counter) _, found = self.checks.Load(id) } @@ -195,7 +229,9 @@ func (self *manager) RegisterServiceChecks(service *ServiceState, checkDefinitio InitiallyPassing: true, } - logger.WithField("service", service.Service).Debugf("adding check: %v", checkDefinition.String()) + logger.WithField("service", service.Service). + WithField("hostContext", service.HostContext). + Debugf("adding check: %v", checkDefinition.String()) if err = self.health.RegisterCheck(checkConfig); err != nil { return err } @@ -207,6 +243,10 @@ func (self *manager) OnCheckStarted(string) { // does nothing } +func (self *manager) OnCheckRegistered(string, health.Result) { + // does nothing +} + func (self *manager) OnCheckCompleted(name string, r health.Result) { if self.closed.Get() { return diff --git a/health/health_test.go b/health/health_test.go index f9f05c3b7..d2117fa16 100644 --- a/health/health_test.go +++ b/health/health_test.go @@ -21,9 +21,23 @@ type svcChangeEvent struct { precedence edge.Precedence } +func newEventTracker(t *testing.T) *eventTracker { + return &eventTracker{ + Assertions: require.New(t), + events: make(chan *svcChangeEvent, 16), + healthSends: make(chan bool, 16), + } +} + type eventTracker struct { *require.Assertions - events chan *svcChangeEvent + events chan *svcChangeEvent + healthSends chan bool +} + +func (self *eventTracker) SendHealthEvent(pass bool) error { + self.healthSends <- pass + return nil } func (self *eventTracker) UpdateCostAndPrecedence(cost uint16, precedence edge.Precedence) error { @@ -32,6 +46,7 @@ func (self *eventTracker) UpdateCostAndPrecedence(cost uint16, precedence edge.P cost: cost, precedence: precedence, } + return nil } @@ -52,6 +67,20 @@ func (self *eventTracker) assertEvent(t time.Duration, cost uint16, p edge.Prece self.Equal(int(p), int(evt.precedence)) } +func (self *eventTracker) assertHealthSend(t time.Duration, checkPassed bool) { + time.Sleep(t) + + var send bool + select { + case send = <-self.healthSends: + case <-time.After(100 * time.Millisecond): + self.Fail("no event found") + return + } + + self.Equal(checkPassed, send) +} + func (self *eventTracker) assertNoEvent(t time.Duration) { select { case <-self.events: @@ -60,16 +89,21 @@ func (self *eventTracker) assertNoEvent(t time.Duration) { } } +func (self *eventTracker) assertNoSend(t time.Duration) { + select { + case <-self.healthSends: + self.Fail("no health send should be found") + case <-time.After(t): + } +} + func Test_ManagerWithEventCounts(t *testing.T) { mgr := NewManager() defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{ - Assertions: req, - events: make(chan *svcChangeEvent, 16), - } + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceRequired, 100, et) @@ -149,10 +183,7 @@ func Test_ManagerWithDurations(t *testing.T) { req := require.New(t) - et := &eventTracker{ - Assertions: req, - events: make(chan *svcChangeEvent, 16), - } + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) @@ -280,7 +311,7 @@ func Test_ManagerWithSimpleHttp(t *testing.T) { defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{Assertions: req, events: make(chan *svcChangeEvent, 16)} + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) healthCheckDef := newHttpCheck() @@ -289,7 +320,7 @@ func Test_ManagerWithSimpleHttp(t *testing.T) { req.NoError(err) et.assertEvent(100*time.Millisecond, 0, edge.PrecedenceFailed) - mgr.UnregisterServiceChecks("my-server") + mgr.UnregisterServiceChecks("my-service") state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) closeF := runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { @@ -307,7 +338,7 @@ func Test_ManagerWithHttpStatusCode(t *testing.T) { defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{Assertions: req, events: make(chan *svcChangeEvent, 16)} + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) healthCheckDef := newHttpCheck() @@ -324,7 +355,7 @@ func Test_ManagerWithHttpStatusCode(t *testing.T) { et.assertEvent(100*time.Millisecond, 0, edge.PrecedenceFailed) closeF() - mgr.UnregisterServiceChecks("my-server") + mgr.UnregisterServiceChecks("my-service") state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) closeF = runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { @@ -343,7 +374,7 @@ func Test_ManagerWithHttpExpectBody(t *testing.T) { defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{Assertions: req, events: make(chan *svcChangeEvent, 16)} + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) healthCheckDef := newHttpCheck() @@ -361,7 +392,7 @@ func Test_ManagerWithHttpExpectBody(t *testing.T) { et.assertEvent(100*time.Millisecond, 0, edge.PrecedenceFailed) closeF() - mgr.UnregisterServiceChecks("my-server") + mgr.UnregisterServiceChecks("my-service") state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) closeF = runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { @@ -381,7 +412,7 @@ func Test_ManagerWithHttpMethod(t *testing.T) { defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{Assertions: req, events: make(chan *svcChangeEvent, 16)} + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) healthCheckDef := newHttpCheck() @@ -405,7 +436,7 @@ func Test_ManagerWithHttpMethod(t *testing.T) { et.assertEvent(100*time.Millisecond, 0, edge.PrecedenceFailed) closeF() - mgr.UnregisterServiceChecks("my-server") + mgr.UnregisterServiceChecks("my-service") state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) closeF = runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { @@ -429,7 +460,7 @@ func Test_ManagerWithHttpBody(t *testing.T) { defer mgr.Shutdown() req := require.New(t) - et := &eventTracker{Assertions: req, events: make(chan *svcChangeEvent, 16)} + et := newEventTracker(t) state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) healthCheckDef := newHttpCheck() @@ -459,7 +490,7 @@ func Test_ManagerWithHttpBody(t *testing.T) { et.assertEvent(100*time.Millisecond, 0, edge.PrecedenceFailed) closeF() - mgr.UnregisterServiceChecks("my-server") + mgr.UnregisterServiceChecks("my-service") state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) closeF = runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { @@ -487,3 +518,38 @@ func Test_ManagerWithHttpBody(t *testing.T) { req.NoError(err) et.assertEvent(100*time.Millisecond, 10, edge.PrecedenceDefault) } + +func Test_ChangeAndHealthSend(t *testing.T) { + mgr := NewManager() + defer mgr.Shutdown() + + req := require.New(t) + et := newEventTracker(t) + state := NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) + + healthCheckDef := &HttpCheckDefinition{ + BaseCheckDefinition: BaseCheckDefinition{ + Interval: 100 * time.Millisecond, + Actions: []*ActionDefinition{ + {Trigger: "change", Action: "send event"}, + }, + }, + Url: "http://localhost:9876", + Timeout: 100 * time.Millisecond, + } + + err := mgr.RegisterServiceChecks(state, []CheckDefinition{healthCheckDef}) + req.NoError(err) + et.assertHealthSend(100*time.Millisecond, false) + et.assertNoSend(200 * time.Millisecond) + + state = NewServiceState("my-service", ziti.PrecedenceDefault, 0, et) + closeF := runHttpCheck(req, func(resp http.ResponseWriter, req *http.Request) { + resp.WriteHeader(200) + }) + defer closeF() + + et.assertHealthSend(500*time.Millisecond, true) + et.assertNoSend(200 * time.Millisecond) + +} diff --git a/pb/edge_ctrl_pb/edge_ctrl.pb.go b/pb/edge_ctrl_pb/edge_ctrl.pb.go index 926fc60a2..06efd9a06 100644 --- a/pb/edge_ctrl_pb/edge_ctrl.pb.go +++ b/pb/edge_ctrl_pb/edge_ctrl.pb.go @@ -44,6 +44,7 @@ const ( ContentType_RemoveTerminatorRequestType ContentType = 20211 ContentType_RemoveTerminatorResponseType ContentType = 20212 ContentType_ValidateSessionsRequestType ContentType = 20213 + ContentType_HealthEventType ContentType = 20214 ContentType_EnrollType ContentType = 20300 ContentType_EnrollCertsType ContentType = 20301 ContentType_CreateApiSessionRequestType ContentType = 20400 @@ -58,6 +59,7 @@ const ( ContentType_UpdateTunnelTerminatorResponseType ContentType = 20409 ContentType_RemoveTunnelTerminatorRequestType ContentType = 20410 ContentType_RemoveTunnelTerminatorResponseType ContentType = 20411 + ContentType_TunnelHealthEventType ContentType = 20412 ) // Enum value maps for ContentType. @@ -82,6 +84,7 @@ var ( 20211: "RemoveTerminatorRequestType", 20212: "RemoveTerminatorResponseType", 20213: "ValidateSessionsRequestType", + 20214: "HealthEventType", 20300: "EnrollType", 20301: "EnrollCertsType", 20400: "CreateApiSessionRequestType", @@ -96,6 +99,7 @@ var ( 20409: "UpdateTunnelTerminatorResponseType", 20410: "RemoveTunnelTerminatorRequestType", 20411: "RemoveTunnelTerminatorResponseType", + 20412: "TunnelHealthEventType", } ContentType_value = map[string]int32{ "Zero": 0, @@ -117,6 +121,7 @@ var ( "RemoveTerminatorRequestType": 20211, "RemoveTerminatorResponseType": 20212, "ValidateSessionsRequestType": 20213, + "HealthEventType": 20214, "EnrollType": 20300, "EnrollCertsType": 20301, "CreateApiSessionRequestType": 20400, @@ -131,6 +136,7 @@ var ( "UpdateTunnelTerminatorResponseType": 20409, "RemoveTunnelTerminatorRequestType": 20410, "RemoveTunnelTerminatorResponseType": 20411, + "TunnelHealthEventType": 20412, } ) @@ -207,6 +213,55 @@ func (SessionType) EnumDescriptor() ([]byte, []int) { return file_edge_ctrl_proto_rawDescGZIP(), []int{1} } +type Header int32 + +const ( + Header_HeaderZero Header = 0 + Header_TerminatorId Header = 1022 + Header_CheckPassed Header = 1023 +) + +// Enum value maps for Header. +var ( + Header_name = map[int32]string{ + 0: "HeaderZero", + 1022: "TerminatorId", + 1023: "CheckPassed", + } + Header_value = map[string]int32{ + "HeaderZero": 0, + "TerminatorId": 1022, + "CheckPassed": 1023, + } +) + +func (x Header) Enum() *Header { + p := new(Header) + *p = x + return p +} + +func (x Header) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Header) Descriptor() protoreflect.EnumDescriptor { + return file_edge_ctrl_proto_enumTypes[2].Descriptor() +} + +func (Header) Type() protoreflect.EnumType { + return &file_edge_ctrl_proto_enumTypes[2] +} + +func (x Header) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Header.Descriptor instead. +func (Header) EnumDescriptor() ([]byte, []int) { + return file_edge_ctrl_proto_rawDescGZIP(), []int{2} +} + type TerminatorPrecedence int32 const ( @@ -240,11 +295,11 @@ func (x TerminatorPrecedence) String() string { } func (TerminatorPrecedence) Descriptor() protoreflect.EnumDescriptor { - return file_edge_ctrl_proto_enumTypes[2].Descriptor() + return file_edge_ctrl_proto_enumTypes[3].Descriptor() } func (TerminatorPrecedence) Type() protoreflect.EnumType { - return &file_edge_ctrl_proto_enumTypes[2] + return &file_edge_ctrl_proto_enumTypes[3] } func (x TerminatorPrecedence) Number() protoreflect.EnumNumber { @@ -253,7 +308,7 @@ func (x TerminatorPrecedence) Number() protoreflect.EnumNumber { // Deprecated: Use TerminatorPrecedence.Descriptor instead. func (TerminatorPrecedence) EnumDescriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{2} + return file_edge_ctrl_proto_rawDescGZIP(), []int{3} } type ServerHello struct { @@ -1367,6 +1422,77 @@ func (x *UpdateTerminatorRequest) GetUpdateCost() bool { return false } +type HealthEventRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionToken string `protobuf:"bytes,1,opt,name=sessionToken,proto3" json:"sessionToken,omitempty"` + Fingerprints []string `protobuf:"bytes,2,rep,name=fingerprints,proto3" json:"fingerprints,omitempty"` + TerminatorId string `protobuf:"bytes,3,opt,name=terminatorId,proto3" json:"terminatorId,omitempty"` + CheckPassed bool `protobuf:"varint,4,opt,name=checkPassed,proto3" json:"checkPassed,omitempty"` +} + +func (x *HealthEventRequest) Reset() { + *x = HealthEventRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_edge_ctrl_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HealthEventRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthEventRequest) ProtoMessage() {} + +func (x *HealthEventRequest) ProtoReflect() protoreflect.Message { + mi := &file_edge_ctrl_proto_msgTypes[17] + 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 HealthEventRequest.ProtoReflect.Descriptor instead. +func (*HealthEventRequest) Descriptor() ([]byte, []int) { + return file_edge_ctrl_proto_rawDescGZIP(), []int{17} +} + +func (x *HealthEventRequest) GetSessionToken() string { + if x != nil { + return x.SessionToken + } + return "" +} + +func (x *HealthEventRequest) GetFingerprints() []string { + if x != nil { + return x.Fingerprints + } + return nil +} + +func (x *HealthEventRequest) GetTerminatorId() string { + if x != nil { + return x.TerminatorId + } + return "" +} + +func (x *HealthEventRequest) GetCheckPassed() bool { + if x != nil { + return x.CheckPassed + } + return false +} + type ValidateSessionsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1378,7 +1504,7 @@ type ValidateSessionsRequest struct { func (x *ValidateSessionsRequest) Reset() { *x = ValidateSessionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[17] + mi := &file_edge_ctrl_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1391,7 +1517,7 @@ func (x *ValidateSessionsRequest) String() string { func (*ValidateSessionsRequest) ProtoMessage() {} func (x *ValidateSessionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[17] + mi := &file_edge_ctrl_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1404,7 +1530,7 @@ func (x *ValidateSessionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ValidateSessionsRequest.ProtoReflect.Descriptor instead. func (*ValidateSessionsRequest) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{17} + return file_edge_ctrl_proto_rawDescGZIP(), []int{18} } func (x *ValidateSessionsRequest) GetSessionTokens() []string { @@ -1428,7 +1554,7 @@ type EnvInfo struct { func (x *EnvInfo) Reset() { *x = EnvInfo{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[18] + mi := &file_edge_ctrl_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1441,7 +1567,7 @@ func (x *EnvInfo) String() string { func (*EnvInfo) ProtoMessage() {} func (x *EnvInfo) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[18] + mi := &file_edge_ctrl_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1454,7 +1580,7 @@ func (x *EnvInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvInfo.ProtoReflect.Descriptor instead. func (*EnvInfo) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{18} + return file_edge_ctrl_proto_rawDescGZIP(), []int{19} } func (x *EnvInfo) GetArch() string { @@ -1501,7 +1627,7 @@ type SdkInfo struct { func (x *SdkInfo) Reset() { *x = SdkInfo{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[19] + mi := &file_edge_ctrl_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1514,7 +1640,7 @@ func (x *SdkInfo) String() string { func (*SdkInfo) ProtoMessage() {} func (x *SdkInfo) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[19] + mi := &file_edge_ctrl_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1527,7 +1653,7 @@ func (x *SdkInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SdkInfo.ProtoReflect.Descriptor instead. func (*SdkInfo) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{19} + return file_edge_ctrl_proto_rawDescGZIP(), []int{20} } func (x *SdkInfo) GetAppId() string { @@ -1585,7 +1711,7 @@ type CreateApiSessionRequest struct { func (x *CreateApiSessionRequest) Reset() { *x = CreateApiSessionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[20] + mi := &file_edge_ctrl_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1598,7 +1724,7 @@ func (x *CreateApiSessionRequest) String() string { func (*CreateApiSessionRequest) ProtoMessage() {} func (x *CreateApiSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[20] + mi := &file_edge_ctrl_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1611,7 +1737,7 @@ func (x *CreateApiSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateApiSessionRequest.ProtoReflect.Descriptor instead. func (*CreateApiSessionRequest) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{20} + return file_edge_ctrl_proto_rawDescGZIP(), []int{21} } func (x *CreateApiSessionRequest) GetEnvInfo() *EnvInfo { @@ -1652,7 +1778,7 @@ type CreateApiSessionResponse struct { func (x *CreateApiSessionResponse) Reset() { *x = CreateApiSessionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[21] + mi := &file_edge_ctrl_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1665,7 +1791,7 @@ func (x *CreateApiSessionResponse) String() string { func (*CreateApiSessionResponse) ProtoMessage() {} func (x *CreateApiSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[21] + mi := &file_edge_ctrl_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1678,7 +1804,7 @@ func (x *CreateApiSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateApiSessionResponse.ProtoReflect.Descriptor instead. func (*CreateApiSessionResponse) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{21} + return file_edge_ctrl_proto_rawDescGZIP(), []int{22} } func (x *CreateApiSessionResponse) GetSessionId() string { @@ -1744,7 +1870,7 @@ type CreateCircuitForServiceRequest struct { func (x *CreateCircuitForServiceRequest) Reset() { *x = CreateCircuitForServiceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[22] + mi := &file_edge_ctrl_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1757,7 +1883,7 @@ func (x *CreateCircuitForServiceRequest) String() string { func (*CreateCircuitForServiceRequest) ProtoMessage() {} func (x *CreateCircuitForServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[22] + mi := &file_edge_ctrl_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1770,7 +1896,7 @@ func (x *CreateCircuitForServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateCircuitForServiceRequest.ProtoReflect.Descriptor instead. func (*CreateCircuitForServiceRequest) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{22} + return file_edge_ctrl_proto_rawDescGZIP(), []int{23} } func (x *CreateCircuitForServiceRequest) GetSessionId() string { @@ -1813,7 +1939,7 @@ type CreateSessionResponse struct { func (x *CreateSessionResponse) Reset() { *x = CreateSessionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[23] + mi := &file_edge_ctrl_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1826,7 +1952,7 @@ func (x *CreateSessionResponse) String() string { func (*CreateSessionResponse) ProtoMessage() {} func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[23] + mi := &file_edge_ctrl_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1839,7 +1965,7 @@ func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSessionResponse) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{23} + return file_edge_ctrl_proto_rawDescGZIP(), []int{24} } func (x *CreateSessionResponse) GetSessionId() string { @@ -1871,7 +1997,7 @@ type CreateCircuitForServiceResponse struct { func (x *CreateCircuitForServiceResponse) Reset() { *x = CreateCircuitForServiceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[24] + mi := &file_edge_ctrl_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1884,7 +2010,7 @@ func (x *CreateCircuitForServiceResponse) String() string { func (*CreateCircuitForServiceResponse) ProtoMessage() {} func (x *CreateCircuitForServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[24] + mi := &file_edge_ctrl_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1897,7 +2023,7 @@ func (x *CreateCircuitForServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateCircuitForServiceResponse.ProtoReflect.Descriptor instead. func (*CreateCircuitForServiceResponse) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{24} + return file_edge_ctrl_proto_rawDescGZIP(), []int{25} } func (x *CreateCircuitForServiceResponse) GetApiSession() *CreateApiSessionResponse { @@ -1947,7 +2073,7 @@ type ServicesList struct { func (x *ServicesList) Reset() { *x = ServicesList{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[25] + mi := &file_edge_ctrl_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1960,7 +2086,7 @@ func (x *ServicesList) String() string { func (*ServicesList) ProtoMessage() {} func (x *ServicesList) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[25] + mi := &file_edge_ctrl_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1973,7 +2099,7 @@ func (x *ServicesList) ProtoReflect() protoreflect.Message { // Deprecated: Use ServicesList.ProtoReflect.Descriptor instead. func (*ServicesList) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{25} + return file_edge_ctrl_proto_rawDescGZIP(), []int{26} } func (x *ServicesList) GetLastUpdate() []byte { @@ -2006,7 +2132,7 @@ type TunnelService struct { func (x *TunnelService) Reset() { *x = TunnelService{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[26] + mi := &file_edge_ctrl_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2019,7 +2145,7 @@ func (x *TunnelService) String() string { func (*TunnelService) ProtoMessage() {} func (x *TunnelService) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[26] + mi := &file_edge_ctrl_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2032,7 +2158,7 @@ func (x *TunnelService) ProtoReflect() protoreflect.Message { // Deprecated: Use TunnelService.ProtoReflect.Descriptor instead. func (*TunnelService) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{26} + return file_edge_ctrl_proto_rawDescGZIP(), []int{27} } func (x *TunnelService) GetId() string { @@ -2095,7 +2221,7 @@ type CreateTunnelTerminatorRequest struct { func (x *CreateTunnelTerminatorRequest) Reset() { *x = CreateTunnelTerminatorRequest{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[27] + mi := &file_edge_ctrl_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2108,7 +2234,7 @@ func (x *CreateTunnelTerminatorRequest) String() string { func (*CreateTunnelTerminatorRequest) ProtoMessage() {} func (x *CreateTunnelTerminatorRequest) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[27] + mi := &file_edge_ctrl_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2121,7 +2247,7 @@ func (x *CreateTunnelTerminatorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTunnelTerminatorRequest.ProtoReflect.Descriptor instead. func (*CreateTunnelTerminatorRequest) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{27} + return file_edge_ctrl_proto_rawDescGZIP(), []int{28} } func (x *CreateTunnelTerminatorRequest) GetServiceName() string { @@ -2193,7 +2319,7 @@ type CreateTunnelTerminatorResponse struct { func (x *CreateTunnelTerminatorResponse) Reset() { *x = CreateTunnelTerminatorResponse{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[28] + mi := &file_edge_ctrl_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2206,7 +2332,7 @@ func (x *CreateTunnelTerminatorResponse) String() string { func (*CreateTunnelTerminatorResponse) ProtoMessage() {} func (x *CreateTunnelTerminatorResponse) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[28] + mi := &file_edge_ctrl_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2219,7 +2345,7 @@ func (x *CreateTunnelTerminatorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTunnelTerminatorResponse.ProtoReflect.Descriptor instead. func (*CreateTunnelTerminatorResponse) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{28} + return file_edge_ctrl_proto_rawDescGZIP(), []int{29} } func (x *CreateTunnelTerminatorResponse) GetApiSession() *CreateApiSessionResponse { @@ -2258,7 +2384,7 @@ type UpdateTunnelTerminatorRequest struct { func (x *UpdateTunnelTerminatorRequest) Reset() { *x = UpdateTunnelTerminatorRequest{} if protoimpl.UnsafeEnabled { - mi := &file_edge_ctrl_proto_msgTypes[29] + mi := &file_edge_ctrl_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2271,7 +2397,7 @@ func (x *UpdateTunnelTerminatorRequest) String() string { func (*UpdateTunnelTerminatorRequest) ProtoMessage() {} func (x *UpdateTunnelTerminatorRequest) ProtoReflect() protoreflect.Message { - mi := &file_edge_ctrl_proto_msgTypes[29] + mi := &file_edge_ctrl_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2284,7 +2410,7 @@ func (x *UpdateTunnelTerminatorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTunnelTerminatorRequest.ProtoReflect.Descriptor instead. func (*UpdateTunnelTerminatorRequest) Descriptor() ([]byte, []int) { - return file_edge_ctrl_proto_rawDescGZIP(), []int{29} + return file_edge_ctrl_proto_rawDescGZIP(), []int{30} } func (x *UpdateTunnelTerminatorRequest) GetTerminatorId() string { @@ -2494,254 +2620,271 @@ var file_edge_ctrl_proto_rawDesc = []byte{ 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, 0x74, - 0x22, 0x3f, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x22, 0x69, 0x0a, 0x07, 0x45, 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, - 0x61, 0x72, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, - 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x73, - 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x73, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x73, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xa1, 0x01, 0x0a, - 0x07, 0x53, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x41, 0x70, 0x70, 0x49, 0x64, 0x12, 0x1e, - 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x22, 0x9d, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, - 0x65, 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x76, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x65, 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, - 0x07, 0x73, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x64, - 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x73, - 0x22, 0xda, 0x02, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x12, 0x36, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x16, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5e, 0x0a, - 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x50, - 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, - 0x6e, 0x63, 0x65, 0x52, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, - 0x69, 0x6e, 0x67, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2e, 0x0a, - 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43, - 0x6f, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x73, 0x74, 0x22, 0xa5, 0x02, - 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, - 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x20, - 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x2e, 0x0a, 0x12, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x74, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x12, 0x56, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, - 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, - 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, - 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0xf6, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, - 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x65, 0x64, 0x67, - 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x22, 0xa2, 0x01, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x66, + 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x12, + 0x22, 0x0a, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x50, 0x61, 0x73, 0x73, + 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x50, + 0x61, 0x73, 0x73, 0x65, 0x64, 0x22, 0x3f, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x22, 0x69, 0x0a, 0x07, 0x45, 0x6e, 0x76, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x4f, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x73, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x73, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4f, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0xa1, 0x01, 0x0a, 0x07, 0x53, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, + 0x05, 0x41, 0x70, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x41, 0x70, + 0x70, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x52, + 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, + 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x9d, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x65, 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, + 0x62, 0x2e, 0x45, 0x6e, 0x76, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x65, 0x6e, 0x76, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, + 0x70, 0x62, 0x2e, 0x53, 0x64, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x64, 0x6b, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0xda, 0x02, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, - 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, - 0x09, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x57, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, - 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, + 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x36, 0x0a, 0x16, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x22, + 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x5e, 0x0a, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, + 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x72, + 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, + 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, + 0x73, 0x74, 0x22, 0xa5, 0x02, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, + 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x12, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x56, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, + 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x3b, - 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x67, 0x0a, 0x0c, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, - 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, - 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x22, 0xa1, 0x01, 0x0a, 0x0d, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xa9, 0x03, 0x0a, 0x1d, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x55, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, - 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x63, - 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, - 0x42, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, - 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, - 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, - 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, - 0x26, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x3b, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44, - 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x65, 0x64, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, + 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x15, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xf6, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0a, 0x61, + 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x26, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x49, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x49, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x57, 0x0a, 0x08, 0x70, 0x65, + 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x65, + 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x65, 0x65, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, + 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x67, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, + 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0xa1, 0x01, 0x0a, 0x0d, 0x54, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xa9, 0x03, + 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x55, 0x0a, 0x08, 0x70, 0x65, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x3d, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, - 0x0a, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x49, 0x64, 0x22, 0xe7, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, - 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x6f, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, - 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, - 0x12, 0x2a, 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x2a, 0xb0, 0x08, 0x0a, - 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, - 0x5a, 0x65, 0x72, 0x6f, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x10, 0xa0, 0x9c, 0x01, 0x12, 0x15, 0x0a, - 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x79, 0x70, 0x65, - 0x10, 0xa1, 0x9c, 0x01, 0x12, 0x0f, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x54, 0x79, 0x70, - 0x65, 0x10, 0xa2, 0x9c, 0x01, 0x12, 0x18, 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x10, 0x86, 0x9d, 0x01, 0x12, - 0x19, 0x0a, 0x13, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x10, 0xe8, 0x9d, 0x01, 0x12, 0x1b, 0x0a, 0x15, 0x41, 0x70, - 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, - 0x79, 0x70, 0x65, 0x10, 0xe9, 0x9d, 0x01, 0x12, 0x1b, 0x0a, 0x15, 0x41, 0x70, 0x69, 0x53, 0x65, + 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x63, 0x6f, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, + 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x70, 0x72, + 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x1a, 0x3b, 0x0a, 0x0d, + 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x1e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0a, + 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, + 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x22, 0xe7, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x73, + 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, + 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, + 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x65, + 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x73, + 0x74, 0x2a, 0xe4, 0x08, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x65, 0x72, 0x6f, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x0f, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x10, 0xa0, + 0x9c, 0x01, 0x12, 0x15, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x6c, 0x6c, + 0x6f, 0x54, 0x79, 0x70, 0x65, 0x10, 0xa1, 0x9c, 0x01, 0x12, 0x0f, 0x0a, 0x09, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x10, 0xa2, 0x9c, 0x01, 0x12, 0x18, 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, - 0x10, 0xea, 0x9d, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, - 0xeb, 0x9d, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x54, 0x79, 0x70, 0x65, 0x10, 0xec, - 0x9d, 0x01, 0x12, 0x1e, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, - 0x75, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xed, - 0x9d, 0x01, 0x12, 0x1f, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, - 0x75, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, - 0xee, 0x9d, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, - 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x10, 0xef, 0x9d, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf0, 0x9d, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf1, 0x9d, 0x01, 0x12, 0x22, 0x0a, - 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf2, 0x9d, - 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, - 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x10, 0xf3, 0x9d, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x65, - 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x10, 0xf4, 0x9d, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x56, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf5, 0x9d, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x45, - 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x10, 0xcc, 0x9e, 0x01, 0x12, 0x15, 0x0a, - 0x0f, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x73, 0x54, 0x79, 0x70, 0x65, - 0x10, 0xcd, 0x9e, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, - 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x10, 0xb0, 0x9f, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb1, 0x9f, 0x01, 0x12, 0x28, 0x0a, 0x22, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x10, 0xb2, 0x9f, 0x01, 0x12, 0x29, 0x0a, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, - 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb3, 0x9f, 0x01, - 0x12, 0x1d, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb4, 0x9f, 0x01, 0x12, - 0x15, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x10, 0xb5, 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb6, 0x9f, 0x01, 0x12, - 0x28, 0x0a, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, - 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb7, 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb8, - 0x9f, 0x01, 0x12, 0x28, 0x0a, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb9, 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x10, 0xba, 0x9f, 0x01, 0x12, 0x28, 0x0a, 0x22, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, + 0x10, 0x86, 0x9d, 0x01, 0x12, 0x19, 0x0a, 0x13, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x10, 0xe8, 0x9d, 0x01, 0x12, + 0x1b, 0x0a, 0x15, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x10, 0xe9, 0x9d, 0x01, 0x12, 0x1b, 0x0a, 0x15, + 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x54, 0x79, 0x70, 0x65, 0x10, 0xea, 0x9d, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x41, 0x70, 0x69, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x10, 0xeb, 0x9d, 0x01, 0x12, 0x1d, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x54, + 0x79, 0x70, 0x65, 0x10, 0xec, 0x9d, 0x01, 0x12, 0x1e, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x10, 0xed, 0x9d, 0x01, 0x12, 0x1f, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x10, 0xee, 0x9d, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xef, 0x9d, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf0, 0x9d, 0x01, 0x12, + 0x21, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf1, + 0x9d, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x10, 0xf2, 0x9d, 0x01, 0x12, 0x21, 0x0a, 0x1b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf3, 0x9d, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf4, 0x9d, 0x01, 0x12, 0x21, 0x0a, + 0x1b, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xf5, 0x9d, 0x01, + 0x12, 0x15, 0x0a, 0x0f, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x10, 0xf6, 0x9d, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x45, 0x6e, 0x72, 0x6f, 0x6c, + 0x6c, 0x54, 0x79, 0x70, 0x65, 0x10, 0xcc, 0x9e, 0x01, 0x12, 0x15, 0x0a, 0x0f, 0x45, 0x6e, 0x72, + 0x6f, 0x6c, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x73, 0x54, 0x79, 0x70, 0x65, 0x10, 0xcd, 0x9e, 0x01, + 0x12, 0x21, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, + 0xb0, 0x9f, 0x01, 0x12, 0x22, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x69, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x10, 0xb1, 0x9f, 0x01, 0x12, 0x28, 0x0a, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb2, 0x9f, + 0x01, 0x12, 0x29, 0x0a, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x69, 0x72, 0x63, 0x75, + 0x69, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb3, 0x9f, 0x01, 0x12, 0x1d, 0x0a, 0x17, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb4, 0x9f, 0x01, 0x12, 0x15, 0x0a, 0x0f, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb5, + 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, + 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb6, 0x9f, 0x01, 0x12, 0x28, 0x0a, 0x22, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x10, 0xb7, 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xbb, 0x9f, 0x01, 0x2a, - 0x21, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, - 0x0a, 0x04, 0x44, 0x69, 0x61, 0x6c, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x69, 0x6e, 0x64, - 0x10, 0x01, 0x2a, 0x3d, 0x0a, 0x14, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, - 0x02, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6f, 0x70, 0x65, 0x6e, 0x7a, 0x69, 0x74, 0x69, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x70, 0x62, - 0x2f, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xb8, 0x9f, 0x01, 0x12, 0x28, + 0x0a, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x10, 0xb9, 0x9f, 0x01, 0x12, 0x27, 0x0a, 0x21, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x10, 0xba, 0x9f, + 0x01, 0x12, 0x28, 0x0a, 0x22, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, + 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0xbb, 0x9f, 0x01, 0x12, 0x1b, 0x0a, 0x15, 0x54, + 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x10, 0xbc, 0x9f, 0x01, 0x2a, 0x21, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x69, 0x61, 0x6c, 0x10, + 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x69, 0x6e, 0x64, 0x10, 0x01, 0x2a, 0x3d, 0x0a, 0x06, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x0a, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5a, + 0x65, 0x72, 0x6f, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x49, 0x64, 0x10, 0xfe, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x50, 0x61, 0x73, 0x73, 0x65, 0x64, 0x10, 0xff, 0x07, 0x2a, 0x3d, 0x0a, 0x14, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x6e, + 0x63, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x00, 0x12, + 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x02, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x7a, 0x69, 0x74, 0x69, + 0x2f, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x70, 0x62, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x63, 0x74, + 0x72, 0x6c, 0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2756,76 +2899,78 @@ func file_edge_ctrl_proto_rawDescGZIP() []byte { return file_edge_ctrl_proto_rawDescData } -var file_edge_ctrl_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_edge_ctrl_proto_msgTypes = make([]protoimpl.MessageInfo, 38) +var file_edge_ctrl_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_edge_ctrl_proto_msgTypes = make([]protoimpl.MessageInfo, 39) var file_edge_ctrl_proto_goTypes = []interface{}{ (ContentType)(0), // 0: edge_ctrl.pb.ContentType (SessionType)(0), // 1: edge_ctrl.pb.SessionType - (TerminatorPrecedence)(0), // 2: edge_ctrl.pb.TerminatorPrecedence - (*ServerHello)(nil), // 3: edge_ctrl.pb.ServerHello - (*ClientHello)(nil), // 4: edge_ctrl.pb.ClientHello - (*Error)(nil), // 5: edge_ctrl.pb.Error - (*Service)(nil), // 6: edge_ctrl.pb.Service - (*Session)(nil), // 7: edge_ctrl.pb.Session - (*ApiSession)(nil), // 8: edge_ctrl.pb.ApiSession - (*ApiSessionAdded)(nil), // 9: edge_ctrl.pb.ApiSessionAdded - (*ApiSessionUpdated)(nil), // 10: edge_ctrl.pb.ApiSessionUpdated - (*ApiSessionRemoved)(nil), // 11: edge_ctrl.pb.ApiSessionRemoved - (*ApiSessionHeartbeat)(nil), // 12: edge_ctrl.pb.ApiSessionHeartbeat - (*SessionRemoved)(nil), // 13: edge_ctrl.pb.SessionRemoved - (*RequestClientReSync)(nil), // 14: edge_ctrl.pb.RequestClientReSync - (*CreateCircuitRequest)(nil), // 15: edge_ctrl.pb.CreateCircuitRequest - (*CreateCircuitResponse)(nil), // 16: edge_ctrl.pb.CreateCircuitResponse - (*CreateTerminatorRequest)(nil), // 17: edge_ctrl.pb.CreateTerminatorRequest - (*RemoveTerminatorRequest)(nil), // 18: edge_ctrl.pb.RemoveTerminatorRequest - (*UpdateTerminatorRequest)(nil), // 19: edge_ctrl.pb.UpdateTerminatorRequest - (*ValidateSessionsRequest)(nil), // 20: edge_ctrl.pb.ValidateSessionsRequest - (*EnvInfo)(nil), // 21: edge_ctrl.pb.EnvInfo - (*SdkInfo)(nil), // 22: edge_ctrl.pb.SdkInfo - (*CreateApiSessionRequest)(nil), // 23: edge_ctrl.pb.CreateApiSessionRequest - (*CreateApiSessionResponse)(nil), // 24: edge_ctrl.pb.CreateApiSessionResponse - (*CreateCircuitForServiceRequest)(nil), // 25: edge_ctrl.pb.CreateCircuitForServiceRequest - (*CreateSessionResponse)(nil), // 26: edge_ctrl.pb.CreateSessionResponse - (*CreateCircuitForServiceResponse)(nil), // 27: edge_ctrl.pb.CreateCircuitForServiceResponse - (*ServicesList)(nil), // 28: edge_ctrl.pb.ServicesList - (*TunnelService)(nil), // 29: edge_ctrl.pb.TunnelService - (*CreateTunnelTerminatorRequest)(nil), // 30: edge_ctrl.pb.CreateTunnelTerminatorRequest - (*CreateTunnelTerminatorResponse)(nil), // 31: edge_ctrl.pb.CreateTunnelTerminatorResponse - (*UpdateTunnelTerminatorRequest)(nil), // 32: edge_ctrl.pb.UpdateTunnelTerminatorRequest - nil, // 33: edge_ctrl.pb.ServerHello.DataEntry - nil, // 34: edge_ctrl.pb.ClientHello.DataEntry - nil, // 35: edge_ctrl.pb.CreateCircuitRequest.PeerDataEntry - nil, // 36: edge_ctrl.pb.CreateCircuitResponse.PeerDataEntry - nil, // 37: edge_ctrl.pb.CreateTerminatorRequest.PeerDataEntry - nil, // 38: edge_ctrl.pb.CreateCircuitForServiceRequest.PeerDataEntry - nil, // 39: edge_ctrl.pb.CreateCircuitForServiceResponse.PeerDataEntry - nil, // 40: edge_ctrl.pb.CreateTunnelTerminatorRequest.PeerDataEntry + (Header)(0), // 2: edge_ctrl.pb.Header + (TerminatorPrecedence)(0), // 3: edge_ctrl.pb.TerminatorPrecedence + (*ServerHello)(nil), // 4: edge_ctrl.pb.ServerHello + (*ClientHello)(nil), // 5: edge_ctrl.pb.ClientHello + (*Error)(nil), // 6: edge_ctrl.pb.Error + (*Service)(nil), // 7: edge_ctrl.pb.Service + (*Session)(nil), // 8: edge_ctrl.pb.Session + (*ApiSession)(nil), // 9: edge_ctrl.pb.ApiSession + (*ApiSessionAdded)(nil), // 10: edge_ctrl.pb.ApiSessionAdded + (*ApiSessionUpdated)(nil), // 11: edge_ctrl.pb.ApiSessionUpdated + (*ApiSessionRemoved)(nil), // 12: edge_ctrl.pb.ApiSessionRemoved + (*ApiSessionHeartbeat)(nil), // 13: edge_ctrl.pb.ApiSessionHeartbeat + (*SessionRemoved)(nil), // 14: edge_ctrl.pb.SessionRemoved + (*RequestClientReSync)(nil), // 15: edge_ctrl.pb.RequestClientReSync + (*CreateCircuitRequest)(nil), // 16: edge_ctrl.pb.CreateCircuitRequest + (*CreateCircuitResponse)(nil), // 17: edge_ctrl.pb.CreateCircuitResponse + (*CreateTerminatorRequest)(nil), // 18: edge_ctrl.pb.CreateTerminatorRequest + (*RemoveTerminatorRequest)(nil), // 19: edge_ctrl.pb.RemoveTerminatorRequest + (*UpdateTerminatorRequest)(nil), // 20: edge_ctrl.pb.UpdateTerminatorRequest + (*HealthEventRequest)(nil), // 21: edge_ctrl.pb.HealthEventRequest + (*ValidateSessionsRequest)(nil), // 22: edge_ctrl.pb.ValidateSessionsRequest + (*EnvInfo)(nil), // 23: edge_ctrl.pb.EnvInfo + (*SdkInfo)(nil), // 24: edge_ctrl.pb.SdkInfo + (*CreateApiSessionRequest)(nil), // 25: edge_ctrl.pb.CreateApiSessionRequest + (*CreateApiSessionResponse)(nil), // 26: edge_ctrl.pb.CreateApiSessionResponse + (*CreateCircuitForServiceRequest)(nil), // 27: edge_ctrl.pb.CreateCircuitForServiceRequest + (*CreateSessionResponse)(nil), // 28: edge_ctrl.pb.CreateSessionResponse + (*CreateCircuitForServiceResponse)(nil), // 29: edge_ctrl.pb.CreateCircuitForServiceResponse + (*ServicesList)(nil), // 30: edge_ctrl.pb.ServicesList + (*TunnelService)(nil), // 31: edge_ctrl.pb.TunnelService + (*CreateTunnelTerminatorRequest)(nil), // 32: edge_ctrl.pb.CreateTunnelTerminatorRequest + (*CreateTunnelTerminatorResponse)(nil), // 33: edge_ctrl.pb.CreateTunnelTerminatorResponse + (*UpdateTunnelTerminatorRequest)(nil), // 34: edge_ctrl.pb.UpdateTunnelTerminatorRequest + nil, // 35: edge_ctrl.pb.ServerHello.DataEntry + nil, // 36: edge_ctrl.pb.ClientHello.DataEntry + nil, // 37: edge_ctrl.pb.CreateCircuitRequest.PeerDataEntry + nil, // 38: edge_ctrl.pb.CreateCircuitResponse.PeerDataEntry + nil, // 39: edge_ctrl.pb.CreateTerminatorRequest.PeerDataEntry + nil, // 40: edge_ctrl.pb.CreateCircuitForServiceRequest.PeerDataEntry + nil, // 41: edge_ctrl.pb.CreateCircuitForServiceResponse.PeerDataEntry + nil, // 42: edge_ctrl.pb.CreateTunnelTerminatorRequest.PeerDataEntry } var file_edge_ctrl_proto_depIdxs = []int32{ - 33, // 0: edge_ctrl.pb.ServerHello.data:type_name -> edge_ctrl.pb.ServerHello.DataEntry - 34, // 1: edge_ctrl.pb.ClientHello.data:type_name -> edge_ctrl.pb.ClientHello.DataEntry + 35, // 0: edge_ctrl.pb.ServerHello.data:type_name -> edge_ctrl.pb.ServerHello.DataEntry + 36, // 1: edge_ctrl.pb.ClientHello.data:type_name -> edge_ctrl.pb.ClientHello.DataEntry 1, // 2: edge_ctrl.pb.Session.type:type_name -> edge_ctrl.pb.SessionType - 6, // 3: edge_ctrl.pb.Session.service:type_name -> edge_ctrl.pb.Service - 8, // 4: edge_ctrl.pb.ApiSessionAdded.apiSessions:type_name -> edge_ctrl.pb.ApiSession - 8, // 5: edge_ctrl.pb.ApiSessionUpdated.apiSessions:type_name -> edge_ctrl.pb.ApiSession - 35, // 6: edge_ctrl.pb.CreateCircuitRequest.peerData:type_name -> edge_ctrl.pb.CreateCircuitRequest.PeerDataEntry - 36, // 7: edge_ctrl.pb.CreateCircuitResponse.peerData:type_name -> edge_ctrl.pb.CreateCircuitResponse.PeerDataEntry - 37, // 8: edge_ctrl.pb.CreateTerminatorRequest.peerData:type_name -> edge_ctrl.pb.CreateTerminatorRequest.PeerDataEntry - 2, // 9: edge_ctrl.pb.CreateTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence - 2, // 10: edge_ctrl.pb.UpdateTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence - 21, // 11: edge_ctrl.pb.CreateApiSessionRequest.envInfo:type_name -> edge_ctrl.pb.EnvInfo - 22, // 12: edge_ctrl.pb.CreateApiSessionRequest.sdkInfo:type_name -> edge_ctrl.pb.SdkInfo - 2, // 13: edge_ctrl.pb.CreateApiSessionResponse.defaultHostingPrecedence:type_name -> edge_ctrl.pb.TerminatorPrecedence - 38, // 14: edge_ctrl.pb.CreateCircuitForServiceRequest.peerData:type_name -> edge_ctrl.pb.CreateCircuitForServiceRequest.PeerDataEntry - 24, // 15: edge_ctrl.pb.CreateCircuitForServiceResponse.apiSession:type_name -> edge_ctrl.pb.CreateApiSessionResponse - 26, // 16: edge_ctrl.pb.CreateCircuitForServiceResponse.session:type_name -> edge_ctrl.pb.CreateSessionResponse - 39, // 17: edge_ctrl.pb.CreateCircuitForServiceResponse.peerData:type_name -> edge_ctrl.pb.CreateCircuitForServiceResponse.PeerDataEntry - 29, // 18: edge_ctrl.pb.ServicesList.services:type_name -> edge_ctrl.pb.TunnelService - 40, // 19: edge_ctrl.pb.CreateTunnelTerminatorRequest.peerData:type_name -> edge_ctrl.pb.CreateTunnelTerminatorRequest.PeerDataEntry - 2, // 20: edge_ctrl.pb.CreateTunnelTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence - 24, // 21: edge_ctrl.pb.CreateTunnelTerminatorResponse.apiSession:type_name -> edge_ctrl.pb.CreateApiSessionResponse - 26, // 22: edge_ctrl.pb.CreateTunnelTerminatorResponse.session:type_name -> edge_ctrl.pb.CreateSessionResponse - 2, // 23: edge_ctrl.pb.UpdateTunnelTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence + 7, // 3: edge_ctrl.pb.Session.service:type_name -> edge_ctrl.pb.Service + 9, // 4: edge_ctrl.pb.ApiSessionAdded.apiSessions:type_name -> edge_ctrl.pb.ApiSession + 9, // 5: edge_ctrl.pb.ApiSessionUpdated.apiSessions:type_name -> edge_ctrl.pb.ApiSession + 37, // 6: edge_ctrl.pb.CreateCircuitRequest.peerData:type_name -> edge_ctrl.pb.CreateCircuitRequest.PeerDataEntry + 38, // 7: edge_ctrl.pb.CreateCircuitResponse.peerData:type_name -> edge_ctrl.pb.CreateCircuitResponse.PeerDataEntry + 39, // 8: edge_ctrl.pb.CreateTerminatorRequest.peerData:type_name -> edge_ctrl.pb.CreateTerminatorRequest.PeerDataEntry + 3, // 9: edge_ctrl.pb.CreateTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence + 3, // 10: edge_ctrl.pb.UpdateTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence + 23, // 11: edge_ctrl.pb.CreateApiSessionRequest.envInfo:type_name -> edge_ctrl.pb.EnvInfo + 24, // 12: edge_ctrl.pb.CreateApiSessionRequest.sdkInfo:type_name -> edge_ctrl.pb.SdkInfo + 3, // 13: edge_ctrl.pb.CreateApiSessionResponse.defaultHostingPrecedence:type_name -> edge_ctrl.pb.TerminatorPrecedence + 40, // 14: edge_ctrl.pb.CreateCircuitForServiceRequest.peerData:type_name -> edge_ctrl.pb.CreateCircuitForServiceRequest.PeerDataEntry + 26, // 15: edge_ctrl.pb.CreateCircuitForServiceResponse.apiSession:type_name -> edge_ctrl.pb.CreateApiSessionResponse + 28, // 16: edge_ctrl.pb.CreateCircuitForServiceResponse.session:type_name -> edge_ctrl.pb.CreateSessionResponse + 41, // 17: edge_ctrl.pb.CreateCircuitForServiceResponse.peerData:type_name -> edge_ctrl.pb.CreateCircuitForServiceResponse.PeerDataEntry + 31, // 18: edge_ctrl.pb.ServicesList.services:type_name -> edge_ctrl.pb.TunnelService + 42, // 19: edge_ctrl.pb.CreateTunnelTerminatorRequest.peerData:type_name -> edge_ctrl.pb.CreateTunnelTerminatorRequest.PeerDataEntry + 3, // 20: edge_ctrl.pb.CreateTunnelTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence + 26, // 21: edge_ctrl.pb.CreateTunnelTerminatorResponse.apiSession:type_name -> edge_ctrl.pb.CreateApiSessionResponse + 28, // 22: edge_ctrl.pb.CreateTunnelTerminatorResponse.session:type_name -> edge_ctrl.pb.CreateSessionResponse + 3, // 23: edge_ctrl.pb.UpdateTunnelTerminatorRequest.precedence:type_name -> edge_ctrl.pb.TerminatorPrecedence 24, // [24:24] is the sub-list for method output_type 24, // [24:24] is the sub-list for method input_type 24, // [24:24] is the sub-list for extension type_name @@ -3044,7 +3189,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidateSessionsRequest); i { + switch v := v.(*HealthEventRequest); i { case 0: return &v.state case 1: @@ -3056,7 +3201,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EnvInfo); i { + switch v := v.(*ValidateSessionsRequest); i { case 0: return &v.state case 1: @@ -3068,7 +3213,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SdkInfo); i { + switch v := v.(*EnvInfo); i { case 0: return &v.state case 1: @@ -3080,7 +3225,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateApiSessionRequest); i { + switch v := v.(*SdkInfo); i { case 0: return &v.state case 1: @@ -3092,7 +3237,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateApiSessionResponse); i { + switch v := v.(*CreateApiSessionRequest); i { case 0: return &v.state case 1: @@ -3104,7 +3249,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateCircuitForServiceRequest); i { + switch v := v.(*CreateApiSessionResponse); i { case 0: return &v.state case 1: @@ -3116,7 +3261,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSessionResponse); i { + switch v := v.(*CreateCircuitForServiceRequest); i { case 0: return &v.state case 1: @@ -3128,7 +3273,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateCircuitForServiceResponse); i { + switch v := v.(*CreateSessionResponse); i { case 0: return &v.state case 1: @@ -3140,7 +3285,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServicesList); i { + switch v := v.(*CreateCircuitForServiceResponse); i { case 0: return &v.state case 1: @@ -3152,7 +3297,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TunnelService); i { + switch v := v.(*ServicesList); i { case 0: return &v.state case 1: @@ -3164,7 +3309,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateTunnelTerminatorRequest); i { + switch v := v.(*TunnelService); i { case 0: return &v.state case 1: @@ -3176,7 +3321,7 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateTunnelTerminatorResponse); i { + switch v := v.(*CreateTunnelTerminatorRequest); i { case 0: return &v.state case 1: @@ -3188,6 +3333,18 @@ func file_edge_ctrl_proto_init() { } } file_edge_ctrl_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTunnelTerminatorResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_edge_ctrl_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdateTunnelTerminatorRequest); i { case 0: return &v.state @@ -3205,8 +3362,8 @@ func file_edge_ctrl_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_edge_ctrl_proto_rawDesc, - NumEnums: 3, - NumMessages: 38, + NumEnums: 4, + NumMessages: 39, NumExtensions: 0, NumServices: 0, }, diff --git a/pb/edge_ctrl_pb/edge_ctrl.proto b/pb/edge_ctrl_pb/edge_ctrl.proto index 79c821b34..da886764c 100644 --- a/pb/edge_ctrl_pb/edge_ctrl.proto +++ b/pb/edge_ctrl_pb/edge_ctrl.proto @@ -26,6 +26,7 @@ enum ContentType { RemoveTerminatorRequestType = 20211; RemoveTerminatorResponseType = 20212; ValidateSessionsRequestType = 20213; + HealthEventType = 20214; EnrollType = 20300; EnrollCertsType = 20301; @@ -43,6 +44,8 @@ enum ContentType { RemoveTunnelTerminatorRequestType = 20410; RemoveTunnelTerminatorResponseType = 20411; + + TunnelHealthEventType = 20412; } enum SessionType { @@ -50,6 +53,12 @@ enum SessionType { Bind = 1; } +enum Header { + HeaderZero = 0; + TerminatorId = 1022; + CheckPassed = 1023; +} + message ServerHello { string version = 1; map data = 2; @@ -163,6 +172,13 @@ message UpdateTerminatorRequest { bool updateCost = 7; } +message HealthEventRequest { + string sessionToken = 1; + repeated string fingerprints = 2; + string terminatorId = 3; + bool checkPassed = 4; +} + message ValidateSessionsRequest { repeated string sessionTokens = 1; } diff --git a/pb/edge_ctrl_pb/messages.go b/pb/edge_ctrl_pb/messages.go index a595fcf4d..4946d6cbc 100644 --- a/pb/edge_ctrl_pb/messages.go +++ b/pb/edge_ctrl_pb/messages.go @@ -36,6 +36,10 @@ func (request *ValidateSessionsRequest) GetContentType() int32 { return int32(ContentType_ValidateSessionsRequestType) } +func (request *HealthEventRequest) GetContentType() int32 { + return int32(ContentType_HealthEventType) +} + func (request *CreateApiSessionRequest) GetContentType() int32 { return int32(ContentType_CreateApiSessionRequestType) } diff --git a/router/handler_edge_ctrl/sessionRemoved.go b/router/handler_edge_ctrl/sessionRemoved.go index 8366a78f8..6a875aad3 100644 --- a/router/handler_edge_ctrl/sessionRemoved.go +++ b/router/handler_edge_ctrl/sessionRemoved.go @@ -53,7 +53,7 @@ func (h *sessionRemovedHandler) HandleReceive(msg *channel2.Message, ch channel2 pfxlog.Logger(). WithField("sessionToken", token). WithField("sessionId", id). - Debugf("removing api session [token: %s] [id: %s]", token, id) + Debugf("removing session [token: %s] [id: %s]", token, id) h.sm.RemoveSession(token) } } else { diff --git a/router/xgress_edge/accept.go b/router/xgress_edge/accept.go index 87e9c4a78..8d11662c0 100644 --- a/router/xgress_edge/accept.go +++ b/router/xgress_edge/accept.go @@ -70,6 +70,11 @@ func (handler edgeBindHandler) BindChannel(ch channel2.Channel) error { Handler: proxy.processUpdateBind, }) + ch.AddReceiveHandler(&edge.AsyncFunctionReceiveAdapter{ + Type: edge.ContentTypeHealthEvent, + Handler: proxy.processHealthEvent, + }) + ch.AddReceiveHandler(&edge.FunctionReceiveAdapter{ Type: edge.ContentTypeStateClosed, Handler: proxy.msgMux.HandleReceive, diff --git a/router/xgress_edge/listener.go b/router/xgress_edge/listener.go index 331f4f634..85f3d7ba9 100644 --- a/router/xgress_edge/listener.go +++ b/router/xgress_edge/listener.go @@ -28,6 +28,7 @@ import ( "github.com/openziti/foundation/channel2" "github.com/openziti/foundation/identity/identity" "github.com/openziti/foundation/transport" + "github.com/openziti/foundation/util/protobufs" "github.com/openziti/sdk-golang/ziti/edge" "github.com/pkg/errors" "time" @@ -334,6 +335,35 @@ func (self *edgeClientConn) processUpdateBind(req *channel2.Message, ch channel2 } } +func (self *edgeClientConn) processHealthEvent(req *channel2.Message, ch channel2.Channel) { + token := string(req.Body) + log := pfxlog.ContextLogger(ch.Label()).WithField("sessionId", token).WithFields(edge.GetLoggerFields(req)) + + terminator, ok := self.listener.factory.hostedServices.Get(token) + + if !ok { + log.Error("failed to update bind, no listener found") + return + } + + checkPassed, _ := req.GetBoolHeader(edge.HealthStatusHeader) + + request := &edge_ctrl_pb.HealthEventRequest{ + SessionToken: token, + Fingerprints: self.fingerprints.Prints(), + TerminatorId: terminator.terminatorId, + CheckPassed: checkPassed, + } + + log = log.WithField("terminator", terminator.terminatorId). + WithField("checkPassed", checkPassed) + log.Debug("sending health event") + + if err := protobufs.Send(self.listener.factory.Channel(), request); err != nil { + log.WithError(err).Error("send failed") + } +} + func (self *edgeClientConn) sendStateConnectedReply(req *channel2.Message, hostData map[uint32][]byte) { connId, _ := req.GetUint32Header(edge.ConnIdHeader) msg := edge.NewStateConnectedMsg(connId) diff --git a/router/xgress_edge_tunnel/fabric.go b/router/xgress_edge_tunnel/fabric.go index f047fc723..d48171625 100644 --- a/router/xgress_edge_tunnel/fabric.go +++ b/router/xgress_edge_tunnel/fabric.go @@ -267,7 +267,7 @@ func (self *fabricProvider) HostService(hostCtx tunnel.HostingContext) (tunnel.H } }) - terminator.terminatorId = string(responseMsg.Body) + terminator.terminatorId = response.TerminatorId return terminator, nil } @@ -314,6 +314,24 @@ func (self *fabricProvider) updateTerminator(terminatorId string, cost *uint16, return nil } +func (self *fabricProvider) sendHealthEvent(terminatorId string, checkPassed bool) error { + msg := channel2.NewMessage(int32(edge_ctrl_pb.ContentType_TunnelHealthEventType), nil) + msg.Headers[int32(edge_ctrl_pb.Header_TerminatorId)] = []byte(terminatorId) + msg.PutBoolHeader(int32(edge_ctrl_pb.Header_CheckPassed), checkPassed) + + logger := logrus.WithField("terminator", terminatorId). + WithField("checkPassed", checkPassed) + logger.Debug("sending health event") + + if err := self.ctrlCh.Channel().Send(msg); err != nil { + logger.WithError(err).Error("health event send failed") + } else { + logger.Debug("health event sent") + } + + return nil +} + func (self *fabricProvider) requestServiceList(lastUpdateToken []byte) { msg := channel2.NewMessage(int32(edge_ctrl_pb.ContentType_ListServicesRequestType), lastUpdateToken) if err := self.ctrlCh.Channel().Send(msg); err != nil { @@ -329,9 +347,18 @@ type tunnelTerminator struct { closed concurrenz.AtomicBoolean } +func (self *tunnelTerminator) SendHealthEvent(pass bool) error { + return self.provider.sendHealthEvent(self.terminatorId, pass) +} + func (self *tunnelTerminator) Close() error { if self.closed.CompareAndSwap(false, true) { + log := logrus.WithField("service", self.context.ServiceName()).WithField("terminator", self.terminatorId) + log.Debug("closing tunnel terminator context") + self.context.OnClose() + log.Debug("unregistering session listener for tunnel terminator") self.closeCallback() + log.Debug("removing tunnel terminator") return self.provider.removeTerminator(self.terminatorId) } return nil diff --git a/router/xgress_edge_tunnel/servicepoll.go b/router/xgress_edge_tunnel/servicepoll.go index 15b11524c..09a73b6ee 100644 --- a/router/xgress_edge_tunnel/servicepoll.go +++ b/router/xgress_edge_tunnel/servicepoll.go @@ -63,15 +63,21 @@ func (self *servicePoller) handleServiceListUpdate(lastUpdateToken []byte, servi idMap[s.Id] = s } + var toRemove []string + // process Deletes self.services.IterCb(func(k string, value interface{}) { svc := value.(*edge.Service) if _, found := idMap[svc.Id]; !found { - self.services.Remove(k) + toRemove = append(toRemove, k) self.serviceListener.HandleServicesChange(ziti.ServiceRemoved, svc) } }) + for _, key := range toRemove { + self.services.Remove(key) + } + // Adds and Updates for _, s := range services { self.services.Upsert(s.Name, s, func(exist bool, valueInMap interface{}, newValue interface{}) interface{} { @@ -82,6 +88,8 @@ func (self *servicePoller) handleServiceListUpdate(lastUpdateToken []byte, servi if !reflect.DeepEqual(valueInMap, s) { self.serviceListener.HandleServicesChange(ziti.ServiceChanged, s) return s + } else { + logrus.WithField("service", s.Name).Debug("no change detected in service definition") } return valueInMap }) @@ -91,7 +99,8 @@ func (self *servicePoller) handleServiceListUpdate(lastUpdateToken []byte, servi // TODO: just push updates down the control channel when necessary func (self *servicePoller) pollServices(pollInterval time.Duration) { if err := self.fabricProvider.authenticate(); err != nil { - logrus.Panic(err) + logrus.WithError(err).Fatal("xgress_edge_tunnel unable to authenticate to controller. " + + "ensure tunneler mode is enabled for this router or disable tunnel listener. exiting ") } ticker := time.NewTicker(pollInterval) diff --git a/router/xgress_edge_tunnel/tunneler.go b/router/xgress_edge_tunnel/tunneler.go index 3682b4f0b..8420391b7 100644 --- a/router/xgress_edge_tunnel/tunneler.go +++ b/router/xgress_edge_tunnel/tunneler.go @@ -65,6 +65,7 @@ func (self *tunneler) Start() error { return errors.Wrap(err, "failed to initialize tproxy interceptor") } } else if self.listenOptions.mode == "host" { + self.listenOptions.resolver = "" self.interceptor = host.New() } else if self.listenOptions.mode == "proxy" { self.listenOptions.resolver = "" diff --git a/tunnel/intercept/const.go b/tunnel/const.go similarity index 73% rename from tunnel/intercept/const.go rename to tunnel/const.go index 0ddc133d1..ad94e15eb 100644 --- a/tunnel/intercept/const.go +++ b/tunnel/const.go @@ -1,7 +1,8 @@ -package intercept +package tunnel const ( InterceptedProtocolKey = "intercepted_protocol" InterceptedIpKey = "intercepted_ip" InterceptedPortKey = "intercepted_port" + SourceIpKey = "source_ip" ) diff --git a/tunnel/entities/host.v1.json b/tunnel/entities/host.v1.json new file mode 100644 index 000000000..f1b46b519 --- /dev/null +++ b/tunnel/entities/host.v1.json @@ -0,0 +1,166 @@ +{ + "schema": { + "$defs": { + "address": { + "oneOf": [ + { + "$ref": "#/$defs/ipAddress" + }, + { + "$ref": "#/$defs/hostname" + } + ] + }, + "hostname": { + "format": "hostname", + "not": { + "$ref": "#/$defs/ipAddressFormat" + }, + "type": "string" + }, + "ipAddress": { + "$ref": "#/$defs/ipAddressFormat", + "type": "string" + }, + "ipAddressFormat": { + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + } + }, + "$id": "http://ziti-edge.netfoundry.io/schemas/host-v1.schema.json", + "additionalProperties": false, + "allOf": [ + { + "oneOf": [ + { + "required": [ + "protocol" + ] + }, + { + "required": [ + "dialInterceptedProtocol" + ] + } + ] + }, + { + "oneOf": [ + { + "required": [ + "address" + ] + }, + { + "required": [ + "dialInterceptedAddress" + ] + } + ] + }, + { + "oneOf": [ + { + "required": [ + "port" + ] + }, + { + "required": [ + "dialInterceptedPort" + ] + } + ] + } + ], + "properties": { + "address": { + "$ref": "#/$defs/address", + "description": "Dial the specified ip address or hostname when a ziti client connects to the service." + }, + "dialInterceptedAddress": { + "description": "Dial the same ip address that was intercepted at the client tunneler. 'address' and 'dialInterceptedAddress' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "dialInterceptedPort": { + "description": "Dial the same port that was intercepted at the client tunneler. 'port' and 'dialInterceptedPort' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "dialInterceptedProtocol": { + "description": "Dial the same protocol that was intercepted at the client tunneler. 'protocol' and 'dialInterceptedProtocol' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "listenOptions": { + "additionalProperties": false, + "properties": { + "bindUsingEdgeIdentity": { + "description": "Associate the hosting terminator with the name of the hosting tunneler's identity. Setting this to 'true' is equivalent to setting 'identiy=$tunneler_id.name'", + "type": "boolean" + }, + "connectTimeoutSeconds": { + "description": "defaults to 5", + "maximum": 2147483647, + "minimum": 0, + "type": "integer" + }, + "cost": { + "description": "defaults to 0", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "identity": { + "description": "Associate the hosting terminator with the specified identity. '$tunneler_id.name' resolves to the name of the hosting tunneler's identity. '$tunneler_id.tag[tagName]' resolves to the value of the 'tagName' tag on the hosting tunneler's identity.", + "type": "string" + }, + "maxConnections": { + "description": "defaults to 3", + "minimum": 1, + "type": "integer" + }, + "precedence": { + "description": "defaults to 'default'", + "enum": [ + "default", + "required", + "failed" + ], + "type": "string" + } + }, + "type": "object" + }, + "port": { + "description": "Dial the specified port when a ziti client connects to the service.", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "protocol": { + "description": "Dial the specified protocol when a ziti client connects to the service.", + "enum": [ + "tcp", + "udp", + "sctp" + ], + "type": "string" + } + }, + "type": "object" + } +} diff --git a/tunnel/entities/host.v2.json b/tunnel/entities/host.v2.json new file mode 100644 index 000000000..e150d300d --- /dev/null +++ b/tunnel/entities/host.v2.json @@ -0,0 +1,305 @@ +{ + "$id": "http://ziti-edge.netfoundry.io/schemas/host-v2.schema.json", + "definitions": { + "action": { + "additionalProperties": false, + "properties": { + "action": { + "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+|send event)", + "type": "string" + }, + "consecutiveEvents": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "duration": { + "$ref": "#/definitions/duration" + }, + "trigger": { + "enum": [ + "fail", + "pass", + "change" + ], + "type": "string" + } + }, + "required": [ + "trigger", + "action" + ], + "type": "object" + }, + "actionList": { + "items": { + "$ref": "#/definitions/action" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "address": { + "oneOf": [ + { + "$ref": "#/definitions/ipAddress" + }, + { + "$ref": "#/definitions/hostname" + } + ] + }, + "duration": { + "pattern": "[0-9]+(h|m|s|ms)", + "type": "string" + }, + "hostname": { + "format": "hostname", + "not": { + "$ref": "#/definitions/ipAddressFormat" + }, + "type": "string" + }, + "httpCheck": { + "additionalProperties": false, + "properties": { + "actions": { + "$ref": "#/definitions/actionList" + }, + "body": { + "type": "string" + }, + "expectInBody": { + "type": "string" + }, + "expectStatus": { + "maximum": 599, + "minimum": 100, + "type": "integer" + }, + "interval": { + "$ref": "#/definitions/duration" + }, + "method": { + "$ref": "#/definitions/method" + }, + "timeout": { + "$ref": "#/definitions/duration" + }, + "url": { + "type": "string" + } + }, + "required": [ + "interval", + "timeout", + "url" + ], + "type": "object" + }, + "httpCheckList": { + "items": { + "$ref": "#/definitions/httpCheck" + }, + "type": "array" + }, + "ipAddress": { + "$ref": "#/definitions/ipAddressFormat", + "type": "string" + }, + "ipAddressFormat": { + "oneOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + }, + "method": { + "enum": [ + "GET", + "POST", + "PUT", + "PATCH" + ], + "type": "string" + }, + "portCheck": { + "additionalProperties": false, + "properties": { + "actions": { + "$ref": "#/definitions/actionList" + }, + "address": { + "type": "string" + }, + "interval": { + "$ref": "#/definitions/duration" + }, + "timeout": { + "$ref": "#/definitions/duration" + } + }, + "required": [ + "interval", + "timeout", + "address" + ], + "type": "object" + }, + "portCheckList": { + "items": { + "$ref": "#/definitions/portCheck" + }, + "type": "array" + }, + "terminator": { + "additionalProperties": false, + "allOf": [ + { + "oneOf": [ + { + "required": [ + "protocol" + ] + }, + { + "required": [ + "dialInterceptedProtocol" + ] + } + ] + }, + { + "oneOf": [ + { + "required": [ + "address" + ] + }, + { + "required": [ + "dialInterceptedAddress" + ] + } + ] + }, + { + "oneOf": [ + { + "required": [ + "port" + ] + }, + { + "required": [ + "dialInterceptedPort" + ] + } + ] + } + ], + "properties": { + "address": { + "$ref": "#/definitions/address", + "description": "Dial the specified ip address or hostname when a ziti client connects to the service." + }, + "dialInterceptedAddress": { + "description": "Dial the same ip address that was intercepted at the client tunneler. 'address' and 'dialInterceptedAddress' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "dialInterceptedPort": { + "description": "Dial the same port that was intercepted at the client tunneler. 'port' and 'dialInterceptedPort' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "dialInterceptedProtocol": { + "description": "Dial the same protocol that was intercepted at the client tunneler. 'protocol' and 'dialInterceptedProtocol' are mutually exclusive.", + "enum": [ + true + ], + "type": "boolean" + }, + "httpChecks": { + "$ref": "#/definitions/httpCheckList" + }, + "listenOptions": { + "additionalProperties": false, + "properties": { + "bindUsingEdgeIdentity": { + "description": "Associate the hosting terminator with the name of the hosting tunneler's identity. Setting this to 'true' is equivalent to setting 'identiy=$tunneler_id.name'", + "type": "boolean" + }, + "connectTimeout": { + "$ref": "#/definitions/duration" + }, + "cost": { + "description": "defaults to 0", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "identity": { + "description": "Associate the hosting terminator with the specified identity. '$tunneler_id.name' resolves to the name of the hosting tunneler's identity. '$tunneler_id.tag[tagName]' resolves to the value of the 'tagName' tag on the hosting tunneler's identity.", + "type": "string" + }, + "maxConnections": { + "description": "defaults to 3", + "minimum": 1, + "type": "integer" + }, + "precedence": { + "description": "defaults to 'default'", + "enum": [ + "default", + "required", + "failed" + ], + "type": "string" + } + }, + "type": "object" + }, + "port": { + "description": "Dial the specified port when a ziti client connects to the service.", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "portChecks": { + "$ref": "#/definitions/portCheckList" + }, + "protocol": { + "description": "Dial the specified protocol when a ziti client connects to the service.", + "enum": [ + "tcp", + "udp", + "sctp" + ], + "type": "string" + } + }, + "type": "object" + }, + "terminatorList": { + "items": { + "$ref": "#/definitions/terminator" + }, + "minItems": 1, + "type": "array" + } + }, + "properties": { + "terminators": { + "$ref": "#/definitions/terminatorList" + } + }, + "type": "object" +} diff --git a/tunnel/entities/service.go b/tunnel/entities/service.go index 24f3305c2..5e3e221fc 100644 --- a/tunnel/entities/service.go +++ b/tunnel/entities/service.go @@ -3,12 +3,20 @@ package entities import ( "fmt" "github.com/openziti/edge/health" + "github.com/openziti/edge/tunnel" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" + "github.com/pkg/errors" + "reflect" + "strconv" + "time" ) const ( ClientConfigV1 = "ziti-tunneler-client.v1" ServerConfigV1 = "ziti-tunneler-server.v1" + HostConfigV1 = "host.v1" + HostConfigV2 = "host.v2" ) type ServiceConfig struct { @@ -19,13 +27,168 @@ type ServiceConfig struct { HttpChecks []*health.HttpCheckDefinition } +func (self *ServiceConfig) GetPortChecks() []*health.PortCheckDefinition { + return self.PortChecks +} + +func (self *ServiceConfig) GetHttpChecks() []*health.HttpCheckDefinition { + return self.HttpChecks +} + func (s *ServiceConfig) String() string { return fmt.Sprintf("%v:%v:%v", s.Protocol, s.Hostname, s.Port) } +type HostV1ListenOptions struct { + BindUsingEdgeIdentity bool + ConnectTimeoutSeconds *int + Cost *int + Identity string + MaxConnections int + Precedence *string +} + +type HostV1Config struct { + Protocol string + DialInterceptedProtocol bool + Address string + DialInterceptedAddress bool + Port int + DialInterceptedPort bool + + PortChecks []*health.PortCheckDefinition + HttpChecks []*health.HttpCheckDefinition + + ListenOptions *HostV1ListenOptions +} + +func (self *HostV1Config) ToHostV2Config() *HostV2Config { + terminator := &HostV2Terminator{ + Protocol: self.Protocol, + DialInterceptedProtocol: self.DialInterceptedProtocol, + Address: self.Address, + DialInterceptedAddress: self.DialInterceptedAddress, + Port: self.Port, + DialInterceptedPort: self.DialInterceptedPort, + PortChecks: self.PortChecks, + HttpChecks: self.HttpChecks, + } + + if self.ListenOptions != nil { + var timeout *time.Duration + if self.ListenOptions.ConnectTimeoutSeconds != nil { + val := time.Duration(*self.ListenOptions.ConnectTimeoutSeconds) * time.Second + timeout = &val + } + terminator.ListenOptions = &HostV2ListenOptions{ + BindUsingEdgeIdentity: self.ListenOptions.BindUsingEdgeIdentity, + ConnectTimeout: timeout, + Cost: self.ListenOptions.Cost, + Identity: self.ListenOptions.Identity, + MaxConnections: self.ListenOptions.MaxConnections, + Precedence: self.ListenOptions.Precedence, + } + } + + return &HostV2Config{ + Terminators: []*HostV2Terminator{ + terminator, + }, + } +} + +type HostV2ListenOptions struct { + BindUsingEdgeIdentity bool + ConnectTimeout *time.Duration + Cost *int + Identity string + MaxConnections int + Precedence *string +} + +type HostV2Terminator struct { + Protocol string + DialInterceptedProtocol bool + Address string + DialInterceptedAddress bool + Port int + DialInterceptedPort bool + + PortChecks []*health.PortCheckDefinition + HttpChecks []*health.HttpCheckDefinition + + ListenOptions *HostV2ListenOptions +} + +func (self *HostV2Terminator) SetListenOptions(options *ziti.ListenOptions) { + if self.ListenOptions != nil { + if self.ListenOptions.Cost != nil { + options.Cost = uint16(*self.ListenOptions.Cost) + } + if self.ListenOptions.Precedence != nil { + options.Precedence = ziti.GetPrecedenceForLabel(*self.ListenOptions.Precedence) + } + } +} + +func (self *HostV2Terminator) GetDialTimeout(defaultTimeout time.Duration) time.Duration { + if self.ListenOptions != nil && self.ListenOptions.ConnectTimeout != nil { + return *self.ListenOptions.ConnectTimeout + } + return defaultTimeout +} + +func (self *HostV2Terminator) GetPortChecks() []*health.PortCheckDefinition { + return self.PortChecks +} + +func (self *HostV2Terminator) GetHttpChecks() []*health.HttpCheckDefinition { + return self.HttpChecks +} + +func (self *HostV2Terminator) getValue(options map[string]interface{}, key string) (string, error) { + val, ok := options[key] + if !ok { + return "", errors.Errorf("%v required but not provided", key) + } + result, ok := val.(string) + if !ok { + return "", errors.Errorf("%v required and present but not a string. val: %v, type: %v", key, val, reflect.TypeOf(val)) + } + return result, nil +} + +func (self *HostV2Terminator) GetProtocol(options map[string]interface{}) (string, error) { + if self.DialInterceptedProtocol { + return self.getValue(options, tunnel.InterceptedProtocolKey) + } + return self.Protocol, nil +} + +func (self *HostV2Terminator) GetAddress(options map[string]interface{}) (string, error) { + if self.DialInterceptedAddress { + return self.getValue(options, tunnel.InterceptedIpKey) + } + return self.Address, nil +} + +func (self *HostV2Terminator) GetPort(options map[string]interface{}) (string, error) { + if self.DialInterceptedPort { + return self.getValue(options, tunnel.InterceptedPortKey) + } + return strconv.Itoa(self.Port), nil +} + +type HostV2Config struct { + Terminators []*HostV2Terminator +} + type Service struct { edge.Service ClientConfig *ServiceConfig + ServerConfig *ServiceConfig + HostV2Config *HostV2Config + StopHostHook func() } diff --git a/tunnel/entities/ziti-tunneler-server-v1.json b/tunnel/entities/ziti-tunneler-server-v1.json new file mode 100644 index 000000000..e5cdcf258 --- /dev/null +++ b/tunnel/entities/ziti-tunneler-server-v1.json @@ -0,0 +1,161 @@ +{ + "schema": { + "$id": "http://edge.openziti.org/schemas/ziti-tunneler-server.v1.config.json", + "additionalProperties": false, + "definitions": { + "action": { + "additionalProperties": false, + "properties": { + "action": { + "pattern": "(mark (un)?healthy|increase cost [0-9]+|decrease cost [0-9]+)", + "type": "string" + }, + "consecutiveEvents": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "duration": { + "$ref": "#/definitions/duration" + }, + "trigger": { + "enum": [ + "fail", + "pass" + ], + "type": "string" + } + }, + "required": [ + "trigger", + "action" + ], + "type": "object" + }, + "actionList": { + "items": { + "$ref": "#/definitions/action" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "duration": { + "pattern": "[0-9]+(h|m|s|ms)", + "type": "string" + }, + "httpCheck": { + "additionalProperties": false, + "properties": { + "actions": { + "$ref": "#/definitions/actionList" + }, + "body": { + "type": "string" + }, + "expectInBody": { + "type": "string" + }, + "expectStatus": { + "maximum": 599, + "minimum": 100, + "type": "integer" + }, + "interval": { + "$ref": "#/definitions/duration" + }, + "method": { + "$ref": "#/definitions/method" + }, + "timeout": { + "$ref": "#/definitions/duration" + }, + "url": { + "type": "string" + } + }, + "required": [ + "interval", + "timeout", + "url" + ], + "type": "object" + }, + "httpCheckList": { + "items": { + "$ref": "#/definitions/httpCheck" + }, + "type": "array" + }, + "method": { + "enum": [ + "GET", + "POST", + "PUT", + "PATCH" + ], + "type": "string" + }, + "portCheck": { + "additionalProperties": false, + "properties": { + "actions": { + "$ref": "#/definitions/actionList" + }, + "address": { + "type": "string" + }, + "interval": { + "$ref": "#/definitions/duration" + }, + "timeout": { + "$ref": "#/definitions/duration" + } + }, + "required": [ + "interval", + "timeout", + "address" + ], + "type": "object" + }, + "portCheckList": { + "items": { + "$ref": "#/definitions/portCheck" + }, + "type": "array" + } + }, + "properties": { + "hostname": { + "type": "string" + }, + "httpChecks": { + "$ref": "#/definitions/httpCheckList" + }, + "port": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "portChecks": { + "$ref": "#/definitions/portCheckList" + }, + "protocol": { + "enum": [ + "tcp", + "udp" + ], + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "hostname", + "port" + ], + "type": "object" + } +} diff --git a/tunnel/intercept/hosting.go b/tunnel/intercept/hosting.go new file mode 100644 index 000000000..e48a07740 --- /dev/null +++ b/tunnel/intercept/hosting.go @@ -0,0 +1,178 @@ +package intercept + +import ( + "github.com/openziti/edge/health" + "github.com/openziti/edge/tunnel" + "github.com/openziti/edge/tunnel/entities" + "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/sdk-golang/ziti/edge" + "net" + "strconv" + "strings" + "time" +) + +const ( + defaultDialTimeout = 5 * time.Second +) + +type healthChecksProvider interface { + GetPortChecks() []*health.PortCheckDefinition + GetHttpChecks() []*health.HttpCheckDefinition +} + +type serviceConfiguration interface { + healthChecksProvider + SetListenOptions(options *ziti.ListenOptions) + GetDialTimeout(defaultTimeout time.Duration) time.Duration + GetProtocol(options map[string]interface{}) (string, error) + GetAddress(options map[string]interface{}) (string, error) + GetPort(options map[string]interface{}) (string, error) +} + +func createHostingContexts(service *entities.Service, identity *edge.CurrentIdentity) []tunnel.HostingContext { + if service.HostV2Config != nil { + var result []tunnel.HostingContext + for _, t := range service.HostV2Config.Terminators { + context := newDefaultHostingContext(identity, service, t) + result = append(result, context) + } + return result + } + + context := &legacyHostingContext{ + baseHostingContext{ + service: service, + options: getDefaultOptions(identity), + dialTimeout: defaultDialTimeout, + }, + } + return []tunnel.HostingContext{context} +} + +type baseHostingContext struct { + service *entities.Service + options *ziti.ListenOptions + dialTimeout time.Duration + onClose func() +} + +func (self *baseHostingContext) ServiceName() string { + return self.service.Name +} + +func (self *baseHostingContext) ListenOptions() *ziti.ListenOptions { + return self.options +} + +func (self *baseHostingContext) dialAddress(options map[string]interface{}, protocol string, address string) (net.Conn, error) { + var sourceIp string + if val, ok := options[tunnel.SourceIpKey]; ok { + sourceIp = val.(string) + } + + if sourceIp != "" { + dialer := net.Dialer{ + LocalAddr: &net.TCPAddr{IP: net.ParseIP(sourceIp)}, + Timeout: self.dialTimeout, + } + return dialer.Dial(protocol, address) + } + + return net.DialTimeout(protocol, address, self.dialTimeout) +} + +func (self *baseHostingContext) SupportHalfClose() bool { + return !strings.Contains(self.service.ServerConfig.Protocol, "udp") +} + +func (self *baseHostingContext) SetCloseCallback(f func()) { + self.onClose = f +} + +func (self *baseHostingContext) OnClose() { + if self.onClose != nil { + self.onClose() + } +} + +func (self *baseHostingContext) getHealthChecks(provider healthChecksProvider) []health.CheckDefinition { + var checkDefinitions []health.CheckDefinition + + for _, checkDef := range provider.GetPortChecks() { + checkDefinitions = append(checkDefinitions, checkDef) + } + + for _, checkDef := range provider.GetHttpChecks() { + checkDefinitions = append(checkDefinitions, checkDef) + } + + return checkDefinitions +} + +func (self *baseHostingContext) GetInitialHealthState() (ziti.Precedence, uint16) { + return self.options.Precedence, self.options.Cost +} + +type legacyHostingContext struct { + baseHostingContext +} + +func (self *legacyHostingContext) GetHealthChecks() []health.CheckDefinition { + return self.getHealthChecks(self.service.ServerConfig) +} + +func (self *legacyHostingContext) Dial(options map[string]interface{}) (net.Conn, error) { + config := self.service.ServerConfig + return self.dialAddress(options, config.Protocol, config.Hostname+":"+strconv.Itoa(config.Port)) +} + +func newDefaultHostingContext(identity *edge.CurrentIdentity, service *entities.Service, config serviceConfiguration) *hostV2HostingContext { + options := getDefaultOptions(identity) + config.SetListenOptions(options) + + return &hostV2HostingContext{ + baseHostingContext: baseHostingContext{ + service: service, + options: options, + dialTimeout: config.GetDialTimeout(5 * time.Second), + }, + config: config, + } +} + +type hostV2HostingContext struct { + baseHostingContext + config serviceConfiguration +} + +func (self *hostV2HostingContext) GetHealthChecks() []health.CheckDefinition { + return self.getHealthChecks(self.config) +} + +func (self *hostV2HostingContext) Dial(options map[string]interface{}) (net.Conn, error) { + protocol, err := self.config.GetProtocol(options) + if err != nil { + return nil, err + } + + address, err := self.config.GetAddress(options) + if err != nil { + return nil, err + } + + port, err := self.config.GetPort(options) + if err != nil { + return nil, err + } + + return self.dialAddress(options, protocol, address+":"+port) +} + +func getDefaultOptions(identity *edge.CurrentIdentity) *ziti.ListenOptions { + options := ziti.DefaultListenOptions() + options.ManualStart = true + options.Precedence = ziti.GetPrecedenceForLabel(identity.DefaultHostingPrecedence) + options.Cost = identity.DefaultHostingCost + return options +} diff --git a/tunnel/intercept/svcpoll.go b/tunnel/intercept/svcpoll.go index f7a23e1c9..3ef065191 100644 --- a/tunnel/intercept/svcpoll.go +++ b/tunnel/intercept/svcpoll.go @@ -25,12 +25,10 @@ import ( "github.com/openziti/foundation/util/stringz" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" - log "github.com/sirupsen/logrus" - "net" + logrus "github.com/sirupsen/logrus" "os" "os/signal" "strconv" - "strings" "sync" "syscall" ) @@ -60,7 +58,7 @@ func (self *ServiceListener) WaitForShutdown() { signal.Notify(sig, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM) for s := range sig { - log.Debugf("caught signal %v", s) + logrus.Debugf("caught signal %v", s) break } @@ -80,13 +78,20 @@ func (self *ServiceListener) HandleProviderReady(provider tunnel.FabricProvider) func (self *ServiceListener) HandleServicesChange(eventType ziti.ServiceEventType, service *edge.Service) { tunnelerService := &entities.Service{Service: *service} + log := logrus.WithField("service", service.Name) + switch eventType { case ziti.ServiceAdded: + log.Info("adding service") self.addService(tunnelerService) case ziti.ServiceRemoved: + log.Info("removing service") self.removeService(tunnelerService) case ziti.ServiceChanged: + log.Info("updating service: removing old service") self.removeService(tunnelerService) + + log.Info("updating service: adding new service") self.addService(tunnelerService) default: pfxlog.Logger().Errorf("unhandled service change event type: %v", eventType) @@ -116,11 +121,27 @@ func (self *ServiceListener) addService(svc *entities.Service) { } if stringz.Contains(svc.Permissions, "Bind") { - serverConfig := &entities.ServiceConfig{} - found, err := svc.GetConfigOfType(entities.ServerConfigV1, serverConfig) + hostV2config := &entities.HostV2Config{} + found, err := svc.GetConfigOfType(entities.HostConfigV2, hostV2config) + if found { + svc.HostV2Config = hostV2config + } + + if !found { + hostV1config := &entities.HostV1Config{} + if found, err = svc.GetConfigOfType(entities.HostConfigV1, hostV1config); found { + svc.HostV2Config = hostV1config.ToHostV2Config() + } + } + + if !found { + serverConfig := &entities.ServiceConfig{} + if found, err = svc.GetConfigOfType(entities.ServerConfigV1, serverConfig); found { + svc.ServerConfig = serverConfig + } + } if found && err == nil { - svc.ServerConfig = serverConfig log.Infof("Hosting newly available service %s", svc.Name) go self.host(svc) } else if !found { @@ -176,83 +197,40 @@ func (self *ServiceListener) host(svc *entities.Service) { return } - options := ziti.DefaultListenOptions() - options.ManualStart = true - options.Precedence = ziti.GetPrecedenceForLabel(currentIdentity.DefaultHostingPrecedence) - options.Cost = currentIdentity.DefaultHostingCost + hostContexts := createHostingContexts(svc, currentIdentity) - context := &hostingContext{ - service: svc, - options: options, - onClose: func() { - self.healthCheckMgr.UnregisterServiceChecks(svc.Id) - }, - } - - hostControl, err := self.provider.HostService(context) - if err != nil { - logger.WithError(err).WithField("service", svc.Name).Errorf("error listening for service") - return - } + var hostControls []tunnel.HostControl stopHook := func() { - _ = hostControl.Close() + for _, hostControl := range hostControls { + _ = hostControl.Close() + } self.healthCheckMgr.UnregisterServiceChecks(svc.Id) } - svc.StopHostHook = stopHook - if err := self.setupHealthChecks(hostControl, svc, currentIdentity); err != nil { - logger.WithError(err).Error("error setting up health checks") - stopHook() - return + for idx, hostContext := range hostContexts { + hostControl, err := self.provider.HostService(hostContext) + if err != nil { + logger.WithError(err).WithField("service", svc.Name).Errorf("error listening for service") + return + } + + context := strconv.Itoa(idx) + + hostContext.SetCloseCallback(func() { + self.healthCheckMgr.UnregisterServiceContextChecks(svc.Name, context) + }) + + hostControls = append(hostControls, hostControl) + + precedence, cost := hostContext.GetInitialHealthState() + serviceState := health.NewServiceStateWithContext(svc.Name, context, precedence, cost, hostControl) + + if err := self.healthCheckMgr.RegisterServiceChecks(serviceState, hostContext.GetHealthChecks()); err != nil { + logger.WithError(err).Error("error setting up health checks") + hostContext.OnClose() + return + } } } - -func (self *ServiceListener) setupHealthChecks(serviceUpdater health.ServiceUpdater, service *entities.Service, identity *edge.CurrentIdentity) error { - precedence := ziti.GetPrecedenceForLabel(identity.DefaultHostingPrecedence) - serviceState := health.NewServiceState(service.Name, precedence, identity.DefaultHostingCost, serviceUpdater) - - var checkDefinitions []health.CheckDefinition - - for _, checkDef := range service.ServerConfig.PortChecks { - checkDefinitions = append(checkDefinitions, checkDef) - } - - for _, checkDef := range service.ServerConfig.HttpChecks { - checkDefinitions = append(checkDefinitions, checkDef) - } - - if len(checkDefinitions) > 0 { - return self.healthCheckMgr.RegisterServiceChecks(serviceState, checkDefinitions) - } - - return nil -} - -type hostingContext struct { - service *entities.Service - options *ziti.ListenOptions - onClose func() -} - -func (self *hostingContext) ServiceName() string { - return self.service.Name -} - -func (self *hostingContext) ListenOptions() *ziti.ListenOptions { - return self.options -} - -func (self *hostingContext) Dial(options map[string]interface{}) (net.Conn, error) { - config := self.service.ServerConfig - return net.Dial(config.Protocol, config.Hostname+":"+strconv.Itoa(config.Port)) -} - -func (self *hostingContext) SupportHalfClose() bool { - return !strings.Contains(self.service.ServerConfig.Protocol, "udp") -} - -func (self *hostingContext) OnClose() { - self.onClose() -} diff --git a/tunnel/provider.go b/tunnel/provider.go index b72ed9f2b..902709580 100644 --- a/tunnel/provider.go +++ b/tunnel/provider.go @@ -2,6 +2,7 @@ package tunnel import ( "encoding/json" + "github.com/openziti/edge/health" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" "github.com/sirupsen/logrus" @@ -14,7 +15,10 @@ type HostingContext interface { ListenOptions() *ziti.ListenOptions Dial(options map[string]interface{}) (net.Conn, error) SupportHalfClose() bool + GetHealthChecks() []health.CheckDefinition + GetInitialHealthState() (ziti.Precedence, uint16) OnClose() + SetCloseCallback(func()) } type HostControl interface { @@ -22,6 +26,7 @@ type HostControl interface { UpdateCost(cost uint16) error UpdatePrecedence(precedence edge.Precedence) error UpdateCostAndPrecedence(cost uint16, precedence edge.Precedence) error + SendHealthEvent(pass bool) error } type FabricProvider interface {