From 69583a1b071caa7afaac87cc678dcf3318988705 Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Wed, 16 Apr 2014 15:26:52 -0400 Subject: [PATCH] Import socketio service work and updates to documentation and setup procedures --- Makefile | 4 + .../commands/run_socketio_service.py | 88 +++++++++++++++++++ awx/main/models/schedules.py | 4 +- awx/settings/defaults.py | 3 + 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 awx/main/management/commands/run_socketio_service.py diff --git a/Makefile b/Makefile index 0777dba001..376becda29 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,7 @@ server: tmux rename-window 'Tower' tmux select-window -t tower:0 tmux split-window -v 'exec make celeryd' + tmux split-window -h 'exec make socketservice' tmux split-window -v 'exec make receiver' tmux split-window -h 'exec make taskmanager' tmux -2 attach-session -t tower @@ -136,6 +137,9 @@ receiver: taskmanager: $(PYTHON) manage.py run_task_system +socketservice: + $(PYTHON) manage.py run_socketio_service + # Run all API unit tests. test: $(PYTHON) manage.py test -v2 main diff --git a/awx/main/management/commands/run_socketio_service.py b/awx/main/management/commands/run_socketio_service.py new file mode 100644 index 0000000000..ea9000d3d8 --- /dev/null +++ b/awx/main/management/commands/run_socketio_service.py @@ -0,0 +1,88 @@ +# Copyright (c) 2014 AnsibleWorks, Inc. +# All Rights Reserved. + +# Python +import os +import datetime +import logging +import json +import signal +import time +from optparse import make_option +from multiprocessing import Process + +# Django +from django.conf import settings +from django.core.management.base import NoArgsCommand, CommandError +from django.db import transaction, DatabaseError +from django.contrib.auth.models import User +from django.utils.dateparse import parse_datetime +from django.utils.timezone import now, is_aware, make_aware +from django.utils.tzinfo import FixedOffset + +# AWX +from awx.main.models import * + +# ZeroMQ +import zmq + +# gevent & socketio +from socketio import socketio_manage +from socketio.server import SocketIOServer +from socketio.namespace import BaseNamespace + +class TestNamespace(BaseNamespace): + + def recv_connect(self): + print("Received client connect for test namespace from %s" % str(self.environ['REMOTE_ADDR'])) + #print("Env: " + str(self.environ)) + self.emit('connect', True) + +class TowerSocket(object): + + def __call__(self, environ, start_response): + path = environ['PATH_INFO'].strip('/') or 'index.html' + print path + if path.startswith('socket.io'): + socketio_manage(environ, {'/socket.io/test': TestNamespace}) + socketio_manage(environ, {'/socket.io/jobs': JobNamespace}) + socketio_manage(environ, {'/socket.io/job_events': JobEventNamespace}) + else: + start_response('404 Not Found', []) + return ['

Not Found

'] + +class Command(NoArgsCommand): + ''' + SocketIO event emitter Tower service + Receives notifications from other services destined for UI notification + ''' + + help = 'Launch the SocketIO event emitter service' + + option_list = NoArgsCommand.option_list + ( + make_option('--receive_port', dest='receive_port', type='int', default=5559, + help='Port to listen for new events that will be destined for a client'), + make_option('--socketio_port', dest='socketio_port', type='int', default=8080, + help='Port to accept socketio requests from clients'),) + + def init_logging(self): + log_levels = dict(enumerate([logging.ERROR, logging.INFO, + logging.DEBUG, 0])) + self.logger = logging.getLogger('awx.main.commands.run_socketio_service') + self.logger.setLevel(log_levels.get(self.verbosity, 0)) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(message)s')) + self.logger.addHandler(handler) + self.logger.propagate = False + + def handle_noargs(self, **options): + self.verbosity = int(options.get('verbosity', 1)) + self.init_logging() + socketio_listen_port = settings.SOCKETIO_LISTEN_PORT + socketio_notification_port = settings.SOCKETIO_NOTIFICATION_PORT + try: + print 'Listening on port http://0.0.0.0:' + str(socketio_listen_port) + server = SocketIOServer(('0.0.0.0', socketio_listen_port), TowerSocket(), resource='socket.io') + server.serve_forever() + except KeyboardInterrupt: + pass diff --git a/awx/main/models/schedules.py b/awx/main/models/schedules.py index 2789a1c7e8..4b82f03f6f 100644 --- a/awx/main/models/schedules.py +++ b/awx/main/models/schedules.py @@ -104,7 +104,9 @@ class Schedule(CommonModel): self.dtend = make_aware(datetime.datetime.strptime(until_date, "%Y%m%dT%H%M%SZ"), get_default_timezone()) if 'count' in self.rrule.lower(): self.dtend = future_rs[-1] - self.unified_job_template.update_computed_fields() + from awx.main.signals import ignore_inventory_computed_fields + with ignore_inventory_computed_fields(): + self.unified_job_template.update_computed_fields() def save(self, *args, **kwargs): self.update_computed_fields() diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 32cc9a659b..f2f437aef2 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -387,6 +387,9 @@ CALLBACK_QUEUE_PORT = "ipc:///tmp/callback_receiver.ipc" TASK_COMMAND_PORT = "tcp://127.0.0.1:6556" +SOCKETIO_NOTIFICATION_PORT = "tcp://127.0.0.1:6557" +SOCKETIO_LISTEN_PORT = 8080 + # Logging configuration. LOGGING = { 'version': 1,