Reorganize message queue trigger directory structure (#1531)
This commit is contained in:
@@ -28,13 +28,13 @@ import (
|
|||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/fission/fission/cmd/fission-bundle/mqtrigger"
|
||||||
"github.com/fission/fission/pkg/buildermgr"
|
"github.com/fission/fission/pkg/buildermgr"
|
||||||
"github.com/fission/fission/pkg/controller"
|
"github.com/fission/fission/pkg/controller"
|
||||||
"github.com/fission/fission/pkg/executor"
|
"github.com/fission/fission/pkg/executor"
|
||||||
"github.com/fission/fission/pkg/info"
|
"github.com/fission/fission/pkg/info"
|
||||||
"github.com/fission/fission/pkg/kubewatcher"
|
"github.com/fission/fission/pkg/kubewatcher"
|
||||||
functionLogger "github.com/fission/fission/pkg/logger"
|
functionLogger "github.com/fission/fission/pkg/logger"
|
||||||
messagequeue "github.com/fission/fission/pkg/mqtrigger"
|
|
||||||
"github.com/fission/fission/pkg/router"
|
"github.com/fission/fission/pkg/router"
|
||||||
"github.com/fission/fission/pkg/storagesvc"
|
"github.com/fission/fission/pkg/storagesvc"
|
||||||
"github.com/fission/fission/pkg/timer"
|
"github.com/fission/fission/pkg/timer"
|
||||||
@@ -72,7 +72,7 @@ func runTimer(logger *zap.Logger, routerUrl string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runMessageQueueMgr(logger *zap.Logger, routerUrl string) {
|
func runMessageQueueMgr(logger *zap.Logger, routerUrl string) {
|
||||||
err := messagequeue.Start(logger, routerUrl)
|
err := mqtrigger.Start(logger, routerUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("error starting message queue manager", zap.Error(err))
|
logger.Fatal("error starting message queue manager", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,13 @@ import (
|
|||||||
"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"
|
||||||
"github.com/fission/fission/pkg/crd"
|
"github.com/fission/fission/pkg/crd"
|
||||||
|
"github.com/fission/fission/pkg/mqtrigger"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Start(logger *zap.Logger, routerUrl string) error {
|
func Start(logger *zap.Logger, routerUrl string) error {
|
||||||
@@ -57,17 +62,39 @@ func Start(logger *zap.Logger, routerUrl string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mqCfg := messageQueue.MessageQueueConfig{
|
mq, err := newMessageQueue(
|
||||||
MQType: mqType,
|
logger,
|
||||||
Url: mqUrl,
|
routerUrl,
|
||||||
Secrets: secrets,
|
messageQueue.Config{
|
||||||
|
MQType: mqType,
|
||||||
|
Url: mqUrl,
|
||||||
|
Secrets: secrets,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("failed to connect to remote message queue server", zap.Error(err))
|
||||||
}
|
}
|
||||||
messageQueue.MakeMessageQueueTriggerManager(logger, fissionClient, routerUrl, mqCfg)
|
|
||||||
|
mqtrigger.MakeMessageQueueTriggerManager(logger, fissionClient, mq).Run()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSecrets(logger *zap.Logger, secretsPath string) (map[string][]byte, error) {
|
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) {
|
||||||
// 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) {
|
||||||
return nil, err
|
return nil, err
|
||||||
+14
-4
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package messageQueue
|
package azurequeuestorage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -34,6 +35,7 @@ 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/messageQueue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: some of these constants should probably be environment variables
|
// TODO: some of these constants should probably be environment variables
|
||||||
@@ -52,6 +54,10 @@ const (
|
|||||||
AzureFunctionInvocationTimeout = 10 * time.Minute
|
AzureFunctionInvocationTimeout = 10 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
validAzureQueueName = regexp.MustCompile(`^[a-z0-9][a-z0-9\\-]*[a-z0-9]$`)
|
||||||
|
)
|
||||||
|
|
||||||
// AzureStorageConnection represents an Azure storage connection.
|
// AzureStorageConnection represents an Azure storage connection.
|
||||||
type AzureStorageConnection struct {
|
type AzureStorageConnection struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
@@ -173,7 +179,7 @@ func newAzureQueueService(client storage.Client) AzureQueueService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAzureStorageConnection(logger *zap.Logger, routerURL string, config MessageQueueConfig) (MessageQueue, error) {
|
func New(logger *zap.Logger, routerURL string, config messageQueue.Config) (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")
|
||||||
@@ -200,7 +206,7 @@ func newAzureStorageConnection(logger *zap.Logger, routerURL string, config Mess
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (asc AzureStorageConnection) subscribe(trigger *fv1.MessageQueueTrigger) (messageQueueSubscription, error) {
|
func (asc AzureStorageConnection) Subscribe(trigger *fv1.MessageQueueTrigger) (messageQueue.Subscription, error) {
|
||||||
asc.logger.Info("subscribing to Azure storage queue", zap.String("queue", trigger.Spec.Topic))
|
asc.logger.Info("subscribing to Azure storage queue", zap.String("queue", trigger.Spec.Topic))
|
||||||
|
|
||||||
if trigger.Spec.FunctionReference.Type != fv1.FunctionReferenceTypeFunctionName {
|
if trigger.Spec.FunctionReference.Type != fv1.FunctionReferenceTypeFunctionName {
|
||||||
@@ -224,7 +230,7 @@ func (asc AzureStorageConnection) subscribe(trigger *fv1.MessageQueueTrigger) (m
|
|||||||
return subscription, nil
|
return subscription, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (asc AzureStorageConnection) unsubscribe(subscription messageQueueSubscription) error {
|
func (asc AzureStorageConnection) Unsubscribe(subscription messageQueue.Subscription) error {
|
||||||
sub := subscription.(*AzureQueueSubscription)
|
sub := subscription.(*AzureQueueSubscription)
|
||||||
|
|
||||||
asc.logger.Info("unsubscribing from Azure storage queue", zap.String("queue", sub.queueName))
|
asc.logger.Info("unsubscribing from Azure storage queue", zap.String("queue", sub.queueName))
|
||||||
@@ -394,3 +400,7 @@ func invokeTriggeredFunction(conn AzureStorageConnection, sub *AzureQueueSubscri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsTopicValid(topic string) bool {
|
||||||
|
return len(topic) >= 3 && len(topic) <= 63 && validAzureQueueName.MatchString(topic)
|
||||||
|
}
|
||||||
+9
-8
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package messageQueue
|
package azurequeuestorage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -32,6 +32,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
fv1 "github.com/fission/fission/pkg/apis/core/v1"
|
fv1 "github.com/fission/fission/pkg/apis/core/v1"
|
||||||
|
"github.com/fission/fission/pkg/mqtrigger/messageQueue"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -112,7 +113,7 @@ func TestNewStorageConnectionMissingAccountName(t *testing.T) {
|
|||||||
logger, err := zap.NewDevelopment()
|
logger, err := zap.NewDevelopment()
|
||||||
panicIf(err)
|
panicIf(err)
|
||||||
|
|
||||||
connection, err := newAzureStorageConnection(logger, DummyRouterURL, MessageQueueConfig{
|
connection, err := New(logger, DummyRouterURL, messageQueue.Config{
|
||||||
MQType: fv1.MessageQueueTypeASQ,
|
MQType: fv1.MessageQueueTypeASQ,
|
||||||
Url: "",
|
Url: "",
|
||||||
})
|
})
|
||||||
@@ -125,7 +126,7 @@ 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 := newAzureStorageConnection(logger, DummyRouterURL, MessageQueueConfig{
|
connection, err := New(logger, DummyRouterURL, messageQueue.Config{
|
||||||
MQType: fv1.MessageQueueTypeASQ,
|
MQType: fv1.MessageQueueTypeASQ,
|
||||||
Url: "",
|
Url: "",
|
||||||
})
|
})
|
||||||
@@ -140,7 +141,7 @@ 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 := newAzureStorageConnection(logger, DummyRouterURL, MessageQueueConfig{
|
connection, err := New(logger, DummyRouterURL, messageQueue.Config{
|
||||||
MQType: "azure-storage-queue",
|
MQType: "azure-storage-queue",
|
||||||
Url: "",
|
Url: "",
|
||||||
})
|
})
|
||||||
@@ -301,7 +302,7 @@ func TestAzureStorageQueuePoisonMessage(t *testing.T) {
|
|||||||
service: service,
|
service: service,
|
||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
}
|
}
|
||||||
subscription, err := connection.subscribe(&fv1.MessageQueueTrigger{
|
subscription, err := connection.Subscribe(&fv1.MessageQueueTrigger{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: TriggerName,
|
Name: TriggerName,
|
||||||
Namespace: metav1.NamespaceDefault,
|
Namespace: metav1.NamespaceDefault,
|
||||||
@@ -319,7 +320,7 @@ func TestAzureStorageQueuePoisonMessage(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, subscription)
|
require.NotNil(t, subscription)
|
||||||
|
|
||||||
connection.unsubscribe(subscription)
|
connection.Unsubscribe(subscription)
|
||||||
|
|
||||||
mock.AssertExpectationsForObjects(t, httpClient, message, poisonMessage, queue, poisonQueue, service)
|
mock.AssertExpectationsForObjects(t, httpClient, message, poisonMessage, queue, poisonQueue, service)
|
||||||
}
|
}
|
||||||
@@ -449,7 +450,7 @@ func runAzureStorageQueueTest(t *testing.T, count int, output bool) {
|
|||||||
service: service,
|
service: service,
|
||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
}
|
}
|
||||||
subscription, err := connection.subscribe(&fv1.MessageQueueTrigger{
|
subscription, err := connection.Subscribe(&fv1.MessageQueueTrigger{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: TriggerName,
|
Name: TriggerName,
|
||||||
Namespace: metav1.NamespaceDefault,
|
Namespace: metav1.NamespaceDefault,
|
||||||
@@ -468,7 +469,7 @@ func runAzureStorageQueueTest(t *testing.T, count int, output bool) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, subscription)
|
require.NotNil(t, subscription)
|
||||||
|
|
||||||
connection.unsubscribe(subscription)
|
connection.Unsubscribe(subscription)
|
||||||
|
|
||||||
mock.AssertExpectationsForObjects(t, httpClient, message, outputMessage, queue, outputQueue, service)
|
mock.AssertExpectationsForObjects(t, httpClient, message, outputMessage, queue, outputQueue, service)
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package messageQueue
|
package kafka
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -32,9 +33,15 @@ 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/messageQueue"
|
||||||
"github.com/fission/fission/pkg/utils"
|
"github.com/fission/fission/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 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 (
|
||||||
Kafka struct {
|
Kafka struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
@@ -46,7 +53,7 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeKafkaMessageQueue(logger *zap.Logger, routerUrl string, mqCfg MessageQueueConfig) (MessageQueue, error) {
|
func New(logger *zap.Logger, routerUrl string, mqCfg messageQueue.Config) (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")
|
||||||
}
|
}
|
||||||
@@ -88,11 +95,7 @@ func makeKafkaMessageQueue(logger *zap.Logger, routerUrl string, mqCfg MessageQu
|
|||||||
return kafka, nil
|
return kafka, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTopicValidForKafka(topic string) bool {
|
func (kafka Kafka) Subscribe(trigger *fv1.MessageQueueTrigger) (messageQueue.Subscription, error) {
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kafka Kafka) subscribe(trigger *fv1.MessageQueueTrigger) (messageQueueSubscription, error) {
|
|
||||||
kafka.logger.Info("inside kakfa subscribe", zap.Any("trigger", trigger))
|
kafka.logger.Info("inside kakfa subscribe", zap.Any("trigger", trigger))
|
||||||
kafka.logger.Info("brokers set", zap.Strings("brokers", kafka.brokers))
|
kafka.logger.Info("brokers set", zap.Strings("brokers", kafka.brokers))
|
||||||
|
|
||||||
@@ -194,7 +197,7 @@ func (kafka Kafka) getTLSConfig() (*tls.Config, error) {
|
|||||||
return &tlsConfig, nil
|
return &tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kafka Kafka) unsubscribe(subscription messageQueueSubscription) error {
|
func (kafka Kafka) Unsubscribe(subscription messageQueue.Subscription) error {
|
||||||
return subscription.(*cluster.Consumer).Close()
|
return subscription.(*cluster.Consumer).Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,3 +339,20 @@ func errorHandler(logger *zap.Logger, trigger *fv1.MessageQueueTrigger, producer
|
|||||||
zap.String("message", err.Error()), zap.String("trigger", trigger.ObjectMeta.Name), zap.String("function_url", funcUrl))
|
zap.String("message", err.Error()), zap.String("trigger", trigger.ObjectMeta.Name), zap.String("function_url", funcUrl))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
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 messageQueue
|
||||||
|
|
||||||
|
import (
|
||||||
|
fv1 "github.com/fission/fission/pkg/apis/core/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Subscription interface{}
|
||||||
|
|
||||||
|
Config struct {
|
||||||
|
MQType string
|
||||||
|
Url string
|
||||||
|
Secrets map[string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueue interface {
|
||||||
|
Subscribe(trigger *fv1.MessageQueueTrigger) (Subscription, error)
|
||||||
|
Unsubscribe(triggerSub Subscription) error
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package messageQueue
|
package nats
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -28,6 +28,7 @@ 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/messageQueue"
|
||||||
"github.com/fission/fission/pkg/utils"
|
"github.com/fission/fission/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeNatsMessageQueue(logger *zap.Logger, routerUrl string, mqCfg MessageQueueConfig) (MessageQueue, error) {
|
func New(logger *zap.Logger, routerUrl string, mqCfg messageQueue.Config) (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.
|
||||||
@@ -68,10 +69,10 @@ func makeNatsMessageQueue(logger *zap.Logger, routerUrl string, mqCfg MessageQue
|
|||||||
return nats, nil
|
return nats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nats Nats) subscribe(trigger *fv1.MessageQueueTrigger) (messageQueueSubscription, error) {
|
func (nats Nats) Subscribe(trigger *fv1.MessageQueueTrigger) (messageQueue.Subscription, error) {
|
||||||
subj := trigger.Spec.Topic
|
subj := trigger.Spec.Topic
|
||||||
|
|
||||||
if !isTopicValidForNats(subj) {
|
if !IsTopicValid(subj) {
|
||||||
return nil, fmt.Errorf("not a valid topic: %q", trigger.Spec.Topic)
|
return nil, fmt.Errorf("not a valid topic: %q", trigger.Spec.Topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,15 +93,10 @@ func (nats Nats) subscribe(trigger *fv1.MessageQueueTrigger) (messageQueueSubscr
|
|||||||
return sub, nil
|
return sub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nats Nats) unsubscribe(subscription messageQueueSubscription) error {
|
func (nats Nats) Unsubscribe(subscription messageQueue.Subscription) error {
|
||||||
return subscription.(ns.Subscription).Close()
|
return subscription.(ns.Subscription).Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTopicValidForNats(topic string) bool {
|
|
||||||
// nats-streaming does not support wildcard channel.
|
|
||||||
return nsUtil.IsChannelNameValid(topic, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func msgHandler(nats *Nats, trigger *fv1.MessageQueueTrigger) func(*ns.Msg) {
|
func msgHandler(nats *Nats, trigger *fv1.MessageQueueTrigger) func(*ns.Msg) {
|
||||||
return func(msg *ns.Msg) {
|
return func(msg *ns.Msg) {
|
||||||
|
|
||||||
@@ -212,5 +208,9 @@ func msgHandler(nats *Nats, trigger *fv1.MessageQueueTrigger) func(*ns.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTopicValid(topic string) bool {
|
||||||
|
// nats-streaming does not support wildcard channel.
|
||||||
|
return nsUtil.IsChannelNameValid(topic, false)
|
||||||
}
|
}
|
||||||
@@ -14,19 +14,22 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package messageQueue
|
package mqtrigger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fission/fission/pkg/utils"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
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/azurequeuestorage"
|
||||||
|
"github.com/fission/fission/pkg/mqtrigger/messageQueue/kafka"
|
||||||
|
"github.com/fission/fission/pkg/mqtrigger/messageQueue/nats"
|
||||||
|
"github.com/fission/fission/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -36,32 +39,19 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
messageQueueSubscription interface{}
|
|
||||||
|
|
||||||
requestType int
|
requestType int
|
||||||
|
|
||||||
MessageQueueConfig struct {
|
|
||||||
MQType string
|
|
||||||
Url string
|
|
||||||
Secrets map[string][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueue interface {
|
|
||||||
subscribe(trigger *fv1.MessageQueueTrigger) (messageQueueSubscription, error)
|
|
||||||
unsubscribe(triggerSub messageQueueSubscription) error
|
|
||||||
}
|
|
||||||
|
|
||||||
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 messageQueue.MessageQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerSubscription struct {
|
triggerSubscription struct {
|
||||||
trigger fv1.MessageQueueTrigger
|
trigger fv1.MessageQueueTrigger
|
||||||
subscription messageQueueSubscription
|
subscription messageQueue.Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
request struct {
|
request struct {
|
||||||
@@ -75,35 +65,23 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeMessageQueueTriggerManager(logger *zap.Logger, fissionClient *crd.FissionClient, routerUrl string, mqConfig MessageQueueConfig) *MessageQueueTriggerManager {
|
func MakeMessageQueueTriggerManager(logger *zap.Logger,
|
||||||
var messageQueue MessageQueue
|
fissionClient *crd.FissionClient, messageQueue messageQueue.MessageQueue) *MessageQueueTriggerManager {
|
||||||
var err error
|
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
switch mqConfig.MQType {
|
|
||||||
case fv1.MessageQueueTypeNats:
|
|
||||||
messageQueue, err = makeNatsMessageQueue(logger, routerUrl, mqConfig)
|
|
||||||
case fv1.MessageQueueTypeASQ:
|
|
||||||
messageQueue, err = newAzureStorageConnection(logger, routerUrl, mqConfig)
|
|
||||||
case fv1.MessageQueueTypeKafka:
|
|
||||||
messageQueue, err = makeKafkaMessageQueue(logger, routerUrl, mqConfig)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("no supported message queue type found for %q", mqConfig.MQType)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal("failed to connect to remote message queue server", zap.Error(err))
|
|
||||||
}
|
|
||||||
mqTriggerMgr.messageQueue = messageQueue
|
|
||||||
go mqTriggerMgr.service()
|
|
||||||
go mqTriggerMgr.syncTriggers()
|
|
||||||
return &mqTriggerMgr
|
return &mqTriggerMgr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mqt *MessageQueueTriggerManager) Run() {
|
||||||
|
go mqt.service()
|
||||||
|
go mqt.syncTriggers()
|
||||||
|
}
|
||||||
|
|
||||||
func (mqt *MessageQueueTriggerManager) service() {
|
func (mqt *MessageQueueTriggerManager) service() {
|
||||||
for {
|
for {
|
||||||
req := <-mqt.reqChan
|
req := <-mqt.reqChan
|
||||||
@@ -189,7 +167,7 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// actually subscribe using the message queue client impl
|
// actually subscribe using the message queue client impl
|
||||||
sub, err := mqt.messageQueue.subscribe(trigger)
|
sub, err := mqt.messageQueue.Subscribe(trigger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mqt.logger.Warn("failed to subscribe to message queue trigger", zap.Error(err), zap.String("trigger_name", trigger.ObjectMeta.Name))
|
mqt.logger.Warn("failed to subscribe to message queue trigger", zap.Error(err), zap.String("trigger_name", trigger.ObjectMeta.Name))
|
||||||
continue
|
continue
|
||||||
@@ -214,7 +192,7 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
|
|||||||
if _, ok := newTriggerMap[key]; ok {
|
if _, ok := newTriggerMap[key]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := mqt.messageQueue.unsubscribe(triggerSub.subscription)
|
err := mqt.messageQueue.Unsubscribe(triggerSub.subscription)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mqt.logger.Warn("failed to unsubscribe from message queue trigger", zap.Error(err), zap.String("trigger_name", triggerSub.trigger.ObjectMeta.Name))
|
mqt.logger.Warn("failed to unsubscribe from message queue trigger", zap.Error(err), zap.String("trigger_name", triggerSub.trigger.ObjectMeta.Name))
|
||||||
continue
|
continue
|
||||||
@@ -228,12 +206,14 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsTopicValid(mqType string, topic string) bool {
|
func IsTopicValid(mqType fv1.MessageQueueType, topic string) bool {
|
||||||
switch mqType {
|
switch mqType {
|
||||||
case fv1.MessageQueueTypeNats:
|
case fv1.MessageQueueTypeNats:
|
||||||
return isTopicValidForNats(topic)
|
return nats.IsTopicValid(topic)
|
||||||
|
case fv1.MessageQueueTypeASQ:
|
||||||
|
return azurequeuestorage.IsTopicValid(topic)
|
||||||
case fv1.MessageQueueTypeKafka:
|
case fv1.MessageQueueTypeKafka:
|
||||||
return isTopicValidForKafka(topic)
|
return kafka.IsTopicValid(topic)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user