| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2016 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/pkg/wildcard" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SQS type.
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// Minio sqs ARN prefix.
 | 
					
						
							|  |  |  | 	minioSqs = "arn:minio:sqs:" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Static string indicating queue type 'amqp'.
 | 
					
						
							|  |  |  | 	queueTypeAMQP = "amqp" | 
					
						
							| 
									
										
										
										
											2016-09-30 14:42:10 +08:00
										 |  |  | 	// Static string indicating queue type 'nats'.
 | 
					
						
							|  |  |  | 	queueTypeNATS = "nats" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	// Static string indicating queue type 'elasticsearch'.
 | 
					
						
							|  |  |  | 	queueTypeElastic = "elasticsearch" | 
					
						
							|  |  |  | 	// Static string indicating queue type 'redis'.
 | 
					
						
							|  |  |  | 	queueTypeRedis = "redis" | 
					
						
							| 
									
										
										
										
											2016-10-04 08:29:55 +08:00
										 |  |  | 	// Static string indicating queue type 'postgresql'.
 | 
					
						
							|  |  |  | 	queueTypePostgreSQL = "postgresql" | 
					
						
							| 
									
										
										
										
											2017-03-18 00:29:17 +08:00
										 |  |  | 	// Static string indicating queue type 'mysql'.
 | 
					
						
							|  |  |  | 	queueTypeMySQL = "mysql" | 
					
						
							| 
									
										
										
										
											2016-12-16 00:23:48 +08:00
										 |  |  | 	// Static string indicating queue type 'kafka'.
 | 
					
						
							|  |  |  | 	queueTypeKafka = "kafka" | 
					
						
							| 
									
										
										
										
											2017-01-10 06:22:10 +08:00
										 |  |  | 	// Static string for Webhooks
 | 
					
						
							|  |  |  | 	queueTypeWebhook = "webhook" | 
					
						
							| 
									
										
										
										
											2017-03-28 02:27:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Notifier format value constants
 | 
					
						
							|  |  |  | 	formatNamespace = "namespace" | 
					
						
							|  |  |  | 	formatAccess    = "access" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-16 11:56:43 +08:00
										 |  |  | // Topic type.
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-08-16 11:56:43 +08:00
										 |  |  | 	// Minio topic ARN prefix.
 | 
					
						
							|  |  |  | 	minioTopic = "arn:minio:sns:" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-16 11:56:43 +08:00
										 |  |  | 	// Static string indicating sns type 'listen'.
 | 
					
						
							|  |  |  | 	snsTypeMinio = "listen" | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var errNotifyNotEnabled = errors.New("requested notifier not enabled") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns true if queueArn is for an AMQP queue.
 | 
					
						
							|  |  |  | func isAMQPQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeAMQP { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	amqpL := serverConfig.Notify.GetAMQPByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	if !amqpL.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Connect to amqp server to validate.
 | 
					
						
							|  |  |  | 	amqpC, err := dialAMQP(amqpL) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to amqp service. %#v", amqpL) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer amqpC.Close() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 14:42:10 +08:00
										 |  |  | // Returns true if natsArn is for an NATS queue.
 | 
					
						
							|  |  |  | func isNATSQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeNATS { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	natsL := serverConfig.Notify.GetNATSByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-09-30 14:42:10 +08:00
										 |  |  | 	if !natsL.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Connect to nats server to validate.
 | 
					
						
							| 
									
										
										
										
											2017-01-12 08:41:05 +08:00
										 |  |  | 	natsC, err := dialNATS(natsL, true) | 
					
						
							| 
									
										
										
										
											2016-09-30 14:42:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to nats service. %#v", natsL) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-12 08:41:05 +08:00
										 |  |  | 	closeNATS(natsC) | 
					
						
							| 
									
										
										
										
											2016-09-30 14:42:10 +08:00
										 |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 06:22:10 +08:00
										 |  |  | // Returns true if queueArn is for an Webhook queue
 | 
					
						
							|  |  |  | func isWebhookQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeWebhook { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	rNotify := serverConfig.Notify.GetWebhookByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2017-03-09 02:00:47 +08:00
										 |  |  | 	return rNotify.Enable | 
					
						
							| 
									
										
										
										
											2017-01-10 06:22:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | // Returns true if queueArn is for an Redis queue.
 | 
					
						
							|  |  |  | func isRedisQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeRedis { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	rNotify := serverConfig.Notify.GetRedisByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	if !rNotify.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Connect to redis server to validate.
 | 
					
						
							|  |  |  | 	rPool, err := dialRedis(rNotify) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to redis service. %#v", rNotify) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer rPool.Close() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns true if queueArn is for an ElasticSearch queue.
 | 
					
						
							|  |  |  | func isElasticQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeElastic { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	esNotify := serverConfig.Notify.GetElasticSearchByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 	if !esNotify.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	elasticC, err := dialElastic(esNotify) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to elasticsearch service %#v", esNotify) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer elasticC.Stop() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 08:29:55 +08:00
										 |  |  | // Returns true if queueArn is for PostgreSQL.
 | 
					
						
							|  |  |  | func isPostgreSQLQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypePostgreSQL { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	pgNotify := serverConfig.Notify.GetPostgreSQLByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-10-04 08:29:55 +08:00
										 |  |  | 	if !pgNotify.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pgC, err := dialPostgreSQL(pgNotify) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to PostgreSQL server %#v", pgNotify) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer pgC.Close() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-18 00:29:17 +08:00
										 |  |  | // Returns true if queueArn is for MySQL.
 | 
					
						
							|  |  |  | func isMySQLQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeMySQL { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	msqlNotify := serverConfig.Notify.GetMySQLByID(sqsArn.AccountID) | 
					
						
							|  |  |  | 	if !msqlNotify.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	myC, err := dialMySQL(msqlNotify) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to connect to MySQL server %#v", msqlNotify) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer myC.Close() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-16 00:23:48 +08:00
										 |  |  | // Returns true if queueArn is for Kafka.
 | 
					
						
							|  |  |  | func isKafkaQueue(sqsArn arnSQS) bool { | 
					
						
							|  |  |  | 	if sqsArn.Type != queueTypeKafka { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 07:20:54 +08:00
										 |  |  | 	kafkaNotifyCfg := serverConfig.Notify.GetKafkaByID(sqsArn.AccountID) | 
					
						
							| 
									
										
										
										
											2016-12-16 00:23:48 +08:00
										 |  |  | 	if !kafkaNotifyCfg.Enable { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	kafkaC, err := dialKafka(kafkaNotifyCfg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Unable to dial Kafka server %#v", kafkaNotifyCfg) | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer kafkaC.Close() | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | // Match function matches wild cards in 'pattern' for events.
 | 
					
						
							|  |  |  | func eventMatch(eventType string, events []string) (ok bool) { | 
					
						
							|  |  |  | 	for _, event := range events { | 
					
						
							| 
									
										
										
										
											2016-08-27 15:27:17 +08:00
										 |  |  | 		ok = wildcard.MatchSimple(event, eventType) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 		if ok { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ok | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Filter rule match, matches an object against the filter rules.
 | 
					
						
							|  |  |  | func filterRuleMatch(object string, frs []filterRule) bool { | 
					
						
							|  |  |  | 	var prefixMatch, suffixMatch = true, true | 
					
						
							|  |  |  | 	for _, fr := range frs { | 
					
						
							|  |  |  | 		if isValidFilterNamePrefix(fr.Name) { | 
					
						
							| 
									
										
										
										
											2017-02-04 15:27:50 +08:00
										 |  |  | 			prefixMatch = hasPrefix(object, fr.Value) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 		} else if isValidFilterNameSuffix(fr.Name) { | 
					
						
							| 
									
										
										
										
											2017-02-04 15:27:50 +08:00
										 |  |  | 			suffixMatch = hasSuffix(object, fr.Value) | 
					
						
							| 
									
										
										
										
											2016-08-05 13:01:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return prefixMatch && suffixMatch | 
					
						
							|  |  |  | } |