Add message queue service factory (#1537)

This commit is contained in:
Ta-Ching Chen
2020-02-20 23:30:39 +08:00
committed by GitHub
parent e0dc7f2f81
commit cc14044b6b
12 changed files with 218 additions and 122 deletions
+10 -23
View File
@@ -29,10 +29,11 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd" "github.com/fission/fission/pkg/crd"
"github.com/fission/fission/pkg/mqtrigger" "github.com/fission/fission/pkg/mqtrigger"
"github.com/fission/fission/pkg/mqtrigger/factory"
"github.com/fission/fission/pkg/mqtrigger/messageQueue" "github.com/fission/fission/pkg/mqtrigger/messageQueue"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/azurequeuestorage" _ "github.com/fission/fission/pkg/mqtrigger/messageQueue/azurequeuestorage"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/kafka" _ "github.com/fission/fission/pkg/mqtrigger/messageQueue/kafka"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/nats" _ "github.com/fission/fission/pkg/mqtrigger/messageQueue/nats"
) )
func Start(logger *zap.Logger, routerUrl string) error { func Start(logger *zap.Logger, routerUrl string) error {
@@ -47,8 +48,7 @@ func Start(logger *zap.Logger, routerUrl string) error {
return errors.Wrap(err, "error waiting for CRDs") return errors.Wrap(err, "error waiting for CRDs")
} }
// Message queue type: nats is the only supported one for now mqType := (fv1.MessageQueueType)(os.Getenv("MESSAGE_QUEUE_TYPE"))
mqType := os.Getenv("MESSAGE_QUEUE_TYPE")
mqUrl := os.Getenv("MESSAGE_QUEUE_URL") mqUrl := os.Getenv("MESSAGE_QUEUE_URL")
secretsPath := strings.TrimSpace(os.Getenv("MESSAGE_QUEUE_SECRETS")) secretsPath := strings.TrimSpace(os.Getenv("MESSAGE_QUEUE_SECRETS"))
@@ -62,38 +62,25 @@ func Start(logger *zap.Logger, routerUrl string) error {
} }
} }
mq, err := newMessageQueue( mq, err := factory.Create(
logger, logger,
routerUrl, mqType,
messageQueue.Config{ messageQueue.Config{
MQType: mqType, MQType: (string)(mqType),
Url: mqUrl, Url: mqUrl,
Secrets: secrets, Secrets: secrets,
}, },
routerUrl,
) )
if err != nil { if err != nil {
logger.Fatal("failed to connect to remote message queue server", zap.Error(err)) logger.Fatal("failed to connect to remote message queue server", zap.Error(err))
} }
mqtrigger.MakeMessageQueueTriggerManager(logger, fissionClient, mq).Run() mqtrigger.MakeMessageQueueTriggerManager(logger, fissionClient, mqType, mq).Run()
return nil return nil
} }
func newMessageQueue(logger *zap.Logger, routerURL string, mqCfg messageQueue.Config) (messageQueue messageQueue.MessageQueue, err error) {
switch mqCfg.MQType {
case fv1.MessageQueueTypeNats:
messageQueue, err = nats.New(logger, routerURL, mqCfg)
case fv1.MessageQueueTypeASQ:
messageQueue, err = azurequeuestorage.New(logger, routerURL, mqCfg)
case fv1.MessageQueueTypeKafka:
messageQueue, err = kafka.New(logger, routerURL, mqCfg)
default:
err = errors.Errorf("no supported message queue type found for %q", mqCfg.MQType)
}
return messageQueue, err
}
func readSecrets(logger *zap.Logger, secretsPath string) (map[string][]byte, error) { func readSecrets(logger *zap.Logger, secretsPath string) (map[string][]byte, error) {
// return if no secrets exist // return if no secrets exist
if _, err := os.Stat(secretsPath); os.IsNotExist(err) { if _, err := os.Stat(secretsPath); os.IsNotExist(err) {
+3
View File
@@ -24,6 +24,9 @@ import (
"github.com/fission/fission/pkg/fission-cli/flag" "github.com/fission/fission/pkg/fission-cli/flag"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
_ "github.com/fission/fission/pkg/mqtrigger/messageQueue/azurequeuestorage"
_ "github.com/fission/fission/pkg/mqtrigger/messageQueue/kafka"
_ "github.com/fission/fission/pkg/mqtrigger/messageQueue/nats"
) )
const ( const (
+10 -46
View File
@@ -23,10 +23,11 @@ import (
"strings" "strings"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
nsUtil "github.com/nats-io/nats-streaming-server/util"
"github.com/robfig/cron" "github.com/robfig/cron"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"github.com/fission/fission/pkg/mqtrigger/validator"
) )
const ( const (
@@ -37,12 +38,6 @@ const (
totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
) )
var (
validAzureQueueName = regexp.MustCompile(`^[a-z0-9][a-z0-9\\-]*[a-z0-9]$`)
// Need to use raw string to support escape sequence for - & . chars
validKafkaTopicName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-\._]*[a-zA-Z0-9]$`)
)
type ( type (
ValidationErrorType int ValidationErrorType int
@@ -163,35 +158,6 @@ func ValidateKubeReference(refName string, name string, namespace string) error
return result.ErrorOrNil() return result.ErrorOrNil()
} }
func IsTopicValid(mqType MessageQueueType, topic string) bool {
switch mqType {
case MessageQueueTypeNats:
return nsUtil.IsChannelNameValid(topic, false)
case MessageQueueTypeASQ:
return len(topic) >= 3 && len(topic) <= 63 && validAzureQueueName.MatchString(topic)
case MessageQueueTypeKafka:
return IsValidKafkaTopic(topic)
}
return false
}
// The validation is based on Kafka's internal implementation: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/internals/Topic.java
func IsValidKafkaTopic(topic string) bool {
if len(topic) == 0 {
return false
}
if topic == "." || topic == ".." {
return false
}
if len(topic) > 249 {
return false
}
if !validKafkaTopicName.MatchString(topic) {
return false
}
return true
}
func IsValidCronSpec(spec string) error { func IsValidCronSpec(spec string) error {
_, err := cron.Parse(spec) _, err := cron.Parse(spec)
return err return err
@@ -528,18 +494,16 @@ func (spec MessageQueueTriggerSpec) Validate() error {
result = multierror.Append(result, spec.FunctionReference.Validate()) result = multierror.Append(result, spec.FunctionReference.Validate())
switch spec.MessageQueueType { if !validator.IsValidMessageQueue((string)(spec.MessageQueueType)) {
case MessageQueueTypeNats, MessageQueueTypeASQ, MessageQueueTypeKafka: // no op
default:
result = multierror.Append(result, MakeValidationErr(ErrorUnsupportedType, "MessageQueueTriggerSpec.MessageQueueType", spec.MessageQueueType, "not a supported message queue type")) result = multierror.Append(result, MakeValidationErr(ErrorUnsupportedType, "MessageQueueTriggerSpec.MessageQueueType", spec.MessageQueueType, "not a supported message queue type"))
} } else {
if !validator.IsValidTopic((string)(spec.MessageQueueType), spec.Topic) {
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "MessageQueueTriggerSpec.Topic", spec.Topic, "not a valid topic"))
}
if !IsTopicValid(spec.MessageQueueType, spec.Topic) { if len(spec.ResponseTopic) > 0 && !validator.IsValidTopic((string)(spec.MessageQueueType), spec.ResponseTopic) {
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "MessageQueueTriggerSpec.Topic", spec.Topic, "not a valid topic")) result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "MessageQueueTriggerSpec.ResponseTopic", spec.ResponseTopic, "not a valid topic"))
} }
if len(spec.ResponseTopic) > 0 && !IsTopicValid(spec.MessageQueueType, spec.ResponseTopic) {
result = multierror.Append(result, MakeValidationErr(ErrorInvalidValue, "MessageQueueTriggerSpec.ResponseTopic", spec.ResponseTopic, "not a valid topic"))
} }
return result.ErrorOrNil() return result.ErrorOrNil()
+5 -13
View File
@@ -30,6 +30,7 @@ import (
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
"github.com/fission/fission/pkg/mqtrigger/validator"
) )
type CreateSubCommand struct { type CreateSubCommand struct {
@@ -58,18 +59,9 @@ func (opts *CreateSubCommand) complete(input cli.Input) error {
fnName := input.String(flagkey.MqtFnName) fnName := input.String(flagkey.MqtFnName)
fnNamespace := input.String(flagkey.NamespaceFunction) fnNamespace := input.String(flagkey.NamespaceFunction)
var mqType fv1.MessageQueueType mqType := (fv1.MessageQueueType)(input.String(flagkey.MqtMQType))
switch input.String(flagkey.MqtMQType) { if !validator.IsValidMessageQueue((string)(mqType)) {
case "": return errors.New("Unsupported message queue type")
mqType = fv1.MessageQueueTypeNats
case fv1.MessageQueueTypeNats:
mqType = fv1.MessageQueueTypeNats
case fv1.MessageQueueTypeASQ:
mqType = fv1.MessageQueueTypeASQ
case fv1.MessageQueueTypeKafka:
mqType = fv1.MessageQueueTypeKafka
default:
return errors.New("Unknown message queue type, currently only \"nats-streaming, azure-storage-queue, kafka \" is supported")
} }
topic := input.String(flagkey.MqtTopic) topic := input.String(flagkey.MqtTopic)
@@ -172,7 +164,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
func checkMQTopicAvailability(mqType fv1.MessageQueueType, topics ...string) error { func checkMQTopicAvailability(mqType fv1.MessageQueueType, topics ...string) error {
for _, t := range topics { for _, t := range topics {
if len(t) > 0 && !fv1.IsTopicValid(mqType, t) { if len(t) > 0 && !validator.IsValidTopic((string)(mqType), t) {
return errors.Errorf("invalid topic for %s: %s", mqType, t) return errors.Errorf("invalid topic for %s: %s", mqType, t)
} }
} }
+1 -1
View File
@@ -127,7 +127,7 @@ var (
MqtName = Flag{Type: String, Name: flagkey.MqtName, Usage: "Message queue trigger name"} MqtName = Flag{Type: String, Name: flagkey.MqtName, Usage: "Message queue trigger name"}
MqtFnName = Flag{Type: String, Name: flagkey.MqtFnName, Usage: "Function name"} MqtFnName = Flag{Type: String, Name: flagkey.MqtFnName, Usage: "Function name"}
MqtMQType = Flag{Type: String, Name: flagkey.MqtMQType, Usage: "Message queue type, e.g. nats-streaming, azure-storage-queue", DefaultValue: "nats-streaming"} MqtMQType = Flag{Type: String, Name: flagkey.MqtMQType, Usage: "Message queue type, e.g. nats-streaming, azure-storage-queue, kafka", DefaultValue: "nats-streaming"}
MqtTopic = Flag{Type: String, Name: flagkey.MqtTopic, Usage: "Message queue Topic the trigger listens on"} MqtTopic = Flag{Type: String, Name: flagkey.MqtTopic, Usage: "Message queue Topic the trigger listens on"}
MqtRespTopic = Flag{Type: String, Name: flagkey.MqtRespTopic, Usage: "Topic that the function response is sent on (response discarded if unspecified)"} MqtRespTopic = Flag{Type: String, Name: flagkey.MqtRespTopic, Usage: "Topic that the function response is sent on (response discarded if unspecified)"}
MqtErrorTopic = Flag{Type: String, Name: flagkey.MqtErrorTopic, Usage: "Topic that the function error messages are sent to (errors discarded if unspecified"} MqtErrorTopic = Flag{Type: String, Name: flagkey.MqtErrorTopic, Usage: "Topic that the function error messages are sent to (errors discarded if unspecified"}
+62
View File
@@ -0,0 +1,62 @@
/*
Copyright 2020 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
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 factory
import (
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/mqtrigger/messageQueue"
)
var (
messageQueueFactories = make(map[fv1.MessageQueueType]MessageQueueFactory)
lock = sync.Mutex{}
)
type (
MessageQueueFactory interface {
Create(logger *zap.Logger, config messageQueue.Config, routerURL string) (messageQueue.MessageQueue, error)
}
)
func Register(mqType fv1.MessageQueueType, factory MessageQueueFactory) {
lock.Lock()
defer lock.Unlock()
if factory == nil {
panic("Nil message queue factory")
}
_, registered := messageQueueFactories[mqType]
if registered {
panic("Message queue factory already register")
}
messageQueueFactories[mqType] = factory
}
func Create(logger *zap.Logger, mqType fv1.MessageQueueType, mqConfig messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
factory, registered := messageQueueFactories[mqType]
if !registered {
return nil, errors.Errorf("no supported message queue type found for %q", mqType)
}
return factory.Create(logger, mqConfig, routerUrl)
}
@@ -30,14 +30,21 @@ import (
"time" "time"
"github.com/Azure/azure-sdk-for-go/storage" "github.com/Azure/azure-sdk-for-go/storage"
"github.com/fission/fission/pkg/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.uber.org/zap" "go.uber.org/zap"
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/mqtrigger/factory"
"github.com/fission/fission/pkg/mqtrigger/messageQueue" "github.com/fission/fission/pkg/mqtrigger/messageQueue"
"github.com/fission/fission/pkg/mqtrigger/validator"
"github.com/fission/fission/pkg/utils"
) )
func init() {
factory.Register(fv1.MessageQueueTypeASQ, &Factory{})
validator.Register(fv1.MessageQueueTypeASQ, IsTopicValid)
}
// TODO: some of these constants should probably be environment variables // TODO: some of these constants should probably be environment variables
const ( const (
// AzureQueuePollingInterval is the polling interval (default is 1 minute). // AzureQueuePollingInterval is the polling interval (default is 1 minute).
@@ -105,6 +112,12 @@ type AzureHTTPClient interface {
Do(req *http.Request) (*http.Response, error) Do(req *http.Request) (*http.Response, error)
} }
type Factory struct{}
func (factory *Factory) Create(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
return New(logger, mqCfg, routerUrl)
}
type azureQueueService struct { type azureQueueService struct {
service storage.QueueServiceClient service storage.QueueServiceClient
} }
@@ -179,7 +192,7 @@ func newAzureQueueService(client storage.Client) AzureQueueService {
} }
} }
func New(logger *zap.Logger, routerURL string, config messageQueue.Config) (messageQueue.MessageQueue, error) { func New(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
account := os.Getenv("AZURE_STORAGE_ACCOUNT_NAME") account := os.Getenv("AZURE_STORAGE_ACCOUNT_NAME")
if len(account) == 0 { if len(account) == 0 {
return nil, errors.New("Required environment variable 'AZURE_STORAGE_ACCOUNT_NAME' is not set") return nil, errors.New("Required environment variable 'AZURE_STORAGE_ACCOUNT_NAME' is not set")
@@ -198,7 +211,7 @@ func New(logger *zap.Logger, routerURL string, config messageQueue.Config) (mess
} }
return &AzureStorageConnection{ return &AzureStorageConnection{
logger: logger.Named("azue_storage"), logger: logger.Named("azue_storage"),
routerURL: routerURL, routerURL: routerUrl,
service: newAzureQueueService(client), service: newAzureQueueService(client),
httpClient: &http.Client{ httpClient: &http.Client{
Timeout: AzureFunctionInvocationTimeout, Timeout: AzureFunctionInvocationTimeout,
@@ -113,10 +113,10 @@ func TestNewStorageConnectionMissingAccountName(t *testing.T) {
logger, err := zap.NewDevelopment() logger, err := zap.NewDevelopment()
panicIf(err) panicIf(err)
connection, err := New(logger, DummyRouterURL, messageQueue.Config{ connection, err := New(logger, messageQueue.Config{
MQType: fv1.MessageQueueTypeASQ, MQType: fv1.MessageQueueTypeASQ,
Url: "", Url: "",
}) }, DummyRouterURL)
require.Nil(t, connection) require.Nil(t, connection)
require.Error(t, err, "Required environment variable 'AZURE_STORAGE_ACCOUNT_NAME' is not set") require.Error(t, err, "Required environment variable 'AZURE_STORAGE_ACCOUNT_NAME' is not set")
} }
@@ -126,10 +126,10 @@ func TestNewStorageConnectionMissingAccessKey(t *testing.T) {
panicIf(err) panicIf(err)
_ = os.Setenv("AZURE_STORAGE_ACCOUNT_NAME", "accountname") _ = os.Setenv("AZURE_STORAGE_ACCOUNT_NAME", "accountname")
connection, err := New(logger, DummyRouterURL, messageQueue.Config{ connection, err := New(logger, messageQueue.Config{
MQType: fv1.MessageQueueTypeASQ, MQType: fv1.MessageQueueTypeASQ,
Url: "", Url: "",
}) }, DummyRouterURL)
_ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_NAME") _ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_NAME")
require.Nil(t, connection) require.Nil(t, connection)
require.Error(t, err, "Required environment variable 'AZURE_STORAGE_ACCOUNT_KEY' is not set") require.Error(t, err, "Required environment variable 'AZURE_STORAGE_ACCOUNT_KEY' is not set")
@@ -141,10 +141,10 @@ func TestNewStorageConnection(t *testing.T) {
_ = os.Setenv("AZURE_STORAGE_ACCOUNT_NAME", "accountname") _ = os.Setenv("AZURE_STORAGE_ACCOUNT_NAME", "accountname")
_ = os.Setenv("AZURE_STORAGE_ACCOUNT_KEY", "bm90IGEga2V5") _ = os.Setenv("AZURE_STORAGE_ACCOUNT_KEY", "bm90IGEga2V5")
connection, err := New(logger, DummyRouterURL, messageQueue.Config{ connection, err := New(logger, messageQueue.Config{
MQType: "azure-storage-queue", MQType: "azure-storage-queue",
Url: "", Url: "",
}) }, DummyRouterURL)
_ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_NAME") _ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_NAME")
_ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_KEY") _ = os.Unsetenv("AZURE_STORAGE_ACCOUNT_KEY")
require.NoError(t, err) require.NoError(t, err)
+16 -2
View File
@@ -33,10 +33,17 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/mqtrigger/factory"
"github.com/fission/fission/pkg/mqtrigger/messageQueue" "github.com/fission/fission/pkg/mqtrigger/messageQueue"
"github.com/fission/fission/pkg/mqtrigger/validator"
"github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils"
) )
func init() {
factory.Register(fv1.MessageQueueTypeKafka, &Factory{})
validator.Register(fv1.MessageQueueTypeKafka, IsTopicValid)
}
var ( var (
// Need to use raw string to support escape sequence for - & . chars // Need to use raw string to support escape sequence for - & . chars
validKafkaTopicName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-\._]*[a-zA-Z0-9]$`) validKafkaTopicName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-\._]*[a-zA-Z0-9]$`)
@@ -51,9 +58,15 @@ type (
authKeys map[string][]byte authKeys map[string][]byte
tls bool tls bool
} }
Factory struct{}
) )
func New(logger *zap.Logger, routerUrl string, mqCfg messageQueue.Config) (messageQueue.MessageQueue, error) { func (factory *Factory) Create(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
return New(logger, mqCfg, routerUrl)
}
func New(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
if len(routerUrl) == 0 || len(mqCfg.Url) == 0 { if len(routerUrl) == 0 || len(mqCfg.Url) == 0 {
return nil, errors.New("the router URL or MQ URL is empty") return nil, errors.New("the router URL or MQ URL is empty")
} }
@@ -340,7 +353,8 @@ func errorHandler(logger *zap.Logger, trigger *fv1.MessageQueueTrigger, producer
} }
} }
// The validation is based on Kafka's internal implementation: https://github.com/apache/kafka/blob/cde6d18983b5d58199f8857d8d61d7efcbe6e54a/clients/src/main/java/org/apache/kafka/common/internals/Topic.java#L36-L47 // The validation is based on Kafka's internal implementation:
// https://github.com/apache/kafka/blob/cde6d18983b5d58199f8857d8d61d7efcbe6e54a/clients/src/main/java/org/apache/kafka/common/internals/Topic.java#L36-L47
func IsTopicValid(topic string) bool { func IsTopicValid(topic string) bool {
if len(topic) == 0 { if len(topic) == 0 {
return false return false
+14 -1
View File
@@ -28,10 +28,17 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/mqtrigger/factory"
"github.com/fission/fission/pkg/mqtrigger/messageQueue" "github.com/fission/fission/pkg/mqtrigger/messageQueue"
"github.com/fission/fission/pkg/mqtrigger/validator"
"github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils"
) )
func init() {
factory.Register(fv1.MessageQueueTypeNats, &Factory{})
validator.Register(fv1.MessageQueueTypeNats, IsTopicValid)
}
const ( const (
natsClusterID = "fissionMQTrigger" natsClusterID = "fissionMQTrigger"
natsProtocol = "nats://" natsProtocol = "nats://"
@@ -45,9 +52,15 @@ type (
nsConn ns.Conn nsConn ns.Conn
routerUrl string routerUrl string
} }
Factory struct{}
) )
func New(logger *zap.Logger, routerUrl string, mqCfg messageQueue.Config) (messageQueue.MessageQueue, error) { func (factory *Factory) Create(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
return New(logger, mqCfg, routerUrl)
}
func New(logger *zap.Logger, mqCfg messageQueue.Config, routerUrl string) (messageQueue.MessageQueue, error) {
conn, err := ns.Connect(natsClusterID, natsClientID, ns.NatsURL(mqCfg.Url), conn, err := ns.Connect(natsClusterID, natsClientID, ns.NatsURL(mqCfg.Url),
ns.SetConnectionLostHandler(func(conn ns.Conn, reason error) { ns.SetConnectionLostHandler(func(conn ns.Conn, reason error) {
// TODO: Better way to handle connection lost problem. // TODO: Better way to handle connection lost problem.
+16 -27
View File
@@ -26,9 +26,6 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd" "github.com/fission/fission/pkg/crd"
"github.com/fission/fission/pkg/mqtrigger/messageQueue" "github.com/fission/fission/pkg/mqtrigger/messageQueue"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/azurequeuestorage"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/kafka"
"github.com/fission/fission/pkg/mqtrigger/messageQueue/nats"
"github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils"
) )
@@ -42,11 +39,12 @@ type (
requestType int requestType int
MessageQueueTriggerManager struct { MessageQueueTriggerManager struct {
logger *zap.Logger logger *zap.Logger
reqChan chan request reqChan chan request
triggers map[string]*triggerSubscription triggers map[string]*triggerSubscription
fissionClient *crd.FissionClient fissionClient *crd.FissionClient
messageQueue messageQueue.MessageQueue messageQueueType fv1.MessageQueueType
messageQueue messageQueue.MessageQueue
} }
triggerSubscription struct { triggerSubscription struct {
@@ -66,13 +64,14 @@ type (
) )
func MakeMessageQueueTriggerManager(logger *zap.Logger, func MakeMessageQueueTriggerManager(logger *zap.Logger,
fissionClient *crd.FissionClient, messageQueue messageQueue.MessageQueue) *MessageQueueTriggerManager { fissionClient *crd.FissionClient, mqType fv1.MessageQueueType, messageQueue messageQueue.MessageQueue) *MessageQueueTriggerManager {
mqTriggerMgr := MessageQueueTriggerManager{ mqTriggerMgr := MessageQueueTriggerManager{
logger: logger.Named("message_queue_trigger_manager"), logger: logger.Named("message_queue_trigger_manager"),
reqChan: make(chan request), reqChan: make(chan request),
triggers: make(map[string]*triggerSubscription), triggers: make(map[string]*triggerSubscription),
fissionClient: fissionClient, fissionClient: fissionClient,
messageQueue: messageQueue, messageQueueType: mqType,
messageQueue: messageQueue,
} }
return &mqTriggerMgr return &mqTriggerMgr
} }
@@ -154,7 +153,9 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
newTriggerMap := make(map[string]*fv1.MessageQueueTrigger) newTriggerMap := make(map[string]*fv1.MessageQueueTrigger)
for index := range newTriggers.Items { for index := range newTriggers.Items {
newTrigger := &newTriggers.Items[index] newTrigger := &newTriggers.Items[index]
newTriggerMap[crd.CacheKey(&newTrigger.ObjectMeta)] = newTrigger if newTrigger.Spec.MessageQueueType == mqt.messageQueueType {
newTriggerMap[crd.CacheKey(&newTrigger.ObjectMeta)] = newTrigger
}
} }
// get current set of triggers // get current set of triggers
@@ -205,15 +206,3 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
} }
} }
func IsTopicValid(mqType fv1.MessageQueueType, topic string) bool {
switch mqType {
case fv1.MessageQueueTypeNats:
return nats.IsTopicValid(topic)
case fv1.MessageQueueTypeASQ:
return azurequeuestorage.IsTopicValid(topic)
case fv1.MessageQueueTypeKafka:
return kafka.IsTopicValid(topic)
}
return false
}
+59
View File
@@ -0,0 +1,59 @@
/*
Copyright 2020 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
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 validator
import (
"sync"
)
var (
topicValidators = make(map[string]TopicValidator)
lock = sync.Mutex{}
)
type (
TopicValidator func(topic string) bool
)
func Register(mqType string, validator TopicValidator) {
lock.Lock()
defer lock.Unlock()
if validator == nil {
panic("Nil message queue topic validator")
}
_, registered := topicValidators[mqType]
if registered {
panic("Message queue topic validator already register")
}
topicValidators[mqType] = validator
}
func IsValidTopic(mqType string, topic string) bool {
validator, registered := topicValidators[mqType]
if !registered {
return false
}
return validator(topic)
}
func IsValidMessageQueue(mqType string) bool {
_, registered := topicValidators[mqType]
return registered
}