Notification driver implementation
Implements blueprint: notification-driver Change-Id: I959b7b6e30ddef5e2591d4ad43177213d53ab0cd
This commit is contained in:
parent
d8d69a79d7
commit
4954298a60
@ -43,6 +43,9 @@ storage = cassandra
|
|||||||
# Provider modules list (a list of comma separated provider module list)
|
# Provider modules list (a list of comma separated provider module list)
|
||||||
providers = fastly
|
providers = fastly
|
||||||
|
|
||||||
|
# Notification modules list (a list of comma separated notification module list)
|
||||||
|
notifications = mailgun
|
||||||
|
|
||||||
# DNS driver module (e.g. default, designate, rackspace)
|
# DNS driver module (e.g. default, designate, rackspace)
|
||||||
dns = default
|
dns = default
|
||||||
|
|
||||||
@ -111,6 +114,7 @@ auth_endpoint = ""
|
|||||||
timeout = 30
|
timeout = 30
|
||||||
delay = 1
|
delay = 1
|
||||||
|
|
||||||
|
|
||||||
[drivers:provider]
|
[drivers:provider]
|
||||||
default_cache_ttl = 86400
|
default_cache_ttl = 86400
|
||||||
|
|
||||||
@ -148,6 +152,13 @@ akamai_https_custom_config_numbers = 'MY_AKAMAI_HTTPS_CONFIG_CUSTOM_NUMBER'
|
|||||||
san_cert_cnames = "MY_SAN_CERT_LIST"
|
san_cert_cnames = "MY_SAN_CERT_LIST"
|
||||||
san_cert_hostname_limit = "MY_SAN_HOSTNAMES_LMIT"
|
san_cert_hostname_limit = "MY_SAN_HOSTNAMES_LMIT"
|
||||||
|
|
||||||
|
[drivers:notification:mailgun]
|
||||||
|
mailgun_api_key = "<operator_api_key>"
|
||||||
|
mailgun_request_url = "https://api.mailgun.net/v2/{0}/events"
|
||||||
|
sand_box = "<your_sand_box_domain>"
|
||||||
|
from_address = "<your_send_from_email_address>"
|
||||||
|
recipients="<a_list_of_email_recipient>"
|
||||||
|
retry_send=5
|
||||||
|
|
||||||
[log_delivery]
|
[log_delivery]
|
||||||
identity_url = OPENSTACK_IDENTITY_URL
|
identity_url = OPENSTACK_IDENTITY_URL
|
||||||
|
@ -51,6 +51,8 @@ _DRIVER_OPTIONS = [
|
|||||||
help='Storage driver to use'),
|
help='Storage driver to use'),
|
||||||
cfg.ListOpt('providers', default=['mock'],
|
cfg.ListOpt('providers', default=['mock'],
|
||||||
help='Provider driver(s) to use'),
|
help='Provider driver(s) to use'),
|
||||||
|
cfg.ListOpt('notifications', default=['mail'],
|
||||||
|
help='Notification driver(s) to use'),
|
||||||
cfg.StrOpt('dns', default='default',
|
cfg.StrOpt('dns', default='default',
|
||||||
help='DNS driver to use'),
|
help='DNS driver to use'),
|
||||||
cfg.StrOpt('distributed_task', default='taskflow',
|
cfg.StrOpt('distributed_task', default='taskflow',
|
||||||
@ -119,6 +121,26 @@ class Bootstrap(object):
|
|||||||
invoke_args=args)
|
invoke_args=args)
|
||||||
return mgr
|
return mgr
|
||||||
|
|
||||||
|
@decorators.lazy_property(write=False)
|
||||||
|
def notification(self):
|
||||||
|
"""notification.
|
||||||
|
|
||||||
|
:returns mgr
|
||||||
|
"""
|
||||||
|
|
||||||
|
LOG.debug((u'Loading notification extension(s)'))
|
||||||
|
|
||||||
|
# create the driver manager to load the appropriate drivers
|
||||||
|
notification_type = 'poppy.notification'
|
||||||
|
args = [self.conf]
|
||||||
|
notification_type_names = self.driver_conf.notifications
|
||||||
|
|
||||||
|
mgr = named.NamedExtensionManager(namespace=notification_type,
|
||||||
|
names=notification_type_names,
|
||||||
|
invoke_on_load=True,
|
||||||
|
invoke_args=args)
|
||||||
|
return mgr
|
||||||
|
|
||||||
@decorators.lazy_property(write=False)
|
@decorators.lazy_property(write=False)
|
||||||
def storage(self):
|
def storage(self):
|
||||||
"""storage.
|
"""storage.
|
||||||
@ -156,7 +178,7 @@ class Bootstrap(object):
|
|||||||
manager_name = self.driver_conf.manager
|
manager_name = self.driver_conf.manager
|
||||||
|
|
||||||
args = [self.conf, self.storage, self.provider, self.dns,
|
args = [self.conf, self.storage, self.provider, self.dns,
|
||||||
self.distributed_task]
|
self.distributed_task, self.notification]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mgr = driver.DriverManager(namespace=manager_type,
|
mgr = driver.DriverManager(namespace=manager_type,
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
# Copyright (c) 2013 Red Hat, 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.
|
||||||
|
|
||||||
"""Rackspace Cloud DNS driver"""
|
"""Rackspace Cloud DNS driver"""
|
||||||
|
|
||||||
from poppy.dns.rackspace import driver
|
from poppy.dns.rackspace import driver
|
||||||
|
@ -21,12 +21,14 @@ import six
|
|||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class ManagerDriverBase(object):
|
class ManagerDriverBase(object):
|
||||||
"""Base class for driver manager."""
|
"""Base class for driver manager."""
|
||||||
def __init__(self, conf, storage, providers, dns, distributed_task):
|
def __init__(self, conf, storage, providers, dns, distributed_task,
|
||||||
|
notification):
|
||||||
self._conf = conf
|
self._conf = conf
|
||||||
self._storage = storage
|
self._storage = storage
|
||||||
self._providers = providers
|
self._providers = providers
|
||||||
self._dns = dns
|
self._dns = dns
|
||||||
self._distributed_task = distributed_task
|
self._distributed_task = distributed_task
|
||||||
|
self._notification = notification
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def conf(self):
|
def conf(self):
|
||||||
@ -60,6 +62,10 @@ class ManagerDriverBase(object):
|
|||||||
def distributed_task(self):
|
def distributed_task(self):
|
||||||
return self._distributed_task
|
return self._distributed_task
|
||||||
|
|
||||||
|
@property
|
||||||
|
def notification(self):
|
||||||
|
return self._notification
|
||||||
|
|
||||||
@abc.abstractproperty
|
@abc.abstractproperty
|
||||||
def services_controller(self):
|
def services_controller(self):
|
||||||
"""Returns the driver's services controller
|
"""Returns the driver's services controller
|
||||||
|
29
poppy/manager/base/notifications.py
Normal file
29
poppy/manager/base/notifications.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationWrapper(object):
|
||||||
|
""""ProviderWrapper class."""
|
||||||
|
|
||||||
|
def send(self, ext, subject, mail_content):
|
||||||
|
"""Send notfications with subject and mail_content
|
||||||
|
|
||||||
|
:param ext
|
||||||
|
:param subject
|
||||||
|
:param mail_content
|
||||||
|
:returns: ext.obj.services_controller.send(subject, mail_content)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return ext.obj.services_controller.send(subject, mail_content)
|
@ -18,6 +18,7 @@ import abc
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from poppy.manager.base import controller
|
from poppy.manager.base import controller
|
||||||
|
from poppy.manager.base import notifications
|
||||||
from poppy.manager.base import providers
|
from poppy.manager.base import providers
|
||||||
|
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ class ServicesControllerBase(controller.ManagerControllerBase):
|
|||||||
super(ServicesControllerBase, self).__init__(manager)
|
super(ServicesControllerBase, self).__init__(manager)
|
||||||
|
|
||||||
self.provider_wrapper = providers.ProviderWrapper()
|
self.provider_wrapper = providers.ProviderWrapper()
|
||||||
|
self.notification_wrapper = notifications.NotificationWrapper()
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def list(self, project_id, marker=None, limit=None):
|
def list(self, project_id, marker=None, limit=None):
|
||||||
|
@ -23,9 +23,10 @@ from poppy.manager.default import controllers
|
|||||||
class DefaultManagerDriver(base.Driver):
|
class DefaultManagerDriver(base.Driver):
|
||||||
"""Default Manager Driver."""
|
"""Default Manager Driver."""
|
||||||
|
|
||||||
def __init__(self, conf, storage, providers, dns, distributed_task):
|
def __init__(self, conf, storage, providers, dns, distributed_task,
|
||||||
|
notification):
|
||||||
super(DefaultManagerDriver, self).__init__(
|
super(DefaultManagerDriver, self).__init__(
|
||||||
conf, storage, providers, dns, distributed_task)
|
conf, storage, providers, dns, distributed_task, notification)
|
||||||
|
|
||||||
@decorators.lazy_property(write=True)
|
@decorators.lazy_property(write=True)
|
||||||
def services_controller(self):
|
def services_controller(self):
|
||||||
|
0
poppy/notification/__init__.py
Normal file
0
poppy/notification/__init__.py
Normal file
21
poppy/notification/base/__init__.py
Normal file
21
poppy/notification/base/__init__.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
from poppy.notification.base import driver
|
||||||
|
from poppy.notification.base import services
|
||||||
|
|
||||||
|
|
||||||
|
Driver = driver.NotificationDriverBase
|
||||||
|
ServicesBase = services.ServicesControllerBase
|
35
poppy/notification/base/controller.py
Normal file
35
poppy/notification/base/controller.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class NotificationControllerBase(object):
|
||||||
|
|
||||||
|
"""Top-level class for controllers.
|
||||||
|
|
||||||
|
:param driver: Instance of the driver
|
||||||
|
instantiating this controller.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, driver):
|
||||||
|
self._driver = driver
|
||||||
|
|
||||||
|
@property
|
||||||
|
def driver(self):
|
||||||
|
return self._driver
|
38
poppy/notification/base/driver.py
Normal file
38
poppy/notification/base/driver.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class NotificationDriverBase(object):
|
||||||
|
"""Interface definition for notification drivers.
|
||||||
|
|
||||||
|
:param conf: Configuration containing options for this driver.
|
||||||
|
:type conf: `oslo_config.ConfigOpts`
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
self._conf = conf
|
||||||
|
|
||||||
|
@abc.abstractproperty
|
||||||
|
def services_controller(self):
|
||||||
|
"""Returns the driver's hostname controller.
|
||||||
|
|
||||||
|
:raises NotImplementedError
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
38
poppy/notification/base/services.py
Normal file
38
poppy/notification/base/services.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from poppy.notification.base import controller
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class ServicesControllerBase(controller.NotificationControllerBase):
|
||||||
|
|
||||||
|
"""Services Controller Base class."""
|
||||||
|
|
||||||
|
def __init__(self, driver):
|
||||||
|
super(ServicesControllerBase, self).__init__(driver)
|
||||||
|
|
||||||
|
def send(self):
|
||||||
|
"""delete.
|
||||||
|
|
||||||
|
:param provider_details
|
||||||
|
:raises NotImplementedError
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise NotImplementedError
|
21
poppy/notification/mailgun/__init__.py
Normal file
21
poppy/notification/mailgun/__init__.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
from poppy.notification.mailgun import driver
|
||||||
|
|
||||||
|
'''Mail notification driver'''
|
||||||
|
|
||||||
|
# Hoist classes into package namespace
|
||||||
|
Driver = driver.MailNotificationDriver
|
18
poppy/notification/mailgun/controller.py
Normal file
18
poppy/notification/mailgun/controller.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
from poppy.notification.mailgun import services
|
||||||
|
|
||||||
|
ServicesController = services.ServicesController
|
83
poppy/notification/mailgun/driver.py
Normal file
83
poppy/notification/mailgun/driver.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
"""Mail Notification Driver implementation."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from poppy.notification import base
|
||||||
|
from poppy.notification.mailgun import controller
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_OPTIONS = [
|
||||||
|
cfg.StrOpt('mailgun_api_key',
|
||||||
|
help='Mail gun secret API Key'),
|
||||||
|
cfg.IntOpt('retry_send', default=5,
|
||||||
|
help='Mailgun send retry'),
|
||||||
|
cfg.StrOpt('mailgun_request_url',
|
||||||
|
help='Mail gun request url'),
|
||||||
|
cfg.StrOpt('sand_box',
|
||||||
|
help='Mail gun sand box domain'),
|
||||||
|
cfg.StrOpt('from_address', default='noreply@poppycdn.org',
|
||||||
|
help='Sent from email address'),
|
||||||
|
cfg.ListOpt('recipients',
|
||||||
|
help='A list of emails addresses to receive notification ')
|
||||||
|
]
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_GROUP = 'drivers:notification:mailgun'
|
||||||
|
|
||||||
|
|
||||||
|
def validate_email_address(email_address):
|
||||||
|
email_re = re.compile('(\w+[.|\w])*@(\w+[.])*\w+')
|
||||||
|
return email_re.match(email_address) is not None
|
||||||
|
|
||||||
|
|
||||||
|
class MailNotificationDriver(base.Driver):
|
||||||
|
"""Mail Notification Driver."""
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
super(MailNotificationDriver, self).__init__(conf)
|
||||||
|
conf.register_opts(MAIL_NOTIFICATION_OPTIONS,
|
||||||
|
group=MAIL_NOTIFICATION_GROUP)
|
||||||
|
self.mail_notification_conf = conf[MAIL_NOTIFICATION_GROUP]
|
||||||
|
self.retry_send = self.mail_notification_conf.retry_send
|
||||||
|
self.mailgun_api_key = self.mail_notification_conf.mailgun_api_key
|
||||||
|
self.mailgun_request_url = (
|
||||||
|
self.mail_notification_conf.mailgun_request_url)
|
||||||
|
self.sand_box = self.mail_notification_conf.sand_box
|
||||||
|
self.from_address = self.mail_notification_conf.from_address
|
||||||
|
self.recipients = self.mail_notification_conf.recipients
|
||||||
|
|
||||||
|
# validate email addresses
|
||||||
|
if not validate_email_address(self.from_address):
|
||||||
|
raise validate_email_address("Notification config error:"
|
||||||
|
"%s is not a valid email address"
|
||||||
|
% self.from_address)
|
||||||
|
|
||||||
|
for address in self.recipients:
|
||||||
|
if not validate_email_address(address):
|
||||||
|
raise validate_email_address("Notification config error:"
|
||||||
|
"%s is not a valid email address"
|
||||||
|
% address)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def services_controller(self):
|
||||||
|
"""Hook for service controller.
|
||||||
|
|
||||||
|
:return service_controller
|
||||||
|
"""
|
||||||
|
|
||||||
|
return controller.ServicesController(self)
|
87
poppy/notification/mailgun/services.py
Normal file
87
poppy/notification/mailgun/services.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from poppy.notification import base
|
||||||
|
from poppy.openstack.common import log
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ServicesController(base.ServicesBase):
|
||||||
|
|
||||||
|
"""Services Controller Base class."""
|
||||||
|
|
||||||
|
def __init__(self, driver):
|
||||||
|
super(ServicesController, self).__init__(driver)
|
||||||
|
|
||||||
|
self.mailgun_api_key = self.driver.mailgun_api_key
|
||||||
|
self.retry_send = self.driver.retry_send
|
||||||
|
self.mailgun_request_url = self.driver.mailgun_request_url
|
||||||
|
self.sand_box = self.driver.sand_box
|
||||||
|
self.from_address = self.driver.from_address
|
||||||
|
self.recipients = self.driver.recipients
|
||||||
|
|
||||||
|
def send(self, subject, mail_content):
|
||||||
|
"""send notification to a (list) of recipients.
|
||||||
|
|
||||||
|
:param subject
|
||||||
|
:param mail_content
|
||||||
|
:raises NotImplementedError
|
||||||
|
"""
|
||||||
|
res = self._send_mail_notification_via_mailgun(subject, mail_content)
|
||||||
|
if res:
|
||||||
|
LOG.info("Send email notification successful."
|
||||||
|
"Subject: %s"
|
||||||
|
"Content: %s" % (subject,
|
||||||
|
mail_content))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def _send_mail_notification_via_mailgun(self, subject, mail_content):
|
||||||
|
'''Send a mail via mail gun'''
|
||||||
|
|
||||||
|
request_url = self.mailgun_request_url.format(self.sand_box)
|
||||||
|
response_status_code = None
|
||||||
|
attempt = 1
|
||||||
|
|
||||||
|
while response_status_code != 200 and self.retry_send != attempt:
|
||||||
|
LOG.info("Sending email notification attempt: %s" % str(attempt))
|
||||||
|
response = requests.post(
|
||||||
|
request_url,
|
||||||
|
auth=('api', self.mailgun_api_key),
|
||||||
|
data={
|
||||||
|
'from': self.from_address,
|
||||||
|
'to': self.recipients,
|
||||||
|
'subject': subject,
|
||||||
|
'text': mail_content
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response_status_code = response.status_code
|
||||||
|
attempt += 1
|
||||||
|
|
||||||
|
if response_status_code != 200:
|
||||||
|
LOG.warning("Send email notification failed. Details:"
|
||||||
|
"From: %s"
|
||||||
|
"To: %s"
|
||||||
|
"Subject: %s"
|
||||||
|
"Content: %s" % (self.from_address,
|
||||||
|
self.recipients,
|
||||||
|
subject,
|
||||||
|
mail_content))
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
@ -60,6 +60,9 @@ poppy.provider =
|
|||||||
poppy.distributed_task =
|
poppy.distributed_task =
|
||||||
taskflow = poppy.distributed_task.taskflow:Driver
|
taskflow = poppy.distributed_task.taskflow:Driver
|
||||||
|
|
||||||
|
poppy.notification =
|
||||||
|
mailgun = poppy.notification.mailgun:Driver
|
||||||
|
|
||||||
|
|
||||||
[wheel]
|
[wheel]
|
||||||
universal = 1
|
universal = 1
|
||||||
|
@ -30,8 +30,9 @@ class DefaultManagerFlavorTests(base.TestCase):
|
|||||||
@mock.patch('poppy.provider.base.driver.ProviderDriverBase')
|
@mock.patch('poppy.provider.base.driver.ProviderDriverBase')
|
||||||
@mock.patch('poppy.dns.base.driver.DNSDriverBase')
|
@mock.patch('poppy.dns.base.driver.DNSDriverBase')
|
||||||
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
||||||
|
@mock.patch('poppy.notification.base.driver.NotificationDriverBase')
|
||||||
def setUp(self, mock_driver, mock_provider, mock_dns,
|
def setUp(self, mock_driver, mock_provider, mock_dns,
|
||||||
mock_distributed_task):
|
mock_distributed_task, mock_notification):
|
||||||
super(DefaultManagerFlavorTests, self).setUp()
|
super(DefaultManagerFlavorTests, self).setUp()
|
||||||
|
|
||||||
# create mocked config and driver
|
# create mocked config and driver
|
||||||
@ -45,7 +46,8 @@ class DefaultManagerFlavorTests(base.TestCase):
|
|||||||
mock_driver,
|
mock_driver,
|
||||||
mock_provider,
|
mock_provider,
|
||||||
mock_dns,
|
mock_dns,
|
||||||
mock_distributed_task)
|
mock_distributed_task,
|
||||||
|
mock_notification)
|
||||||
|
|
||||||
# stubbed driver
|
# stubbed driver
|
||||||
self.fc = flavors.DefaultFlavorsController(manager_driver)
|
self.fc = flavors.DefaultFlavorsController(manager_driver)
|
||||||
|
35
tests/unit/manager/default/test_notification_wrapper.py
Normal file
35
tests/unit/manager/default/test_notification_wrapper.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from poppy.manager.base import notifications
|
||||||
|
from tests.unit import base
|
||||||
|
|
||||||
|
|
||||||
|
class TestProviderWrapper(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestProviderWrapper, self).setUp()
|
||||||
|
self.notifications_wrapper_obj = notifications.NotificationWrapper()
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
mock_obj = mock.Mock()
|
||||||
|
mock_ext = mock.Mock(obj=mock_obj)
|
||||||
|
self.notifications_wrapper_obj.send(mock_ext,
|
||||||
|
"test_subject",
|
||||||
|
"test_mail_content")
|
||||||
|
mock_ext.obj.services_controller.send.assert_called_once_with(
|
||||||
|
"test_subject", "test_mail_content")
|
@ -98,11 +98,12 @@ class MonkeyPatchControllers(object):
|
|||||||
class DefaultManagerServiceTests(base.TestCase):
|
class DefaultManagerServiceTests(base.TestCase):
|
||||||
|
|
||||||
@mock.patch('poppy.bootstrap.Bootstrap')
|
@mock.patch('poppy.bootstrap.Bootstrap')
|
||||||
|
@mock.patch('poppy.notification.base.driver.NotificationDriverBase')
|
||||||
@mock.patch('poppy.dns.base.driver.DNSDriverBase')
|
@mock.patch('poppy.dns.base.driver.DNSDriverBase')
|
||||||
@mock.patch('poppy.storage.base.driver.StorageDriverBase')
|
@mock.patch('poppy.storage.base.driver.StorageDriverBase')
|
||||||
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
||||||
def setUp(self, mock_distributed_task, mock_storage,
|
def setUp(self, mock_distributed_task, mock_storage,
|
||||||
mock_dns, mock_bootstrap):
|
mock_dns, mock_notification, mock_bootstrap):
|
||||||
# NOTE(TheSriram): the mock.patch decorator applies mocks
|
# NOTE(TheSriram): the mock.patch decorator applies mocks
|
||||||
# in the reverse order of the arguments present
|
# in the reverse order of the arguments present
|
||||||
super(DefaultManagerServiceTests, self).setUp()
|
super(DefaultManagerServiceTests, self).setUp()
|
||||||
@ -127,7 +128,8 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||||||
mock_storage,
|
mock_storage,
|
||||||
mock_providers,
|
mock_providers,
|
||||||
mock_dns,
|
mock_dns,
|
||||||
mock_distributed_task)
|
mock_distributed_task,
|
||||||
|
mock_notification)
|
||||||
|
|
||||||
# stubbed driver
|
# stubbed driver
|
||||||
self.sc = services.DefaultServicesController(manager_driver)
|
self.sc = services.DefaultServicesController(manager_driver)
|
||||||
|
0
tests/unit/notification/__init__.py
Normal file
0
tests/unit/notification/__init__.py
Normal file
0
tests/unit/notification/mailgun/__init__.py
Normal file
0
tests/unit/notification/mailgun/__init__.py
Normal file
60
tests/unit/notification/mailgun/test_driver.py
Normal file
60
tests/unit/notification/mailgun/test_driver.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
"""Unittests for mail notification driver implementation."""
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from poppy.notification.mailgun import driver
|
||||||
|
from tests.unit import base
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_OPTIONS = [
|
||||||
|
cfg.StrOpt('mailgun_api_key', default='123',
|
||||||
|
help='Mail gun secret API Key'),
|
||||||
|
cfg.IntOpt('retry_send', default=5,
|
||||||
|
help='Mailgun send retry'),
|
||||||
|
cfg.StrOpt('mailgun_request_url', default='http://123.com/{0}',
|
||||||
|
help='Mail gun request url'),
|
||||||
|
cfg.StrOpt('sand_box', default='123.com',
|
||||||
|
help='Mail gun sand box domain'),
|
||||||
|
cfg.StrOpt('from_address', default='noreply@poppycdn.org',
|
||||||
|
help='Sent from email address'),
|
||||||
|
cfg.ListOpt('recipients', default=['recipient@gmail.com'],
|
||||||
|
help='A list of emails addresses to receive notification ')
|
||||||
|
]
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_GROUP = 'drivers:notification:mailgun'
|
||||||
|
|
||||||
|
|
||||||
|
class TestDriver(base.TestCase):
|
||||||
|
|
||||||
|
@mock.patch.object(driver, 'MAIL_NOTIFICATION_OPTIONS',
|
||||||
|
new=MAIL_NOTIFICATION_OPTIONS)
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDriver, self).setUp()
|
||||||
|
|
||||||
|
self.conf = cfg.ConfigOpts()
|
||||||
|
self.mailgun_notification_driver = (
|
||||||
|
driver.MailNotificationDriver(self.conf))
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
self.assertTrue(self.mailgun_notification_driver is not None)
|
||||||
|
|
||||||
|
def test_service_contoller(self):
|
||||||
|
self.assertTrue(self.mailgun_notification_driver.services_controller
|
||||||
|
is not None)
|
||||||
|
self.assertTrue(self.mailgun_notification_driver.retry_send == 5)
|
60
tests/unit/notification/mailgun/test_services.py
Normal file
60
tests/unit/notification/mailgun/test_services.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace, 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.
|
||||||
|
|
||||||
|
"""Unittests for TaskFlow distributed_task service_controller."""
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from poppy.notification.mailgun import driver
|
||||||
|
from tests.unit import base
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_OPTIONS = [
|
||||||
|
cfg.StrOpt('mailgun_api_key', default='123',
|
||||||
|
help='Mail gun secret API Key'),
|
||||||
|
cfg.IntOpt('retry_send', default=5,
|
||||||
|
help='Mailgun send retry'),
|
||||||
|
cfg.StrOpt('mailgun_request_url', default='http://123.com/{0}',
|
||||||
|
help='Mail gun request url'),
|
||||||
|
cfg.StrOpt('sand_box', default='123.com',
|
||||||
|
help='Mail gun sand box domain'),
|
||||||
|
cfg.StrOpt('from_address', default='noreply@poppycdn.org',
|
||||||
|
help='Sent from email address'),
|
||||||
|
cfg.ListOpt('recipients', default=['recipient@gmail.com'],
|
||||||
|
help='A list of emails addresses to receive notification ')
|
||||||
|
]
|
||||||
|
|
||||||
|
MAIL_NOTIFICATION_GROUP = 'drivers:notification:mail'
|
||||||
|
|
||||||
|
|
||||||
|
class TestServiceController(base.TestCase):
|
||||||
|
|
||||||
|
@mock.patch.object(driver, 'MAIL_NOTIFICATION_OPTIONS',
|
||||||
|
new=MAIL_NOTIFICATION_OPTIONS)
|
||||||
|
def setUp(self):
|
||||||
|
super(TestServiceController, self).setUp()
|
||||||
|
|
||||||
|
self.conf = cfg.ConfigOpts()
|
||||||
|
self.mail_notification_driver = (
|
||||||
|
driver.MailNotificationDriver(self.conf))
|
||||||
|
self.controller = self.mail_notification_driver.services_controller
|
||||||
|
|
||||||
|
@mock.patch.object(requests, 'post', new=mock.Mock())
|
||||||
|
def test_send_mail_notification(self):
|
||||||
|
self.assertTrue(self.controller.retry_send == 5)
|
||||||
|
self.controller.send("A Subject", "Some random text")
|
||||||
|
requests.post.assert_called_once()
|
Loading…
Reference in New Issue
Block a user