<commit_before>import re
import time
import requests as rq
from requests.exceptions import ConnectionError, ReadTimeout
from adslproxy.db import RedisClient
from adslproxy.config import *
import platform
from random import choice

if platform.python_version().startswith('2.'):
    import commands as subprocess
elif platform.python_version().startswith('3.'):
    import subprocess
else:
    raise ValueError('python version must be 2 or 3')

class Sender():
    def __init__(self):
        self.proxy = None
        self.headers = [
            {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'},
            {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'},
            {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36'}
        ]

    def get_ip(self, ifname=ADSL_IFNAME):
        (status, output) = subprocess.getstatusoutput('ifconfig')
        if status == 0:
            pattern = re.compile(ifname + '.*?inet.*?(\d+\.\d+\.\d+\.\d+).*?netmask', re.S)
            result = re.search(pattern, output)
            if result:
                ip = result.group(1)
                return ip

    def test_proxy(self, proxy):
        try:
            if proxy != self.proxy:
                print('start texting')
                headers = choice(self.headers)
                proxies = {'http':'http://'+proxy}
                print(proxies)
                html = rq.get(TEST_URL,proxies=proxies,headers=headers,timeout = 20)
                if html.status_code == 200:
                    print(html.status_code)
                    if get_yanzhengma(self,html.text):
                        print("OK")
                        self.proxy = '{}\t{}'.format(proxy,headers)
                        return True
                else:
                    self.proxy = proxy
                    return False
            else:
                self.proxy = proxy
                return False
        except:
            return False

    def remove_proxy(self):
        self.redis = RedisClient()
        self.redis.remove(CLIENT_NAME)
        print('Successfully Removed Proxy')

    def set_proxy(self, proxy):
        self.redis = RedisClient()
        if self.redis.set(CLIENT_NAME, proxy):
            print('Successfully Set Proxy', proxy)

    def get_yanzhengma(self,html):
        n = re.findall('Robot Check',html)
        if not n:
            return True
        else:
            return False

    def adsl(self):
        while True:
            print('ADSL Start, Please wait')
            (status, output) = subprocess.getstatusoutput(ADSL_BASH)
            if status == 0:
                print('ADSL Successfully')
                ip = self.get_ip()
                if ip:
                    proxy = '{ip}:{port}'.format(ip=ip, port=PROXY_PORT)
                    print("new proxy ",proxy)
                    if self.test_proxy(proxy):
                        print('Valid Proxy')
                        self.set_proxy(proxy)
                        print('Sleeping',ADSL_CYCLE + 15)
                        time.sleep(ADSL_CYCLE)
                        self.remove_proxy()
                        time.sleep(15)
                    else:
                        print('Invalid Proxy')
                else:
                    print('Get IP Failed, Re Dialing')
                    time.sleep(ADSL_ERROR_CYCLE)
            else:
                print('ADSL Failed, Please Check')
                time.sleep(ADSL_ERROR_CYCLE)

def run():
    sender = Sender()
    sender.adsl()

if __name__ == '__main__':
    run()
<commit_msg>Update sender.py<commit_after>import re
import time
import requests as rq
from requests.exceptions import ConnectionError, ReadTimeout
from adslproxy.db import RedisClient
from adslproxy.config import *
import platform
from random import choice

if platform.python_version().startswith('2.'):
    import commands as subprocess
elif platform.python_version().startswith('3.'):
    import subprocess
else:
    raise ValueError('python version must be 2 or 3')

class Sender():
    def __init__(self):
        self.proxy = None
        self.headers = [
            {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'},
            {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'},
            {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36'}
        ]

    def get_ip(self, ifname=ADSL_IFNAME):
        (status, output) = subprocess.getstatusoutput('ifconfig')
        if status == 0:
            pattern = re.compile(ifname + '.*?inet.*?(\d+\.\d+\.\d+\.\d+).*?netmask', re.S)
            result = re.search(pattern, output)
            if result:
                ip = result.group(1)
                return ip

    def test_proxy(self, proxy):
        try:
            if proxy != self.proxy:
                print('start texting')
                headers = choice(self.headers)
                proxies = {'http':'http://'+proxy}
                print(proxies)
                html = rq.get(TEST_URL,proxies=proxies,headers=headers,timeout = 20)
                if html.status_code == 200:
                    print(html.status_code)
                    if self.get_yanzhengma(self,html.text):
                        print("OK")
                        self.proxy = '{}\t{}'.format(proxy,headers)
                        return True
                else:
                    self.proxy = proxy
                    return False
            else:
                self.proxy = proxy
                return False
        except:
            return False

    def remove_proxy(self):
        self.redis = RedisClient()
        self.redis.remove(CLIENT_NAME)
        print('Successfully Removed Proxy')

    def set_proxy(self, proxy):
        self.redis = RedisClient()
        if self.redis.set(CLIENT_NAME, proxy):
            print('Successfully Set Proxy', proxy)

    def get_yanzhengma(self,html):
        n = re.findall('Robot Check',html)
        if not n:
            return True
        else:
            return False

    def adsl(self):
        while True:
            print('ADSL Start, Please wait')
            (status, output) = subprocess.getstatusoutput(ADSL_BASH)
            if status == 0:
                print('ADSL Successfully')
                ip = self.get_ip()
                if ip:
                    proxy = '{ip}:{port}'.format(ip=ip, port=PROXY_PORT)
                    print("new proxy ",proxy)
                    if self.test_proxy(proxy):
                        print('Valid Proxy')
                        self.set_proxy(proxy)
                        print('Sleeping',ADSL_CYCLE + 15)
                        time.sleep(ADSL_CYCLE)
                        self.remove_proxy()
                        time.sleep(15)
                    else:
                        print('Invalid Proxy')
                else:
                    print('Get IP Failed, Re Dialing')
                    time.sleep(ADSL_ERROR_CYCLE)
            else:
                print('ADSL Failed, Please Check')
                time.sleep(ADSL_ERROR_CYCLE)

def run():
    sender = Sender()
    sender.adsl()

if __name__ == '__main__':
    run()
<|endoftext|>


<commit_before>import asyncio

import async_timeout

from .log import logger
from .processor import TProcessor
from .protocol import TBinaryProtocol, TFramedTransport

class Server:
    def __init__(self, processor, protocol_cls=TBinaryProtocol, timeout=None, framed=False):
        self.processor = processor
        self.protocol_cls = protocol_cls
        self.timeout = timeout
        self.framed = framed

    async def __call__(self, reader, writer):
        client_addr = writer.get_extra_info('peername')
        logger.debug(f"client {client_addr} has opened a connection")

        if self.framed:
            reader = TFramedTransport(reader)
            writer = TFramedTransport(writer)

        iproto = self.protocol_cls(reader)
        oproto = self.protocol_cls(writer)

        try:
            while not reader.at_eof():
                with async_timeout.timeout(self.timeout):
                    await self.processor.process(iproto, oproto)
        except ConnectionError:
            logger.debug(f"client {client_addr} has closed the connection (ConnectionError)")
        except asyncio.TimeoutError:
            logger.debug(f"timeout when processing the client request from {client_addr}")
        except asyncio.IncompleteReadError:
            logger.debug(f"client {client_addr} has closed the connection (asyncio.IncompleteReadError)")
        except Exception:
            # app exception
            logger.exception("unhandled app exception")
        finally:
            writer.close()
            await writer.wait_closed()

async def create_server(
    service,
    handler,
    address=("127.0.0.1", 6000),
    protocol_cls=TBinaryProtocol,
    timeout=None,
    framed=False,
    **kw,
):
    """ create a thrift server.
    This function is a :ref:`coroutine <coroutine>`.

    :param service: thrift Service
    :param handler: a dispatcher object which is a namespace for all thrift api functions.
    :param address:  (host, port) tuple, default is ('127.0.0.1', 6000)
    :param protocol_cls: thrift protocol class, default is :class:`TBinaryProtocol`
    :param timeout: server side timeout, default is None
    :param kw: params relaied to asyncio.start_server
    :return: a :class:`Server` object which can be used to stop the service
    """
    host, port = address
    processor = TProcessor(service, handler)
    server = await asyncio.start_server(
        Server(processor, protocol_cls, timeout=timeout, framed=framed), host, port, **kw
    )
    return server
<commit_msg>BUG: writer.wait_closed throws error if connection resets (#2)<commit_after>import asyncio

import async_timeout

from .log import logger
from .processor import TProcessor
from .protocol import TBinaryProtocol, TFramedTransport

class Server:
    def __init__(self, processor, protocol_cls=TBinaryProtocol, timeout=None, framed=False):
        self.processor = processor
        self.protocol_cls = protocol_cls
        self.timeout = timeout
        self.framed = framed

    async def __call__(self, reader, writer):
        client_addr = writer.get_extra_info('peername')
        logger.debug(f"client {client_addr} has opened a connection")

        if self.framed:
            reader = TFramedTransport(reader)
            writer = TFramedTransport(writer)

        iproto = self.protocol_cls(reader)
        oproto = self.protocol_cls(writer)

        try:
            while not reader.at_eof():
                with async_timeout.timeout(self.timeout):
                    await self.processor.process(iproto, oproto)
        except ConnectionError:
            logger.debug(f"client {client_addr} has closed the connection (ConnectionError)")
        except asyncio.TimeoutError:
            logger.debug(f"timeout when processing the client request from {client_addr}")
        except asyncio.IncompleteReadError:
            logger.debug(f"client {client_addr} has closed the connection")
        except Exception:
            # app exception
            logger.exception("unhandled app exception")
        finally:
            writer.close()

async def create_server(
    service,
    handler,
    address=("127.0.0.1", 6000),
    protocol_cls=TBinaryProtocol,
    timeout=None,
    framed=False,
    **kw,
):
    """ create a thrift server.
    This function is a :ref:`coroutine <coroutine>`.

    :param service: thrift Service
    :param handler: a dispatcher object which is a namespace for all thrift api functions.
    :param address:  (host, port) tuple, default is ('127.0.0.1', 6000)
    :param protocol_cls: thrift protocol class, default is :class:`TBinaryProtocol`
    :param timeout: server side timeout, default is None
    :param kw: params relaied to asyncio.start_server
    :return: a :class:`Server` object which can be used to stop the service
    """
    host, port = address
    processor = TProcessor(service, handler)
    server = await asyncio.start_server(
        Server(processor, protocol_cls, timeout=timeout, framed=framed), host, port, **kw
    )
    return server
<|endoftext|>


<commit_before># This software and any associated files are copyright 2010 Brian Carver and
# Michael Lissner.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#  Under Sections 7(a) and 7(b) of version 3 of the GNU Affero General Public
#  License, that license is supplemented by the following terms:
#
#  a) You are required to preserve this legal notice and all author
#  attributions in this program and its accompanying documentation.
#
#  b) You are prohibited from misrepresenting the origin of any material
#  within this covered work and you are required to mark in reasonable
#  ways how any modified versions differ from the original version.

import settings
from django.core.management import setup_environ
setup_environ(settings)

from alert.alertSystem.models import Document
from optparse import OptionParser
import gc, errno, os, os.path, string, time

'''
This script finds all the documents that have PDF in their local_path field,
moves them to the correct pdf directory, then renames their extension so it's
pdf, not PDF.
'''

def queryset_iterator(queryset, chunksize=100):
    '''
    from: http://djangosnippets.org/snippets/1949/
    Iterate over a Django Queryset ordered by the primary key

    This method loads a maximum of chunksize (default: 1000) rows in its
    memory at the same time while django normally would load all rows in its
    memory. Using the iterator() method only causes it to not preload all the
    classes.

    Note that the implementation of the iterator does not support ordered query sets.
    '''
    documentUUID = 0
    last_pk = queryset.order_by('-documentUUID')[0].documentUUID
    queryset = queryset.order_by('documentUUID')
    while documentUUID < last_pk:
        for row in queryset.filter(documentUUID__gt=documentUUID)[:chunksize]:
            documentUUID = row.documentUUID
            yield row
        gc.collect()

def mkdir_p(path):
    # make a directory and its parents, if it doesn't exist
    try:
        os.makedirs(path)
    except OSError as exc: # Python >2.5
        if exc.errno == errno.EEXIST:
            pass
        else: raise

def update_new_path(doc):
    '''
    Iterate over ALL files, and check if their local_path field corresponds
    with a file in PDF. If so, move the file, assuming it doesn't create a
    collision.
    '''
    root = settings.MEDIA_ROOT
    new_path = str(doc.local_path)
    new_path_full = os.path.join(root, new_path)

    old_path_full = new_path_full.replace('pdf', 'PDF')

    # If the old path already exists, then it's a hit.
    # We need to move the file to a better location.
    if os.exists(old_path_full):
        # Before we move it, we need to check if we can move it to a new location
        # without a collision occuring.
        if os.exists(new_path_full):
            new_path_full = new_path_full + '_2'
            new_path = new_path + '_2'
            doc.local_path = new_path
            doc.save()

            if os.path.exists(new_path_full):
                new_path_full = new_path_full[:-2] + '_3'
                new_path = new_path[:-2] + '_3'
                doc.local_path = new_path
                doc.save()

                if os.path.exists(new_path_full):
                    new_path_full = new_path_full[:-2] + '_4'
                    new_path = new_path[:-2] + '_4'
                    doc.local_path = new_path
                    doc.save()

                    if os.path.exists(new_path_full):
                        print "Insane. The thing existed four times!"
                    exit(1)

    # Path existing problems are solved. Move the thing.
    os.rename(old_path_full, new_path_full)

def update_path(doc):
    # Rename the path
    old_path = str(doc.local_path)
    new_path = old_path.replace('PDF', 'pdf')
    doc.local_path = new_path
    doc.save()

    # Move the file
    root = settings.MEDIA_ROOT
    old_path_full = os.path.join(root, old_path)
    new_path_full = os.path.join(root, new_path)

    # Check if the file already exists. Fix if so.
    if os.path.exists(new_path_full):
        # Problem. Fix it. Recursion would make this less terrible.
        new_path_full = new_path_full + '_2'
        new_path = new_path + '_2'
        doc.local_path = new_path
        doc.save()

        if os.path.exists(new_path_full):
            new_path_full = new_path_full[:-2] + '_3'
            new_path = new_path[:-2] + '_3'
            doc.local_path = new_path
            doc.save()

            if os.path.exists(new_path_full):
                new_path_full = new_path_full[:-2] + '_4'
                new_path = new_path[:-2] + '_4'
                doc.local_path = new_path
                doc.save()

                if os.path.exists(new_path_full):
                    print "Insane. The thing existed four times!"
                    exit(1)

    # Path existing problems are solved. Move the thing.
    os.rename(old_path_full, new_path_full)

def main():
    usage = "usage: %prog"
    parser = OptionParser(usage)
    (options, args) = parser.parse_args()

    # run the script across the entire DB
    queryset = queryset_iterator(Document.objects.all())
    for doc in queryset:
        update_new_path(doc)
    exit(0)

if __name__ == '__main__':
    main()
<commit_msg>A new version of the PDF tool.<commit_after># This software and any associated files are copyright 2010 Brian Carver and
# Michael Lissner.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#  Under Sections 7(a) and 7(b) of version 3 of the GNU Affero General Public
#  License, that license is supplemented by the following terms:
#
#  a) You are required to preserve this legal notice and all author
#  attributions in this program and its accompanying documentation.
#
#  b) You are prohibited from misrepresenting the origin of any material
#  within this covered work and you are required to mark in reasonable
#  ways how any modified versions differ from the original version.

import settings
from django.core.management import setup_environ
setup_environ(settings)

from alert.alertSystem.models import Document
from optparse import OptionParser
import gc, errno, os, os.path, string, time

'''
This script finds all the documents that have PDF in their local_path field,
moves them to the correct pdf directory, then renames their extension so it's
pdf, not PDF.
'''

def queryset_iterator(queryset, chunksize=100):
    '''
    from: http://djangosnippets.org/snippets/1949/
    Iterate over a Django Queryset ordered by the primary key

    This method loads a maximum of chunksize (default: 1000) rows in its
    memory at the same time while django normally would load all rows in its
    memory. Using the iterator() method only causes it to not preload all the
    classes.

    Note that the implementation of the iterator does not support ordered query sets.
    '''
    documentUUID = 0
    last_pk = queryset.order_by('-documentUUID')[0].documentUUID
    queryset = queryset.order_by('documentUUID')
    while documentUUID < last_pk:
        for row in queryset.filter(documentUUID__gt=documentUUID)[:chunksize]:
            documentUUID = row.documentUUID
            yield row
        gc.collect()

def mkdir_p(path):
    # make a directory and its parents, if it doesn't exist
    try:
        os.makedirs(path)
    except OSError as exc: # Python >2.5
        if exc.errno == errno.EEXIST:
            pass
        else: raise

def update_new_path(doc):
    '''
    Iterate over ALL files, and check if their local_path field corresponds
    with a file in PDF. If so, move the file, assuming it doesn't create a
    collision.
    '''
    root = settings.MEDIA_ROOT
    new_path = str(doc.local_path)
    new_path_full = os.path.join(root, new_path)

    old_path_full = new_path_full.replace('pdf', 'PDF')
    print "Old Path: " + old_path_full

    # If the old path already exists, then it's a hit.
    # We need to move the file to a better location.
    if os.exists(old_path_full):
        print "Old path exists."
        # Before we move it, we need to check if we can move it to a new location
        # without a collision occuring.
        if os.exists(new_path_full):
            new_path_full = new_path_full + '_2'
            new_path = new_path + '_2'
            doc.local_path = new_path
            doc.save()

            if os.path.exists(new_path_full):
                new_path_full = new_path_full[:-2] + '_3'
                new_path = new_path[:-2] + '_3'
                doc.local_path = new_path
                doc.save()

                if os.path.exists(new_path_full):
                    new_path_full = new_path_full[:-2] + '_4'
                    new_path = new_path[:-2] + '_4'
                    doc.local_path = new_path
                    doc.save()

                    if os.path.exists(new_path_full):
                        print "Insane. The thing existed four times!"
                    exit(1)

    # Path existing problems are solved. Move the thing.
    print "Moving file to: " + new_path_full
    os.rename(old_path_full, new_path_full)

def update_path(doc):
    # Rename the path
    old_path = str(doc.local_path)
    new_path = old_path.replace('PDF', 'pdf')
    doc.local_path = new_path
    doc.save()

    # Move the file
    root = settings.MEDIA_ROOT
    old_path_full = os.path.join(root, old_path)
    new_path_full = os.path.join(root, new_path)

    # Check if the file already exists. Fix if so.
    if os.path.exists(new_path_full):
        # Problem. Fix it. Recursion would make this less terrible.
        new_path_full = new_path_full + '_2'
        new_path = new_path + '_2'
        doc.local_path = new_path
        doc.save()

        if os.path.exists(new_path_full):
            new_path_full = new_path_full[:-2] + '_3'
            new_path = new_path[:-2] + '_3'
            doc.local_path = new_path
            doc.save()

            if os.path.exists(new_path_full):
                new_path_full = new_path_full[:-2] + '_4'
                new_path = new_path[:-2] + '_4'
                doc.local_path = new_path
                doc.save()

                if os.path.exists(new_path_full):
                    print "Insane. The thing existed four times!"
                    exit(1)

    # Path existing problems are solved. Move the thing.
    os.rename(old_path_full, new_path_full)

def main():
    usage = "usage: %prog"
    parser = OptionParser(usage)
    (options, args) = parser.parse_args()

    # run the script across the entire DB
    queryset = queryset_iterator(Document.objects.all())
    for doc in queryset:
        update_new_path(doc)
    exit(0)

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>from enum import Enum

from django.contrib.auth.models import User
from django.contrib.gis.db import models

from django.utils import timezone
from django.urls import reverse

from emstrack.models import AddressModel, UpdatedByModel, defaults

# User and ambulance location models

# Ambulance model

class AmbulanceStatus(Enum):
    UK = 'Unknown'
    AV = 'Available'
    OS = 'Out of service'
    PB = 'Patient bound'
    AP = 'At patient'
    HB = 'Hospital bound'
    AH = 'At hospital'

class AmbulanceCapability(Enum):
    B = 'Basic'
    A = 'Advanced'
    R = 'Rescue'

class Ambulance(UpdatedByModel):

    # ambulance properties
    identifier = models.CharField(max_length=50, unique=True)

    AMBULANCE_CAPABILITY_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCapability]
    capability = models.CharField(max_length=1,
                                  choices = AMBULANCE_CAPABILITY_CHOICES)

    # status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default = 0)
    location = models.PointField(srid=4326, default = defaults['location'])
    location_timestamp = models.DateTimeField(null=True, blank=True)

    @classmethod
    def from_db(cls, db, field_names, values):
        # call super
        instance = super(Ambulance, cls).from_db(db, field_names, values)

        # store the original field values on the instance
        instance._loaded_values = dict(zip(field_names, values))

        # return instance
        return instance

    def save(self, *args, **kwargs):
        # save to Ambulance
        super().save(*args, **kwargs)

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_ambulance(self)

        # save to AmbulanceUpdate
        data = {k: getattr(self, k)
                for k in ('status', 'orientation',
                          'location', 'location_timestamp',
                          'comment', 'updated_by', 'updated_on')}
        data['ambulance'] = self;
        obj = AmbulanceUpdate(**data)
        obj.save()

    def delete(self, *args, **kwargs):
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_ambulance(self)
        super().delete(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('ambulance:detail', kwargs={'pk': self.id})

    def __str__(self):
        return ('Ambulance {}(id={}) ({}) [{}]:\n' +
                '    Status: {}\n' +
                '  Location: {} @ {}\n' +
                '   Updated: {} by {}').format(self.identifier,
                                               self.id,
                                               AmbulanceCapability[self.capability].value,
                                               self.comment,
                                               AmbulanceStatus[self.status].value,
                                               self.location,
                                               self.location_timestamp,
                                               self.updated_by,
                                               self.updated_on)

class AmbulanceUpdate(models.Model):

    # ambulance id
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # ambulance status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default = 0)
    location = models.PointField(srid=4326, default = defaults['location'])
    location_timestamp = models.DateTimeField(null=True, blank=True)

    # updated by
    comment = models.CharField(max_length=254, null=True, blank=True)
    updated_by = models.ForeignKey(User,
                                   on_delete=models.CASCADE)
    updated_on = models.DateTimeField()

# Call related models

class AmbulanceCallTimes(models.Model):

    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE, default=1)

    dispatch_time = models.DateTimeField(null=True, blank=True)
    departure_time = models.DateTimeField(null=True, blank=True)
    patient_time = models.DateTimeField(null=True, blank=True)
    hospital_time = models.DateTimeField(null=True, blank=True)
    end_time = models.DateTimeField(null=True, blank=True)

# Patient might be expanded in the future

class Patient(models.Model):
    """
    A model that provides patient fields.
    """

    name = models.CharField(max_length=254, default = "")
    age = models.IntegerField(null=True)

class CallPriority(Enum):
    A = 'Urgent'
    B = 'Emergency'
    C = 'C'
    D = 'D'
    E = 'Not urgent'

class Call(AddressModel, UpdatedByModel):

    # active status
    active = models.BooleanField(default=False)

    # ambulances assigned to call
    ambulances = models.ManyToManyField(AmbulanceCallTimes)

    # patients
    patients = models.ManyToManyField(Patient)

    # details
    details = models.CharField(max_length=500, default = "")

    # call priority
    CALL_PRIORITY_CHOICES = \
        [(m.name, m.value) for m in CallPriority]
    priority = models.CharField(max_length=1,
                                choices=CALL_PRIORITY_CHOICES,
                                default=CallPriority.E.name)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "{} ({})".format(self.location, self.priority)

# Location related models

class LocationType(Enum):
    B = 'Base'
    A = 'AED'
    O = 'Other'

class Location(AddressModel, UpdatedByModel):

    # location name
    name = models.CharField(max_length=254, unique=True)

    # location type
    LOCATION_TYPE_CHOICES = \
        [(m.name, m.value) for m in LocationType]
    priority = models.CharField(max_length=1,
                                choices=LOCATION_TYPE_CHOICES,
                                default=LocationType.O.name)

    # location
    location = models.PointField(srid=4326, null=True)

    def __str__(self):
        return "{} @{} ({})".format(self.name, self.location, self.comment)

# THOSE NEED REVIEWING

class Region(models.Model):
    name = models.CharField(max_length=254, unique=True)
    center = models.PointField(srid=4326, null=True)

    def __str__(self):
        return self.name<commit_msg>Changed location_timestamp to default to timezone.now instead of allowing blank or null.<commit_after>from enum import Enum

from django.contrib.auth.models import User
from django.contrib.gis.db import models

from django.utils import timezone
from django.urls import reverse

from emstrack.models import AddressModel, UpdatedByModel, defaults

# User and ambulance location models

# Ambulance model

class AmbulanceStatus(Enum):
    UK = 'Unknown'
    AV = 'Available'
    OS = 'Out of service'
    PB = 'Patient bound'
    AP = 'At patient'
    HB = 'Hospital bound'
    AH = 'At hospital'

class AmbulanceCapability(Enum):
    B = 'Basic'
    A = 'Advanced'
    R = 'Rescue'

class Ambulance(UpdatedByModel):

    # ambulance properties
    identifier = models.CharField(max_length=50, unique=True)

    AMBULANCE_CAPABILITY_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCapability]
    capability = models.CharField(max_length=1,
                                  choices = AMBULANCE_CAPABILITY_CHOICES)

    # status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default = 0)
    location = models.PointField(srid=4326, default = defaults['location'])
    location_timestamp = models.DateTimeField(default=timezone.now)

    @classmethod
    def from_db(cls, db, field_names, values):
        # call super
        instance = super(Ambulance, cls).from_db(db, field_names, values)

        # store the original field values on the instance
        instance._loaded_values = dict(zip(field_names, values))

        # return instance
        return instance

    def save(self, *args, **kwargs):
        # save to Ambulance
        super().save(*args, **kwargs)

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_ambulance(self)

        # save to AmbulanceUpdate
        data = {k: getattr(self, k)
                for k in ('status', 'orientation',
                          'location', 'location_timestamp',
                          'comment', 'updated_by', 'updated_on')}
        data['ambulance'] = self;
        obj = AmbulanceUpdate(**data)
        obj.save()

    def delete(self, *args, **kwargs):
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_ambulance(self)
        super().delete(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('ambulance:detail', kwargs={'pk': self.id})

    def __str__(self):
        return ('Ambulance {}(id={}) ({}) [{}]:\n' +
                '    Status: {}\n' +
                '  Location: {} @ {}\n' +
                '   Updated: {} by {}').format(self.identifier,
                                               self.id,
                                               AmbulanceCapability[self.capability].value,
                                               self.comment,
                                               AmbulanceStatus[self.status].value,
                                               self.location,
                                               self.location_timestamp,
                                               self.updated_by,
                                               self.updated_on)

class AmbulanceUpdate(models.Model):

    # ambulance id
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # ambulance status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default = 0)
    location = models.PointField(srid=4326, default = defaults['location'])
    location_timestamp = models.DateTimeField(null=True, blank=True)

    # updated by
    comment = models.CharField(max_length=254, null=True, blank=True)
    updated_by = models.ForeignKey(User,
                                   on_delete=models.CASCADE)
    updated_on = models.DateTimeField()

# Call related models

class AmbulanceCallTimes(models.Model):

    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE, default=1)

    dispatch_time = models.DateTimeField(null=True, blank=True)
    departure_time = models.DateTimeField(null=True, blank=True)
    patient_time = models.DateTimeField(null=True, blank=True)
    hospital_time = models.DateTimeField(null=True, blank=True)
    end_time = models.DateTimeField(null=True, blank=True)

# Patient might be expanded in the future

class Patient(models.Model):
    """
    A model that provides patient fields.
    """

    name = models.CharField(max_length=254, default = "")
    age = models.IntegerField(null=True)

class CallPriority(Enum):
    A = 'Urgent'
    B = 'Emergency'
    C = 'C'
    D = 'D'
    E = 'Not urgent'

class Call(AddressModel, UpdatedByModel):

    # active status
    active = models.BooleanField(default=False)

    # ambulances assigned to call
    ambulances = models.ManyToManyField(AmbulanceCallTimes)

    # patients
    patients = models.ManyToManyField(Patient)

    # details
    details = models.CharField(max_length=500, default = "")

    # call priority
    CALL_PRIORITY_CHOICES = \
        [(m.name, m.value) for m in CallPriority]
    priority = models.CharField(max_length=1,
                                choices=CALL_PRIORITY_CHOICES,
                                default=CallPriority.E.name)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "{} ({})".format(self.location, self.priority)

# Location related models

class LocationType(Enum):
    B = 'Base'
    A = 'AED'
    O = 'Other'

class Location(AddressModel, UpdatedByModel):

    # location name
    name = models.CharField(max_length=254, unique=True)

    # location type
    LOCATION_TYPE_CHOICES = \
        [(m.name, m.value) for m in LocationType]
    ltype = models.CharField(max_length=1,
                             choices=LOCATION_TYPE_CHOICES,
                             default=LocationType.O.name)

    # location
    location = models.PointField(srid=4326, null=True)

    def __str__(self):
        return "{} @{} ({})".format(self.name, self.location, self.comment)

# THOSE NEED REVIEWING

class Region(models.Model):
    name = models.CharField(max_length=254, unique=True)
    center = models.PointField(srid=4326, null=True)

    def __str__(self):
        return self.name<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
import six
import json
from django import VERSION as DJANGO_VERSION
from django.core.exceptions import ValidationError
from django.forms import widgets
from django.utils.html import escape, format_html, format_html_join
from django.utils.translation import ugettext_lazy as _, ugettext

class JSONMultiWidget(widgets.MultiWidget):
    """Base class for MultiWidgets using a JSON field in database"""
    def __init__(self, glossary_fields):
        unique_keys = set([field.name for field in glossary_fields])
        if len(glossary_fields) > len(unique_keys):
            raise AttributeError('List of glossary_fields may contain only unique keys')
        self.glossary_fields = glossary_fields[:]
        super(JSONMultiWidget, self).__init__((field.widget for field in glossary_fields))

    def decompress(self, values):
        if not isinstance(values, dict):
            values = json.loads(values or '{}')
        for field in self.glossary_fields:
            if isinstance(field.widget, widgets.MultiWidget):
                values[field.name] = field.widget.decompress(values.get(field.name))
            else:
                values.setdefault(field.name, field.initial)
        return values

    def value_from_datadict(self, data, files, name):
        result = {}
        for field in self.glossary_fields:
            if isinstance(field.widget, widgets.MultiWidget):
                result[field.name] = field.widget.value_from_datadict(data, files, field.name)
            elif getattr(field.widget, 'allow_multiple_selected', False):
                result[field.name] = list(map(escape, data.getlist(field.name)))
            else:
                result[field.name] = escape(data.get(field.name, ''))
        return result

    def render(self, name, values, attrs):
        values = self.decompress(values)
        field_attrs = dict(**attrs)
        render_fields = []
        for field in self.glossary_fields:
            field_attrs['id'] = attrs['id'] + '_' + field.name
            render_fields.append((
                field.name,
                six.text_type(field.label),
                field.widget.render(field.name, values.get(field.name), field_attrs),
                six.text_type(field.help_text)
            ))
        html = format_html_join('\n',
            '

{1}

{2}
{3}
',
            render_fields)
        return html

if DJANGO_VERSION[0] <= 1 and DJANGO_VERSION[1] <= 5:
    input_widget = widgets.TextInput
else:
    input_widget = widgets.NumberInput

class NumberInputWidget(input_widget):
    validation_pattern = re.compile('^\d+$')
    required = True
    required_message = _("In '%(label)s': This field is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' shall contain a valid number.")

    def validate(self, value):
        if not self.validation_pattern.match(value):
            raise ValidationError(self.validation_message, code='invalid', params={'value': value})

def _compile_validation_pattern(widget, units):
    """
    Assure that passed in units are valid size units.
    Return a tuple with a regular expression to be used for validating and a message if this
    validation failed.
    """
    for u in units:
        if u not in widget.POSSIBLE_UNITS:
            raise ValidationError('{0} is not a valid unit for CascadingSizeField'.format(u))
    endings = (' %s ' % ugettext("or")).join("'%s'" % u.replace('%', '%%') for u in units)
    params = {'label': '%(label)s', 'value': '%(value)s', 'field': '%(field)s', 'endings': endings}
    return re.compile(r'^(\d+)\s*({0})$'.format('|'.join(units))), widget.invalid_message % params

class CascadingSizeWidget(widgets.TextInput):
    """
    Use this field for validating Input Fields containing a value ending in ``px``, ``em`` or ``%``.
    Use it for values representing a margin, padding, width or height.
    """
    POSSIBLE_UNITS = ['px', 'em', '%']
    DEFAULT_ATTRS = {'style': 'width: 5em;'}
    required_message = _("In '%(label)s': This field is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' shall contain a valid number, ending in %(endings)s.")

    def __init__(self, allowed_units=POSSIBLE_UNITS, attrs=DEFAULT_ATTRS, required=True):
        self.validation_pattern, self.invalid_message = _compile_validation_pattern(self, allowed_units)
        self.required = required
        super(CascadingSizeWidget, self).__init__(attrs=attrs)

    def validate(self, value):
        if not value:
            if self.required:
                raise ValidationError(self.required_message, code='required', params={})
            return
        match = self.validation_pattern.match(value)
        if not (match and match.group(1).isdigit()):
            params = {'value': value}
            raise ValidationError(self.invalid_message, code='invalid', params=params)

class MultipleTextInputWidget(widgets.MultiWidget):
    """
    A widgets accepting multiple input values to be used for rendering CSS inline styles.
    Additionally this widget validates the input data and raises a ValidationError
    """
    required = False

    def __init__(self, labels, required=None, attrs=None):
        text_widgets = [widgets.TextInput({'placeholder': label}) for label in labels]
        super(MultipleTextInputWidget, self).__init__(text_widgets, attrs)
        self.labels = labels[:]
        if required is not None:
            self.required = required
        self.validation_errors = []
        # check if derived classes contain proper error messages
        if hasattr(self, 'validation_pattern') and not hasattr(self, 'invalid_message'):
            raise AttributeError("Multiple...InputWidget class is missing element: 'invalid_message'")
        if self.required and not hasattr(self, 'required_message'):
            raise AttributeError("Multiple...InputWidget class is missing element: 'required_message'")

    def __iter__(self):
        self.validation_errors = []
        for label in self.labels:
            yield label

    def decompress(self, values):
        if not isinstance(values, dict):
            values = {}
        for key in self.labels:
            values.setdefault(key, None)
        return values

    def value_from_datadict(self, data, files, name):
        values = {}
        for key in self.labels:
            values[key] = escape(data.get('{0}-{1}'.format(name, key), ''))
        return values

    def render(self, name, values, attrs):
        widgets = []
        values = values or {}
        for index, key in enumerate(self.labels):
            label = '{0}-{1}'.format(name, key)
            errors = key in self.validation_errors and 'errors' or ''
            widgets.append((self.widgets[index].render(label, values.get(key), attrs), errors))
        return format_html('
{0}
',
                    format_html_join('\n', '
{0}
', widgets))

    def validate(self, value, field_name):
        if hasattr(self, 'validation_pattern'):
            val = value.get(field_name)
            if not val:
                if self.required:
                    raise ValidationError(self.required_message, code='required', params={'field': field_name})
                return
            if val and not self.validation_pattern.match(val):
                self.validation_errors.append(field_name)
                params = {'value': val, 'field': field_name}
                raise ValidationError(self.invalid_message, code='invalid', params=params)

class MultipleCascadingSizeWidget(MultipleTextInputWidget):
    POSSIBLE_UNITS = ['px', 'em', '%']
    DEFAULT_ATTRS = {'style': 'width: 4em;'}
    required_message = _("In '%(label)s': Field '%(field)s' is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' for field '%(field)s' shall contain a valid number, ending in %(endings)s.")

    def __init__(self, labels, allowed_units=POSSIBLE_UNITS, attrs=DEFAULT_ATTRS, required=True):
        self.validation_pattern, self.invalid_message = _compile_validation_pattern(self, allowed_units)
        self.required = required
        super(MultipleCascadingSizeWidget, self).__init__(labels, attrs=attrs)
<commit_msg>MultiValueWidget can be initialized<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
import six
import json
from django import VERSION as DJANGO_VERSION
from django.core.exceptions import ValidationError
from django.forms import widgets
from django.utils.html import escape, format_html, format_html_join
from django.utils.translation import ugettext_lazy as _, ugettext

class JSONMultiWidget(widgets.MultiWidget):
    """Base class for MultiWidgets using a JSON field in database"""
    def __init__(self, glossary_fields):
        unique_keys = set([field.name for field in glossary_fields])
        if len(glossary_fields) > len(unique_keys):
            raise AttributeError('List of glossary_fields may contain only unique keys')
        self.glossary_fields = glossary_fields[:]
        super(JSONMultiWidget, self).__init__((field.widget for field in glossary_fields))

    def decompress(self, values):
        if not isinstance(values, dict):
            values = json.loads(values or '{}')
        for field in self.glossary_fields:
            if isinstance(field.widget, widgets.MultiWidget):
                values[field.name] = field.widget.decompress(values.get(field.name, field.initial))
            else:
                values.setdefault(field.name, field.initial)
        return values

    def value_from_datadict(self, data, files, name):
        result = {}
        for field in self.glossary_fields:
            if isinstance(field.widget, widgets.MultiWidget):
                result[field.name] = field.widget.value_from_datadict(data, files, field.name)
            elif getattr(field.widget, 'allow_multiple_selected', False):
                result[field.name] = list(map(escape, data.getlist(field.name)))
            else:
                result[field.name] = escape(data.get(field.name, ''))
        return result

    def render(self, name, values, attrs):
        values = self.decompress(values)
        field_attrs = dict(**attrs)
        render_fields = []
        for field in self.glossary_fields:
            field_attrs['id'] = attrs['id'] + '_' + field.name
            render_fields.append((
                field.name,
                six.text_type(field.label),
                field.widget.render(field.name, values.get(field.name), field_attrs),
                six.text_type(field.help_text)
            ))
        html = format_html_join('\n',
            '

{1}

{2}
{3}
',
            render_fields)
        return html

if DJANGO_VERSION[0] <= 1 and DJANGO_VERSION[1] <= 5:
    input_widget = widgets.TextInput
else:
    input_widget = widgets.NumberInput

class NumberInputWidget(input_widget):
    validation_pattern = re.compile('^\d+$')
    required = True
    required_message = _("In '%(label)s': This field is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' shall contain a valid number.")

    def validate(self, value):
        if not self.validation_pattern.match(value):
            raise ValidationError(self.validation_message, code='invalid', params={'value': value})

def _compile_validation_pattern(widget, units):
    """
    Assure that passed in units are valid size units.
    Return a tuple with a regular expression to be used for validating and a message if this
    validation failed.
    """
    for u in units:
        if u not in widget.POSSIBLE_UNITS:
            raise ValidationError('{0} is not a valid unit for CascadingSizeField'.format(u))
    endings = (' %s ' % ugettext("or")).join("'%s'" % u.replace('%', '%%') for u in units)
    params = {'label': '%(label)s', 'value': '%(value)s', 'field': '%(field)s', 'endings': endings}
    return re.compile(r'^(\d+)\s*({0})$'.format('|'.join(units))), widget.invalid_message % params

class CascadingSizeWidget(widgets.TextInput):
    """
    Use this field for validating Input Fields containing a value ending in ``px``, ``em`` or ``%``.
    Use it for values representing a margin, padding, width or height.
    """
    POSSIBLE_UNITS = ['px', 'em', '%']
    DEFAULT_ATTRS = {'style': 'width: 5em;'}
    required_message = _("In '%(label)s': This field is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' shall contain a valid number, ending in %(endings)s.")

    def __init__(self, allowed_units=POSSIBLE_UNITS, attrs=DEFAULT_ATTRS, required=True):
        self.validation_pattern, self.invalid_message = _compile_validation_pattern(self, allowed_units)
        self.required = required
        super(CascadingSizeWidget, self).__init__(attrs=attrs)

    def validate(self, value):
        if not value:
            if self.required:
                raise ValidationError(self.required_message, code='required', params={})
            return
        match = self.validation_pattern.match(value)
        if not (match and match.group(1).isdigit()):
            params = {'value': value}
            raise ValidationError(self.invalid_message, code='invalid', params=params)

class MultipleTextInputWidget(widgets.MultiWidget):
    """
    A widgets accepting multiple input values to be used for rendering CSS inline styles.
    Additionally this widget validates the input data and raises a ValidationError
    """
    required = False

    def __init__(self, labels, required=None, attrs=None):
        text_widgets = [widgets.TextInput({'placeholder': label}) for label in labels]
        super(MultipleTextInputWidget, self).__init__(text_widgets, attrs)
        self.labels = labels[:]
        if required is not None:
            self.required = required
        self.validation_errors = []
        # check if derived classes contain proper error messages
        if hasattr(self, 'validation_pattern') and not hasattr(self, 'invalid_message'):
            raise AttributeError("Multiple...InputWidget class is missing element: 'invalid_message'")
        if self.required and not hasattr(self, 'required_message'):
            raise AttributeError("Multiple...InputWidget class is missing element: 'required_message'")

    def __iter__(self):
        self.validation_errors = []
        for label in self.labels:
            yield label

    def decompress(self, values):
        if not isinstance(values, dict):
            values = {}
        for key in self.labels:
            values.setdefault(key, None)
        return values

    def value_from_datadict(self, data, files, name):
        values = {}
        for key in self.labels:
            values[key] = escape(data.get('{0}-{1}'.format(name, key), ''))
        return values

    def render(self, name, values, attrs):
        widgets = []
        values = values or {}
        for index, key in enumerate(self.labels):
            label = '{0}-{1}'.format(name, key)
            errors = key in self.validation_errors and 'errors' or ''
            widgets.append((self.widgets[index].render(label, values.get(key), attrs), errors))
        return format_html('
{0}
',
                    format_html_join('\n', '
{0}
', widgets))

    def validate(self, value, field_name):
        if hasattr(self, 'validation_pattern'):
            val = value.get(field_name)
            if not val:
                if self.required:
                    raise ValidationError(self.required_message, code='required', params={'field': field_name})
                return
            if val and not self.validation_pattern.match(val):
                self.validation_errors.append(field_name)
                params = {'value': val, 'field': field_name}
                raise ValidationError(self.invalid_message, code='invalid', params=params)

class MultipleCascadingSizeWidget(MultipleTextInputWidget):
    POSSIBLE_UNITS = ['px', 'em', '%']
    DEFAULT_ATTRS = {'style': 'width: 4em;'}
    required_message = _("In '%(label)s': Field '%(field)s' is required.")
    invalid_message = _("In '%(label)s': Value '%(value)s' for field '%(field)s' shall contain a valid number, ending in %(endings)s.")

    def __init__(self, labels, allowed_units=POSSIBLE_UNITS, attrs=DEFAULT_ATTRS, required=True):
        self.validation_pattern, self.invalid_message = _compile_validation_pattern(self, allowed_units)
        self.required = required
        super(MultipleCascadingSizeWidget, self).__init__(labels, attrs=attrs)
<|endoftext|>


<commit_before>"""cmsplugin_zinnia"""
__version__ = '0.2.dev'
__license__ = 'BSD License'

__author__ = 'Fantomas42'
__email__ = 'fantomas42@gmail.com'

__url__ = 'https://github.com/Fantomas42/cmsplugin-zinnia'
<commit_msg>bumping to version 0.2<commit_after>"""cmsplugin_zinnia"""
__version__ = '0.2'
__license__ = 'BSD License'

__author__ = 'Fantomas42'
__email__ = 'fantomas42@gmail.com'

__url__ = 'https://github.com/Fantomas42/cmsplugin-zinnia'
<|endoftext|>


<commit_before>"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import sys
import traceback
from coalib.misc.StringConstants import StringConstants
from coalib.misc.i18n import _
from coalib.output.LOG_LEVEL import LOG_LEVEL
from coalib.processes.Process import Process
from coalib.processes.communication.LogMessage import LogMessage

class Analyser(Process):
    """
    This is the base class for every analyser. If you want to write an analyser, inherit from this class and overwrite
    at least the run_analyser method. You can send debug/warning/error messages through the debug_msg(), warn_msg(),
    fail_msg() functions. These will send the appropriate messages so that they are outputted. Be aware that if you
    use fail_msg(), you are expected to also terminate the analyser run-through immediately.

    If you need some setup or teardown for your analyser, feel free to overwrite the set_up() and tear_down() functions.
    They will be invoked before/after every run_analyser invocation.

    Settings are available at all times through self.settings. You can access the translation database with the self._()
    function, it will be routed to the usual gettext _(). Be aware that the strings you use are not necessarily in the
    database, especially if your analyser is not shipped with coala. Feel free to use your own translation database in
    this case or consider make your analyser available to the coala project.
    """
    def __init__(self, settings,
                 message_queue,
                 TIMEOUT=0.2):
        self.settings = settings
        self.message_queue = message_queue
        self.TIMEOUT = TIMEOUT

    def _(self, msg):
        return _(msg)

    def set_up(self):
        pass

    def tear_down(self):
        pass

    def debug_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.DEBUG, delimiter, *args)

    def warn_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.WARNING, delimiter, *args)

    def fail_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.ERROR, delimiter, *args)

    def __send_msg(self, log_level, delimiter, *args):
        if len(args) == 0:
            return

        msg = ""
        for i in range(len(args) - 1):
            msg += str(args[i]) + str(delimiter)
        msg += str(args[-1])

        self.message_queue.put(LogMessage(log_level, msg), timeout=self.TIMEOUT)

    def run_analyser(self):
        raise NotImplementedError

    def run(self):
        try:
            self.debug_msg(_("Setting up analyser..."))
            self.set_up()
            self.debug_msg(_("Running analyser..."))
            retval = self.run_analyser()
            self.debug_msg(_("Tearing down analyser..."))
            self.tear_down()

            return retval
        except:
            exception = sys.exc_info()
            self.debug_msg(_("Unknown failure in worker process.\n"
                             "Exception: {}\nTraceback:\n{}").format(str(exception[0]),
                                                                     traceback.extract_tb(exception[2])))
            self.warn_msg(_("An unknown failure occurred and an analyzer run is aborted."),
                          StringConstants.THIS_IS_A_BUG)

    @staticmethod
    def kind():
        """
        :return: The kind of the analyser
        """
        raise NotImplementedError

    @staticmethod
    def get_needed_settings():
        """
        This method has to determine which settings are needed by this analyser. The user will be prompted for needed
        settings that are not available in the settings file so don't include settings where a default value would do.

        :return: a dictionary of needed settings as keys and help texts as values
        """
        return {}
<commit_msg>Analyser: Codestyle fix<commit_after>"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import sys
import traceback
from coalib.misc.StringConstants import StringConstants
from coalib.misc.i18n import _
from coalib.output.LOG_LEVEL import LOG_LEVEL
from coalib.processes.Process import Process
from coalib.processes.communication.LogMessage import LogMessage

class Analyser(Process):
    """
    This is the base class for every analyser. If you want to write an analyser, inherit from this class and overwrite
    at least the run_analyser method. You can send debug/warning/error messages through the debug_msg(), warn_msg(),
    fail_msg() functions. These will send the appropriate messages so that they are outputted. Be aware that if you
    use fail_msg(), you are expected to also terminate the analyser run-through immediately.

    If you need some setup or teardown for your analyser, feel free to overwrite the set_up() and tear_down() functions.
    They will be invoked before/after every run_analyser invocation.

    Settings are available at all times through self.settings. You can access the translation database with the self._()
    function, it will be routed to the usual gettext _(). Be aware that the strings you use are not necessarily in the
    database, especially if your analyser is not shipped with coala. Feel free to use your own translation database in
    this case or consider make your analyser available to the coala project.
    """
    def __init__(self,
                 settings,
                 message_queue,
                 TIMEOUT=0.2):
        self.settings = settings
        self.message_queue = message_queue
        self.TIMEOUT = TIMEOUT

    def _(self, msg):
        return _(msg)

    def set_up(self):
        pass

    def tear_down(self):
        pass

    def debug_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.DEBUG, delimiter, *args)

    def warn_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.WARNING, delimiter, *args)

    def fail_msg(self, *args, delimiter=' '):
        self.__send_msg(LOG_LEVEL.ERROR, delimiter, *args)

    def __send_msg(self, log_level, delimiter, *args):
        if len(args) == 0:
            return

        msg = ""
        for i in range(len(args) - 1):
            msg += str(args[i]) + str(delimiter)
        msg += str(args[-1])

        self.message_queue.put(LogMessage(log_level, msg), timeout=self.TIMEOUT)

    def run_analyser(self):
        raise NotImplementedError

    def run(self):
        try:
            self.debug_msg(_("Setting up analyser..."))
            self.set_up()
            self.debug_msg(_("Running analyser..."))
            retval = self.run_analyser()
            self.debug_msg(_("Tearing down analyser..."))
            self.tear_down()

            return retval
        except:
            exception = sys.exc_info()
            self.debug_msg(_("Unknown failure in worker process.\n"
                             "Exception: {}\nTraceback:\n{}").format(str(exception[0]),
                                                                     traceback.extract_tb(exception[2])))
            self.warn_msg(_("An unknown failure occurred and an analyzer run is aborted."),
                          StringConstants.THIS_IS_A_BUG)

    @staticmethod
    def kind():
        """
        :return: The kind of the analyser
        """
        raise NotImplementedError

    @staticmethod
    def get_needed_settings():
        """
        This method has to determine which settings are needed by this analyser. The user will be prompted for needed
        settings that are not available in the settings file so don't include settings where a default value would do.

        :return: a dictionary of needed settings as keys and help texts as values
        """
        return {}
<|endoftext|>


<commit_before>"""Production settings and globals."""

from base import *  # NOQA
from boto.utils import get_instance_metadata

instance_metadata = get_instance_metadata(timeout=5)

if not instance_metadata:
    raise ImproperlyConfigured('Unable to access the instance metadata')

# HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in-production  # NOQA
ALLOWED_HOSTS = [
    'rf.azavea.com',
    '.elb.amazonaws.com',
    'localhost'
]

# ELBs use the instance IP in the Host header and ALLOWED_HOSTS checks against
# the Host header.
ALLOWED_HOSTS.append(instance_metadata['local-ipv4'])
# END HOST CONFIGURATION
<commit_msg>Temporarily disable SMTP email backend on staging/production<commit_after>"""Production settings and globals."""

from base import *  # NOQA
from boto.utils import get_instance_metadata

instance_metadata = get_instance_metadata(timeout=5)

if not instance_metadata:
    raise ImproperlyConfigured('Unable to access the instance metadata')

# HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in-production  # NOQA
ALLOWED_HOSTS = [
    'rf.azavea.com',
    '.elb.amazonaws.com',
    'localhost'
]

# ELBs use the instance IP in the Host header and ALLOWED_HOSTS checks against
# the Host header.
ALLOWED_HOSTS.append(instance_metadata['local-ipv4'])
# END HOST CONFIGURATION

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Metaswitch Networks
# All Rights Reserved.
#
#    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.

# Etcd-based transport for the Calico/OpenStack Plugin.

# Standard Python library imports.
import etcd
import eventlet
import eventlet.event
import json
import re
import weakref

# OpenStack imports.
from oslo.config import cfg
from neutron.openstack.common import log

# Calico imports.
from calico.datamodel_v1 import (READY_KEY, CONFIG_DIR, TAGS_KEY_RE, HOST_DIR,
                                 key_for_endpoint, PROFILE_DIR,
                                 key_for_profile, key_for_profile_rules,
                                 key_for_profile_tags, key_for_config)

# Register Calico-specific options.
calico_opts = [
    cfg.StrOpt('etcd_host', default='localhost',
               help="The hostname or IP of the etcd node/proxy"),
    cfg.IntOpt('etcd_port', default=4001,
               help="The port to use for the etcd node/proxy"),
]
cfg.CONF.register_opts(calico_opts, 'calico')

OPENSTACK_ENDPOINT_RE = re.compile(
    r'^' + HOST_DIR +
    r'/(?P<hostname>[^/]+)/.*openstack.*/endpoint/(?P<endpoint_id>[^/]+)')

json_decoder = json.JSONDecoder()

PERIODIC_RESYNC_INTERVAL_SECS = 30

LOG = log.getLogger(__name__)

class CalicoTransportEtcd(object):
    """Calico transport implementation based on etcd."""

    def __init__(self, driver):
        # Explicitly store the driver as a weakreference. This prevents
        # the reference loop between transport and driver keeping the objects
        # alive.
        self.driver = weakref.proxy(driver)

        # Prepare client for accessing etcd data.
        self.client = etcd.Client(host=cfg.CONF.calico.etcd_host,
                                  port=cfg.CONF.calico.etcd_port)

        # Spawn a green thread for periodically resynchronizing etcd against
        # the OpenStack database.
        eventlet.spawn(self.periodic_resync_thread)

    def periodic_resync_thread(self):
        while True:
            LOG.info("Calico plugin doing periodic resync.")
            try:
                # Write non-default config that Felices need.
                self.provide_felix_config()

                # Resynchronize endpoint data.
                self.resync_endpoints()

                # Resynchronize security group data.
                self.resync_security_groups()

            except:
                LOG.exception("Exception in periodic resync thread")

            # Sleep until time for next resync.
            LOG.info("Calico plugin finished periodic resync.  "
                     "Next resync in %s seconds.",
                     PERIODIC_RESYNC_INTERVAL_SECS)
            eventlet.sleep(PERIODIC_RESYNC_INTERVAL_SECS)

    def resync_endpoints(self):
        pass

    def resync_security_groups(self):
        pass

    def write_profile_to_etcd(self, profile):
        """
        Write a single security profile into etcd.
        """
        self.client.write(
            key_for_profile_rules(profile.id),
            json.dumps(profile_rules(profile))
        )
        self.client.write(
            key_for_profile_tags(profile.id),
            json.dumps(profile_tags(profile))
        )

    def endpoint_created(self, port):
        """
        Write appropriate data to etcd for an endpoint creation event.
        """
        # First, write etcd data for the new endpoint.
        self.write_port_to_etcd(port)

    def endpoint_updated(self, port, profile):
        """
        Write data to etcd for an endpoint updated event.
        """
        # Do the same as for endpoint_created.
        self.endpoint_created(port, profile)

    def endpoint_deleted(self, port):
        """
        Delete data from etcd for an endpoint deleted event.
        """
        # TODO: What do we do about profiles here?
        # Delete the etcd key for this endpoint.
        key = self.port_etcd_key(port)
        try:
            self.client.delete(key)
        except etcd.EtcdKeyNotFound:
            # Already gone, treat as success.
            LOG.debug("Key %s, which we were deleting, disappeared", key)

    def security_group_updated(self, sg):
        # Update the data that we're keeping for this security group.
        with self._sgs_semaphore:
            self.sgs[sg['id']] = sg

        # Identify all the needed profiles that incorporate this security
        # group, and rewrite their data.
        # Take the profile lock so that no-one can modify needed_profiles
        # while we iterate over it.  (This is probably unneeded since there
        # aren't any yield points in the loop but better safe than sorry.)
        profiles_to_rewrite = set()
        with self.profile_semaphore:
            for profile_id in self.needed_profiles:
                if sg['id'] in self.profile_tags(profile_id):
                    # Write etcd data for this profile.
                    profiles_to_rewrite.add(profile_id)
        for profile_id in profiles_to_rewrite:
            self.write_profile_to_etcd(profile_id)

    def write_port_to_etcd(self, port):
        """
        Writes a given port dictionary to etcd.
        """
        data = port_etcd_data(port)
        self.client.write(port_etcd_key(port), json.dumps(data))

    def provide_felix_config(self):
        """Specify the prefix of the TAP interfaces that Felix should
        look for and work with.  This config setting does not have a
        default value, because different cloud systems will do
        different things.  Here we provide the prefix that Neutron
        uses.
        """
        # First read the config values, so as to avoid unnecessary
        # writes.
        prefix = None
        ready = None
        iface_pfx_key = key_for_config('InterfacePrefix')
        try:
            prefix = self.client.read(iface_pfx_key).value
            ready = self.client.read(READY_KEY).value
        except etcd.EtcdKeyNotFound:
            LOG.info('%s values are missing', CONFIG_DIR)

        # Now write the values that need writing.
        if prefix != 'tap':
            LOG.info('%s -> tap', iface_pfx_key)
            self.client.write(iface_pfx_key, 'tap')
        if ready != 'true':
            # TODO Set this flag only once we're really ready!
            LOG.info('%s -> true', READY_KEY)
            self.client.write(READY_KEY, 'true')

def _neutron_rule_to_etcd_rule(rule):
    """
    Translate a single Neutron rule dict to a single dict in our
    etcd format.
    """
    ethertype = rule['ethertype']
    etcd_rule = {}
    # Map the ethertype field from Neutron to etcd format.
    etcd_rule['ip_version'] = {'IPv4': 4,
                               'IPv6': 6}[ethertype]
    # Map the protocol field from Neutron to etcd format.
    if rule['protocol'] is None or rule['protocol'] == -1:
        pass
    elif rule['protocol'] == 'icmp':
        etcd_rule['protocol'] = {'IPv4': 'icmp',
                                 'IPv6': 'icmpv6'}[ethertype]
    else:
        etcd_rule['protocol'] = rule['protocol']

    # OpenStack (sometimes) represents 'any IP address' by setting
    # both 'remote_group_id' and 'remote_ip_prefix' to None.  We
    # translate that to an explicit 0.0.0.0/0 (for IPv4) or ::/0
    # (for IPv6).
    net = rule['remote_ip_prefix']
    if not (net or rule['remote_group_id']):
        net = {'IPv4': '0.0.0.0/0',
               'IPv6': '::/0'}[ethertype]
    port_spec = None
    if rule['protocol'] == 'icmp':
        # OpenStack stashes the ICMP match criteria in
        # port_range_min/max.
        icmp_type = rule['port_range_min']
        if icmp_type is not None and icmp_type != -1:
            etcd_rule['icmp_type'] = icmp_type
        icmp_code = rule['port_range_max']
        if icmp_code is not None and icmp_code != -1:
            etcd_rule['icmp_code'] = icmp_code
    else:
        # src/dst_ports is a list in which each entry can be a
        # single number, or a string describing a port range.
        if rule['port_range_min'] == -1:
            port_spec = ['1:65535']
        elif rule['port_range_min'] == rule['port_range_max']:
            if rule['port_range_min'] is not None:
                port_spec = [rule['port_range_min']]
        else:
            port_spec = ['%s:%s' % (rule['port_range_min'],
                                    rule['port_range_max'])]

    # Put it all together and add to either the inbound or the
    # outbound list.
    if rule['direction'] == 'ingress':
        if rule['remote_group_id'] is not None:
            etcd_rule['src_tag'] = rule['remote_group_id']
        if net is not None:
            etcd_rule['src_net'] = net
        if port_spec is not None:
            etcd_rule['dst_ports'] = port_spec
        LOG.info("=> Inbound Calico rule %s" % etcd_rule)
    else:
        if rule['remote_group_id'] is not None:
            etcd_rule['dst_tag'] = rule['remote_group_id']
        if net is not None:
            etcd_rule['dst_net'] = net
        if port_spec is not None:
            etcd_rule['dst_ports'] = port_spec
        LOG.info("=> Outbound Calico rule %s" % etcd_rule)

    return etcd_rule

def port_etcd_key(port):
    """
    Determine what the etcd key is for a port.
    """
    return key_for_endpoint(port['binding:host_id'],
                            "openstack",
                            port['device_id'],
                            port['id'])

def port_etcd_data(port):
    """
    Build the dictionary of data that will be written into etcd for a port.
    """
    # Construct the simpler port data.
    data = {'state': 'active' if port['admin_state_up'] else 'inactive',
            'name': port['interface_name'],
            'mac': port['mac_address'],
            'profile_id': port['security_groups']}

    # Collect IPv6 and IPv6 addresses.  On the way, also set the
    # corresponding gateway fields.  If there is more than one IPv4 or IPv6
    # gateway, the last one (in port['fixed_ips']) wins.
    ipv4_nets = []
    ipv6_nets = []
    for ip in port['fixed_ips']:
        if ':' in ip['ip_address']:
            ipv6_nets.append(ip['ip_address'] + '/128')
            if ip['gateway'] is not None:
                data['ipv6_gateway'] = ip['gateway']
        else:
            ipv4_nets.append(ip['ip_address'] + '/32')
            if ip['gateway'] is not None:
                data['ipv4_gateway'] = ip['gateway']
    data['ipv4_nets'] = ipv4_nets
    data['ipv6_nets'] = ipv6_nets

    # Return that data.
    return data

def profile_tags(profile):
    """
    Get the tags from a given security profile.
    """
    return profile.id.split('_')

def profile_rules(profile):
    """
    Get a dictionary of profile rules, ready for writing into etcd as JSON.
    """
    inbound_rules = [
        _neutron_rule_to_etcd_rule(rule) for rule in profile.inbound_rules
    ]
    outbound_rules = [
        _neutron_rule_to_etcd_rule(rule) for rule in profile.outbound_rules
    ]

    return {'inbound_rules': inbound_rules, 'outbound_rules': outbound_rules}
<commit_msg>Transport no longer handles endpoint updated<commit_after># -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Metaswitch Networks
# All Rights Reserved.
#
#    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.

# Etcd-based transport for the Calico/OpenStack Plugin.

# Standard Python library imports.
import etcd
import eventlet
import eventlet.event
import json
import re
import weakref

# OpenStack imports.
from oslo.config import cfg
from neutron.openstack.common import log

# Calico imports.
from calico.datamodel_v1 import (READY_KEY, CONFIG_DIR, TAGS_KEY_RE, HOST_DIR,
                                 key_for_endpoint, PROFILE_DIR,
                                 key_for_profile, key_for_profile_rules,
                                 key_for_profile_tags, key_for_config)

# Register Calico-specific options.
calico_opts = [
    cfg.StrOpt('etcd_host', default='localhost',
               help="The hostname or IP of the etcd node/proxy"),
    cfg.IntOpt('etcd_port', default=4001,
               help="The port to use for the etcd node/proxy"),
]
cfg.CONF.register_opts(calico_opts, 'calico')

OPENSTACK_ENDPOINT_RE = re.compile(
    r'^' + HOST_DIR +
    r'/(?P<hostname>[^/]+)/.*openstack.*/endpoint/(?P<endpoint_id>[^/]+)')

json_decoder = json.JSONDecoder()

PERIODIC_RESYNC_INTERVAL_SECS = 30

LOG = log.getLogger(__name__)

class CalicoTransportEtcd(object):
    """Calico transport implementation based on etcd."""

    def __init__(self, driver):
        # Explicitly store the driver as a weakreference. This prevents
        # the reference loop between transport and driver keeping the objects
        # alive.
        self.driver = weakref.proxy(driver)

        # Prepare client for accessing etcd data.
        self.client = etcd.Client(host=cfg.CONF.calico.etcd_host,
                                  port=cfg.CONF.calico.etcd_port)

        # Spawn a green thread for periodically resynchronizing etcd against
        # the OpenStack database.
        eventlet.spawn(self.periodic_resync_thread)

    def periodic_resync_thread(self):
        while True:
            LOG.info("Calico plugin doing periodic resync.")
            try:
                # Write non-default config that Felices need.
                self.provide_felix_config()

                # Resynchronize endpoint data.
                self.resync_endpoints()

                # Resynchronize security group data.
                self.resync_security_groups()

            except:
                LOG.exception("Exception in periodic resync thread")

            # Sleep until time for next resync.
            LOG.info("Calico plugin finished periodic resync.  "
                     "Next resync in %s seconds.",
                     PERIODIC_RESYNC_INTERVAL_SECS)
            eventlet.sleep(PERIODIC_RESYNC_INTERVAL_SECS)

    def resync_endpoints(self):
        pass

    def resync_security_groups(self):
        pass

    def write_profile_to_etcd(self, profile):
        """
        Write a single security profile into etcd.
        """
        self.client.write(
            key_for_profile_rules(profile.id),
            json.dumps(profile_rules(profile))
        )
        self.client.write(
            key_for_profile_tags(profile.id),
            json.dumps(profile_tags(profile))
        )

    def endpoint_created(self, port):
        """
        Write appropriate data to etcd for an endpoint creation event.
        """
        # Write etcd data for the new endpoint.
        self.write_port_to_etcd(port)

    def endpoint_deleted(self, port):
        """
        Delete data from etcd for an endpoint deleted event.
        """
        # TODO: What do we do about profiles here?
        # Delete the etcd key for this endpoint.
        key = self.port_etcd_key(port)
        try:
            self.client.delete(key)
        except etcd.EtcdKeyNotFound:
            # Already gone, treat as success.
            LOG.debug("Key %s, which we were deleting, disappeared", key)

    def security_group_updated(self, sg):
        # Update the data that we're keeping for this security group.
        with self._sgs_semaphore:
            self.sgs[sg['id']] = sg

        # Identify all the needed profiles that incorporate this security
        # group, and rewrite their data.
        # Take the profile lock so that no-one can modify needed_profiles
        # while we iterate over it.  (This is probably unneeded since there
        # aren't any yield points in the loop but better safe than sorry.)
        profiles_to_rewrite = set()
        with self.profile_semaphore:
            for profile_id in self.needed_profiles:
                if sg['id'] in self.profile_tags(profile_id):
                    # Write etcd data for this profile.
                    profiles_to_rewrite.add(profile_id)
        for profile_id in profiles_to_rewrite:
            self.write_profile_to_etcd(profile_id)

    def write_port_to_etcd(self, port):
        """
        Writes a given port dictionary to etcd.
        """
        data = port_etcd_data(port)
        self.client.write(port_etcd_key(port), json.dumps(data))

    def provide_felix_config(self):
        """Specify the prefix of the TAP interfaces that Felix should
        look for and work with.  This config setting does not have a
        default value, because different cloud systems will do
        different things.  Here we provide the prefix that Neutron
        uses.
        """
        # First read the config values, so as to avoid unnecessary
        # writes.
        prefix = None
        ready = None
        iface_pfx_key = key_for_config('InterfacePrefix')
        try:
            prefix = self.client.read(iface_pfx_key).value
            ready = self.client.read(READY_KEY).value
        except etcd.EtcdKeyNotFound:
            LOG.info('%s values are missing', CONFIG_DIR)

        # Now write the values that need writing.
        if prefix != 'tap':
            LOG.info('%s -> tap', iface_pfx_key)
            self.client.write(iface_pfx_key, 'tap')
        if ready != 'true':
            # TODO Set this flag only once we're really ready!
            LOG.info('%s -> true', READY_KEY)
            self.client.write(READY_KEY, 'true')

def _neutron_rule_to_etcd_rule(rule):
    """
    Translate a single Neutron rule dict to a single dict in our
    etcd format.
    """
    ethertype = rule['ethertype']
    etcd_rule = {}
    # Map the ethertype field from Neutron to etcd format.
    etcd_rule['ip_version'] = {'IPv4': 4,
                               'IPv6': 6}[ethertype]
    # Map the protocol field from Neutron to etcd format.
    if rule['protocol'] is None or rule['protocol'] == -1:
        pass
    elif rule['protocol'] == 'icmp':
        etcd_rule['protocol'] = {'IPv4': 'icmp',
                                 'IPv6': 'icmpv6'}[ethertype]
    else:
        etcd_rule['protocol'] = rule['protocol']

    # OpenStack (sometimes) represents 'any IP address' by setting
    # both 'remote_group_id' and 'remote_ip_prefix' to None.  We
    # translate that to an explicit 0.0.0.0/0 (for IPv4) or ::/0
    # (for IPv6).
    net = rule['remote_ip_prefix']
    if not (net or rule['remote_group_id']):
        net = {'IPv4': '0.0.0.0/0',
               'IPv6': '::/0'}[ethertype]
    port_spec = None
    if rule['protocol'] == 'icmp':
        # OpenStack stashes the ICMP match criteria in
        # port_range_min/max.
        icmp_type = rule['port_range_min']
        if icmp_type is not None and icmp_type != -1:
            etcd_rule['icmp_type'] = icmp_type
        icmp_code = rule['port_range_max']
        if icmp_code is not None and icmp_code != -1:
            etcd_rule['icmp_code'] = icmp_code
    else:
        # src/dst_ports is a list in which each entry can be a
        # single number, or a string describing a port range.
        if rule['port_range_min'] == -1:
            port_spec = ['1:65535']
        elif rule['port_range_min'] == rule['port_range_max']:
            if rule['port_range_min'] is not None:
                port_spec = [rule['port_range_min']]
        else:
            port_spec = ['%s:%s' % (rule['port_range_min'],
                                    rule['port_range_max'])]

    # Put it all together and add to either the inbound or the
    # outbound list.
    if rule['direction'] == 'ingress':
        if rule['remote_group_id'] is not None:
            etcd_rule['src_tag'] = rule['remote_group_id']
        if net is not None:
            etcd_rule['src_net'] = net
        if port_spec is not None:
            etcd_rule['dst_ports'] = port_spec
        LOG.info("=> Inbound Calico rule %s" % etcd_rule)
    else:
        if rule['remote_group_id'] is not None:
            etcd_rule['dst_tag'] = rule['remote_group_id']
        if net is not None:
            etcd_rule['dst_net'] = net
        if port_spec is not None:
            etcd_rule['dst_ports'] = port_spec
        LOG.info("=> Outbound Calico rule %s" % etcd_rule)

    return etcd_rule

def port_etcd_key(port):
    """
    Determine what the etcd key is for a port.
    """
    return key_for_endpoint(port['binding:host_id'],
                            "openstack",
                            port['device_id'],
                            port['id'])

def port_etcd_data(port):
    """
    Build the dictionary of data that will be written into etcd for a port.
    """
    # Construct the simpler port data.
    data = {'state': 'active' if port['admin_state_up'] else 'inactive',
            'name': port['interface_name'],
            'mac': port['mac_address'],
            'profile_id': port['security_groups']}

    # Collect IPv6 and IPv6 addresses.  On the way, also set the
    # corresponding gateway fields.  If there is more than one IPv4 or IPv6
    # gateway, the last one (in port['fixed_ips']) wins.
    ipv4_nets = []
    ipv6_nets = []
    for ip in port['fixed_ips']:
        if ':' in ip['ip_address']:
            ipv6_nets.append(ip['ip_address'] + '/128')
            if ip['gateway'] is not None:
                data['ipv6_gateway'] = ip['gateway']
        else:
            ipv4_nets.append(ip['ip_address'] + '/32')
            if ip['gateway'] is not None:
                data['ipv4_gateway'] = ip['gateway']
    data['ipv4_nets'] = ipv4_nets
    data['ipv6_nets'] = ipv6_nets

    # Return that data.
    return data

def profile_tags(profile):
    """
    Get the tags from a given security profile.
    """
    return profile.id.split('_')

def profile_rules(profile):
    """
    Get a dictionary of profile rules, ready for writing into etcd as JSON.
    """
    inbound_rules = [
        _neutron_rule_to_etcd_rule(rule) for rule in profile.inbound_rules
    ]
    outbound_rules = [
        _neutron_rule_to_etcd_rule(rule) for rule in profile.outbound_rules
    ]

    return {'inbound_rules': inbound_rules, 'outbound_rules': outbound_rules}
<|endoftext|>


<commit_before>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  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 os.path
from datetime import datetime

from robot.utils import WINDOWS, XmlWriter, unicode

class LibdocXmlWriter(object):

    def write(self, libdoc, outfile):
        writer = XmlWriter(outfile, usage='Libdoc spec')
        self._write_start(libdoc, writer)
        self._write_keywords('inits', 'init', libdoc.inits, libdoc.source, writer)
        self._write_keywords('keywords', 'kw', libdoc.keywords, libdoc.source, writer)
        self._write_end(writer)

    def _write_start(self, libdoc, writer):
        generated = datetime.utcnow().replace(microsecond=0).isoformat() + 'Z'
        attrs = {'name': libdoc.name,
                 'type': libdoc.type,
                 'format': libdoc.doc_format,
                 'scope': libdoc.scope,
                 'generated': generated,
                 'specversion': '3'}
        self._add_source_info(attrs, libdoc, writer.output)
        writer.start('keywordspec', attrs)
        writer.element('version', libdoc.version)
        writer.element('doc', libdoc.doc)

    def _add_source_info(self, attrs, item, outfile, lib_source=None):
        if item.source and item.source != lib_source:
            attrs['source'] = self._format_source(item.source, outfile)
        if item.lineno > 0:
            attrs['lineno'] = str(item.lineno)

    def _format_source(self, source, outfile):
        if not os.path.exists(source):
            return source
        source = os.path.normpath(source)
        if not (hasattr(outfile, 'name')
                and os.path.isfile(outfile.name)
                and self._on_same_drive(source, outfile.name)):
            return source
        return os.path.relpath(source, os.path.dirname(outfile.name))

    def _on_same_drive(self, path1, path2):
        if not WINDOWS:
            return True
        return os.path.splitdrive(path1)[0] == os.path.splitdrive(path2)[0]

    def _get_old_style_scope(self, libdoc):
        if libdoc.type == 'RESOURCE':
            return ''
        return {'GLOBAL': 'global',
                'SUITE': 'test suite',
                'TEST': 'test case'}[libdoc.scope]

    def _write_keywords(self, list_name, kw_type, keywords, lib_source, writer):
        writer.start(list_name)
        for kw in keywords:
            attrs = self._get_start_attrs(kw_type, kw, lib_source, writer)
            writer.start(kw_type, attrs)
            self._write_arguments(kw, writer)
            writer.element('doc', kw.doc)
            writer.element('shortdoc', kw.shortdoc)
            if kw_type == 'kw' and kw.tags:
                writer.start('tags')
                for tag in kw.tags:
                    writer.element('tag', tag)
                writer.end('tags')
            writer.end(kw_type)
        writer.end(list_name)

    def _write_arguments(self, kw, writer):
        writer.start('arguments', {'repr': unicode(kw.args)})
        for arg in kw.args:
            writer.start('arg', {'kind': arg.kind,
                                 'required': 'true' if arg.required else 'false',
                                 'repr': unicode(arg)})
            if arg.name:
                writer.element('name', arg.name)
            if arg.types:
                for type_repr in arg.types_reprs:
                    writer.element('type', type_repr)
            if arg.default is not arg.NOTSET:
                writer.element('default', arg.default_repr)
            writer.end('arg')
        writer.end('arguments')

    def _get_start_attrs(self, kw_type, kw, lib_source, writer):
        if kw_type == 'init':
            attrs = {'name': kw.name}
        else:
            attrs = {'name': kw.name}
            if kw.deprecated:
                attrs['deprecated'] = 'true'
        self._add_source_info(attrs, kw, writer.output, lib_source)
        return attrs

    def _write_end(self, writer):
        writer.end('keywordspec')
        writer.close()
<commit_msg>Update xmlwriter.py<commit_after>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  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 os.path
from datetime import datetime

from robot.utils import WINDOWS, XmlWriter, unicode

class LibdocXmlWriter(object):

    def write(self, libdoc, outfile):
        writer = XmlWriter(outfile, usage='Libdoc spec')
        self._write_start(libdoc, writer)
        self._write_keywords('inits', 'init', libdoc.inits, libdoc.source, writer)
        self._write_keywords('keywords', 'kw', libdoc.keywords, libdoc.source, writer)
        self._write_end(writer)

    def _write_start(self, libdoc, writer):
        generated = datetime.utcnow().replace(microsecond=0).isoformat() + 'Z'
        attrs = {'name': libdoc.name,
                 'type': libdoc.type,
                 'format': libdoc.doc_format,
                 'scope': libdoc.scope,
                 'generated': generated,
                 'specversion': '3'}
        self._add_source_info(attrs, libdoc, writer.output)
        writer.start('keywordspec', attrs)
        writer.element('version', libdoc.version)
        writer.element('doc', libdoc.doc)

    def _add_source_info(self, attrs, item, outfile, lib_source=None):
        if item.source and item.source != lib_source:
            attrs['source'] = self._format_source(item.source, outfile)
        if item.lineno > 0:
            attrs['lineno'] = str(item.lineno)

    def _format_source(self, source, outfile):
        if not os.path.exists(source):
            return source
        source = os.path.normpath(source)
        if not (hasattr(outfile, 'name')
                and os.path.isfile(outfile.name)
                and self._on_same_drive(source, outfile.name)):
            return source
        return os.path.relpath(source, os.path.dirname(outfile.name))

    def _on_same_drive(self, path1, path2):
        if not WINDOWS:
            return True
        return os.path.splitdrive(path1)[0] == os.path.splitdrive(path2)[0]

    def _get_old_style_scope(self, libdoc):
        if libdoc.type == 'RESOURCE':
            return ''
        return {'GLOBAL': 'global',
                'SUITE': 'test suite',
                'TEST': 'test case'}[libdoc.scope]

    def _write_keywords(self, list_name, kw_type, keywords, lib_source, writer):
        writer.start(list_name)
        for kw in keywords:
            attrs = self._get_start_attrs(kw_type, kw, lib_source, writer)
            writer.start(kw_type, attrs)
            self._write_arguments(kw, writer)
            writer.element('doc', kw.doc)
            writer.element('shortdoc', kw.shortdoc)
            if kw_type == 'kw' and kw.tags:
                writer.start('tags')
                for tag in kw.tags:
                    writer.element('tag', tag)
                writer.end('tags')
            writer.end(kw_type)
        writer.end(list_name)

    def _write_arguments(self, kw, writer):
        writer.start('arguments', {'repr': unicode(kw.args)})
        for arg in kw.args:
            writer.start('arg', {'kind': arg.kind,
                                 'required': 'true' if arg.required else 'false',
                                 'repr': unicode(arg)})
            if arg.name:
                writer.element('name', arg.name)
            if arg.types:
                for type_repr in arg.types_reprs:
                    writer.element('type', type_repr)
            if arg.default is not arg.NOTSET:
                writer.element('default', arg.default_repr)
            writer.end('arg')
        writer.end('arguments')

    def _get_start_attrs(self, kw_type, kw, lib_source, writer):
        attrs = {'name': kw.name}
        if kw_type != 'init' and kw.deprecated:
            attrs['deprecated'] = 'true'
        self._add_source_info(attrs, kw, writer.output, lib_source)
        return attrs

    def _write_end(self, writer):
        writer.end('keywordspec')
        writer.close()
<|endoftext|>