@ -22,7 +22,6 @@ import (
"encoding/xml"
"encoding/xml"
"fmt"
"fmt"
"io"
"io"
"net"
"net/url"
"net/url"
"path"
"path"
"sort"
"sort"
@ -50,6 +49,7 @@ import (
type NotificationSys struct {
type NotificationSys struct {
sync . RWMutex
sync . RWMutex
targetList * event . TargetList
targetList * event . TargetList
targetResCh chan event . TargetIDResult
bucketRulesMap map [ string ] event . RulesMap
bucketRulesMap map [ string ] event . RulesMap
bucketRemoteTargetRulesMap map [ string ] map [ event . TargetID ] event . RulesMap
bucketRemoteTargetRulesMap map [ string ] map [ event . TargetID ] event . RulesMap
peerClients [ ] * peerRESTClient
peerClients [ ] * peerRESTClient
@ -662,19 +662,6 @@ func (sys *NotificationSys) AddRemoteTarget(bucketName string, target event.Targ
return nil
return nil
}
}
// RemoteTargetExist - checks whether given target ID is a HTTP/PeerRPC client target or not.
func ( sys * NotificationSys ) RemoteTargetExist ( bucketName string , targetID event . TargetID ) bool {
sys . Lock ( )
defer sys . Unlock ( )
targetMap , ok := sys . bucketRemoteTargetRulesMap [ bucketName ]
if ok {
_ , ok = targetMap [ targetID ]
}
return ok
}
// Loads notification policies for all buckets into NotificationSys.
// Loads notification policies for all buckets into NotificationSys.
func ( sys * NotificationSys ) load ( buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
func ( sys * NotificationSys ) load ( buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
for _ , bucket := range buckets {
for _ , bucket := range buckets {
@ -713,6 +700,17 @@ func (sys *NotificationSys) Init(buckets []BucketInfo, objAPI ObjectLayer) error
}
}
}
}
go func ( ) {
for res := range sys . targetResCh {
if res . Err != nil {
reqInfo := & logger . ReqInfo { }
reqInfo . AppendTags ( "targetID" , res . ID . Name )
ctx := logger . SetReqInfo ( GlobalContext , reqInfo )
logger . LogOnceIf ( ctx , res . Err , res . ID )
}
}
} ( )
return sys . load ( buckets , objAPI )
return sys . load ( buckets , objAPI )
}
}
@ -759,7 +757,9 @@ func (sys *NotificationSys) ConfiguredTargetIDs() []event.TargetID {
for _ , rmap := range sys . bucketRulesMap {
for _ , rmap := range sys . bucketRulesMap {
for _ , rules := range rmap {
for _ , rules := range rmap {
for _ , targetSet := range rules {
for _ , targetSet := range rules {
targetIDs = append ( targetIDs , targetSet . ToSlice ( ) ... )
for id := range targetSet {
targetIDs = append ( targetIDs , id )
}
}
}
}
}
}
}
@ -780,69 +780,41 @@ func (sys *NotificationSys) RemoveNotification(bucketName string) {
delete ( sys . bucketRulesMap , bucketName )
delete ( sys . bucketRulesMap , bucketName )
targetIDSet := event . NewTargetIDSet ( )
for targetID := range sys . bucketRemoteTargetRulesMap [ bucketName ] {
for targetID := range sys . bucketRemoteTargetRulesMap [ bucketName ] {
sys . targetList . Remove ( targetID )
targetIDSet [ targetID ] = struct { } { }
delete ( sys . bucketRemoteTargetRulesMap [ bucketName ] , targetID )
delete ( sys . bucketRemoteTargetRulesMap [ bucketName ] , targetID )
}
}
sys . targetList . Remove ( targetIDSet )
delete ( sys . bucketRemoteTargetRulesMap , bucketName )
delete ( sys . bucketRemoteTargetRulesMap , bucketName )
}
}
// RemoveAllRemoteTargets - closes and removes all HTTP/PeerRPC client targets.
// RemoveAllRemoteTargets - closes and removes all notification targets.
func ( sys * NotificationSys ) RemoveAllRemoteTargets ( ) {
func ( sys * NotificationSys ) RemoveAllRemoteTargets ( ) {
sys . Lock ( )
sys . Lock ( )
defer sys . Unlock ( )
defer sys . Unlock ( )
for _ , targetMap := range sys . bucketRemoteTargetRulesMap {
for _ , targetMap := range sys . bucketRemoteTargetRulesMap {
for targetID := range targetMap {
targetIDSet := event . NewTargetIDSet ( )
sys . targetList . Remove ( targetID )
for k := range targetMap {
}
targetIDSet [ k ] = struct { } { }
}
}
// RemoveRemoteTarget - closes and removes target by target ID.
func ( sys * NotificationSys ) RemoveRemoteTarget ( bucketName string , targetID event . TargetID ) {
for terr := range sys . targetList . Remove ( targetID ) {
reqInfo := ( & logger . ReqInfo { } ) . AppendTags ( "targetID" , terr . ID . Name )
ctx := logger . SetReqInfo ( GlobalContext , reqInfo )
logger . LogIf ( ctx , terr . Err )
}
sys . Lock ( )
defer sys . Unlock ( )
if _ , ok := sys . bucketRemoteTargetRulesMap [ bucketName ] ; ok {
delete ( sys . bucketRemoteTargetRulesMap [ bucketName ] , targetID )
if len ( sys . bucketRemoteTargetRulesMap [ bucketName ] ) == 0 {
delete ( sys . bucketRemoteTargetRulesMap , bucketName )
}
}
}
func ( sys * NotificationSys ) send ( bucketName string , eventData event . Event , targetIDs ... event . TargetID ) ( errs [ ] event . TargetIDErr ) {
errCh := sys . targetList . Send ( eventData , targetIDs ... )
for terr := range errCh {
errs = append ( errs , terr )
if sys . RemoteTargetExist ( bucketName , terr . ID ) {
sys . RemoveRemoteTarget ( bucketName , terr . ID )
}
}
sys . targetList . Remove ( targetIDSet )
}
}
return errs
}
}
// Send - sends event data to all matching targets.
// Send - sends event data to all matching targets.
func ( sys * NotificationSys ) Send ( args eventArgs ) [ ] event . TargetIDErr {
func ( sys * NotificationSys ) Send ( args eventArgs ) {
sys . RLock ( )
sys . RLock ( )
targetIDSet := sys . bucketRulesMap [ args . BucketName ] . Match ( args . EventName , args . Object . Name )
targetIDSet := sys . bucketRulesMap [ args . BucketName ] . Match ( args . EventName , args . Object . Name )
sys . RUnlock ( )
sys . RUnlock ( )
if len ( targetIDSet ) == 0 {
if len ( targetIDSet ) == 0 {
return nil
return
}
}
targetIDs := targetIDSet . ToSlice ( )
sys . targetList . Send ( args . ToEvent ( true ) , targetIDSet , sys . targetResCh )
return sys . send ( args . BucketName , args . ToEvent ( ) , targetIDs ... )
}
}
// PutBucketObjectLockConfig - put bucket object lock configuration to all peers.
// PutBucketObjectLockConfig - put bucket object lock configuration to all peers.
@ -1204,6 +1176,7 @@ func NewNotificationSys(endpoints EndpointZones) *NotificationSys {
// bucketRulesMap/bucketRemoteTargetRulesMap are initialized by NotificationSys.Init()
// bucketRulesMap/bucketRemoteTargetRulesMap are initialized by NotificationSys.Init()
return & NotificationSys {
return & NotificationSys {
targetList : event . NewTargetList ( ) ,
targetList : event . NewTargetList ( ) ,
targetResCh : make ( chan event . TargetIDResult ) ,
bucketRulesMap : make ( map [ string ] event . RulesMap ) ,
bucketRulesMap : make ( map [ string ] event . RulesMap ) ,
bucketRemoteTargetRulesMap : make ( map [ string ] map [ event . TargetID ] event . RulesMap ) ,
bucketRemoteTargetRulesMap : make ( map [ string ] map [ event . TargetID ] event . RulesMap ) ,
peerClients : newPeerRestClients ( endpoints ) ,
peerClients : newPeerRestClients ( endpoints ) ,
@ -1221,23 +1194,13 @@ type eventArgs struct {
}
}
// ToEvent - converts to notification event.
// ToEvent - converts to notification event.
func ( args eventArgs ) ToEvent ( ) event . Event {
func ( args eventArgs ) ToEvent ( escape bool ) event . Event {
getOriginEndpoint := func ( ) string {
host := globalMinioHost
if host == "" {
// FIXME: Send FQDN or hostname of this machine than sending IP address.
host = sortIPs ( localIP4 . ToSlice ( ) ) [ 0 ]
}
return fmt . Sprintf ( "%s://%s" , getURLScheme ( globalIsSSL ) , net . JoinHostPort ( host , globalMinioPort ) )
}
eventTime := UTCNow ( )
eventTime := UTCNow ( )
uniqueID := fmt . Sprintf ( "%X" , eventTime . UnixNano ( ) )
uniqueID := fmt . Sprintf ( "%X" , eventTime . UnixNano ( ) )
respElements := map [ string ] string {
respElements := map [ string ] string {
"x-amz-request-id" : args . RespElements [ "requestId" ] ,
"x-amz-request-id" : args . RespElements [ "requestId" ] ,
"x-minio-origin-endpoint" : getOriginEndpoint ( ) , // MinIO specific custom elements.
"x-minio-origin-endpoint" : globalMinioEndpoint , // MinIO specific custom elements.
}
}
// Add deployment as part of
// Add deployment as part of
if globalDeploymentID != "" {
if globalDeploymentID != "" {
@ -1246,6 +1209,10 @@ func (args eventArgs) ToEvent() event.Event {
if args . RespElements [ "content-length" ] != "" {
if args . RespElements [ "content-length" ] != "" {
respElements [ "content-length" ] = args . RespElements [ "content-length" ]
respElements [ "content-length" ] = args . RespElements [ "content-length" ]
}
}
keyName := args . Object . Name
if escape {
keyName = url . QueryEscape ( args . Object . Name )
}
newEvent := event . Event {
newEvent := event . Event {
EventVersion : "2.0" ,
EventVersion : "2.0" ,
EventSource : "minio:s3" ,
EventSource : "minio:s3" ,
@ -1264,7 +1231,7 @@ func (args eventArgs) ToEvent() event.Event {
ARN : policy . ResourceARNPrefix + args . BucketName ,
ARN : policy . ResourceARNPrefix + args . BucketName ,
} ,
} ,
Object : event . Object {
Object : event . Object {
Key : url . QueryEscape ( args . Object . Name ) ,
Key : keyName ,
VersionID : "1" ,
VersionID : "1" ,
Sequencer : uniqueID ,
Sequencer : uniqueID ,
} ,
} ,
@ -1308,19 +1275,10 @@ func sendEvent(args eventArgs) {
}
}
if globalHTTPListen . HasSubscribers ( ) {
if globalHTTPListen . HasSubscribers ( ) {
globalHTTPListen . Publish ( args . ToEvent ( ) )
globalHTTPListen . Publish ( args . ToEvent ( false ) )
}
}
notifyCh := globalNotificationSys . Send ( args )
globalNotificationSys . Send ( args )
go func ( ) {
for _ , err := range notifyCh {
reqInfo := & logger . ReqInfo { BucketName : args . BucketName , ObjectName : args . Object . Name }
reqInfo . AppendTags ( "EventName" , args . EventName . String ( ) )
reqInfo . AppendTags ( "targetID" , err . ID . Name )
ctx := logger . SetReqInfo ( GlobalContext , reqInfo )
logger . LogOnceIf ( ctx , err . Err , err . ID )
}
} ( )
}
}
func readNotificationConfig ( ctx context . Context , objAPI ObjectLayer , bucketName string ) ( * event . Config , error ) {
func readNotificationConfig ( ctx context . Context , objAPI ObjectLayer , bucketName string ) ( * event . Config , error ) {