little-cui closed pull request #220: SC-49 Pact broker module for consumer-driven contract testing URL: https://github.com/apache/incubator-servicecomb-service-center/pull/220
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/server/bootstrap/bootstrap.go b/server/bootstrap/bootstrap.go index 058d034d..1bd7a5a7 100644 --- a/server/bootstrap/bootstrap.go +++ b/server/bootstrap/bootstrap.go @@ -45,6 +45,9 @@ import _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/i // module import _ "github.com/apache/incubator-servicecomb-service-center/server/govern" +// module +import _ "github.com/apache/incubator-servicecomb-service-center/server/broker" + import ( "github.com/apache/incubator-servicecomb-service-center/pkg/util" "github.com/apache/incubator-servicecomb-service-center/server/handler/auth" diff --git a/server/broker/README.md b/server/broker/README.md new file mode 100644 index 00000000..9f579081 --- /dev/null +++ b/server/broker/README.md @@ -0,0 +1,98 @@ +# Pact Broker Module + +Pact broker module enables consumer-driven contract testing in service-center. + +## Pact broker services + +* Consumer microservices can publish pact. + +``` +PUT /pacts/provider/:providerId/consumer/:consumerId/version/:number +'{ + "provider" : "", + "consumer" : "", + ... + +}' +``` + +* Provider microservices can retrieve pacts published by consumer microservices, verify the pacts, and publish the verification results. + + 1. Retrieving the information about the pacts associated with a provider + +``` +GET /pacts/provider/:providerId/latest + +Response: +{ + "_links" : { + "pacts" : [ + { + "href" : "/pacts/provider/:providerId/consumer/:consumerId/version/:number" + "name" : "Pact between consumerId and providerId with version number" + } + ] + } +} +``` + + 2. Retrieving the actual pact between a consumer and provider for verification + +``` +GET /pacts/provider/:providerId/consumer/:consumerId/version/:number +Response: +{ + "pact" : []byte +} +``` + + 3. Publishing the pact verification result to the broker + +``` +POST /pacts/provider/:providerId/consumer/:consumerId/pact-version/:number/verification-results +'{ + "success" : true + "providerApplicationVersion" : "0.0.1" +}' + +Response: +{ + "confirmation" : { + "providerName" : "" + "providerApplicationVersion" : "0.0.1" + "success" : true + "verificationDate" : "" + } +} +``` + +* Consumer microservices can retrieve the verification results published by the providers. + +``` +GET /verification-results/consumer/:consumerId/version/:version/latest + +Response: +{ + "result" : { + "success" : true + "providerSummary" : { + "successful" : [ + ] + "failed" : [ + ] + "unknown" : [ + ] + } + "_embedded" : { + "verificationResults" : [ + { + "providerName" : "" + "providerApplicationVersion" : "" + "success" : true + "verificationDate" : "" + } + ] + } + } +} +``` \ No newline at end of file diff --git a/server/broker/broker.go b/server/broker/broker.go new file mode 100644 index 00000000..fc807bee --- /dev/null +++ b/server/broker/broker.go @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + roa "github.com/apache/incubator-servicecomb-service-center/pkg/rest" +) + +func init() { + registerREST() +} + +func registerREST() { + roa.RegisterServent(&BrokerController{}) +} diff --git a/server/broker/broker.pb.go b/server/broker/broker.pb.go new file mode 100644 index 00000000..0dffd1cd --- /dev/null +++ b/server/broker/broker.pb.go @@ -0,0 +1,950 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: server/broker/broker.proto + +/* +Package broker is a generated protocol buffer package. + +It is generated from these files: + server/broker/broker.proto + +It has these top-level messages: + Participant + Version + Pact + PactVersion + Tag + PublishPactRequest + PublishPactResponse + GetAllProviderPactsRequest + ConsumerInfo + Links + GetAllProviderPactsResponse + GetProviderConsumerVersionPactRequest + GetProviderConsumerVersionPactResponse + Verification + VerificationSummary + VerificationDetail + VerificationDetails + VerificationResult + PublishVerificationRequest + PublishVerificationResponse + RetrieveVerificationRequest + RetrieveVerificationResponse + BaseBrokerRequest + BrokerAPIInfoEntry + BrokerHomeResponse +*/ +package broker + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import services "github.com/apache/incubator-servicecomb-service-center/server/core/proto" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Participant struct { + Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + AppId string `protobuf:"bytes,2,opt,name=appId" json:"appId,omitempty"` + ServiceName string `protobuf:"bytes,3,opt,name=serviceName" json:"serviceName,omitempty"` +} + +func (m *Participant) Reset() { *m = Participant{} } +func (m *Participant) String() string { return proto.CompactTextString(m) } +func (*Participant) ProtoMessage() {} +func (*Participant) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Participant) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *Participant) GetAppId() string { + if m != nil { + return m.AppId + } + return "" +} + +func (m *Participant) GetServiceName() string { + if m != nil { + return m.ServiceName + } + return "" +} + +type Version struct { + Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Number string `protobuf:"bytes,2,opt,name=number" json:"number,omitempty"` + ParticipantId int32 `protobuf:"varint,3,opt,name=participantId" json:"participantId,omitempty"` + Order int32 `protobuf:"varint,4,opt,name=order" json:"order,omitempty"` +} + +func (m *Version) Reset() { *m = Version{} } +func (m *Version) String() string { return proto.CompactTextString(m) } +func (*Version) ProtoMessage() {} +func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Version) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *Version) GetNumber() string { + if m != nil { + return m.Number + } + return "" +} + +func (m *Version) GetParticipantId() int32 { + if m != nil { + return m.ParticipantId + } + return 0 +} + +func (m *Version) GetOrder() int32 { + if m != nil { + return m.Order + } + return 0 +} + +type Pact struct { + Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + ConsumerParticipantId int32 `protobuf:"varint,2,opt,name=consumerParticipantId" json:"consumerParticipantId,omitempty"` + ProviderParticipantId int32 `protobuf:"varint,3,opt,name=providerParticipantId" json:"providerParticipantId,omitempty"` + Sha []byte `protobuf:"bytes,4,opt,name=sha,proto3" json:"sha,omitempty"` + Content []byte `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` +} + +func (m *Pact) Reset() { *m = Pact{} } +func (m *Pact) String() string { return proto.CompactTextString(m) } +func (*Pact) ProtoMessage() {} +func (*Pact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Pact) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *Pact) GetConsumerParticipantId() int32 { + if m != nil { + return m.ConsumerParticipantId + } + return 0 +} + +func (m *Pact) GetProviderParticipantId() int32 { + if m != nil { + return m.ProviderParticipantId + } + return 0 +} + +func (m *Pact) GetSha() []byte { + if m != nil { + return m.Sha + } + return nil +} + +func (m *Pact) GetContent() []byte { + if m != nil { + return m.Content + } + return nil +} + +type PactVersion struct { + Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + VersionId int32 `protobuf:"varint,2,opt,name=versionId" json:"versionId,omitempty"` + PactId int32 `protobuf:"varint,3,opt,name=pactId" json:"pactId,omitempty"` + ProviderParticipantId int32 `protobuf:"varint,4,opt,name=providerParticipantId" json:"providerParticipantId,omitempty"` +} + +func (m *PactVersion) Reset() { *m = PactVersion{} } +func (m *PactVersion) String() string { return proto.CompactTextString(m) } +func (*PactVersion) ProtoMessage() {} +func (*PactVersion) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *PactVersion) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *PactVersion) GetVersionId() int32 { + if m != nil { + return m.VersionId + } + return 0 +} + +func (m *PactVersion) GetPactId() int32 { + if m != nil { + return m.PactId + } + return 0 +} + +func (m *PactVersion) GetProviderParticipantId() int32 { + if m != nil { + return m.ProviderParticipantId + } + return 0 +} + +type Tag struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + VersionId int32 `protobuf:"varint,2,opt,name=versionId" json:"versionId,omitempty"` +} + +func (m *Tag) Reset() { *m = Tag{} } +func (m *Tag) String() string { return proto.CompactTextString(m) } +func (*Tag) ProtoMessage() {} +func (*Tag) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *Tag) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Tag) GetVersionId() int32 { + if m != nil { + return m.VersionId + } + return 0 +} + +type PublishPactRequest struct { + ProviderId string `protobuf:"bytes,1,opt,name=providerId" json:"providerId,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumerId" json:"consumerId,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"` + Pact []byte `protobuf:"bytes,4,opt,name=pact,proto3" json:"pact,omitempty"` +} + +func (m *PublishPactRequest) Reset() { *m = PublishPactRequest{} } +func (m *PublishPactRequest) String() string { return proto.CompactTextString(m) } +func (*PublishPactRequest) ProtoMessage() {} +func (*PublishPactRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *PublishPactRequest) GetProviderId() string { + if m != nil { + return m.ProviderId + } + return "" +} + +func (m *PublishPactRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *PublishPactRequest) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *PublishPactRequest) GetPact() []byte { + if m != nil { + return m.Pact + } + return nil +} + +type PublishPactResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` +} + +func (m *PublishPactResponse) Reset() { *m = PublishPactResponse{} } +func (m *PublishPactResponse) String() string { return proto.CompactTextString(m) } +func (*PublishPactResponse) ProtoMessage() {} +func (*PublishPactResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *PublishPactResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +type GetAllProviderPactsRequest struct { + ProviderId string `protobuf:"bytes,1,opt,name=providerId" json:"providerId,omitempty"` + BaseUrl *BaseBrokerRequest `protobuf:"bytes,2,opt,name=baseUrl" json:"baseUrl,omitempty"` +} + +func (m *GetAllProviderPactsRequest) Reset() { *m = GetAllProviderPactsRequest{} } +func (m *GetAllProviderPactsRequest) String() string { return proto.CompactTextString(m) } +func (*GetAllProviderPactsRequest) ProtoMessage() {} +func (*GetAllProviderPactsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *GetAllProviderPactsRequest) GetProviderId() string { + if m != nil { + return m.ProviderId + } + return "" +} + +func (m *GetAllProviderPactsRequest) GetBaseUrl() *BaseBrokerRequest { + if m != nil { + return m.BaseUrl + } + return nil +} + +type ConsumerInfo struct { + Href string `protobuf:"bytes,1,opt,name=href" json:"href,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` +} + +func (m *ConsumerInfo) Reset() { *m = ConsumerInfo{} } +func (m *ConsumerInfo) String() string { return proto.CompactTextString(m) } +func (*ConsumerInfo) ProtoMessage() {} +func (*ConsumerInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *ConsumerInfo) GetHref() string { + if m != nil { + return m.Href + } + return "" +} + +func (m *ConsumerInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type Links struct { + Pacts []*ConsumerInfo `protobuf:"bytes,1,rep,name=pacts" json:"pacts,omitempty"` +} + +func (m *Links) Reset() { *m = Links{} } +func (m *Links) String() string { return proto.CompactTextString(m) } +func (*Links) ProtoMessage() {} +func (*Links) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *Links) GetPacts() []*ConsumerInfo { + if m != nil { + return m.Pacts + } + return nil +} + +type GetAllProviderPactsResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + XLinks *Links `protobuf:"bytes,2,opt,name=_links,json=Links" json:"_links,omitempty"` +} + +func (m *GetAllProviderPactsResponse) Reset() { *m = GetAllProviderPactsResponse{} } +func (m *GetAllProviderPactsResponse) String() string { return proto.CompactTextString(m) } +func (*GetAllProviderPactsResponse) ProtoMessage() {} +func (*GetAllProviderPactsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *GetAllProviderPactsResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *GetAllProviderPactsResponse) GetXLinks() *Links { + if m != nil { + return m.XLinks + } + return nil +} + +type GetProviderConsumerVersionPactRequest struct { + ProviderId string `protobuf:"bytes,1,opt,name=providerId" json:"providerId,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumerId" json:"consumerId,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"` + BaseUrl *BaseBrokerRequest `protobuf:"bytes,4,opt,name=baseUrl" json:"baseUrl,omitempty"` +} + +func (m *GetProviderConsumerVersionPactRequest) Reset() { *m = GetProviderConsumerVersionPactRequest{} } +func (m *GetProviderConsumerVersionPactRequest) String() string { return proto.CompactTextString(m) } +func (*GetProviderConsumerVersionPactRequest) ProtoMessage() {} +func (*GetProviderConsumerVersionPactRequest) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{11} +} + +func (m *GetProviderConsumerVersionPactRequest) GetProviderId() string { + if m != nil { + return m.ProviderId + } + return "" +} + +func (m *GetProviderConsumerVersionPactRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *GetProviderConsumerVersionPactRequest) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *GetProviderConsumerVersionPactRequest) GetBaseUrl() *BaseBrokerRequest { + if m != nil { + return m.BaseUrl + } + return nil +} + +type GetProviderConsumerVersionPactResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + Pact []byte `protobuf:"bytes,2,opt,name=pact,proto3" json:"pact,omitempty"` +} + +func (m *GetProviderConsumerVersionPactResponse) Reset() { + *m = GetProviderConsumerVersionPactResponse{} +} +func (m *GetProviderConsumerVersionPactResponse) String() string { return proto.CompactTextString(m) } +func (*GetProviderConsumerVersionPactResponse) ProtoMessage() {} +func (*GetProviderConsumerVersionPactResponse) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{12} +} + +func (m *GetProviderConsumerVersionPactResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *GetProviderConsumerVersionPactResponse) GetPact() []byte { + if m != nil { + return m.Pact + } + return nil +} + +type Verification struct { + Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Number int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` + PactVersionId int32 `protobuf:"varint,3,opt,name=pactVersionId" json:"pactVersionId,omitempty"` + Success bool `protobuf:"varint,4,opt,name=success" json:"success,omitempty"` + ProviderVersion string `protobuf:"bytes,5,opt,name=providerVersion" json:"providerVersion,omitempty"` + BuildUrl string `protobuf:"bytes,6,opt,name=buildUrl" json:"buildUrl,omitempty"` + VerificationDate string `protobuf:"bytes,7,opt,name=verificationDate" json:"verificationDate,omitempty"` +} + +func (m *Verification) Reset() { *m = Verification{} } +func (m *Verification) String() string { return proto.CompactTextString(m) } +func (*Verification) ProtoMessage() {} +func (*Verification) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +func (m *Verification) GetId() int32 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *Verification) GetNumber() int32 { + if m != nil { + return m.Number + } + return 0 +} + +func (m *Verification) GetPactVersionId() int32 { + if m != nil { + return m.PactVersionId + } + return 0 +} + +func (m *Verification) GetSuccess() bool { + if m != nil { + return m.Success + } + return false +} + +func (m *Verification) GetProviderVersion() string { + if m != nil { + return m.ProviderVersion + } + return "" +} + +func (m *Verification) GetBuildUrl() string { + if m != nil { + return m.BuildUrl + } + return "" +} + +func (m *Verification) GetVerificationDate() string { + if m != nil { + return m.VerificationDate + } + return "" +} + +type VerificationSummary struct { + Successful []string `protobuf:"bytes,1,rep,name=successful" json:"successful,omitempty"` + Failed []string `protobuf:"bytes,2,rep,name=failed" json:"failed,omitempty"` + Unknown []string `protobuf:"bytes,3,rep,name=unknown" json:"unknown,omitempty"` +} + +func (m *VerificationSummary) Reset() { *m = VerificationSummary{} } +func (m *VerificationSummary) String() string { return proto.CompactTextString(m) } +func (*VerificationSummary) ProtoMessage() {} +func (*VerificationSummary) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +func (m *VerificationSummary) GetSuccessful() []string { + if m != nil { + return m.Successful + } + return nil +} + +func (m *VerificationSummary) GetFailed() []string { + if m != nil { + return m.Failed + } + return nil +} + +func (m *VerificationSummary) GetUnknown() []string { + if m != nil { + return m.Unknown + } + return nil +} + +type VerificationDetail struct { + ProviderName string `protobuf:"bytes,1,opt,name=providerName" json:"providerName,omitempty"` + ProviderApplicationVersion string `protobuf:"bytes,2,opt,name=providerApplicationVersion" json:"providerApplicationVersion,omitempty"` + Success bool `protobuf:"varint,3,opt,name=success" json:"success,omitempty"` + VerificationDate string `protobuf:"bytes,4,opt,name=verificationDate" json:"verificationDate,omitempty"` +} + +func (m *VerificationDetail) Reset() { *m = VerificationDetail{} } +func (m *VerificationDetail) String() string { return proto.CompactTextString(m) } +func (*VerificationDetail) ProtoMessage() {} +func (*VerificationDetail) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +func (m *VerificationDetail) GetProviderName() string { + if m != nil { + return m.ProviderName + } + return "" +} + +func (m *VerificationDetail) GetProviderApplicationVersion() string { + if m != nil { + return m.ProviderApplicationVersion + } + return "" +} + +func (m *VerificationDetail) GetSuccess() bool { + if m != nil { + return m.Success + } + return false +} + +func (m *VerificationDetail) GetVerificationDate() string { + if m != nil { + return m.VerificationDate + } + return "" +} + +type VerificationDetails struct { + VerificationResults []*VerificationDetail `protobuf:"bytes,1,rep,name=verificationResults" json:"verificationResults,omitempty"` +} + +func (m *VerificationDetails) Reset() { *m = VerificationDetails{} } +func (m *VerificationDetails) String() string { return proto.CompactTextString(m) } +func (*VerificationDetails) ProtoMessage() {} +func (*VerificationDetails) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } + +func (m *VerificationDetails) GetVerificationResults() []*VerificationDetail { + if m != nil { + return m.VerificationResults + } + return nil +} + +type VerificationResult struct { + Success bool `protobuf:"varint,1,opt,name=success" json:"success,omitempty"` + ProviderSummary *VerificationSummary `protobuf:"bytes,2,opt,name=providerSummary" json:"providerSummary,omitempty"` + XEmbedded *VerificationDetails `protobuf:"bytes,3,opt,name=_embedded,json=Embedded" json:"_embedded,omitempty"` +} + +func (m *VerificationResult) Reset() { *m = VerificationResult{} } +func (m *VerificationResult) String() string { return proto.CompactTextString(m) } +func (*VerificationResult) ProtoMessage() {} +func (*VerificationResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *VerificationResult) GetSuccess() bool { + if m != nil { + return m.Success + } + return false +} + +func (m *VerificationResult) GetProviderSummary() *VerificationSummary { + if m != nil { + return m.ProviderSummary + } + return nil +} + +func (m *VerificationResult) GetXEmbedded() *VerificationDetails { + if m != nil { + return m.XEmbedded + } + return nil +} + +type PublishVerificationRequest struct { + ProviderId string `protobuf:"bytes,1,opt,name=providerId" json:"providerId,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumerId" json:"consumerId,omitempty"` + PactId int32 `protobuf:"varint,3,opt,name=pactId" json:"pactId,omitempty"` + Success bool `protobuf:"varint,4,opt,name=success" json:"success,omitempty"` + ProviderApplicationVersion string `protobuf:"bytes,5,opt,name=providerApplicationVersion" json:"providerApplicationVersion,omitempty"` +} + +func (m *PublishVerificationRequest) Reset() { *m = PublishVerificationRequest{} } +func (m *PublishVerificationRequest) String() string { return proto.CompactTextString(m) } +func (*PublishVerificationRequest) ProtoMessage() {} +func (*PublishVerificationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } + +func (m *PublishVerificationRequest) GetProviderId() string { + if m != nil { + return m.ProviderId + } + return "" +} + +func (m *PublishVerificationRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *PublishVerificationRequest) GetPactId() int32 { + if m != nil { + return m.PactId + } + return 0 +} + +func (m *PublishVerificationRequest) GetSuccess() bool { + if m != nil { + return m.Success + } + return false +} + +func (m *PublishVerificationRequest) GetProviderApplicationVersion() string { + if m != nil { + return m.ProviderApplicationVersion + } + return "" +} + +type PublishVerificationResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + Confirmation *VerificationDetail `protobuf:"bytes,2,opt,name=confirmation" json:"confirmation,omitempty"` +} + +func (m *PublishVerificationResponse) Reset() { *m = PublishVerificationResponse{} } +func (m *PublishVerificationResponse) String() string { return proto.CompactTextString(m) } +func (*PublishVerificationResponse) ProtoMessage() {} +func (*PublishVerificationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } + +func (m *PublishVerificationResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *PublishVerificationResponse) GetConfirmation() *VerificationDetail { + if m != nil { + return m.Confirmation + } + return nil +} + +type RetrieveVerificationRequest struct { + ConsumerId string `protobuf:"bytes,1,opt,name=consumerId" json:"consumerId,omitempty"` + ConsumerVersion string `protobuf:"bytes,2,opt,name=consumerVersion" json:"consumerVersion,omitempty"` +} + +func (m *RetrieveVerificationRequest) Reset() { *m = RetrieveVerificationRequest{} } +func (m *RetrieveVerificationRequest) String() string { return proto.CompactTextString(m) } +func (*RetrieveVerificationRequest) ProtoMessage() {} +func (*RetrieveVerificationRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } + +func (m *RetrieveVerificationRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *RetrieveVerificationRequest) GetConsumerVersion() string { + if m != nil { + return m.ConsumerVersion + } + return "" +} + +type RetrieveVerificationResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + Result *VerificationResult `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` +} + +func (m *RetrieveVerificationResponse) Reset() { *m = RetrieveVerificationResponse{} } +func (m *RetrieveVerificationResponse) String() string { return proto.CompactTextString(m) } +func (*RetrieveVerificationResponse) ProtoMessage() {} +func (*RetrieveVerificationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } + +func (m *RetrieveVerificationResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *RetrieveVerificationResponse) GetResult() *VerificationResult { + if m != nil { + return m.Result + } + return nil +} + +type BaseBrokerRequest struct { + HostAddress string `protobuf:"bytes,1,opt,name=hostAddress" json:"hostAddress,omitempty"` + Scheme string `protobuf:"bytes,2,opt,name=scheme" json:"scheme,omitempty"` +} + +func (m *BaseBrokerRequest) Reset() { *m = BaseBrokerRequest{} } +func (m *BaseBrokerRequest) String() string { return proto.CompactTextString(m) } +func (*BaseBrokerRequest) ProtoMessage() {} +func (*BaseBrokerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } + +func (m *BaseBrokerRequest) GetHostAddress() string { + if m != nil { + return m.HostAddress + } + return "" +} + +func (m *BaseBrokerRequest) GetScheme() string { + if m != nil { + return m.Scheme + } + return "" +} + +type BrokerAPIInfoEntry struct { + Href string `protobuf:"bytes,1,opt,name=href" json:"href,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` + Templated bool `protobuf:"varint,4,opt,name=templated" json:"templated,omitempty"` +} + +func (m *BrokerAPIInfoEntry) Reset() { *m = BrokerAPIInfoEntry{} } +func (m *BrokerAPIInfoEntry) String() string { return proto.CompactTextString(m) } +func (*BrokerAPIInfoEntry) ProtoMessage() {} +func (*BrokerAPIInfoEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } + +func (m *BrokerAPIInfoEntry) GetHref() string { + if m != nil { + return m.Href + } + return "" +} + +func (m *BrokerAPIInfoEntry) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *BrokerAPIInfoEntry) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *BrokerAPIInfoEntry) GetTemplated() bool { + if m != nil { + return m.Templated + } + return false +} + +type BrokerHomeResponse struct { + Response *services.Response `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"` + XLinks map[string]*BrokerAPIInfoEntry `protobuf:"bytes,2,rep,name=_links,json=Links" json:"_links,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Curies []*BrokerAPIInfoEntry `protobuf:"bytes,3,rep,name=curies" json:"curies,omitempty"` +} + +func (m *BrokerHomeResponse) Reset() { *m = BrokerHomeResponse{} } +func (m *BrokerHomeResponse) String() string { return proto.CompactTextString(m) } +func (*BrokerHomeResponse) ProtoMessage() {} +func (*BrokerHomeResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } + +func (m *BrokerHomeResponse) GetResponse() *services.Response { + if m != nil { + return m.Response + } + return nil +} + +func (m *BrokerHomeResponse) GetXLinks() map[string]*BrokerAPIInfoEntry { + if m != nil { + return m.XLinks + } + return nil +} + +func (m *BrokerHomeResponse) GetCuries() []*BrokerAPIInfoEntry { + if m != nil { + return m.Curies + } + return nil +} + +func init() { + proto.RegisterType((*Participant)(nil), "Participant") + proto.RegisterType((*Version)(nil), "Version") + proto.RegisterType((*Pact)(nil), "Pact") + proto.RegisterType((*PactVersion)(nil), "PactVersion") + proto.RegisterType((*Tag)(nil), "Tag") + proto.RegisterType((*PublishPactRequest)(nil), "PublishPactRequest") + proto.RegisterType((*PublishPactResponse)(nil), "PublishPactResponse") + proto.RegisterType((*GetAllProviderPactsRequest)(nil), "GetAllProviderPactsRequest") + proto.RegisterType((*ConsumerInfo)(nil), "ConsumerInfo") + proto.RegisterType((*Links)(nil), "Links") + proto.RegisterType((*GetAllProviderPactsResponse)(nil), "GetAllProviderPactsResponse") + proto.RegisterType((*GetProviderConsumerVersionPactRequest)(nil), "GetProviderConsumerVersionPactRequest") + proto.RegisterType((*GetProviderConsumerVersionPactResponse)(nil), "GetProviderConsumerVersionPactResponse") + proto.RegisterType((*Verification)(nil), "Verification") + proto.RegisterType((*VerificationSummary)(nil), "VerificationSummary") + proto.RegisterType((*VerificationDetail)(nil), "VerificationDetail") + proto.RegisterType((*VerificationDetails)(nil), "VerificationDetails") + proto.RegisterType((*VerificationResult)(nil), "VerificationResult") + proto.RegisterType((*PublishVerificationRequest)(nil), "PublishVerificationRequest") + proto.RegisterType((*PublishVerificationResponse)(nil), "PublishVerificationResponse") + proto.RegisterType((*RetrieveVerificationRequest)(nil), "RetrieveVerificationRequest") + proto.RegisterType((*RetrieveVerificationResponse)(nil), "RetrieveVerificationResponse") + proto.RegisterType((*BaseBrokerRequest)(nil), "BaseBrokerRequest") + proto.RegisterType((*BrokerAPIInfoEntry)(nil), "BrokerAPIInfoEntry") + proto.RegisterType((*BrokerHomeResponse)(nil), "BrokerHomeResponse") +} + +func init() { proto.RegisterFile("server/broker/broker.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 1037 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x8e, 0x1b, 0x35, + 0x14, 0xd6, 0x64, 0x93, 0x6c, 0x72, 0x92, 0xd2, 0xe2, 0x2d, 0x28, 0x4a, 0x4b, 0x15, 0x19, 0x8a, + 0x02, 0x54, 0x59, 0xb1, 0xfc, 0x14, 0x21, 0x54, 0x69, 0x97, 0xae, 0xca, 0x4a, 0xb4, 0x8a, 0x0c, + 0xed, 0x05, 0x42, 0xaa, 0x26, 0x33, 0x27, 0x9b, 0x61, 0xe7, 0x0f, 0xdb, 0x13, 0xb4, 0x17, 0xdc, + 0x70, 0xc7, 0x63, 0xf0, 0x02, 0xf0, 0x06, 0x3c, 0x02, 0xcf, 0xc1, 0x15, 0xcf, 0x80, 0xec, 0xb1, + 0x27, 0x33, 0xc9, 0x64, 0xb7, 0x91, 0x10, 0x57, 0xf1, 0xf9, 0xf1, 0xf1, 0x77, 0xbe, 0x73, 0xe6, + 0xd8, 0x81, 0xa1, 0x40, 0xbe, 0x44, 0x7e, 0x38, 0xe3, 0xc9, 0x45, 0xf1, 0x33, 0x49, 0x79, 0x22, + 0x93, 0xe1, 0xc8, 0xd8, 0xbc, 0x84, 0xe3, 0xa1, 0x56, 0x1d, 0x2a, 0x4d, 0xe0, 0xa1, 0xc8, 0x3d, + 0xe8, 0x73, 0xe8, 0x4d, 0x5d, 0x2e, 0x03, 0x2f, 0x48, 0xdd, 0x58, 0x92, 0xd7, 0xa0, 0x11, 0xf8, + 0x03, 0x67, 0xe4, 0x8c, 0x5b, 0xac, 0x11, 0xf8, 0xe4, 0x36, 0xb4, 0xdc, 0x34, 0x3d, 0xf3, 0x07, + 0x8d, 0x91, 0x33, 0xee, 0xb2, 0x5c, 0x20, 0x23, 0xe8, 0x99, 0x30, 0xcf, 0xdc, 0x08, 0x07, 0x7b, + 0xda, 0x56, 0x56, 0xd1, 0x08, 0xf6, 0x5f, 0x20, 0x17, 0x41, 0x12, 0x6f, 0x84, 0x7c, 0x13, 0xda, + 0x71, 0x16, 0xcd, 0x90, 0x9b, 0x98, 0x46, 0x22, 0xef, 0xc0, 0x8d, 0x74, 0x85, 0xe4, 0xcc, 0xd7, + 0x61, 0x5b, 0xac, 0xaa, 0x54, 0x80, 0x12, 0xee, 0x23, 0x1f, 0x34, 0xb5, 0x35, 0x17, 0xe8, 0xef, + 0x0e, 0x34, 0xa7, 0xae, 0xb7, 0x89, 0xff, 0x63, 0x78, 0xc3, 0x4b, 0x62, 0x91, 0x45, 0xc8, 0xa7, + 0x95, 0xe0, 0x0d, 0xed, 0x52, 0x6f, 0x54, 0xbb, 0x52, 0x9e, 0x2c, 0x03, 0x7f, 0x7d, 0x57, 0x0e, + 0xa9, 0xde, 0x48, 0x6e, 0xc1, 0x9e, 0x58, 0xb8, 0x1a, 0x58, 0x9f, 0xa9, 0x25, 0x19, 0xc0, 0xbe, + 0x97, 0xc4, 0x12, 0x63, 0x39, 0x68, 0x69, 0xad, 0x15, 0xe9, 0xaf, 0x8e, 0xe2, 0xdd, 0x93, 0xdb, + 0x48, 0xba, 0x0b, 0xdd, 0x65, 0x6e, 0x2a, 0xb0, 0xae, 0x14, 0x8a, 0xc2, 0xd4, 0xf5, 0x56, 0x80, + 0x8c, 0xb4, 0x1d, 0x77, 0xf3, 0x0a, 0xdc, 0xf4, 0x21, 0xec, 0x7d, 0xeb, 0x9e, 0x13, 0x02, 0xcd, + 0x58, 0x55, 0xd3, 0xd1, 0x55, 0xd1, 0xeb, 0xab, 0x61, 0xd0, 0x5f, 0x1c, 0x20, 0xd3, 0x6c, 0x16, + 0x06, 0x62, 0xa1, 0x72, 0x61, 0xf8, 0x63, 0x86, 0x42, 0x92, 0x7b, 0x00, 0xf6, 0xa0, 0x33, 0xdf, + 0x84, 0x2b, 0x69, 0x94, 0xdd, 0xd2, 0x5e, 0x34, 0x56, 0x49, 0xa3, 0x58, 0x33, 0x67, 0x98, 0xce, + 0xb2, 0xa2, 0x82, 0xa8, 0x32, 0x35, 0x14, 0xeb, 0x35, 0xfd, 0x02, 0x0e, 0x2a, 0x18, 0x44, 0x9a, + 0xc4, 0x02, 0xc9, 0x7d, 0xe8, 0x70, 0xb3, 0xd6, 0x10, 0x7a, 0x47, 0xdd, 0x89, 0x35, 0xb2, 0xc2, + 0x44, 0x7f, 0x80, 0xe1, 0x13, 0x94, 0xc7, 0x61, 0x38, 0x2d, 0xa8, 0xf1, 0xa4, 0x78, 0xd5, 0x4c, + 0x1e, 0xc0, 0xfe, 0xcc, 0x15, 0xf8, 0x9c, 0x87, 0x3a, 0x8d, 0xde, 0x11, 0x99, 0x9c, 0xb8, 0x02, + 0x4f, 0xf4, 0x27, 0x68, 0x82, 0x30, 0xeb, 0x42, 0x3f, 0x85, 0xfe, 0x97, 0x36, 0xcb, 0x78, 0x9e, + 0xa8, 0x6c, 0x16, 0x1c, 0xe7, 0x96, 0x70, 0xb5, 0x2e, 0x8a, 0xd0, 0x58, 0x15, 0x81, 0x3e, 0x80, + 0xd6, 0xd7, 0x41, 0x7c, 0x21, 0xc8, 0xdb, 0xd0, 0x52, 0x29, 0x8b, 0x81, 0x33, 0xda, 0x1b, 0xf7, + 0x8e, 0x6e, 0x4c, 0xca, 0xe1, 0x58, 0x6e, 0xa3, 0x1e, 0xdc, 0xa9, 0xcd, 0x68, 0x27, 0x5e, 0xc8, + 0x5b, 0xd0, 0x7e, 0x19, 0xaa, 0x43, 0x4d, 0x62, 0xed, 0x89, 0x86, 0xc0, 0x72, 0x24, 0xf4, 0x0f, + 0x07, 0xee, 0x3f, 0x41, 0x69, 0x8f, 0xb0, 0x38, 0x4c, 0x37, 0xff, 0x3f, 0xcd, 0x50, 0x22, 0xbf, + 0x79, 0x3d, 0xf9, 0x1e, 0xbc, 0x7b, 0x1d, 0xe0, 0xdd, 0x18, 0xb2, 0xbd, 0xd8, 0x28, 0xf5, 0xe2, + 0xdf, 0x0e, 0xf4, 0x5f, 0x20, 0x0f, 0xe6, 0x81, 0xe7, 0xca, 0xeb, 0x67, 0x5f, 0xab, 0x3a, 0xfb, + 0x8a, 0x69, 0x50, 0x9e, 0x7d, 0x25, 0xa5, 0xe2, 0x42, 0x64, 0x9e, 0x87, 0x42, 0xe8, 0x8c, 0x3b, + 0xcc, 0x8a, 0x64, 0x0c, 0x37, 0x2d, 0xa7, 0xc6, 0x5d, 0x0f, 0x9c, 0x2e, 0x5b, 0x57, 0x93, 0x21, + 0x74, 0x66, 0x59, 0x10, 0xfa, 0x8a, 0xb6, 0xb6, 0x76, 0x29, 0x64, 0xf2, 0x3e, 0xdc, 0x5a, 0x96, + 0xd0, 0x3f, 0x76, 0x25, 0x0e, 0xf6, 0xb5, 0xcf, 0x86, 0x9e, 0x9e, 0xc3, 0x41, 0x39, 0xd3, 0x6f, + 0xb2, 0x28, 0x72, 0xf9, 0xa5, 0x2a, 0xa7, 0xc1, 0x34, 0xcf, 0x42, 0xdd, 0xa7, 0x5d, 0x56, 0xd2, + 0x28, 0x02, 0xe6, 0x6e, 0x10, 0xa2, 0x2a, 0xb5, 0xb2, 0x19, 0x49, 0xa5, 0x96, 0xc5, 0x17, 0x71, + 0xf2, 0x93, 0x2a, 0xb3, 0x32, 0x58, 0x91, 0xfe, 0xe9, 0x00, 0x29, 0x9f, 0xf4, 0x18, 0xa5, 0x1b, + 0x84, 0x84, 0x42, 0xdf, 0xa6, 0xf6, 0x6c, 0x35, 0xb5, 0x2a, 0x3a, 0xf2, 0x08, 0x86, 0x56, 0x3e, + 0x4e, 0xd3, 0xd0, 0x04, 0xb0, 0x04, 0xe5, 0xbd, 0x76, 0x85, 0x47, 0x99, 0xef, 0xbd, 0x2a, 0xdf, + 0x75, 0x4c, 0x35, 0xb7, 0x30, 0xf5, 0x7d, 0x95, 0xa9, 0x1c, 0xbf, 0x20, 0xa7, 0x70, 0x50, 0x76, + 0x65, 0x28, 0xb2, 0xb0, 0xf8, 0xb4, 0x0f, 0x26, 0x9b, 0x5b, 0x58, 0x9d, 0x3f, 0xfd, 0x6d, 0x8d, + 0x9e, 0x5c, 0x5f, 0x86, 0xee, 0x54, 0xa1, 0x3f, 0x5a, 0xb5, 0x8a, 0x29, 0x9a, 0xf9, 0xc4, 0x6f, + 0x4f, 0x6a, 0x0a, 0xca, 0xd6, 0x9d, 0xc9, 0x87, 0xd0, 0x7d, 0x89, 0xd1, 0x0c, 0x7d, 0x1f, 0xf3, + 0x36, 0x5d, 0xdf, 0x69, 0x12, 0x64, 0x9d, 0x53, 0xe3, 0x45, 0xff, 0x72, 0x60, 0x68, 0x66, 0x74, + 0x15, 0xea, 0x7f, 0x33, 0x22, 0xb6, 0xdd, 0x86, 0xdb, 0x3f, 0x97, 0xab, 0x1b, 0xa3, 0x75, 0x5d, + 0x63, 0xd0, 0x9f, 0xe1, 0x4e, 0x6d, 0x3e, 0xbb, 0x4d, 0x90, 0x87, 0xd0, 0xf7, 0x92, 0x78, 0x1e, + 0xf0, 0x48, 0x6f, 0x37, 0x65, 0xa8, 0x2d, 0x7d, 0xc5, 0x91, 0x9e, 0xc3, 0x1d, 0x86, 0x92, 0x07, + 0xb8, 0xc4, 0x2d, 0x7c, 0x96, 0xf8, 0x72, 0x36, 0xf8, 0x1a, 0xc3, 0x4d, 0xaf, 0x3a, 0xff, 0x0c, + 0xa9, 0xeb, 0x6a, 0xca, 0xe1, 0x6e, 0xfd, 0x41, 0xbb, 0x25, 0xfa, 0x01, 0xb4, 0xb9, 0x6e, 0xcb, + 0xda, 0x14, 0xf3, 0x8e, 0x65, 0xc6, 0x85, 0x3e, 0x85, 0xd7, 0x37, 0xc6, 0xb8, 0x7a, 0x70, 0x2e, + 0x12, 0x21, 0x8f, 0x7d, 0x9f, 0xdb, 0x96, 0xee, 0xb2, 0xb2, 0x4a, 0x35, 0x81, 0xf0, 0x16, 0x58, + 0x5c, 0x9d, 0x46, 0xa2, 0x29, 0x90, 0x3c, 0xd4, 0xf1, 0xf4, 0x4c, 0x5d, 0x93, 0xa7, 0xb1, 0xe4, + 0x97, 0xaf, 0x7a, 0xf5, 0xaa, 0xd7, 0xa6, 0x0c, 0x64, 0x68, 0x9f, 0xb8, 0xb9, 0xa0, 0x5e, 0x45, + 0x12, 0xa3, 0x34, 0x74, 0x25, 0xfa, 0xa6, 0xb5, 0x56, 0x0a, 0xfa, 0x8f, 0x63, 0x8f, 0xfc, 0x2a, + 0x89, 0x70, 0x57, 0xae, 0x3e, 0x29, 0x5d, 0xbc, 0x6a, 0x12, 0xdc, 0x9b, 0x6c, 0xc6, 0xca, 0xef, + 0x62, 0x9d, 0x89, 0xb9, 0x90, 0x15, 0xc5, 0x5e, 0xc6, 0x03, 0x14, 0x7a, 0x7c, 0x2a, 0x8a, 0x37, + 0xb3, 0x66, 0xc6, 0x65, 0xf8, 0x14, 0x60, 0x15, 0x41, 0x3d, 0x5b, 0x2f, 0xf0, 0xd2, 0x50, 0xa1, + 0x96, 0xe4, 0x3d, 0x68, 0x2d, 0xdd, 0x30, 0xc3, 0xa2, 0x5c, 0x35, 0xb1, 0x72, 0x8f, 0xcf, 0x1b, + 0x9f, 0x39, 0x27, 0x9d, 0xef, 0xda, 0xf9, 0x9f, 0x8e, 0x59, 0x5b, 0xff, 0xa7, 0xf8, 0xe8, 0xdf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xdb, 0x8f, 0x7b, 0x26, 0x93, 0x0c, 0x00, 0x00, +} diff --git a/server/broker/broker.proto b/server/broker/broker.proto new file mode 100644 index 00000000..645e064a --- /dev/null +++ b/server/broker/broker.proto @@ -0,0 +1,158 @@ +syntax = "proto3"; + +import "server/core/proto/services.proto"; +option go_package = "broker"; + +/* +Definitions of objects +*/ + +message Participant { + int32 id = 1; + string appId = 2; + string serviceName = 3; +} + +message Version { + int32 id = 1; + string number = 2; + int32 participantId = 3; + int32 order = 4; +} + +message Pact { + int32 id = 1; + int32 consumerParticipantId = 2; + int32 providerParticipantId = 3; + bytes sha = 4; + bytes content = 5; +} + +message PactVersion { + int32 id = 1; + int32 versionId = 2; + int32 pactId = 3; + int32 providerParticipantId = 4; +} + +message Tag { + string name = 1; + int32 versionId = 2; +} + +message PublishPactRequest { + string providerId = 1; + string consumerId = 2; + string version = 3; + bytes pact = 4; +} + +message PublishPactResponse { + Response response = 1; +} + +message GetAllProviderPactsRequest { + string providerId = 1; + BaseBrokerRequest baseUrl = 2; +} + +message ConsumerInfo { + string href = 1; + string name = 2; +} + +message Links { + repeated ConsumerInfo pacts = 1; +} + +message GetAllProviderPactsResponse { + Response response = 1; + Links _links = 2; +} + +message GetProviderConsumerVersionPactRequest { + string providerId = 1; + string consumerId = 2; + string version = 3; + BaseBrokerRequest baseUrl = 4; +} + +message GetProviderConsumerVersionPactResponse { + Response response = 1; + bytes pact = 2; +} + +message Verification { + int32 id = 1; + int32 number = 2; + int32 pactVersionId = 3; // id of the version object + bool success = 4; + string providerVersion = 5; + string buildUrl = 6; + string verificationDate = 7; +} + +message VerificationSummary { + repeated string successful = 1; + repeated string failed = 2; + repeated string unknown = 3; +} + +message VerificationDetail { + string providerName = 1; + string providerApplicationVersion = 2; + bool success = 3; + string verificationDate = 4; +} + +message VerificationDetails { + repeated VerificationDetail verificationResults = 1; +} + +message VerificationResult { + bool success = 1; + VerificationSummary providerSummary = 2; + VerificationDetails _embedded = 3; +} + +message PublishVerificationRequest { + string providerId = 1; + string consumerId = 2; + int32 pactId = 3; + bool success = 4; + string providerApplicationVersion = 5; +} + +message PublishVerificationResponse { + Response response = 1; + VerificationDetail confirmation = 2; +} + +message RetrieveVerificationRequest { + string consumerId = 1; + string consumerVersion = 2; +} + +message RetrieveVerificationResponse { + Response response = 1; + VerificationResult result = 2; +} + +message BaseBrokerRequest { + string hostAddress = 1; + string scheme = 2; +} + + +message BrokerAPIInfoEntry { + string href = 1; + string name = 2; + string title = 3; + bool templated = 4; +} + +message BrokerHomeResponse { + Response response = 1; + map<string, BrokerAPIInfoEntry> _links = 2; + repeated BrokerAPIInfoEntry curies = 3; +} diff --git a/server/broker/broker_key_generator.go b/server/broker/broker_key_generator.go new file mode 100644 index 00000000..e10ebdbf --- /dev/null +++ b/server/broker/broker_key_generator.go @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "strconv" + + "github.com/apache/incubator-servicecomb-service-center/pkg/util" +) + +const ( + BROKER_ROOT_KEY = "cse-pact" + BROKER_PARTICIPANT_KEY = "participant" + BROKER_VERSION_KEY = "version" + BROKER_PACT_KEY = "pact" + BROKER_PACT_VERSION_KEY = "pact-version" + BROKER_PACT_TAG_KEY = "pact-tag" + BROKER_PACT_VERIFICATION_KEY = "verification" + BROKER_PACT_LATEST = "latest" +) + +// GetBrokerRootKey returns url (/cse-pact) +func GetBrokerRootKey() string { + return util.StringJoin([]string{ + "", + BROKER_ROOT_KEY, + }, "/") +} + +//GetBrokerLatestKey returns pact related keys +func GetBrokerLatestKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PACT_LATEST, + tenant, + }, "/") +} + +//GetBrokerParticipantKey returns the participant root key +func GetBrokerParticipantKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PARTICIPANT_KEY, + tenant, + }, "/") +} + +//GenerateBrokerParticipantKey returns the participant key +func GenerateBrokerParticipantKey(tenant string, appId string, serviceName string) string { + return util.StringJoin([]string{ + GetBrokerParticipantKey(tenant), + appId, + serviceName, + }, "/") +} + +//GetBrokerVersionKey returns th root version key +func GetBrokerVersionKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_VERSION_KEY, + tenant, + }, "/") +} + +//GenerateBrokerVersionKey returns the version key +func GenerateBrokerVersionKey(tenant string, number string, participantId int32) string { + return util.StringJoin([]string{ + GetBrokerVersionKey(tenant), + number, + strconv.Itoa(int(participantId)), + }, "/") +} + +//GetBrokerPactKey returns the pact root key +func GetBrokerPactKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PACT_KEY, + tenant, + }, "/") +} + +//GenerateBrokerPactKey returns the pact key +func GenerateBrokerPactKey(tenant string, consumerParticipantId int32, + providerParticipantId int32, sha []byte) string { + return util.StringJoin([]string{ + GetBrokerPactKey(tenant), + strconv.Itoa(int(consumerParticipantId)), + strconv.Itoa(int(providerParticipantId)), + string(sha), + }, "/") +} + +//GetBrokerPactVersionKey returns the pact version root key +func GetBrokerPactVersionKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PACT_VERSION_KEY, + tenant, + }, "/") +} + +//GenerateBrokerPactVersionKey returns the pact version root key +func GenerateBrokerPactVersionKey(tenant string, versionId int32, pactId int32) string { + return util.StringJoin([]string{ + GetBrokerPactVersionKey(tenant), + strconv.Itoa(int(versionId)), + strconv.Itoa(int(pactId)), + }, "/") +} + +//GetBrokerTagKey returns the broker tag root key +func GetBrokerTagKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PACT_TAG_KEY, + tenant, + }, "/") +} + +//GenerateBrokerTagKey returns the broker tag key +func GenerateBrokerTagKey(tenant string, versionId int32) string { + return util.StringJoin([]string{ + GetBrokerTagKey(tenant), + strconv.Itoa(int(versionId)), + }, "/") +} + +//GetBrokerVerificationKey returns the verification root key +func GetBrokerVerificationKey(tenant string) string { + return util.StringJoin([]string{ + GetBrokerRootKey(), + BROKER_PACT_VERIFICATION_KEY, + tenant, + }, "/") +} + +//GenerateBrokerVerificationKey returns he verification key +func GenerateBrokerVerificationKey(tenant string, pactVersionId int32, number int32) string { + return util.StringJoin([]string{ + GetBrokerVerificationKey(tenant), + strconv.Itoa(int(pactVersionId)), + strconv.Itoa(int(number)), + }, "/") +} + +//GetBrokerLatestParticipantIDKey returns the latest participant ID +func GetBrokerLatestParticipantIDKey() string { + return util.StringJoin([]string{ + GetBrokerLatestKey("default"), + BROKER_PARTICIPANT_KEY, + }, "/") +} + +//GetBrokerLatestVersionIDKey returns latest version ID +func GetBrokerLatestVersionIDKey() string { + return util.StringJoin([]string{ + GetBrokerLatestKey("default"), + BROKER_VERSION_KEY, + }, "/") +} + +//GetBrokerLatestPactIDKey returns latest pact ID +func GetBrokerLatestPactIDKey() string { + return util.StringJoin([]string{ + GetBrokerLatestKey("default"), + BROKER_PACT_KEY, + }, "/") +} + +//GetBrokerLatestPactVersionIDKey returns lated pact version ID +func GetBrokerLatestPactVersionIDKey() string { + return util.StringJoin([]string{ + GetBrokerLatestKey("default"), + BROKER_PACT_VERSION_KEY, + }, "/") +} + +//GetBrokerLatestVerificationIDKey returns the lastest verification ID +func GetBrokerLatestVerificationIDKey() string { + return util.StringJoin([]string{ + GetBrokerLatestKey("default"), + BROKER_PACT_VERIFICATION_KEY, + }, "/") +} diff --git a/server/broker/controller.go b/server/broker/controller.go new file mode 100644 index 00000000..2f817c53 --- /dev/null +++ b/server/broker/controller.go @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "strconv" + + "github.com/apache/incubator-servicecomb-service-center/pkg/rest" + scerr "github.com/apache/incubator-servicecomb-service-center/server/error" + "github.com/apache/incubator-servicecomb-service-center/server/rest/controller" +) + +const DEFAULT_SCHEME = "http" + +type BrokerController struct { +} + +func (brokerService *BrokerController) URLPatterns() []rest.Route { + return []rest.Route{ + // for handling broker requests + {rest.HTTP_METHOD_GET, + "/", + brokerService.GetHome}, + {rest.HTTP_METHOD_PUT, + "/pacts/provider/:providerId/consumer/:consumerId/version/:number", + brokerService.PublishPact}, + {rest.HTTP_METHOD_GET, + "/pacts/provider/:providerId/latest", + brokerService.GetAllProviderPacts}, + {rest.HTTP_METHOD_GET, + "/pacts/provider/:providerId/consumer/:consumerId/version/:number", + brokerService.GetPactsOfProvider}, + {rest.HTTP_METHOD_DELETE, + "/pacts/delete", + brokerService.DeletePacts}, + {rest.HTTP_METHOD_POST, + "/pacts/provider/:providerId/consumer/:consumerId/pact-version/:sha/verification-results", + brokerService.PublishVerificationResults}, + {rest.HTTP_METHOD_GET, + "/verification-results/consumer/:consumerId/version/:consumerVersion/latest", + brokerService.RetrieveVerificationResults}, + } +} + +func (brokerService *BrokerController) GetHome(w http.ResponseWriter, r *http.Request) { + request := &BaseBrokerRequest{ + HostAddress: r.Host, + Scheme: getScheme(r), + } + resp, _ := BrokerServiceAPI.GetBrokerHome(r.Context(), request) + + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func (*BrokerController) PublishPact(w http.ResponseWriter, r *http.Request) { + message, err := ioutil.ReadAll(r.Body) + if err != nil { + PactLogger.Error("body err\n", err) + controller.WriteError(w, scerr.ErrInvalidParams, err.Error()) + return + } + request := &PublishPactRequest{ + ProviderId: r.URL.Query().Get(":providerId"), + ConsumerId: r.URL.Query().Get(":consumerId"), + Version: r.URL.Query().Get(":number"), + Pact: message, + } + PactLogger.Infof("PublishPact: providerId = %s, consumerId = %s, version = %s\n", + request.ProviderId, request.ConsumerId, request.Version) + resp, err := BrokerServiceAPI.PublishPact(r.Context(), request) + + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func (*BrokerController) GetAllProviderPacts(w http.ResponseWriter, r *http.Request) { + request := &GetAllProviderPactsRequest{ + ProviderId: r.URL.Query().Get(":providerId"), + BaseUrl: &BaseBrokerRequest{ + HostAddress: r.Host, + Scheme: getScheme(r), + }, + } + resp, err := BrokerServiceAPI.GetAllProviderPacts(r.Context(), request /*, href*/) + linksObj, err := json.Marshal(resp) + if err != nil { + return + } + PactLogger.Infof("Pact info: %s\n", string(linksObj)) + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func (*BrokerController) GetPactsOfProvider(w http.ResponseWriter, r *http.Request) { + request := &GetProviderConsumerVersionPactRequest{ + ProviderId: r.URL.Query().Get(":providerId"), + ConsumerId: r.URL.Query().Get(":consumerId"), + Version: r.URL.Query().Get(":number"), + BaseUrl: &BaseBrokerRequest{ + HostAddress: r.Host, + Scheme: getScheme(r), + }, + } + + resp, _ := BrokerServiceAPI.GetPactsOfProvider(r.Context(), request) + respInternal := resp.Response + resp.Response = nil + //controller.WriteResponse(w, respInternal, resp.Pact) + controller.WriteBytes(w, respInternal, resp.Pact) +} + +func (*BrokerController) DeletePacts(w http.ResponseWriter, r *http.Request) { + resp, _ := BrokerServiceAPI.DeletePacts(r.Context(), &BaseBrokerRequest{ + HostAddress: r.Host, + Scheme: getScheme(r), + }) + controller.WriteResponse(w, resp, nil) +} + +func (*BrokerController) PublishVerificationResults(w http.ResponseWriter, r *http.Request) { + requestBody, err := ioutil.ReadAll(r.Body) + if err != nil { + PactLogger.Error("body err", err) + controller.WriteError(w, scerr.ErrInvalidParams, err.Error()) + return + } + request := &PublishVerificationRequest{} + err = json.Unmarshal(requestBody, request) + if err != nil { + PactLogger.Error("Unmarshal error", err) + controller.WriteError(w, scerr.ErrInvalidParams, err.Error()) + return + } + request.ProviderId = r.URL.Query().Get(":providerId") + request.ConsumerId = r.URL.Query().Get(":consumerId") + i, err := strconv.ParseInt(r.URL.Query().Get(":sha"), 10, 32) + if err != nil { + PactLogger.Error("Invalid pactId", err) + controller.WriteError(w, scerr.ErrInvalidParams, err.Error()) + return + } + request.PactId = int32(i) + PactLogger.Infof("PublishVerificationResults: %s, %s, %d, %t, %s\n", + request.ProviderId, request.ConsumerId, request.PactId, request.Success, + request.ProviderApplicationVersion) + resp, err := BrokerServiceAPI.PublishVerificationResults(r.Context(), + request) + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func (*BrokerController) RetrieveVerificationResults(w http.ResponseWriter, r *http.Request) { + request := &RetrieveVerificationRequest{} + request.ConsumerId = r.URL.Query().Get(":consumerId") + request.ConsumerVersion = r.URL.Query().Get(":consumerVersion") + PactLogger.Infof("Retrieve verification results for: %s, %s\n", + request.ConsumerId, request.ConsumerVersion) + resp, _ := BrokerServiceAPI.RetrieveVerificationResults(r.Context(), request) + respInternal := resp.Response + resp.Response = nil + controller.WriteResponse(w, respInternal, resp) +} + +func getScheme(r *http.Request) string { + if len(r.URL.Scheme) < 1 { + return DEFAULT_SCHEME + } + return r.URL.Scheme +} diff --git a/server/broker/service.go b/server/broker/service.go new file mode 100644 index 00000000..bde8f3e8 --- /dev/null +++ b/server/broker/service.go @@ -0,0 +1,874 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "crypto/sha1" + "encoding/json" + "fmt" + "math" + "strconv" + "strings" + "time" + + "github.com/apache/incubator-servicecomb-service-center/pkg/util" + apt "github.com/apache/incubator-servicecomb-service-center/server/core" + pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto" + scerr "github.com/apache/incubator-servicecomb-service-center/server/error" + "github.com/apache/incubator-servicecomb-service-center/server/infra/registry" + serviceUtil "github.com/apache/incubator-servicecomb-service-center/server/service/util" + "golang.org/x/net/context" +) + +var BrokerServiceAPI *BrokerService = &BrokerService{} + +type BrokerService struct { +} + +func (*BrokerService) GetBrokerHome(ctx context.Context, + in *BaseBrokerRequest) (*BrokerHomeResponse, error) { + + if in == nil || len(in.HostAddress) == 0 { + PactLogger.Errorf(nil, "Get Participant versions request failed: invalid params.") + return &BrokerHomeResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + + return GetBrokerHomeResponse(in.HostAddress, in.Scheme), nil +} + +func (*BrokerService) GetPactsOfProvider(ctx context.Context, + in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, error) { + PactLogger.Infof("GetPactsOfProvider: (%s, %s, %s)\n", + in.ProviderId, in.ConsumerId, in.Version) + + resp, pactId, err := RetrieveProviderConsumerPact(ctx, in) + if err != nil || resp.GetPact() == nil || pactId == -1 { + PactLogger.Errorf(nil, "Get pacts of provider failed: %s\n", + resp.Response.Message) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, err.Error()), + }, err + } + + urlValue := GenerateBrokerAPIPath(in.BaseUrl.Scheme, in.BaseUrl.HostAddress, + BROKER_PUBLISH_VERIFICATION_URL, + strings.NewReplacer(":providerId", in.ProviderId, + ":consumerId", in.ConsumerId, + ":pact", fmt.Sprint(pactId))) + + links := ",\"_links\": {" + + "\"pb:publish-verification-results\": {" + + "\"title\": \"Publish verification results\"," + + "\"href\": \"" + urlValue + + "\"" + + "}" + + "}}" + + linksBytes := []byte(links) + pactBytes := resp.GetPact() + sliceOfResp := pactBytes[0 : len(pactBytes)-2] + finalBytes := append(sliceOfResp, linksBytes...) + + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Success."), + Pact: finalBytes, + }, nil + //controller.WriteText(http.StatusBadRequest, resp.Response.Message, w) + +} + +func (*BrokerService) DeletePacts(ctx context.Context, + in *BaseBrokerRequest) (*pb.Response, error) { + + resp, err := DeletePactData(ctx, in) + + return resp, err +} + +func (*BrokerService) RetrieveProviderPacts(ctx context.Context, + in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) { + if in == nil || len(in.ProviderId) == 0 { + PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.") + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + tenant := GetDefaultTenantProject() + + provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId) + if err != nil { + PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."), + }, err + } + if provider == nil { + PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."), + }, nil + } + // Get the provider participant + //providerParticipantKey := apt.GenerateBrokerParticipantKey(tenant, provider.AppId, provider.ServiceName) + providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName) + if err != nil || providerParticipant == nil { + PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."), + }, err + } + PactLogger.Infof("[RetrieveProviderPacts] Provider participant id : %d", providerParticipant.Id) + // Get all versions + versionKey := util.StringJoin([]string{GetBrokerVersionKey(tenant), ""}, "/") + versions, err := Store().Version().Search(ctx, + registry.WithPrefix(), + registry.WithStrKey(versionKey)) + + if err != nil { + return nil, err + } + if len(versions.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPacts] No versions found, sorry") + return nil, nil + } + // Store versions in a map + versionObjects := make(map[int32]Version) + for i := 0; i < len(versions.Kvs); i++ { + version := &Version{} + err = json.Unmarshal(versions.Kvs[i].Value, version) + if err != nil { + return nil, err + } + PactLogger.Infof("[RetrieveProviderPacts] Version found : (%d, %s)", version.Id, version.Number) + versionObjects[version.Id] = *version + } + // Get all pactversions and filter using the provider participant id + pactVersionKey := util.StringJoin([]string{GetBrokerPactVersionKey(tenant), ""}, "/") + pactVersions, err := Store().PactVersion().Search(ctx, + registry.WithStrKey(pactVersionKey), + registry.WithPrefix()) + + if err != nil { + return nil, err + } + if len(pactVersions.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry") + return nil, nil + } + participantToVersionObj := make(map[int32]Version) + for i := 0; i < len(pactVersions.Kvs); i++ { + pactVersion := &PactVersion{} + err = json.Unmarshal(pactVersions.Kvs[i].Value, pactVersion) + if err != nil { + return nil, err + } + if pactVersion.ProviderParticipantId != providerParticipant.Id { + continue + } + PactLogger.Infof("[RetrieveProviderPacts] Pact version found: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId) + vObj := versionObjects[pactVersion.VersionId] + if v1Obj, ok := participantToVersionObj[vObj.ParticipantId]; ok { + if vObj.Order > v1Obj.Order { + participantToVersionObj[vObj.ParticipantId] = vObj + } + } else { + participantToVersionObj[vObj.ParticipantId] = vObj + } + } + // Get all participants + participantKey := util.StringJoin([]string{GetBrokerParticipantKey(tenant), ""}, "/") + participants, err := Store().Participant().Search(ctx, + registry.WithStrKey(participantKey), + registry.WithPrefix()) + + if err != nil { + return nil, err + } + if len(participants.Kvs) == 0 { + return nil, nil + } + consumerInfoArr := make([]*ConsumerInfo, 0) + for i := 0; i < len(participants.Kvs); i++ { + participant := &Participant{} + err = json.Unmarshal(participants.Kvs[i].Value, participant) + if err != nil { + return nil, err + } + if _, ok := participantToVersionObj[participant.Id]; !ok { + continue + } + PactLogger.Infof("[RetrieveProviderPacts] Consumer found: (%d, %s, %s)", participant.Id, participant.AppId, participant.ServiceName) + consumerVersion := participantToVersionObj[participant.Id].Number + consumerId, err := serviceUtil.GetServiceId(ctx, &pb.MicroServiceKey{ + Tenant: tenant, + AppId: participant.AppId, + ServiceName: participant.ServiceName, + Version: consumerVersion, + }) + if err != nil { + return nil, err + } + PactLogger.Infof("[RetrieveProviderPacts] Consumer microservice found: %s", consumerId) + + urlValue := GenerateBrokerAPIPath(in.BaseUrl.Scheme, in.BaseUrl.HostAddress, + BROKER_PUBLISH_URL, + strings.NewReplacer(":providerId", in.ProviderId, + ":consumerId", consumerId, + ":number", consumerVersion)) + + consumerInfo := &ConsumerInfo{ + Href: urlValue, + Name: consumerId, + } + consumerInfoArr = append(consumerInfoArr, consumerInfo) + } + links := &Links{ + Pacts: consumerInfoArr, + } + resJson, err := json.Marshal(links) + if err != nil { + return nil, err + } + PactLogger.Infof("Json : %s", string(resJson)) + response := &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."), + XLinks: links, + } + return response, nil +} + +func (*BrokerService) GetAllProviderPacts(ctx context.Context, + in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) { + + if in == nil || len(in.ProviderId) == 0 { + PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.") + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + tenant := GetDefaultTenantProject() + + provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId) + if err != nil { + PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."), + }, err + } + if provider == nil { + PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."), + }, nil + } + // Get the provider participant + //providerParticipantKey := apt.GenerateBrokerParticipantKey(tenant, provider.AppId, provider.ServiceName) + providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName) + if err != nil || providerParticipant == nil { + PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId) + return &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."), + }, err + } + PactLogger.Infof("[RetrieveProviderPacts] Provider participant id : %d", providerParticipant.Id) + // Get all versions + versionKey := util.StringJoin([]string{GetBrokerVersionKey(tenant), ""}, "/") + versions, err := Store().Version().Search(ctx, + registry.WithPrefix(), + registry.WithStrKey(versionKey)) + + if err != nil { + return nil, err + } + if len(versions.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPacts] No versions found, sorry") + return nil, nil + } + // Store versions in a map + versionObjects := make(map[int32]Version) + for i := 0; i < len(versions.Kvs); i++ { + version := &Version{} + err = json.Unmarshal(versions.Kvs[i].Value, version) + if err != nil { + return nil, err + } + PactLogger.Infof("[RetrieveProviderPacts] Version found : (%d, %s)", version.Id, version.Number) + versionObjects[version.Id] = *version + } + // Get all pactversions and filter using the provider participant id + pactVersionKey := util.StringJoin([]string{GetBrokerPactVersionKey(tenant), ""}, "/") + pactVersions, err := Store().PactVersion().Search(ctx, + registry.WithStrKey(pactVersionKey), + registry.WithPrefix()) + + if err != nil { + return nil, err + } + if len(pactVersions.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry") + return nil, nil + } + participantToVersionObj := make(map[int32]Version) + for i := 0; i < len(pactVersions.Kvs); i++ { + pactVersion := &PactVersion{} + err = json.Unmarshal(pactVersions.Kvs[i].Value, pactVersion) + if err != nil { + return nil, err + } + if pactVersion.ProviderParticipantId != providerParticipant.Id { + continue + } + PactLogger.Infof("[RetrieveProviderPacts] Pact version found: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId) + vObj := versionObjects[pactVersion.VersionId] + if v1Obj, ok := participantToVersionObj[vObj.ParticipantId]; ok { + if vObj.Order > v1Obj.Order { + participantToVersionObj[vObj.ParticipantId] = vObj + } + } else { + participantToVersionObj[vObj.ParticipantId] = vObj + } + } + // Get all participants + participantKey := util.StringJoin([]string{GetBrokerParticipantKey(tenant), ""}, "/") + participants, err := Store().Participant().Search(ctx, + registry.WithStrKey(participantKey), + registry.WithPrefix()) + + if err != nil { + return nil, err + } + if len(participants.Kvs) == 0 { + return nil, nil + } + consumerInfoArr := make([]*ConsumerInfo, 0) + for i := 0; i < len(participants.Kvs); i++ { + participant := &Participant{} + err = json.Unmarshal(participants.Kvs[i].Value, participant) + if err != nil { + return nil, err + } + if _, ok := participantToVersionObj[participant.Id]; !ok { + continue + } + PactLogger.Infof("[RetrieveProviderPacts] Consumer found: (%d, %s, %s)", participant.Id, participant.AppId, participant.ServiceName) + consumerVersion := participantToVersionObj[participant.Id].Number + consumerId, err := serviceUtil.GetServiceId(ctx, &pb.MicroServiceKey{ + Tenant: tenant, + AppId: participant.AppId, + ServiceName: participant.ServiceName, + Version: consumerVersion, + }) + if err != nil { + return nil, err + } + PactLogger.Infof("[RetrieveProviderPacts] Consumer microservice found: %s", consumerId) + + urlValue := GenerateBrokerAPIPath(in.BaseUrl.Scheme, in.BaseUrl.HostAddress, + BROKER_PUBLISH_URL, + strings.NewReplacer(":providerId", in.ProviderId, + ":consumerId", consumerId, + ":number", consumerVersion)) + + consumerInfo := &ConsumerInfo{ + Href: urlValue, + Name: consumerId, + } + consumerInfoArr = append(consumerInfoArr, consumerInfo) + } + links := &Links{ + Pacts: consumerInfoArr, + } + resJson, err := json.Marshal(links) + if err != nil { + return nil, err + } + PactLogger.Infof("Json : %s", string(resJson)) + response := &GetAllProviderPactsResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."), + XLinks: links, + } + return response, nil +} + +func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *RetrieveVerificationRequest) (*RetrieveVerificationResponse, error) { + if in == nil || len(in.ConsumerId) == 0 || len(in.ConsumerVersion) == 0 { + PactLogger.Errorf(nil, "verification result retrieve request failed: invalid params.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + tenant := GetDefaultTenantProject() + consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId) + if err != nil { + PactLogger.Errorf(err, "verification result retrieve request failed, consumerId is %s: query consumer failed.", in.ConsumerId) + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."), + }, err + } + if consumer == nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, consumerId is %s: consumer not exist.", in.ConsumerId) + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."), + }, nil + } + PactLogger.Infof("Consumer service found: (%s, %s, %s, %s)", consumer.ServiceId, consumer.AppId, consumer.ServiceName, consumer.Version) + // Get consumer participant + consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName) + if err != nil || consumerParticipant == nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, consumer participant cannot be searched.", in.ConsumerId) + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."), + }, err + } + PactLogger.Infof("Consumer participant found: (%d, %s, %s)", consumerParticipant.Id, consumerParticipant.AppId, consumerParticipant.ServiceName) + // Get version + version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id) + if err != nil || version == nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, version cannot be searched.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."), + }, err + } + PactLogger.Infof("Version found/created: (%d, %s, %d, %d)", version.Id, version.Number, version.ParticipantId, version.Order) + key := util.StringJoin([]string{GetBrokerPactVersionKey(tenant), strconv.Itoa(int(version.Id))}, "/") + pactVersions, err := Store().PactVersion().Search(ctx, + registry.WithPrefix(), + registry.WithStrKey(key)) + + if err != nil || len(pactVersions.Kvs) == 0 { + PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."), + }, err + } + overAllSuccess := false + + successfuls := make([]string, 0) + fails := make([]string, 0) + unknowns := make([]string, 0) + + verificationDetailsArr := make([]*VerificationDetail, 0) + for j := 0; j < len(pactVersions.Kvs); j++ { + pactVersion := &PactVersion{} + err = json.Unmarshal(pactVersions.Kvs[j].Value, &pactVersion) + if err != nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, pact version cannot be searched.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."), + }, err + } + key = util.StringJoin([]string{GetBrokerVerificationKey(tenant), strconv.Itoa(int(pactVersion.Id))}, "/") + verifications, err := Store().Verification().Search(ctx, + registry.WithPrefix(), + registry.WithStrKey(key)) + + if err != nil || len(verifications.Kvs) == 0 { + PactLogger.Errorf(nil, "verification result retrieve request failed, verification results cannot be searched.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification results cannot be searched."), + }, err + } + lastNumber := int32(math.MinInt32) + var lastVerificationResult *Verification + for i := 0; i < len(verifications.Kvs); i++ { + verification := &Verification{} + err = json.Unmarshal(verifications.Kvs[i].Value, &verification) + if err != nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."), + }, err + } + if verification.Number > lastNumber { + lastNumber = verification.Number + lastVerificationResult = verification + } + } + if lastVerificationResult == nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, verification result cannot be found.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be found."), + }, err + } + PactLogger.Infof("Verification result found: (%d, %d, %d, %t, %s, %s, %s)", + lastVerificationResult.Id, lastVerificationResult.Number, lastVerificationResult.PactVersionId, + lastVerificationResult.Success, lastVerificationResult.ProviderVersion, + lastVerificationResult.BuildUrl, lastVerificationResult.VerificationDate) + + key = util.StringJoin([]string{GetBrokerParticipantKey(tenant), ""}, "/") + participants, err := Store().Participant().Search(ctx, + registry.WithStrKey(key), + registry.WithPrefix()) + + if err != nil || len(participants.Kvs) == 0 { + PactLogger.Errorf(nil, "verification result retrieve request failed, provider participant cannot be searched.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider participant cannot be searched."), + }, err + } + var providerParticipant *Participant + for i := 0; i < len(participants.Kvs); i++ { + participant := &Participant{} + err = json.Unmarshal(participants.Kvs[i].Value, &participant) + if err != nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."), + }, err + } + if participant.Id == pactVersion.ProviderParticipantId { + providerParticipant = participant + break + } + } + if providerParticipant == nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."), + }, err + } + serviceFindReq := &pb.GetExistenceRequest{ + Type: "microservice", + AppId: providerParticipant.AppId, + ServiceName: providerParticipant.ServiceName, + Version: lastVerificationResult.ProviderVersion, + } + resp, err := apt.ServiceAPI.Exist(ctx, serviceFindReq) + if err != nil { + PactLogger.Errorf(nil, "verification result retrieve request failed, provider service cannot be found.") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider service cannot be found."), + }, err + } + providerName := resp.ServiceId + verificationDetail := &VerificationDetail{ + ProviderName: providerName, + ProviderApplicationVersion: lastVerificationResult.ProviderVersion, + Success: lastVerificationResult.Success, + VerificationDate: lastVerificationResult.VerificationDate, + } + verificationDetailsArr = append(verificationDetailsArr, verificationDetail) + if verificationDetail.Success == true { + successfuls = append(successfuls, providerName) + } else { + fails = append(fails, providerName) + } + overAllSuccess = overAllSuccess && verificationDetail.Success + } + verificationDetails := &VerificationDetails{VerificationResults: verificationDetailsArr} + verificationSummary := &VerificationSummary{Successful: successfuls, Failed: fails, Unknown: unknowns} + verificationResult := &VerificationResult{Success: overAllSuccess, ProviderSummary: verificationSummary, XEmbedded: verificationDetails} + PactLogger.Infof("Verification result retrieved successfully ...") + return &RetrieveVerificationResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Verification result retrieved successfully."), + Result: verificationResult, + }, nil +} + +func (*BrokerService) PublishVerificationResults(ctx context.Context, in *PublishVerificationRequest) (*PublishVerificationResponse, error) { + if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 { + PactLogger.Errorf(nil, "verification result publish request failed: invalid params.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + tenant := GetDefaultTenantProject() + consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId) + if err != nil { + PactLogger.Errorf(err, "verification result publish request failed, consumerId is %s: query consumer failed.", in.ConsumerId) + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."), + }, err + } + if consumer == nil { + PactLogger.Errorf(nil, "verification result publish request failed, consumerId is %s: consumer not exist.", in.ConsumerId) + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."), + }, nil + } + PactLogger.Infof("Consumer service found: (%s, %s, %s, %s)", consumer.ServiceId, consumer.AppId, consumer.ServiceName, consumer.Version) + // Get consumer participant + consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName) + if err != nil || consumerParticipant == nil { + PactLogger.Errorf(nil, "verification result publish request failed, consumer participant cannot be searched.", in.ConsumerId) + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."), + }, err + } + PactLogger.Infof("Consumer participant found: (%d, %s, %s)", consumerParticipant.Id, consumerParticipant.AppId, consumerParticipant.ServiceName) + // Get version + version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id) + if err != nil || version == nil { + PactLogger.Errorf(nil, "verification result publish request failed, version cannot be searched.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."), + }, err + } + PactLogger.Infof("Version found/created: (%d, %s, %d, %d)", version.Id, version.Number, version.ParticipantId, version.Order) + key := util.StringJoin([]string{GetBrokerPactKey(tenant), ""}, "/") + pacts, err := Store().Pact().Search(ctx, + registry.WithStrKey(key), + registry.WithPrefix()) + + if err != nil || len(pacts.Kvs) == 0 { + PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."), + }, err + } + pactExists := false + for i := 0; i < len(pacts.Kvs); i++ { + pact := &Pact{} + err = json.Unmarshal(pacts.Kvs[i].Value, &pact) + if err != nil { + PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."), + }, err + } + if pact.Id == in.PactId { + pactExists = true + } + } + if pactExists == false { + PactLogger.Errorf(nil, "verification result publish request failed, pact does not exists.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact does not exists."), + }, err + } + pactVersion, err := GetPactVersion(ctx, tenant, version.Id, in.PactId) + if err != nil || pactVersion == nil { + PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."), + }, err + } + // Check if some verification results already exists + key = util.StringJoin([]string{GetBrokerVerificationKey(tenant), strconv.Itoa(int(pactVersion.Id))}, "/") + verifications, err := Store().Verification().Search(ctx, + registry.WithStrKey(key), + registry.WithPrefix()) + + if err != nil { + PactLogger.Errorf(nil, "verification result publish request failed, verification result cannot be searched.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be searched."), + }, err + } + lastNumber := int32(math.MinInt32) + if len(verifications.Kvs) != 0 { + for i := 0; i < len(verifications.Kvs); i++ { + verification := &Verification{} + err = json.Unmarshal(verifications.Kvs[i].Value, &verification) + if err != nil { + PactLogger.Errorf(nil, "verification result publish request failed, verification result unmarshall error.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."), + }, err + } + if verification.Number > lastNumber { + lastNumber = verification.Number + } + } + } + if lastNumber < 0 { + lastNumber = 0 + } else { + lastNumber++ + } + verificationDate := time.Now().Format(time.RFC3339) + verificationKey := GenerateBrokerVerificationKey(tenant, pactVersion.Id, lastNumber) + id, err := GetData(ctx, GetBrokerLatestVerificationIDKey()) + verification := &Verification{ + Id: int32(id) + 1, + Number: lastNumber, + PactVersionId: pactVersion.Id, + Success: in.Success, + ProviderVersion: in.ProviderApplicationVersion, + BuildUrl: "", + VerificationDate: verificationDate, + } + response, err := CreateVerification(PactLogger, ctx, verificationKey, *verification) + if err != nil { + return response, err + } + PactLogger.Infof("Verification result inserted: (%d, %d, %d, %t, %s, %s, %s)", + verification.Id, verification.Number, verification.PactVersionId, + verification.Success, verification.ProviderVersion, verification.BuildUrl, verification.VerificationDate) + verificationResponse := &VerificationDetail{ + ProviderName: in.ProviderId, + ProviderApplicationVersion: verification.ProviderVersion, + Success: verification.Success, + VerificationDate: verification.VerificationDate, + } + PactLogger.Infof("Verification result published successfully ...") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Verification result published successfully."), + Confirmation: verificationResponse, + }, nil +} + +func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (*PublishPactResponse, error) { + if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 || len(in.Pact) == 0 { + PactLogger.Errorf(nil, "pact publish request failed: invalid params.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."), + }, nil + } + tenant := GetDefaultTenantProject() + + provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId) + if err != nil { + PactLogger.Errorf(err, "pact publish failed, providerId is %s: query provider failed.", in.ProviderId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."), + }, err + } + if provider == nil { + PactLogger.Errorf(nil, "pact publish failed, providerId is %s: provider not exist.", in.ProviderId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."), + }, nil + } + PactLogger.Infof("Provider service found: (%s, %s, %s, %s)", provider.ServiceId, provider.AppId, provider.ServiceName, provider.Version) + consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId) + if err != nil { + PactLogger.Errorf(err, "pact publish failed, consumerId is %s: query consumer failed.", in.ConsumerId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."), + }, err + } + if consumer == nil { + PactLogger.Errorf(nil, "pact publish failed, consumerId is %s: consumer not exist.", in.ConsumerId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."), + }, nil + } + + // check that the consumer has that vesion in the url + if strings.Compare(consumer.GetVersion(), in.Version) != 0 { + util.Logger().Errorf(nil, + "pact publish failed, version (%s) does not exist for consmer", in.Version) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer Version does not exist."), + }, nil + } + + PactLogger.Infof("Consumer service found: (%s, %s, %s, %s)", consumer.ServiceId, consumer.AppId, consumer.ServiceName, consumer.Version) + // Get or create provider participant + providerParticipantKey := GenerateBrokerParticipantKey(tenant, provider.AppId, provider.ServiceName) + providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, provider participant cannot be searched.", in.ProviderId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."), + }, err + } + if providerParticipant == nil { + id, err := GetData(ctx, GetBrokerLatestParticipantIDKey()) + providerParticipant = &Participant{Id: int32(id) + 1, AppId: provider.AppId, ServiceName: provider.ServiceName} + response, err := CreateParticipant(PactLogger, ctx, providerParticipantKey, *providerParticipant) + if err != nil { + return response, err + } + } + PactLogger.Infof("Provider participant found: (%d, %s, %s)", providerParticipant.Id, providerParticipant.AppId, providerParticipant.ServiceName) + // Get or create consumer participant + consumerParticipantKey := GenerateBrokerParticipantKey(tenant, consumer.AppId, consumer.ServiceName) + consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, consumer participant cannot be searched.", in.ConsumerId) + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."), + }, err + } + if consumerParticipant == nil { + id, err := GetData(ctx, GetBrokerLatestParticipantIDKey()) + consumerParticipant = &Participant{Id: int32(id) + 1, AppId: consumer.AppId, ServiceName: consumer.ServiceName} + response, err := CreateParticipant(PactLogger, ctx, consumerParticipantKey, *consumerParticipant) + if err != nil { + return response, err + } + } + PactLogger.Infof("Consumer participant found: (%d, %s, %s)", consumerParticipant.Id, consumerParticipant.AppId, consumerParticipant.ServiceName) + // Get or create version + versionKey := GenerateBrokerVersionKey(tenant, in.Version, consumerParticipant.Id) + version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, version cannot be searched.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."), + }, err + } + if version == nil { + order := GetLastestVersionNumberForParticipant(ctx, tenant, consumerParticipant.Id) + PactLogger.Infof("Old version order: %d", order) + order++ + id, err := GetData(ctx, GetBrokerLatestVersionIDKey()) + version = &Version{Id: int32(id) + 1, Number: in.Version, ParticipantId: consumerParticipant.Id, Order: order} + response, err := CreateVersion(PactLogger, ctx, versionKey, *version) + if err != nil { + return response, err + } + } + PactLogger.Infof("Version found/created: (%d, %s, %d, %d)", version.Id, version.Number, version.ParticipantId, version.Order) + // Get or create pact + sha1 := sha1.Sum(in.Pact) + var sha []byte = sha1[:] + pactKey := GenerateBrokerPactKey(tenant, consumerParticipant.Id, providerParticipant.Id, sha) + pact, err := GetPact(ctx, tenant, consumerParticipant.Id, providerParticipant.Id, sha) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact cannot be searched.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."), + }, err + } + if pact == nil { + id, err := GetData(ctx, GetBrokerLatestPactIDKey()) + pact = &Pact{Id: int32(id) + 1, ConsumerParticipantId: consumerParticipant.Id, + ProviderParticipantId: providerParticipant.Id, Sha: sha, Content: in.Pact} + response, err := CreatePact(PactLogger, ctx, pactKey, *pact) + if err != nil { + return response, err + } + } + PactLogger.Infof("Pact found/created: (%d, %d, %d, %s)", pact.Id, pact.ConsumerParticipantId, pact.ProviderParticipantId, pact.Sha) + // Get or create pact version + pactVersionKey := GenerateBrokerPactVersionKey(tenant, version.Id, pact.Id) + pactVersion, err := GetPactVersion(ctx, tenant, version.Id, pact.Id) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact version cannot be searched.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."), + }, err + } + if pactVersion == nil { + id, err := GetData(ctx, GetBrokerLatestPactVersionIDKey()) + pactVersion = &PactVersion{Id: int32(id) + 1, VersionId: version.Id, PactId: pact.Id, ProviderParticipantId: providerParticipant.Id} + response, err := CreatePactVersion(PactLogger, ctx, pactVersionKey, *pactVersion) + if err != nil { + return response, err + } + } + PactLogger.Infof("PactVersion found/create: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId) + PactLogger.Infof("Pact published successfully ...") + return &PublishPactResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Pact published successfully."), + }, nil +} diff --git a/server/broker/service_test.go b/server/broker/service_test.go new file mode 100644 index 00000000..516b8c34 --- /dev/null +++ b/server/broker/service_test.go @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "fmt" + + "github.com/apache/incubator-servicecomb-service-center/pkg/util" + "github.com/apache/incubator-servicecomb-service-center/server/core" + pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "golang.org/x/net/context" +) + +const ( + TEST_BROKER_NO_SERVICE_ID = "noServiceId" + TEST_BROKER_NO_VERSION = "noVersion" + TEST_BROKER_TOO_LONG_SERVICEID = "addasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasadafd" + //Consumer + TEST_BROKER_CONSUMER_VERSION = "4.0.0" + TEST_BROKER_CONSUMER_NAME = "broker_name_consumer" + TEST_BROKER_CONSUMER_APP = "broker_group_consumer" + //Provider + TEST_BROKER_PROVIDER_VERSION = "3.0.0" + TEST_BROKER_PROVIDER_NAME = "broker_name_provider" + TEST_BROKER_PROVIDER_APP = "broker_group_provider" +) + +var brokerResource = BrokerServiceAPI +var serviceResource = core.ServiceAPI +var consumerServiceId string +var providerServiceId string + +var _ = Describe("BrokerController", func() { + Describe("brokerDependency", func() { + Context("normal", func() { + It("PublishPact", func() { + fmt.Println("UT===========PublishPact") + + //(1) create consumer service + resp, err := serviceResource.Create(getContext(), &pb.CreateServiceRequest{ + Service: &pb.MicroService{ + ServiceName: TEST_BROKER_CONSUMER_NAME, + AppId: TEST_BROKER_CONSUMER_APP, + Version: TEST_BROKER_CONSUMER_VERSION, + Level: "FRONT", + Schemas: []string{ + "xxxxxxxx", + }, + Status: "UP", + }, + }) + + Expect(err).To(BeNil()) + consumerServiceId = resp.ServiceId + Expect(resp.GetResponse().Code).To(Equal(pb.Response_SUCCESS)) + + //(2) create provider service + resp, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{ + Service: &pb.MicroService{ + ServiceName: TEST_BROKER_PROVIDER_NAME, + AppId: TEST_BROKER_PROVIDER_APP, + Version: TEST_BROKER_PROVIDER_VERSION, + Level: "FRONT", + Schemas: []string{ + "xxxxxxxx", + }, + Status: "UP", + Properties: map[string]string{"allowCrossApp": "true"}, + }, + }) + Expect(err).To(BeNil()) + providerServiceId = resp.ServiceId + Expect(resp.GetResponse().Code).To(Equal(pb.Response_SUCCESS)) + + //(3) publish a pact between two services + respPublishPact, err := brokerResource.PublishPact(getContext(), + &PublishPactRequest{ + ProviderId: providerServiceId, + ConsumerId: consumerServiceId, + Version: TEST_BROKER_CONSUMER_VERSION, + Pact: []byte("hello"), + }) + + Expect(err).To(BeNil()) + Expect(respPublishPact.GetResponse().Code).To(Equal(pb.Response_SUCCESS)) + }) + + It("PublishPact-noProviderServiceId", func() { + fmt.Println("UT===========PublishPact, no provider serviceID") + + //publish a pact between two services + respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{ + ProviderId: TEST_BROKER_NO_SERVICE_ID, + ConsumerId: consumerServiceId, + Version: TEST_BROKER_CONSUMER_VERSION, + Pact: []byte("hello"), + }) + + Expect(respPublishPact.GetResponse().Code).ToNot(Equal(pb.Response_SUCCESS)) + }) + + It("PublishPact-noConumerServiceId", func() { + fmt.Println("UT===========PublishPact, no consumer serviceID") + + //publish a pact between two services + respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{ + ProviderId: providerServiceId, + ConsumerId: TEST_BROKER_NO_SERVICE_ID, + Version: TEST_BROKER_CONSUMER_VERSION, + Pact: []byte("hello"), + }) + + Expect(respPublishPact.GetResponse().Code).ToNot(Equal(pb.Response_SUCCESS)) + }) + + It("PublishPact-noConumerVersion", func() { + fmt.Println("UT===========PublishPact, no consumer Version") + + //publish a pact between two services + respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{ + ProviderId: providerServiceId, + ConsumerId: consumerServiceId, + Version: TEST_BROKER_NO_VERSION, + Pact: []byte("hello"), + }) + + Expect(respPublishPact.GetResponse().Code).ToNot(Equal(pb.Response_SUCCESS)) + }) + + It("GetBrokerHome", func() { + fmt.Println("UT===========GetBrokerHome") + + respGetHome, _ := brokerResource.GetBrokerHome(getContext(), &BaseBrokerRequest{ + HostAddress: "localhost", + Scheme: "http", + }) + + Expect(respGetHome).NotTo(BeNil()) + + }) + + It("GetBrokerAllProviderPacts", func() { + fmt.Println("UT===========GetBrokerAllProviderPacts") + + respGetAllProviderPacts, _ := brokerResource.GetAllProviderPacts(getContext(), + &GetAllProviderPactsRequest{ + ProviderId: providerServiceId, + BaseUrl: &BaseBrokerRequest{ + HostAddress: "localhost", + Scheme: "http", + }}) + + Expect(respGetAllProviderPacts).NotTo(BeNil()) + Expect(respGetAllProviderPacts.GetResponse().Code).To(Equal(pb.Response_SUCCESS)) + }) + + It("GetBrokerPactsOfProvider", func() { + fmt.Println("UT===========GetBrokerPactsOfProvider") + + respGetAllProviderPacts, _ := brokerResource.GetPactsOfProvider(getContext(), + &GetProviderConsumerVersionPactRequest{ + ProviderId: providerServiceId, + ConsumerId: consumerServiceId, + Version: TEST_BROKER_CONSUMER_VERSION, + BaseUrl: &BaseBrokerRequest{ + HostAddress: "localhost", + Scheme: "http", + }}) + + Expect(respGetAllProviderPacts).NotTo(BeNil()) + Expect(respGetAllProviderPacts.GetResponse().Code).To(Equal(pb.Response_SUCCESS)) + }) + + }) + }) +}) + +func getContext() context.Context { + ctx := context.TODO() + ctx = util.SetContext(ctx, "domain", "default") + ctx = util.SetContext(ctx, "project", "default") + ctx = util.SetContext(ctx, "noCache", "1") + return ctx +} diff --git a/server/broker/store.go b/server/broker/store.go new file mode 100644 index 00000000..0cdddc59 --- /dev/null +++ b/server/broker/store.go @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "sync" + + "github.com/apache/incubator-servicecomb-service-center/pkg/util" + sstore "github.com/apache/incubator-servicecomb-service-center/server/core/backend/store" +) + +const ( + PARTICIPANT sstore.StoreType = iota + VERSION + PACT + PACT_VERSION + PACT_TAG + VERIFICATION + PACT_LATEST + typeEnd +) + +var TypeNames = []string{ + PARTICIPANT: "PARTICIPANT", + VERSION: "VERSION", + PACT: "PACT", + PACT_VERSION: "PACT_VERSION", + PACT_TAG: "PACT_TAG", + VERIFICATION: "VERIFICATION", + PACT_LATEST: "PACT_LATEST", +} + +var TypeRoots = map[sstore.StoreType]string{ + PARTICIPANT: GetBrokerParticipantKey(""), + VERSION: GetBrokerVersionKey(""), + PACT: GetBrokerPactKey(""), + PACT_VERSION: GetBrokerPactVersionKey(""), + PACT_TAG: GetBrokerTagKey(""), + VERIFICATION: GetBrokerVerificationKey(""), + PACT_LATEST: GetBrokerLatestKey(""), +} + +var store = &BKvStore{} + +func Store() *BKvStore { + return store +} + +func (s *BKvStore) StoreSize(t sstore.StoreType) int { + return 100 +} + +func (s *BKvStore) newStore(t sstore.StoreType, opts ...sstore.KvCacherCfgOption) { + opts = append(opts, + sstore.WithKey(TypeRoots[t]), + sstore.WithInitSize(s.StoreSize(t)), + ) + s.newIndexer(t, sstore.NewKvCacher(opts...)) +} + +func (s *BKvStore) store() { + for t := sstore.StoreType(0); t != typeEnd; t++ { + s.newStore(t) + } + for _, i := range s.bindexers { + <-i.Ready() + } + util.SafeCloseChan(s.bready) + + util.Logger().Debugf("all indexers are ready") +} + +func init() { + store.Initialize() + store.Run() + store.Ready() +} + +type BKvStore struct { + *sstore.KvStore + bindexers map[sstore.StoreType]*sstore.Indexer + block sync.RWMutex + bready chan struct{} + bisClose bool +} + +func (s *BKvStore) Initialize() { + s.KvStore = sstore.Store() + s.KvStore.Initialize() + s.bindexers = make(map[sstore.StoreType]*sstore.Indexer) + s.bready = make(chan struct{}) + + for i := sstore.StoreType(0); i != typeEnd; i++ { + store.newNullStore(i) + } +} + +func (s *BKvStore) newNullStore(t sstore.StoreType) { + s.newIndexer(t, sstore.NullCacher) +} + +func (s *BKvStore) newIndexer(t sstore.StoreType, cacher sstore.Cacher) { + indexer := sstore.NewCacheIndexer(t, cacher) + s.bindexers[t] = indexer + indexer.Run() +} + +func (s *BKvStore) Run() { + go s.store() +} + +func (s *BKvStore) Ready() <-chan struct{} { + return s.bready +} + +func (s *BKvStore) Participant() *sstore.Indexer { + return s.bindexers[PARTICIPANT] +} + +func (s *BKvStore) Version() *sstore.Indexer { + return s.bindexers[VERSION] +} + +func (s *BKvStore) Pact() *sstore.Indexer { + return s.bindexers[PACT] +} + +func (s *BKvStore) PactVersion() *sstore.Indexer { + return s.bindexers[PACT_VERSION] +} + +func (s *BKvStore) PactTag() *sstore.Indexer { + return s.bindexers[PACT_TAG] +} + +func (s *BKvStore) Verification() *sstore.Indexer { + return s.bindexers[VERIFICATION] +} + +func (s *BKvStore) PactLatest() *sstore.Indexer { + return s.bindexers[PACT_LATEST] +} diff --git a/server/broker/util.go b/server/broker/util.go new file mode 100644 index 00000000..23e98ca1 --- /dev/null +++ b/server/broker/util.go @@ -0,0 +1,680 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 broker + +import ( + "context" + "encoding/json" + "errors" + "math" + "net/url" + "strconv" + "strings" + + "github.com/ServiceComb/paas-lager" + "github.com/ServiceComb/paas-lager/third_party/forked/cloudfoundry/lager" + "github.com/apache/incubator-servicecomb-service-center/pkg/util" + backend "github.com/apache/incubator-servicecomb-service-center/server/core/backend" + pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto" + scerr "github.com/apache/incubator-servicecomb-service-center/server/error" + "github.com/apache/incubator-servicecomb-service-center/server/infra/registry" + serviceUtil "github.com/apache/incubator-servicecomb-service-center/server/service/util" +) + +var PactLogger lager.Logger + +const ( + BROKER_HOME_URL = "/" + BROKER_PARTICIPANTS_URL = "/participants" + BROKER_PARTICIPANT_URL = "/participants/:participantId" + BROKER_PARTY_VERSIONS_URL = "/participants/:participantId/versions" + BROKER_PARTY_LATEST_VERSION_URL = "/participants/:participantId/versions/latest" + BROKER_PARTY_VERSION_URL = "/participants/:participantId/versions/:number" + BROKER_PROVIDER_URL = "/pacts/provider" + BROKER_PROVIDER_LATEST_PACTS_URL = "/pacts/provider/:providerId/latest" + BROKER_PROVIDER_LATEST_PACTS_TAG_URL = "/pacts/provider/:providerId/latest/:tag" + BROKER_PACTS_LATEST_URL = "/pacts/latest" + + BROKER_PUBLISH_URL = "/pacts/provider/:providerId/consumer/:consumerId/version/:number" + BROKER_PUBLISH_VERIFICATION_URL = "/pacts/provider/:providerId/consumer/:consumerId/pact-version/:pact/verification-results" + BROKER_WEBHOOHS_URL = "/webhooks" + + BROKER_CURIES_URL = "/doc/:rel" +) + +var brokerAPILinksValues = map[string]string{ + "self": BROKER_HOME_URL, + "pb:publish-pact": BROKER_PUBLISH_URL, + "pb:latest-pact-versions": BROKER_PACTS_LATEST_URL, + "pb:pacticipants": BROKER_PARTICIPANTS_URL, + "pb:latest-provider-pacts": BROKER_PROVIDER_LATEST_PACTS_URL, + "pb:latest-provider-pacts-with-tag": BROKER_PROVIDER_LATEST_PACTS_TAG_URL, + "pb:webhooks": BROKER_WEBHOOHS_URL, +} + +var brokerAPILinksTempl = map[string]bool{ + "self": false, + "pb:publish-pact": true, + "pb:latest-pact-versions": false, + "pb:pacticipants": false, + "pb:latest-provider-pacts": true, + "pb:latest-provider-pacts-with-tag": true, + "pb:webhooks": false, +} + +var brokerAPILinksTitles = map[string]string{ + "self": "Index", + "pb:publish-pact": "Publish a pact", + "pb:latest-pact-versions": "Latest pact versions", + "pb:pacticipants": "Pacticipants", + "pb:latest-provider-pacts": "Latest pacts by provider", + "pb:latest-provider-pacts-with-tag": "Latest pacts by provider with a specified tag", + "pb:webhooks": "Webhooks", +} + +func init() { + //define Broker logger + stlager.Init(stlager.Config{ + LoggerLevel: "INFO", + LoggerFile: "broker_srvc.log", + EnableRsyslog: false, + }) + PactLogger = stlager.NewLogger("broker_srvc") +} + +func GetDefaultTenantProject() string { + return util.StringJoin([]string{"default", "default"}, "/") +} + +//GenerateBrokerAPIPath creates the API link from the constant template +func GenerateBrokerAPIPath(scheme string, host string, apiPath string, + replacer *strings.Replacer) string { + genPath := url.URL{ + Scheme: scheme, + Host: host, + Path: apiPath, + } + if replacer != nil { + return replacer.Replace(genPath.String()) + } + return genPath.String() +} + +//GetBrokerHomeLinksAPIS return the generated Home links +func GetBrokerHomeLinksAPIS(scheme string, host string, apiKey string) string { + return GenerateBrokerAPIPath(scheme, host, brokerAPILinksValues[apiKey], + strings.NewReplacer(":providerId", "{provider}", + ":consumerId", "{consumer}", + ":number", "{consumerApplicationVersion}", + ":tag", "{tag}")) +} + +//CreateBrokerHomeResponse create the templated broker home response +func CreateBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse { + + var apiEntries map[string]*BrokerAPIInfoEntry + apiEntries = make(map[string]*BrokerAPIInfoEntry) + + for k := range brokerAPILinksValues { + apiEntries[k] = &BrokerAPIInfoEntry{ + Href: GetBrokerHomeLinksAPIS(scheme, host, k), + Title: brokerAPILinksTitles[k], + Templated: brokerAPILinksTempl[k], + } + } + + curies := []*BrokerAPIInfoEntry{} + curies = append(curies, &BrokerAPIInfoEntry{ + Name: "pb", + Href: GenerateBrokerAPIPath(scheme, host, BROKER_CURIES_URL, + strings.NewReplacer(":rel", "{rel}")), + }) + + return &BrokerHomeResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "Broker Home."), + XLinks: apiEntries, + Curies: curies, + } +} + +//GetBrokerHomeResponse gets the homeResponse from cache if it exists +func GetBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse { + brokerResp := CreateBrokerHomeResponse(host, scheme) + if brokerResp == nil { + return nil + } + return brokerResp +} + +//GetBrokerParticipantUtils returns the participant from ETCD +func GetBrokerParticipantUtils(ctx context.Context, tenant string, appId string, + serviceName string, opts ...registry.PluginOpOption) (*Participant, error) { + + key := GenerateBrokerParticipantKey(tenant, appId, serviceName) + opts = append(opts, registry.WithStrKey(key)) + participants, err := Store().Participant().Search(ctx, opts...) + + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, participant with, could not be searched.") + return nil, err + } + + if len(participants.Kvs) == 0 { + PactLogger.Info("GetParticipant found no participant") + return nil, nil + } + + participant := &Participant{} + err = json.Unmarshal(participants.Kvs[0].Value, participant) + if err != nil { + return nil, err + } + PactLogger.Infof("GetParticipant: (%d, %s, %s)", participant.Id, participant.AppId, + participant.ServiceName) + return participant, nil +} + +//GetBrokerParticipantFromServiceId returns the participant and the service from ETCD +func GetBrokerParticipantFromServiceId(ctx context.Context, serviceId string) (*Participant, + *pb.MicroService, error, error) { + + tenant := GetDefaultTenantProject() + serviceParticipant, err := serviceUtil.GetService(ctx, tenant, serviceId) + if err != nil { + PactLogger.Errorf(err, + "get participant failed, serviceId is %s: query provider failed.", serviceId) + return nil, nil, nil, err + } + if serviceParticipant == nil { + PactLogger.Errorf(nil, + "get participant failed, serviceId is %s: service not exist.", serviceId) + return nil, nil, nil, errors.New("get participant, serviceId not exist.") + } + // Get or create provider participant + participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, serviceParticipant.AppId, + serviceParticipant.ServiceName) + if errBroker != nil { + PactLogger.Errorf(errBroker, + "get participant failed, serviceId %s: query participant failed.", serviceId) + return nil, serviceParticipant, errBroker, err + } + if participant == nil { + PactLogger.Errorf(nil, + "get participant failed, particpant does not exist for serviceId %s", serviceId) + return nil, serviceParticipant, errors.New("particpant does not exist for serviceId."), err + } + + return participant, serviceParticipant, errBroker, nil +} + +//GetBrokerParticipantFromService returns the participant given the microservice +func GetBrokerParticipantFromService(ctx context.Context, + microservice *pb.MicroService) (*Participant, error) { + if microservice == nil { + return nil, nil + } + tenant := GetDefaultTenantProject() + participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, microservice.AppId, + microservice.ServiceName) + if errBroker != nil { + PactLogger.Errorf(errBroker, + "get participant failed, serviceId %s: query participant failed.", + microservice.ServiceId) + return nil, errBroker + } + return participant, errBroker +} + +func GetParticipant(ctx context.Context, domain string, appId string, + serviceName string) (*Participant, error) { + key := GenerateBrokerParticipantKey(domain, appId, serviceName) + participants, err := Store().Participant().Search(ctx, registry.WithStrKey(key)) + if err != nil { + return nil, err + } + if len(participants.Kvs) == 0 { + PactLogger.Info("GetParticipant found no participant") + return nil, nil + } + participant := &Participant{} + err = json.Unmarshal(participants.Kvs[0].Value, participant) + if err != nil { + return nil, err + } + PactLogger.Infof("GetParticipant: (%d, %s, %s)", participant.Id, participant.AppId, participant.ServiceName) + return participant, nil +} + +func GetVersion(ctx context.Context, domain string, number string, + participantId int32) (*Version, error) { + key := GenerateBrokerVersionKey(domain, number, participantId) + versions, err := Store().Version().Search(ctx, registry.WithStrKey(key)) + if err != nil { + return nil, err + } + if len(versions.Kvs) == 0 { + return nil, nil + } + version := &Version{} + err = json.Unmarshal(versions.Kvs[0].Value, version) + if err != nil { + return nil, err + } + PactLogger.Infof("GetVersion: (%d, %s, %d, %d)", version.Id, version.Number, version.ParticipantId, version.Order) + return version, nil +} + +func GetPact(ctx context.Context, domain string, consumerParticipantId int32, producerParticipantId int32, sha []byte) (*Pact, error) { + key := GenerateBrokerPactKey(domain, consumerParticipantId, producerParticipantId, sha) + versions, err := Store().Pact().Search(ctx, registry.WithStrKey(key)) + if err != nil { + return nil, err + } + if len(versions.Kvs) == 0 { + return nil, nil + } + pact := &Pact{} + err = json.Unmarshal(versions.Kvs[0].Value, pact) + if err != nil { + return nil, err + } + PactLogger.Infof("GetPact: (%d, %d, %d, %s, %s)", pact.Id, pact.ConsumerParticipantId, pact.ProviderParticipantId, string(pact.Sha), string(pact.Content)) + return pact, nil +} + +func GetPactVersion(ctx context.Context, domain string, versionId int32, + pactId int32) (*PactVersion, error) { + key := GenerateBrokerPactVersionKey(domain, versionId, pactId) + versions, err := Store().PactVersion().Search(ctx, registry.WithStrKey(key)) + if err != nil { + return nil, err + } + if len(versions.Kvs) == 0 { + return nil, nil + } + pactVersion := &PactVersion{} + err = json.Unmarshal(versions.Kvs[0].Value, pactVersion) + if err != nil { + return nil, err + } + PactLogger.Infof("GetPactVersion: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId) + return pactVersion, nil +} + +func GetData(ctx context.Context, key string) (int, error) { + values, err := Store().PactLatest().Search(ctx, registry.WithStrKey(key)) + if err != nil { + return -1, err + } + if len(values.Kvs) == 0 { + return -1, nil + } + id, err := strconv.Atoi(string(values.Kvs[0].Value)) + if err != nil { + return -1, err + } + return id, nil +} + +func StoreData(ctx context.Context, key string, value string) error { + _, err := backend.Registry().Do(ctx, registry.PUT, + registry.WithStrKey(key), + registry.WithValue([]byte(value))) + return err +} + +func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participantKey string, participant Participant) (*PublishPactResponse, error) { + data, err := json.Marshal(participant) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."), + }, err + } + + _, err = backend.Registry().Do(ctx, registry.PUT, + registry.WithStrKey(participantKey), + registry.WithValue(data)) + + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."), + }, err + } + + k := GetBrokerLatestParticipantIDKey() + v := strconv.Itoa(int(participant.Id)) + PactLogger.Infof("Inserting (%s, %s)", k, v) + err = StoreData(ctx, k, v) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."), + }, err + } + PactLogger.Infof("Participant created for key: %s", participantKey) + return nil, nil +} + +func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey string, + version Version) (*PublishPactResponse, error) { + data, err := json.Marshal(version) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."), + }, err + } + + _, err = backend.Registry().Do(ctx, registry.PUT, + registry.WithStrKey(versionKey), + registry.WithValue(data)) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."), + }, err + } + k := GetBrokerLatestVersionIDKey() + v := strconv.Itoa(int(version.Id)) + PactLogger.Infof("Inserting (%s, %s)", k, v) + err = StoreData(ctx, k, v) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."), + }, err + } + PactLogger.Infof("Version created for key: %s", versionKey) + return nil, nil +} + +func CreatePact(pactLogger lager.Logger, ctx context.Context, + pactKey string, pact Pact) (*PublishPactResponse, error) { + data, err := json.Marshal(pact) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."), + }, err + } + + _, err = backend.Registry().Do(ctx, + registry.PUT, + registry.WithStrKey(pactKey), + registry.WithValue(data)) + + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."), + }, err + } + k := GetBrokerLatestPactIDKey() + v := strconv.Itoa(int(pact.Id)) + PactLogger.Infof("Inserting (%s, %s)", k, v) + err = StoreData(ctx, k, v) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."), + }, err + } + PactLogger.Infof("Pact created for key: %s", pactKey) + return nil, nil +} + +func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersionKey string, pactVersion PactVersion) (*PublishPactResponse, error) { + data, err := json.Marshal(pactVersion) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."), + }, err + } + + _, err = backend.Registry().Do(ctx, + registry.PUT, registry.WithValue(data), registry.WithStrKey(pactVersionKey)) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."), + }, err + } + k := GetBrokerLatestPactVersionIDKey() + v := strconv.Itoa(int(pactVersion.Id)) + PactLogger.Infof("Inserting (%s, %s)", k, v) + err = StoreData(ctx, k, v) + if err != nil { + PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.") + return &PublishPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."), + }, err + } + PactLogger.Infof("Pact version created for key: %s", pactVersionKey) + return nil, nil +} + +func CreateVerification(pactLogger lager.Logger, ctx context.Context, + verificationKey string, verification Verification) (*PublishVerificationResponse, error) { + data, err := json.Marshal(verification) + if err != nil { + PactLogger.Errorf(nil, "verification result publish failed, verification result marshal error.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "verification result marshal error."), + }, err + } + + _, err = backend.Registry().Do(ctx, registry.PUT, + registry.WithStrKey(verificationKey), + registry.WithValue(data)) + if err != nil { + PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."), + }, err + } + k := GetBrokerLatestVerificationIDKey() + v := strconv.Itoa(int(verification.Id)) + PactLogger.Infof("Inserting (%s, %s)", k, v) + err = StoreData(ctx, k, v) + if err != nil { + PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.") + return &PublishVerificationResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."), + }, err + } + PactLogger.Infof("Verification result created for key: %s", verificationKey) + return nil, nil +} + +func GetLastestVersionNumberForParticipant(ctx context.Context, + tenant string, participantId int32) int32 { + key := util.StringJoin([]string{ + GetBrokerVersionKey(tenant), ""}, "/") + versions, err := Store().Version().Search(ctx, + registry.WithStrKey(key), + registry.WithPrefix()) + + if err != nil || len(versions.Kvs) == 0 { + return -1 + } + order := int32(math.MinInt32) + for i := 0; i < len(versions.Kvs); i++ { + version := &Version{} + err = json.Unmarshal(versions.Kvs[i].Value, &version) + if err != nil { + return -1 + } + if version.ParticipantId != participantId { + continue + } + if version.Order > order { + order = version.Order + } + } + return order +} + +func RetrieveProviderConsumerPact(ctx context.Context, + in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, int32, error) { + if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 { + PactLogger.Errorf(nil, "pact retrieve request failed: invalid params.") + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Request format invalid."), + }, -1, nil + } + tenant := GetDefaultTenantProject() + // Get provider microservice + provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId) + if err != nil { + PactLogger.Errorf(err, "pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Query provider failed."), + }, -1, err + } + if provider == nil { + PactLogger.Errorf(nil, "pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Provider does not exist."), + }, -1, nil + } + // Get consumer microservice + consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId) + if err != nil { + PactLogger.Errorf(err, "pact retrieve failed, consumerId is %s: query consumer failed.", in.ConsumerId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Query consumer failed."), + }, -1, err + } + if consumer == nil { + PactLogger.Errorf(nil, "pact retrieve failed, consumerId is %s: consumer not exist.", in.ConsumerId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Consumer does not exist."), + }, -1, nil + } + // Get provider participant + //providerParticipantKey := apt.GenerateBrokerParticipantKey(tenant, provider.AppId, provider.ServiceName) + providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName) + if err != nil || providerParticipant == nil { + PactLogger.Errorf(nil, "pact retrieve failed, provider participant %s cannot be searched.", in.ProviderId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "Provider participant cannot be searched."), + }, -1, err + } + // Get consumer participant + //consumerParticipantKey := apt.GenerateBrokerParticipantKey(tenant, consumer.AppId, consumer.ServiceName) + consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName) + if err != nil || consumerParticipant == nil { + PactLogger.Errorf(nil, "pact retrieve failed, consumer participant %s cannot be searched.", in.ConsumerId) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "consumer participant cannot be searched."), + }, -1, err + } + // Get or create version + //versionKey := apt.GenerateBrokerVersionKey(tenant, in.Version, consumerParticipant.Id) + version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id) + if err != nil || version == nil { + PactLogger.Errorf(nil, "pact retrieve failed, version cannot be searched.") + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be searched."), + }, -1, err + } + // Get all pactversions and filter using the provider participant id + pactVersionKey := util.StringJoin([]string{ + GetBrokerPactVersionKey(tenant), + strconv.Itoa(int(version.Id))}, + "/") + pactVersions, err := Store().PactVersion().Search(ctx, + registry.WithPrefix(), + registry.WithStrKey(pactVersionKey)) + + if err != nil { + return nil, -1, err + } + if len(pactVersions.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPact] No pact version found, sorry") + return nil, -1, nil + } + pactIds := make(map[int32]int32) + for i := 0; i < len(pactVersions.Kvs); i++ { + pactVersion := &PactVersion{} + err = json.Unmarshal(pactVersions.Kvs[i].Value, pactVersion) + if err != nil { + return nil, -1, err + } + // Obviously true, but checking it anyways + if pactVersion.VersionId == version.Id { + pactid := pactVersion.PactId + pactIds[pactid] = pactid + } + } + if len(pactIds) == 0 { + PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.") + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."), + }, -1, err + } + pactKey := util.StringJoin([]string{ + GetBrokerPactKey(tenant), + strconv.Itoa(int(consumerParticipant.Id)), + strconv.Itoa(int(providerParticipant.Id))}, + "/") + pacts, err := Store().PactVersion().Search(ctx, + registry.WithStrKey(pactKey), + registry.WithPrefix()) + + if err != nil { + return nil, -1, err + } + if len(pacts.Kvs) == 0 { + PactLogger.Info("[RetrieveProviderPact] No pact version found, sorry") + return nil, -1, nil + } + for i := 0; i < len(pacts.Kvs); i++ { + pactObj := &Pact{} + err = json.Unmarshal(pacts.Kvs[i].Value, pactObj) + if err != nil { + return nil, -1, err + } + if _, ok := pactIds[pactObj.Id]; ok { + //PactLogger.Infof("pact retrieve succeeded, found pact: %s", string(pactObj.Content)) + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(pb.Response_SUCCESS, "pact found."), + Pact: pactObj.Content, + }, pactObj.Id, nil + } + } + PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.") + return &GetProviderConsumerVersionPactResponse{ + Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."), + }, -1, nil +} + +func DeletePactData(ctx context.Context, + in *BaseBrokerRequest) (*pb.Response, error) { + //tenant := util.ParseTenantProject(ctx) + allPactKey := GetBrokerRootKey() //GetBrokerVerificationKey("default") //util.StringJoin([]string{ apt.GetRootKey(), apt.REGISTRY_PACT_ROOT_KEY }, "/") + + _, err := backend.Registry().Do(ctx, + registry.DEL, registry.WithStrKey(allPactKey), registry.WithPrefix()) + if err != nil { + return pb.CreateResponse(scerr.ErrInternal, "error deleting pacts."), err + } + return pb.CreateResponse(pb.Response_SUCCESS, "deleting pacts Succeed."), nil +} diff --git a/server/rest/controller/rest_util.go b/server/rest/controller/rest_util.go index 749900bf..be626d5b 100644 --- a/server/rest/controller/rest_util.go +++ b/server/rest/controller/rest_util.go @@ -57,3 +57,15 @@ func WriteResponse(w http.ResponseWriter, resp *pb.Response, obj interface{}) { WriteError(w, resp.GetCode(), resp.GetMessage()) } + +func WriteBytes(w http.ResponseWriter, resp *pb.Response, json []byte) { + if resp.GetCode() == pb.Response_SUCCESS { + w.Header().Add("X-Response-Status", fmt.Sprint(http.StatusOK)) + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + w.Write(json) + return + } + WriteError(w, resp.GetCode(), resp.GetMessage()) +} + ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services