Added Send mail functionality & Dockerized application #1
9
config.ini
Normal file
9
config.ini
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[server]
|
||||||
|
server_host = 0.0.0.0
|
||||||
|
server_port = 8081
|
||||||
|
|
||||||
|
[app]
|
||||||
|
to_mail = test111@mailinator.com
|
||||||
|
from_mail = test@gmail.com
|
||||||
|
from_mail_password = test@123
|
||||||
|
|
171
main.py
Normal file
171
main.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Serve cloud init files
|
||||||
|
"""
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import smtplib
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
from email.header import Header
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
|
import uuid as uuid_module
|
||||||
|
from ipaddress import AddressValueError, IPv4Address, IPv6Address
|
||||||
|
|
||||||
|
import cherrypy
|
||||||
|
|
||||||
|
PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
PeterSurda marked this conversation as resolved
|
|||||||
|
CONFIG = configparser.ConfigParser()
|
||||||
|
CONFIG.read(os.path.join(PATH, "config.ini"))
|
||||||
|
|
||||||
|
TO_MAIL = CONFIG["app"].get("to_mail")
|
||||||
|
FROM_MAIL = CONFIG["app"].get("from_mail")
|
||||||
|
FROM_MAIL_PASSWORD = CONFIG["app"].get("from_mail_password")
|
||||||
|
print("TO_MAIL: ", TO_MAIL)
|
||||||
|
print("FROM_MAIL: ", FROM_MAIL)
|
||||||
|
print("FROM_MAIL_PASSWORD: ", FROM_MAIL_PASSWORD)
|
||||||
|
|
||||||
|
|
||||||
|
class CloudInitRequest:
|
||||||
|
"""
|
||||||
|
Request data for persistence across methods
|
||||||
|
"""
|
||||||
|
def __init__(self, request, uuid=None):
|
||||||
|
self.remoteip = None
|
||||||
|
self.hostinfo = ('localhost', )
|
||||||
|
self.request = request
|
||||||
|
self.meta_data = None
|
||||||
|
self.meta_data_loaded = False
|
||||||
|
self.user_data = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.uuid = str(uuid_module.UUID('{' + uuid + '}'))
|
||||||
|
# ValueError is wrong UUID syntax
|
||||||
|
# TypeError is None
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
self.uuid = None
|
||||||
|
|
||||||
|
self._init_ip()
|
||||||
|
|
||||||
|
def _can_ip_be_proxy(self):
|
||||||
|
"""
|
||||||
|
Assuming the connection is through a proxy, is this proxy permitted?
|
||||||
|
Can't proxy from a publicly reachable IP.
|
||||||
|
"""
|
||||||
|
self.remoteip = self.request.remote.ip
|
||||||
|
try:
|
||||||
|
ipobj = IPv4Address(self.remoteip)
|
||||||
|
except AddressValueError:
|
||||||
|
try:
|
||||||
|
ipobj = IPv6Address(self.remoteip)
|
||||||
|
except AddressValueError:
|
||||||
|
return False
|
||||||
|
return not ipobj.is_global
|
||||||
|
|
||||||
|
def _init_ip(self):
|
||||||
|
"""
|
||||||
|
Get remote IP
|
||||||
|
"""
|
||||||
|
if self._can_ip_be_proxy():
|
||||||
|
try:
|
||||||
|
self.remoteip = self.request.headers.get(
|
||||||
|
'X-Real-Ip',
|
||||||
|
self.request.remote.ip
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.hostinfo = socket.gethostbyaddr(self.remoteip)
|
||||||
|
forward_lookup = socket.gethostbyname(self.hostinfo[0])
|
||||||
|
if forward_lookup != self.remoteip:
|
||||||
|
self.hostinfo = ('localhost', )
|
||||||
|
except socket.herror:
|
||||||
|
self.hostinfo = ('localhost', )
|
||||||
|
except socket.gaierror:
|
||||||
|
self.hostinfo = (self.remoteip, )
|
||||||
|
|
||||||
|
|
||||||
|
class CloudInitApp:
|
||||||
|
"""
|
||||||
|
Serve cloud init files
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _content_type(data):
|
||||||
|
if not data:
|
||||||
|
return "text/cloud-config"
|
||||||
|
if data.startswith("#include"):
|
||||||
|
return "text/x-include-url"
|
||||||
|
if data.startswith("## template: jinja"):
|
||||||
|
return "text/jinja2"
|
||||||
|
return "text/cloud-config"
|
||||||
|
|
||||||
|
def _send_mail(self):
|
||||||
|
try:
|
||||||
|
# pylint: disable=deprecated-lambda
|
||||||
|
cl = cherrypy.request.headers['Content-Length']
|
||||||
|
rawbody = cherrypy.request.body.read(int(cl))
|
||||||
|
req_body = json.loads(rawbody)
|
||||||
|
subject = req_body['subject']
|
||||||
|
body = req_body['body']
|
||||||
|
client = smtplib.SMTP('smtp.gmail.com')
|
||||||
|
msg = MIMEText(body, 'plain', 'utf-8')
|
||||||
|
msg['Subject'] = Header(subject, 'utf-8')
|
||||||
|
msg['From'] = FROM_MAIL
|
||||||
|
msg['To'] = TO_MAIL
|
||||||
|
|
||||||
|
client.ehlo()
|
||||||
|
client.starttls()
|
||||||
|
client.ehlo()
|
||||||
|
client.login(msg["From"], FROM_MAIL_PASSWORD)
|
||||||
|
client.sendmail(msg['From'], msg['To'], msg.as_string())
|
||||||
|
client.quit()
|
||||||
|
return "mail sent successfully"
|
||||||
|
except Exception as e:
|
||||||
|
return "some error: {}".format(e)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def send_mail(self):
|
||||||
|
"""
|
||||||
|
v1 api endpoint user-data
|
||||||
|
"""
|
||||||
|
return self._send_mail()
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = CloudInitApp()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cherrypy.server.socket_host = \
|
||||||
|
CONFIG["server"].get("server_host", "127.0.0.1")
|
||||||
|
cherrypy.server.socket_port = \
|
||||||
|
CONFIG["server"].getint("server_port", 8081)
|
||||||
|
ENGINE = cherrypy.engine
|
||||||
|
|
||||||
|
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
CONFIG = {
|
||||||
|
'/include': {
|
||||||
|
'tools.staticdir.on': True,
|
||||||
|
'tools.staticdir.dir': os.path.join(CURRENT_DIR,
|
||||||
|
'data',
|
||||||
|
'include'),
|
||||||
|
'tools.staticdir.content_types': {
|
||||||
|
'yml': 'text/yaml'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cherrypy.tree.mount(ROOT, config=CONFIG)
|
||||||
|
|
||||||
|
if hasattr(ENGINE, "signal_handler"):
|
||||||
|
ENGINE.signal_handler.subscribe()
|
||||||
|
if hasattr(ENGINE, "console_control_handler"):
|
||||||
|
ENGINE.console_control_handler.subscribe()
|
||||||
|
try:
|
||||||
|
ENGINE.start()
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
ENGINE.block()
|
18
requirements.txt
Normal file
18
requirements.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
cheroot==8.6.0
|
||||||
|
CherryPy==18.6.1
|
||||||
|
importlib-resources==5.4.0
|
||||||
|
jaraco.classes==3.2.1
|
||||||
|
jaraco.collections==3.5.1
|
||||||
|
jaraco.context==4.1.1
|
||||||
|
jaraco.functools==3.5.0
|
||||||
|
jaraco.text==3.7.0
|
||||||
|
Jinja2==3.0.3
|
||||||
|
MarkupSafe==2.0.1
|
||||||
|
more-itertools==8.12.0
|
||||||
|
portend==3.1.0
|
||||||
|
pytz==2021.3
|
||||||
|
PyYAML==6.0
|
||||||
|
six==1.16.0
|
||||||
|
tempora==5.0.1
|
||||||
|
zc.lockfile==2.0
|
||||||
|
zipp==3.7.0
|
Loading…
Reference in New Issue
Block a user
this should go under
__main__