<commit_before># -*- coding: utf-8 -*-
#!/usr/bin/python
##-------------------------------------------------------------------
## @copyright 2015 DennyZhang.com
## File : tcp_port_scan.py
## Author : DennyZhang.com <denny@dennyzhang.com>
## Description :
## --
## Created : <2016-01-15>
## Updated: Time-stamp: <2016-08-12 08:59:30>
##-------------------------------------------------------------------
import argparse
import subprocess
import os, sys

################################################################################
# TODO: move to common library
def strip_remove_comments(string):
    # remove empty lines and comments (# ...) from string
    l = []
    for line in string.split("\n"):
        line = line.strip()
        if line.startswith("#") or line == "":
            continue
        l.append(line)
    return "\n".join(l)

def strip_remove_emptylines(string):
    l = []
    for line in string.split("\n"):
        line = line.strip()
        if line == "":
            continue
        l.append(line)
    return "\n".join(l)

def string_remove_patterns(string, opt_list):
    l = []
    # remove entries from string
    for line in string.split("\n"):
        should_remove = False
        for item in opt_list:
            if item in line:
                should_remove = True
        if should_remove is False:
            l.append(line)
    return "\n".join(l)

def string_remove_extra_whitespace(string):
    return ' '.join(string.split())

def load_parameters_from_file(fname):
    l = []
    return l

# TODO: add common logging
################################################################################
nmap_command = "sudo nmap -sS -PN %s" # ("-p T:XXX,XXX 192.168.0.16")

open_port_dict = {}
insecure_port_dict = {}

def nmap_check(server_ip, ports):
    if ports == "":
        nmap_opts = server_ip
    else:
        nmap_opts = "-p '%s' %s" % (ports, server_ip)

    command = nmap_command % (nmap_opts)
    print "Run: %s" % (command)
    nmap_output =subprocess.check_output(command, shell=True)
    print nmap_output
    return nmap_output

def get_portlist_by_nmap_output(nmap_output, server_ip):
    opt_list = ["Starting Nmap ", "Nmap scan report for ", "Host is ", \
                "Not shown: ", " STATE ", " closed ", \
                " filtered unknown", "Nmap done: "]
    output = string_remove_patterns(nmap_output, opt_list)
    output = string_remove_extra_whitespace(output)
    output = strip_remove_emptylines(output)
    return output.split("\n")

def audit_open_ports(port_list, white_list, server_ip):
    insecure_port_list = []
    for item in port_list:
        port = item.split("/")[0]

        if "*:%s" % (port) not in white_list and \
           "%s:%s" % (server_ip, port) not in white_list:
            insecure_port_list.append(item)

    return insecure_port_list

def tcp_port_scan(server_list, white_list, extra_ports):
    # TODO: change to multi-threading
    for server_ip in server_list:
        nmap_output = nmap_check(server_ip, "")
        nmap_port_list = get_portlist_by_nmap_output(nmap_output, server_ip)
        open_port_dict[server_ip] = nmap_port_list

    # TODO: change to multi-threading
    # Check customized ports
    if extra_ports != "":
        for server_ip in server_list:
            nmap_output = nmap_check(server_ip, "T:%s" % (extra_ports))
            nmap_port_list = get_portlist_by_nmap_output(nmap_output, server_ip)
            open_port_dict[server_ip] = sorted(list(set(open_port_dict[server_ip]) \
                                                    | set(nmap_port_list)))

    # reduce result: whether any insecure ports open
    detected_insecure_ports = False
    for server_ip in server_list:
        ports = audit_open_ports(open_port_dict[server_ip], white_list, server_ip)

        if len(ports) != 0:
            detected_insecure_ports = True
            insecure_port_dict[server_ip] = ports

    if detected_insecure_ports is True:
        print "Error: Detected insecure TCP ports open"
        for server_ip in insecure_port_dict.keys():
            print "\nServer: %s " % (server_ip)
            print "\n".join(insecure_port_dict[server_ip])
        sys.exit(1)
    else:
        print "OK: No insecure TCP ports open"

################################################################################
if __name__=='__main__':
    # Sample:
    # python ./tcp_port_scan.py --server_list_file /tmp/server_list --white_list_file /tmp/white_list --extra_port "48080,18080"
    parser = argparse.ArgumentParser()
    parser.add_argument('--server_list_file', required=True,
                        help="ip list to scan", type=str)
    parser.add_argument('--white_list_file', required=True,
                        help="safe ports to allow open", type=str)
    parser.add_argument('--extra_ports', required=True,
                        help="customized tcp ports to scan", type=str)
    args = parser.parse_args()
    server_list_file = args.server_list_file
    white_list_file = args.white_list_file
    extra_ports = args.extra_ports

    white_list = ["*:22", "*:80"]
    server_list = ["104.131.129.100", "104.236.159.226"]
    # server_list = ["104.131.129.100"]

    tcp_port_scan(server_list, white_list, extra_ports)

## File : tcp_port_scan.py ends
<commit_msg>add output prefix to easily identity critical message<commit_after># -*- coding: utf-8 -*-
#!/usr/bin/python
##-------------------------------------------------------------------
## @copyright 2015 DennyZhang.com
## File : tcp_port_scan.py
## Author : DennyZhang.com <denny@dennyzhang.com>
## Description :
## --
## Created : <2016-01-15>
## Updated: Time-stamp: <2016-08-12 09:03:13>
##-------------------------------------------------------------------
import argparse
import subprocess
import os, sys

################################################################################
# TODO: move to common library
def strip_remove_comments(string):
    # remove empty lines and comments (# ...) from string
    l = []
    for line in string.split("\n"):
        line = line.strip()
        if line.startswith("#") or line == "":
            continue
        l.append(line)
    return "\n".join(l)

def strip_remove_emptylines(string):
    l = []
    for line in string.split("\n"):
        line = line.strip()
        if line == "":
            continue
        l.append(line)
    return "\n".join(l)

def string_remove_patterns(string, opt_list):
    l = []
    # remove entries from string
    for line in string.split("\n"):
        should_remove = False
        for item in opt_list:
            if item in line:
                should_remove = True
        if should_remove is False:
            l.append(line)
    return "\n".join(l)

def string_remove_extra_whitespace(string):
    return ' '.join(string.split())

def load_parameters_from_file(fname):
    l = []
    return l

# TODO: add common logging
################################################################################
nmap_command = "sudo nmap -sS -PN %s" # ("-p T:XXX,XXX 192.168.0.16")
output_prefix = "============="
open_port_dict = {}
insecure_port_dict = {}

def nmap_check(server_ip, ports):
    if ports == "":
        nmap_opts = server_ip
    else:
        nmap_opts = "-p %s %s" % (ports, server_ip)
    command = nmap_command % (nmap_opts)
    print output_prefix, "Run: %s" % (command)
    nmap_output =subprocess.check_output(command, shell=True)
    print nmap_output
    return nmap_output

def get_portlist_by_nmap_output(nmap_output, server_ip):
    opt_list = ["Starting Nmap ", "Nmap scan report for ", "Host is ", \
                "Not shown: ", " STATE ", " closed ", \
                " filtered unknown", "Nmap done: "]
    output = string_remove_patterns(nmap_output, opt_list)
    output = string_remove_extra_whitespace(output)
    output = strip_remove_emptylines(output)
    return output.split("\n")

def audit_open_ports(port_list, white_list, server_ip):
    insecure_port_list = []
    for item in port_list:
        port = item.split("/")[0]

        if "*:%s" % (port) not in white_list and \
           "%s:%s" % (server_ip, port) not in white_list:
            insecure_port_list.append(item)

    return insecure_port_list

def tcp_port_scan(server_list, white_list, extra_ports):
    # TODO: change to multi-threading
    for server_ip in server_list:
        nmap_output = nmap_check(server_ip, "")
        nmap_port_list = get_portlist_by_nmap_output(nmap_output, server_ip)
        open_port_dict[server_ip] = nmap_port_list

    # TODO: change to multi-threading
    print output_prefix, "Run extra checks for given ports: extra_ports"
    if extra_ports != "":
        for server_ip in server_list:
            nmap_output = nmap_check(server_ip, "T:%s" % (extra_ports))
            nmap_port_list = get_portlist_by_nmap_output(nmap_output, server_ip)
            open_port_dict[server_ip] = sorted(list(set(open_port_dict[server_ip]) \
                                                    | set(nmap_port_list)))

    # reduce result: whether any insecure ports open
    detected_insecure_ports = False
    for server_ip in server_list:
        ports = audit_open_ports(open_port_dict[server_ip], white_list, server_ip)
        if len(ports) != 0:
            detected_insecure_ports = True
            insecure_port_dict[server_ip] = ports

    if detected_insecure_ports is True:
        print output_prefix, "Error: Detected insecure TCP ports open"
        for server_ip in insecure_port_dict.keys():
            print "\nServer: %s " % (server_ip)
            print "\n".join(insecure_port_dict[server_ip])
        sys.exit(1)
    else:
        print "OK: No insecure TCP ports open"

################################################################################
if __name__=='__main__':
    # Sample:
    # python ./tcp_port_scan.py --server_list_file /tmp/server_list --white_list_file /tmp/white_list --extra_port "48080,18080"
    parser = argparse.ArgumentParser()
    parser.add_argument('--server_list_file', required=True,
                        help="ip list to scan", type=str)
    parser.add_argument('--white_list_file', required=True,
                        help="safe ports to allow open", type=str)
    parser.add_argument('--extra_ports', required=True,
                        help="customized tcp ports to scan", type=str)
    args = parser.parse_args()
    server_list_file = args.server_list_file
    white_list_file = args.white_list_file
    extra_ports = args.extra_ports

    white_list = ["*:22", "*:80"]
    server_list = ["104.131.129.100", "104.236.159.226"]
    # server_list = ["104.131.129.100"]

    tcp_port_scan(server_list, white_list, extra_ports)

## File : tcp_port_scan.py ends
<|endoftext|>


<commit_before># SIM-CITY webservice
#
# Copyright 2015 Netherlands eScience Center
#
# 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.

#
# This file implements a mock version of the normal webservice
#
import bottle
from bottle import (post, get, run, delete, request, response, HTTPResponse,
                    static_file, hook)
import simcity
from simcity.util import listfiles
from simcityweb.util import get_simulation_versions
from simcityweb import error, get_simulation_config
from uuid import uuid4
import os
import json
import sys

prefix = '/explore'

config = simcity.Config()
config.add_section('task-db', {})
config.add_section('Simulations', {
    'max_jobs': 1,
    'path': 'simulations'
})
config.add_section('Schemas', {
    'path': 'schemas'
})
config.add_section('Resources', {
    'path': 'resources'
})

simcity.init(config)

# Get project directory
file_dir = os.path.dirname(os.path.realpath(__file__))
project_dir = os.path.dirname(file_dir)

config_sim = simcity.get_config().section('Simulations')

# Mock database using a dictionary
mock_db = dict()

# Load a json file with pre made test tasks
def load_pre_made_tasks():
    for _root, dirs, files in os.walk('mock_tasks', topdown=False):
        for name in files:
            if name.endswith('.json'):
                filename = os.path.join(_root, name)
                with open(filename) as _file:
                    task = json.load(_file)
                    mock_db[task['id']] = task

# WARNING:
# Loading the json file in this manner probably means
# it is loaded for every request so we shouldn't make too many
load_pre_made_tasks()

# Remove spaces from json output
bottle.uninstall('json')
bottle.install(bottle.JSONPlugin(
    json_dumps=lambda x: json.dumps(x, separators=(',', ':'))))

# Remove trailing / from request
@hook('before_request')
def strip_path():
    request.environ['PATH_INFO'] = request.environ['PATH_INFO'].rstrip('/')

@get(prefix)
def root():
    return get_doc_type('swagger')

@get(prefix + '/doc')
def get_doc():
    doc_format = request.query.get('format', 'html')
    return get_doc_type(doc_format)

@get(prefix + '/doc')
def get_doc():
    doc_format = request.query.get('format', 'html')
    return get_doc_type(doc_format)

def get_doc_type(doc_type):
    docs = {
        'html': 'apiary.html',
        'swagger': 'swagger.json',
        'api-blueprint': 'apiary.apib'
    }
    if doc_type not in docs:
        return error(409, "documentation {0} not found. choose between {1}"
                     .format(doc_type, docs.keys()))

    return static_file(os.path.join('docs', docs[doc_type]), root=project_dir)

@get(prefix + '/simulate')
def simulate_list():
    simulations = {}
    try:
        for f in listfiles('simulations'):
            if not f.endswith('.json') or f.endswith('.min.json'):
                continue

            name = f[:-5]
            simulations[name] = {
                'name': name,
                'versions': get_simulation_versions(name)
            }

        return simulations
    except HTTPResponse as ex:
        return ex

@get(prefix + '/simulate/<name>')
def get_simulation_by_name(name):
    try:
        response.status = 200
        return {'name': name, 'versions': get_simulation_versions(name)}
    except HTTPResponse as ex:
        return ex

@get(prefix + '/simulate/<name>/<version>')
def get_simulation_by_name_version(name, version=None):
    try:
        sim, version = get_simulation_config(name, version, 'simulations')
        chosen_sim = sim[version]
        chosen_sim['name'] = name
        chosen_sim['version'] = version
        response.status = 200
        return chosen_sim
    except HTTPResponse as ex:
        return ex

@post(prefix + '/simulate/<name>')
def simulate_name(name):
    return simulate_name_version(name)

@post(prefix + '/simulate/<name>/<version>')
def simulate_name_version(name, version=None):
    if not hasattr(simulate_name_version, 'nextId'):
        # Initialize static variable
        simulate_name_version.nextId = 0

    try:
        sim, version = get_simulation_config(name, version, 'simulations')
        sim = sim[version]
        query = dict(request.json)
        if '_id' in query:
            task_id = query['_id']
            del query['_id']
        else:
            task_id = str(simulate_name_version.nextId)
            simulate_name_version.nextId += 1

        simcity.parse_parameters(query, sim['properties'])
    except HTTPResponse as ex:
        return ex
    except ValueError as ex:
        return error(400, ex)
    except EnvironmentError as ex:
        return error(500, ex.message)

    # Create the response we would normally get from
    # the database
    task_props = {
        'id': task_id,
        'key': task_id,
        'value': {
            '_id': task_id,
            '_rev': uuid4().hex,
            'lock': 0,
            'done': 0,
            'name': name,
            'command': sim['command'],
            'arguments': sim.get('arguments', []),
            'parallelism': sim.get('parallelism', '*'),
            'version': version,
            'input': query,
            'uploads': {},
            'error': []
        }
    }

    if 'ensemble' in query:
        task_props['ensemble'] = query['ensemble']
    if 'simulation' in query:
        task_props['simulation'] = query['simulation']

    if task_id in mock_db:
        return error(400, "simulation name " + task_id + " already taken")

    # Add the new task to the "database"
    mock_db[task_id] = task_props

    response.status = 201  # created

    # Normally we return a link to the database, but now
    # we point to sim-city-webservice
    host = bottle.request.get_header('host')
    url = '%s/task/%s' % (host, task_id)
    response.set_header('Location', url)
    return task_props

@get(prefix + '/schema')
def schema_list():
    files = listfiles('schemas')
    return {'schemas': [f[:-5] for f in files if f.endswith('.json')]}

@get(prefix + '/schema/<name>')
def schema_name(name):
    return static_file(os.path.join('schemas', name + '.json'),
                       root=project_dir)

@get(prefix + '/resource')
def resource_list():
    files = listfiles('resources')
    return {"resources": [f[:-5] for f in files if f.endswith('.json')]}

@get(prefix + '/resource/<name>')
def resource_name(name):
    return static_file(os.path.join('resources', name + '.json'),
                       root=project_dir)

@get(prefix + '/view/totals')
def overview():
    try:
        return mock_overview_total()
    except:
        return error(500, "cannot read overview")

def mock_overview_total():
    views = ['todo', 'locked', 'error', 'done',
             'finished_jobs', 'active_jobs', 'pending_jobs']

    num = dict((view, 0) for view in views)

    for key, task in mock_db.items():
        for view in views:
            if view in task['value'] and task['value'][view] == 1:
                num[view] += 1

    return num

@post(prefix + '/job')
def submit_job():
    if not hasattr(submit_job, 'batch_id'):
        submit_job.batch_id = 1

    # Mock the response for submitting the job
    host = config_sim['default_host']
    _prefix = host + '-'
    batch_id = str(submit_job.batch_id)
    submit_job.batch_id += 1
    job_id = 'job_' + _prefix + uuid4().hex

    response.status = 201  # created
    return {'_id': job_id, 'batch_id': batch_id, 'hostname': host}

@get(prefix + '/simulation/<_id>')
def get_simulation(_id):
    if _id in mock_db:
        return mock_db[_id]['value']
    else:
        return error(404, "simulation does not exist")

@get(prefix + '/view/simulations/<name>/<version>')
def simulations_view(name, version):
    ensemble = request.query.get('ensemble')
    version = get_simulation_config(name, version, 'simulations')[1]

    simulations = [task for k, task in mock_db.items() if
                   task['value']['name'] == name and
                   task['value']['version'] == version and
                   (ensemble is None or task['value']['ensemble'] == ensemble)]

    response.status = 200
    return {'total_rows': len(simulations), 'offset': 0, 'rows': simulations}

@get(prefix + '/simulation/<id>/<attachment>')
def get_attachment(id, attachment):
    return static_file(os.path.join('mock_results', attachment), root=project_dir)

@delete(prefix + '/simulation/<_id>')
def del_simulation(_id):
    rev = request.query.get('rev')
    if rev is None:
        rev = request.get_header('If-Match')
    if rev is None:
        return error(409, "revision not specified")

    if _id in mock_db:
        task = mock_db[_id]
        if task['value']['_rev'] == rev:
            del mock_db[_id]
            return {'ok': True}
        else:
            return error(409, "resource conflict")
    else:
        return error(404, "Resource does not exist")

@get(prefix + '/hosts')
def get_hosts():
    hosts = {}
    for section in simcity.get_config().sections():
        if section.endswith('-host'):
            host_name = section[:-5]
            hosts[host_name] = {}
            if config_sim.get('default_host') == host_name:
                hosts[host_name]['default'] = True

    return hosts

if __name__ == '__main__':
    run(host='localhost', port=9090, server='wsgiref')
<commit_msg>using no_database for mock server<commit_after># SIM-CITY webservice
#
# Copyright 2015 Netherlands eScience Center
#
# 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.

#
# This file implements a mock version of the normal webservice
#
import bottle
from bottle import (post, get, run, delete, request, response, HTTPResponse,
                    static_file, hook)
import simcity
from simcity.util import listfiles
from simcityweb.util import get_simulation_versions
from simcityweb import error, get_simulation_config
from uuid import uuid4
import os
import json
import sys

prefix = '/explore'

config = simcity.Config()
config.add_section('task-db', {
    'no_database': True
})
config.add_section('Simulations', {
    'max_jobs': 1,
    'path': 'simulations'
})
config.add_section('Schemas', {
    'path': 'schemas'
})
config.add_section('Resources', {
    'path': 'resources'
})

simcity.init(config)

# Get project directory
file_dir = os.path.dirname(os.path.realpath(__file__))
project_dir = os.path.dirname(file_dir)

config_sim = simcity.get_config().section('Simulations')

# Mock database using a dictionary
mock_db = dict()

# Load a json file with pre made test tasks
def load_pre_made_tasks():
    for _root, dirs, files in os.walk('mock_tasks', topdown=False):
        for name in files:
            if name.endswith('.json'):
                filename = os.path.join(_root, name)
                with open(filename) as _file:
                    task = json.load(_file)
                    mock_db[task['id']] = task

# WARNING:
# Loading the json file in this manner probably means
# it is loaded for every request so we shouldn't make too many
load_pre_made_tasks()

# Remove spaces from json output
bottle.uninstall('json')
bottle.install(bottle.JSONPlugin(
    json_dumps=lambda x: json.dumps(x, separators=(',', ':'))))

# Remove trailing / from request
@hook('before_request')
def strip_path():
    request.environ['PATH_INFO'] = request.environ['PATH_INFO'].rstrip('/')

@get(prefix)
def root():
    return get_doc_type('swagger')

@get(prefix + '/doc')
def get_doc():
    doc_format = request.query.get('format', 'html')
    return get_doc_type(doc_format)

@get(prefix + '/doc')
def get_doc():
    doc_format = request.query.get('format', 'html')
    return get_doc_type(doc_format)

def get_doc_type(doc_type):
    docs = {
        'html': 'apiary.html',
        'swagger': 'swagger.json',
        'api-blueprint': 'apiary.apib'
    }
    if doc_type not in docs:
        return error(409, "documentation {0} not found. choose between {1}"
                     .format(doc_type, docs.keys()))

    return static_file(os.path.join('docs', docs[doc_type]), root=project_dir)

@get(prefix + '/simulate')
def simulate_list():
    simulations = {}
    try:
        for f in listfiles('simulations'):
            if not f.endswith('.json') or f.endswith('.min.json'):
                continue

            name = f[:-5]
            simulations[name] = {
                'name': name,
                'versions': get_simulation_versions(name)
            }

        return simulations
    except HTTPResponse as ex:
        return ex

@get(prefix + '/simulate/<name>')
def get_simulation_by_name(name):
    try:
        response.status = 200
        return {'name': name, 'versions': get_simulation_versions(name)}
    except HTTPResponse as ex:
        return ex

@get(prefix + '/simulate/<name>/<version>')
def get_simulation_by_name_version(name, version=None):
    try:
        sim, version = get_simulation_config(name, version, 'simulations')
        chosen_sim = sim[version]
        chosen_sim['name'] = name
        chosen_sim['version'] = version
        response.status = 200
        return chosen_sim
    except HTTPResponse as ex:
        return ex

@post(prefix + '/simulate/<name>')
def simulate_name(name):
    return simulate_name_version(name)

@post(prefix + '/simulate/<name>/<version>')
def simulate_name_version(name, version=None):
    if not hasattr(simulate_name_version, 'nextId'):
        # Initialize static variable
        simulate_name_version.nextId = 0

    try:
        sim, version = get_simulation_config(name, version, 'simulations')
        sim = sim[version]
        query = dict(request.json)
        if '_id' in query:
            task_id = query['_id']
            del query['_id']
        else:
            task_id = str(simulate_name_version.nextId)
            simulate_name_version.nextId += 1

        simcity.parse_parameters(query, sim['properties'])
    except HTTPResponse as ex:
        return ex
    except ValueError as ex:
        return error(400, ex)
    except EnvironmentError as ex:
        return error(500, ex.message)

    # Create the response we would normally get from
    # the database
    task_props = {
        'id': task_id,
        'key': task_id,
        'value': {
            '_id': task_id,
            '_rev': uuid4().hex,
            'lock': 0,
            'done': 0,
            'name': name,
            'command': sim['command'],
            'arguments': sim.get('arguments', []),
            'parallelism': sim.get('parallelism', '*'),
            'version': version,
            'input': query,
            'uploads': {},
            'error': []
        }
    }

    if 'ensemble' in query:
        task_props['ensemble'] = query['ensemble']
    if 'simulation' in query:
        task_props['simulation'] = query['simulation']

    if task_id in mock_db:
        return error(400, "simulation name " + task_id + " already taken")

    # Add the new task to the "database"
    mock_db[task_id] = task_props

    response.status = 201  # created

    # Normally we return a link to the database, but now
    # we point to sim-city-webservice
    host = bottle.request.get_header('host')
    url = '%s/task/%s' % (host, task_id)
    response.set_header('Location', url)
    return task_props

@get(prefix + '/schema')
def schema_list():
    files = listfiles('schemas')
    return {'schemas': [f[:-5] for f in files if f.endswith('.json')]}

@get(prefix + '/schema/<name>')
def schema_name(name):
    return static_file(os.path.join('schemas', name + '.json'),
                       root=project_dir)

@get(prefix + '/resource')
def resource_list():
    files = listfiles('resources')
    return {"resources": [f[:-5] for f in files if f.endswith('.json')]}

@get(prefix + '/resource/<name>')
def resource_name(name):
    return static_file(os.path.join('resources', name + '.json'),
                       root=project_dir)

@get(prefix + '/view/totals')
def overview():
    try:
        return mock_overview_total()
    except:
        return error(500, "cannot read overview")

def mock_overview_total():
    views = ['todo', 'locked', 'error', 'done',
             'finished_jobs', 'active_jobs', 'pending_jobs']

    num = dict((view, 0) for view in views)

    for key, task in mock_db.items():
        for view in views:
            if view in task['value'] and task['value'][view] == 1:
                num[view] += 1

    return num

@post(prefix + '/job')
def submit_job():
    if not hasattr(submit_job, 'batch_id'):
        submit_job.batch_id = 1

    # Mock the response for submitting the job
    host = config_sim['default_host']
    _prefix = host + '-'
    batch_id = str(submit_job.batch_id)
    submit_job.batch_id += 1
    job_id = 'job_' + _prefix + uuid4().hex

    response.status = 201  # created
    return {'_id': job_id, 'batch_id': batch_id, 'hostname': host}

@get(prefix + '/simulation/<_id>')
def get_simulation(_id):
    if _id in mock_db:
        return mock_db[_id]['value']
    else:
        return error(404, "simulation does not exist")

@get(prefix + '/view/simulations/<name>/<version>')
def simulations_view(name, version):
    ensemble = request.query.get('ensemble')
    version = get_simulation_config(name, version, 'simulations')[1]

    simulations = [task for k, task in mock_db.items() if
                   task['value']['name'] == name and
                   task['value']['version'] == version and
                   (ensemble is None or task['value']['ensemble'] == ensemble)]

    response.status = 200
    return {'total_rows': len(simulations), 'offset': 0, 'rows': simulations}

@get(prefix + '/simulation/<id>/<attachment>')
def get_attachment(id, attachment):
    return static_file(os.path.join('mock_results', attachment), root=project_dir)

@delete(prefix + '/simulation/<_id>')
def del_simulation(_id):
    rev = request.query.get('rev')
    if rev is None:
        rev = request.get_header('If-Match')
    if rev is None:
        return error(409, "revision not specified")

    if _id in mock_db:
        task = mock_db[_id]
        if task['value']['_rev'] == rev:
            del mock_db[_id]
            return {'ok': True}
        else:
            return error(409, "resource conflict")
    else:
        return error(404, "Resource does not exist")

@get(prefix + '/hosts')
def get_hosts():
    hosts = {}
    for section in simcity.get_config().sections():
        if section.endswith('-host'):
            host_name = section[:-5]
            hosts[host_name] = {}
            if config_sim.get('default_host') == host_name:
                hosts[host_name]['default'] = True

    return hosts

if __name__ == '__main__':
    run(host='localhost', port=9090, server='wsgiref')
<|endoftext|>


<commit_before>"""
voxel.py
-----------

Convert meshes to a simple voxel data structure and back again.
"""
import numpy as np

from . import ops
from . import transforms
from . import morphology
from . import encoding as enc

from .. import caching
from .. import transformations as tr

from ..parent import Geometry
from ..constants import log

class VoxelGrid(Geometry):
    """
    Store 3D voxels.
    """

    def __init__(self, encoding, transform=None, metadata=None):
        if transform is None:
            transform = np.eye(4)
        if isinstance(encoding, np.ndarray):
            encoding = enc.DenseEncoding(encoding.astype(bool))
        if encoding.dtype != bool:
            raise ValueError('encoding must have dtype bool')
        self._data = caching.DataStore()
        self.encoding = encoding
        self._data['transform'] = transforms.Transform(transform)
        self._cache = caching.Cache(id_function=self._data.crc)

        self.metadata = dict()
        # update the mesh metadata with passed metadata
        if isinstance(metadata, dict):
            self.metadata.update(metadata)
        elif metadata is not None:
            raise ValueError(
                'metadata should be a dict or None, got %s' % str(metadata))

    def md5(self):
        return self._data.md5()

    def crc(self):
        return self._data.crc()

    @property
    def encoding(self):
        """
        `Encoding` object providing the occupancy grid.

        See `trimesh.voxel.encoding` for implementations.
        """
        return self._data['encoding']

    @encoding.setter
    def encoding(self, encoding):
        if isinstance(encoding, np.ndarray):
            encoding = enc.DenseEncoding(encoding)
        elif not isinstance(encoding, enc.Encoding):
            raise ValueError(
                'encoding must be an Encoding, got %s' % str(encoding))
        if len(encoding.shape) != 3:
            raise ValueError(
                'encoding must be rank 3, got shape %s' % str(encoding.shape))
        if encoding.dtype != bool:
            raise ValueError(
                'encoding must be binary, got %s' % encoding.dtype)
        self._data['encoding'] = encoding

    @property
    def _transform(self):
        return self._data['transform']

    @property
    def transform(self):
        """4x4 homogeneous transformation matrix."""
        return self._transform.matrix

    @transform.setter
    def transform(self, matrix):
        """4x4 homogeneous transformation matrix."""
        self._transform.matrix = matrix

    @property
    def translation(self):
        """Location of voxel at [0, 0, 0]."""
        return self._transform.translation

    @property
    def origin(self):
        """Deprecated. Use `self.translation`."""
        # DEPRECATED. Use translation instead
        return self.translation

    @property
    def scale(self):
        """
        3-element float representing per-axis scale.

        Raises a `RuntimeError` if `self.transform` has rotation or
        shear components.
        """
        return self._transform.scale

    @property
    def pitch(self):
        """
        Uniform scaling factor representing the side length of each voxel.

        Raises a `RuntimeError` if `self.transformation` has rotation or shear
        components of has non-uniform scaling.
        """
        return self._transform.pitch

    @property
    def element_volume(self):
        return self._transform.unit_volume

    def apply_transform(self, matrix):
        self._transform.apply_transform(matrix)
        return self

    def strip(self):
        """
        Mutate self by stripping leading/trailing planes of zeros.

        Returns
        --------
        self after mutation occurs in-place
        """
        encoding, padding = self.encoding.stripped
        self.encoding = encoding
        self._transform.matrix[:3, 3] = self.indices_to_points(padding[:, 0])
        return self

    @caching.cache_decorator
    def bounds(self):
        indices = self.sparse_indices
        bounds = np.array([indices.min(axis=0) - 0.5,
                           indices.max(axis=0) + 0.5])
        bounds = self._transform.transform_points(bounds)
        bounds.flags.writeable = False
        return bounds

    @caching.cache_decorator
    def extents(self):
        bounds = self.bounds
        extents = bounds[1] - bounds[0]
        extents.flags.writeable = False
        return extents

    @caching.cache_decorator
    def is_empty(self):
        return self.encoding.is_empty

    @property
    def shape(self):
        """3-tuple of ints denoting shape of occupancy grid."""
        return self.encoding.shape

    @caching.cache_decorator
    def filled_count(self):
        """int, number of occupied voxels in the grid."""
        return self.encoding.sum.item()

    def is_filled(self, point):
        """
        Query points to see if the voxel cells they lie in are
        filled or not.

        Parameters
        ----------
        point : (n, 3) float
          Points in space

        Returns
        ---------
        is_filled : (n,) bool
          Is cell occupied or not for each point
        """
        point = np.asanyarray(point)
        indices = self.points_to_indices(point)
        in_range = np.logical_and(
            np.all(indices < np.array(self.shape), axis=-1),
            np.all(indices >= 0, axis=-1))

        is_filled = np.zeros_like(in_range)
        is_filled[in_range] = self.encoding.gather_nd(indices[in_range])
        return is_filled

    def fill(self, method='holes', **kwargs):
        """
        Mutates self by filling in the encoding according to `morphology.fill`.

        Parameters
        ----------
        method: implementation key, one of
            `trimesh.voxel.morphology.fill.fillers` keys
        **kwargs: additional kwargs passed to the keyed implementation

        Returns
        ----------
        self after replacing encoding with a filled version.
        """
        self.encoding = morphology.fill(self.encoding, method=method, **kwargs)
        return self

    def hollow(self, structure=None):
        """
        Mutates self by removing internal voxels leaving only surface elements.

        Surviving elements are those in encoding that are adjacent to an empty
        voxel, where adjacency is controlled by `structure`.

        Parameters
        ----------
        structure: adjacency structure. If None, square connectivity is used.

        Returns
        ----------
        self after replacing encoding with a surface version.
        """
        self.encoding = morphology.surface(self.encoding)
        return self

    @caching.cache_decorator
    def marching_cubes(self):
        """
        A marching cubes Trimesh representation of the voxels.

        No effort was made to clean or smooth the result in any way;
        it is merely the result of applying the scikit-image
        measure.marching_cubes function to self.encoding.dense.

        Returns
        ---------
        meshed: Trimesh object representing the current voxel
                        object, as returned by marching cubes algorithm.
        """
        meshed = ops.matrix_to_marching_cubes(matrix=self.matrix)
        return meshed

    @property
    def matrix(self):
        """
        Return a DENSE matrix of the current voxel encoding

        Returns
        -------------
        dense : (a, b, c) bool
          Numpy array of dense matrix
          Shortcut to voxel.encoding.dense
        """
        return self.encoding.dense

    @caching.cache_decorator
    def volume(self):
        """
        What is the volume of the filled cells in the current voxel object.

        Returns
        ---------
        volume: float, volume of filled cells
        """
        return self.filled_count * self.element_volume

    @caching.cache_decorator
    def points(self):
        """
        The center of each filled cell as a list of points.

        Returns
        ----------
        points: (self.filled, 3) float, list of points
        """
        return self._transform.transform_points(
            self.sparse_indices.astype(float))

    @property
    def sparse_indices(self):
        """(n, 3) int array of sparse indices of occupied voxels."""
        return self.encoding.sparse_indices

    def as_boxes(self, colors=None, **kwargs):
        """
        A rough Trimesh representation of the voxels with a box
        for each filled voxel.

        Parameters
        ----------
        colors : (3,) or (4,) float or uint8
                 (X, Y, Z, 3) or (X, Y, Z, 4) float or uint8
         Where matrix.shape == (X, Y, Z)

        Returns
        ---------
        mesh : trimesh.Trimesh
          Mesh with one box per filled cell.
        """

        if colors is not None:
            colors = np.asanyarray(colors)
            if colors.ndim == 4:
                encoding = self.encoding
                if colors.shape[:3] == encoding.shape:
                    # TODO jackd: more efficient implementation?
                    # encoding.as_mask?
                    colors = colors[encoding.dense]
                else:
                    log.warning('colors incorrect shape!')
                    colors = None
            elif colors.shape not in ((3,), (4,)):
                log.warning('colors incorrect shape!')
                colors = None

        mesh = ops.multibox(
            centers=self.sparse_indices.astype(float), colors=colors)

        mesh = mesh.apply_transform(self.transform)
        return mesh

    def points_to_indices(self, points):
        """
        Convert points to indices in the matrix array.

        Parameters
        ----------
        points: (n, 3) float, point in space

        Returns
        ---------
        indices: (n, 3) int array of indices into self.encoding
        """
        points = self._transform.inverse_transform_points(points)
        return np.round(points).astype(int)

    def indices_to_points(self, indices):
        return self._transform.transform_points(indices.astype(float))

    def show(self, *args, **kwargs):
        """
        Convert the current set of voxels into a trimesh for visualization
        and show that via its built- in preview method.
        """
        return self.as_boxes(kwargs.pop(
            'colors', None)).show(*args, **kwargs)

    def copy(self):
        return VoxelGrid(self.encoding.copy(),
                         self._transform.matrix.copy())

    def revoxelized(self, shape):
        """
        Create a new VoxelGrid without rotations, reflections or shearing.

        Parameters
        ----------
        shape: 3-tuple of ints denoting the shape of the returned VoxelGrid.

        Returns
        ----------
        VoxelGrid of the given shape with (possibly non-uniform) scale and
        translation transformation matrix.
        """
        from .. import util
        shape = tuple(shape)
        bounds = self.bounds.copy()
        extents = self.extents
        points = util.grid_linspace(bounds, shape).reshape(shape + (3,))
        dense = self.is_filled(points)
        scale = extents / np.asanyarray(shape)
        translate = bounds[0]
        return VoxelGrid(
            dense,
            transform=tr.scale_and_translate(scale, translate))
<commit_msg>Get AABB after transform to compute bounds<commit_after>"""
voxel.py
-----------

Convert meshes to a simple voxel data structure and back again.
"""
import numpy as np

from . import ops
from . import transforms
from . import morphology
from . import encoding as enc

from .. import bounds as bounds_module
from .. import caching
from .. import transformations as tr

from ..parent import Geometry
from ..constants import log

class VoxelGrid(Geometry):
    """
    Store 3D voxels.
    """

    def __init__(self, encoding, transform=None, metadata=None):
        if transform is None:
            transform = np.eye(4)
        if isinstance(encoding, np.ndarray):
            encoding = enc.DenseEncoding(encoding.astype(bool))
        if encoding.dtype != bool:
            raise ValueError('encoding must have dtype bool')
        self._data = caching.DataStore()
        self.encoding = encoding
        self._data['transform'] = transforms.Transform(transform)
        self._cache = caching.Cache(id_function=self._data.crc)

        self.metadata = dict()
        # update the mesh metadata with passed metadata
        if isinstance(metadata, dict):
            self.metadata.update(metadata)
        elif metadata is not None:
            raise ValueError(
                'metadata should be a dict or None, got %s' % str(metadata))

    def md5(self):
        return self._data.md5()

    def crc(self):
        return self._data.crc()

    @property
    def encoding(self):
        """
        `Encoding` object providing the occupancy grid.

        See `trimesh.voxel.encoding` for implementations.
        """
        return self._data['encoding']

    @encoding.setter
    def encoding(self, encoding):
        if isinstance(encoding, np.ndarray):
            encoding = enc.DenseEncoding(encoding)
        elif not isinstance(encoding, enc.Encoding):
            raise ValueError(
                'encoding must be an Encoding, got %s' % str(encoding))
        if len(encoding.shape) != 3:
            raise ValueError(
                'encoding must be rank 3, got shape %s' % str(encoding.shape))
        if encoding.dtype != bool:
            raise ValueError(
                'encoding must be binary, got %s' % encoding.dtype)
        self._data['encoding'] = encoding

    @property
    def _transform(self):
        return self._data['transform']

    @property
    def transform(self):
        """4x4 homogeneous transformation matrix."""
        return self._transform.matrix

    @transform.setter
    def transform(self, matrix):
        """4x4 homogeneous transformation matrix."""
        self._transform.matrix = matrix

    @property
    def translation(self):
        """Location of voxel at [0, 0, 0]."""
        return self._transform.translation

    @property
    def origin(self):
        """Deprecated. Use `self.translation`."""
        # DEPRECATED. Use translation instead
        return self.translation

    @property
    def scale(self):
        """
        3-element float representing per-axis scale.

        Raises a `RuntimeError` if `self.transform` has rotation or
        shear components.
        """
        return self._transform.scale

    @property
    def pitch(self):
        """
        Uniform scaling factor representing the side length of each voxel.

        Raises a `RuntimeError` if `self.transformation` has rotation or shear
        components of has non-uniform scaling.
        """
        return self._transform.pitch

    @property
    def element_volume(self):
        return self._transform.unit_volume

    def apply_transform(self, matrix):
        self._transform.apply_transform(matrix)
        return self

    def strip(self):
        """
        Mutate self by stripping leading/trailing planes of zeros.

        Returns
        --------
        self after mutation occurs in-place
        """
        encoding, padding = self.encoding.stripped
        self.encoding = encoding
        self._transform.matrix[:3, 3] = self.indices_to_points(padding[:, 0])
        return self

    @caching.cache_decorator
    def bounds(self):
        indices = self.sparse_indices
        # get all 8 corners of the AABB
        corners = bounds_module.corners([indices.min(axis=0) - 0.5,
                                         indices.max(axis=0) + 0.5])
        # transform these corners to a new frame
        corners = self._transform.transform_points(corners)
        # get the AABB of corners in-frame
        bounds = np.array([corners.min(axis=0), corners.max(axis=0)])
        bounds.flags.writeable = False
        return bounds

    @caching.cache_decorator
    def extents(self):
        bounds = self.bounds
        extents = bounds[1] - bounds[0]
        extents.flags.writeable = False
        return extents

    @caching.cache_decorator
    def is_empty(self):
        return self.encoding.is_empty

    @property
    def shape(self):
        """3-tuple of ints denoting shape of occupancy grid."""
        return self.encoding.shape

    @caching.cache_decorator
    def filled_count(self):
        """int, number of occupied voxels in the grid."""
        return self.encoding.sum.item()

    def is_filled(self, point):
        """
        Query points to see if the voxel cells they lie in are
        filled or not.

        Parameters
        ----------
        point : (n, 3) float
          Points in space

        Returns
        ---------
        is_filled : (n,) bool
          Is cell occupied or not for each point
        """
        point = np.asanyarray(point)
        indices = self.points_to_indices(point)
        in_range = np.logical_and(
            np.all(indices < np.array(self.shape), axis=-1),
            np.all(indices >= 0, axis=-1))

        is_filled = np.zeros_like(in_range)
        is_filled[in_range] = self.encoding.gather_nd(indices[in_range])
        return is_filled

    def fill(self, method='holes', **kwargs):
        """
        Mutates self by filling in the encoding according to `morphology.fill`.

        Parameters
        ----------
        method: implementation key, one of
            `trimesh.voxel.morphology.fill.fillers` keys
        **kwargs: additional kwargs passed to the keyed implementation

        Returns
        ----------
        self after replacing encoding with a filled version.
        """
        self.encoding = morphology.fill(self.encoding, method=method, **kwargs)
        return self

    def hollow(self, structure=None):
        """
        Mutates self by removing internal voxels leaving only surface elements.

        Surviving elements are those in encoding that are adjacent to an empty
        voxel, where adjacency is controlled by `structure`.

        Parameters
        ----------
        structure: adjacency structure. If None, square connectivity is used.

        Returns
        ----------
        self after replacing encoding with a surface version.
        """
        self.encoding = morphology.surface(self.encoding)
        return self

    @caching.cache_decorator
    def marching_cubes(self):
        """
        A marching cubes Trimesh representation of the voxels.

        No effort was made to clean or smooth the result in any way;
        it is merely the result of applying the scikit-image
        measure.marching_cubes function to self.encoding.dense.

        Returns
        ---------
        meshed: Trimesh object representing the current voxel
                        object, as returned by marching cubes algorithm.
        """
        meshed = ops.matrix_to_marching_cubes(matrix=self.matrix)
        return meshed

    @property
    def matrix(self):
        """
        Return a DENSE matrix of the current voxel encoding

        Returns
        -------------
        dense : (a, b, c) bool
          Numpy array of dense matrix
          Shortcut to voxel.encoding.dense
        """
        return self.encoding.dense

    @caching.cache_decorator
    def volume(self):
        """
        What is the volume of the filled cells in the current voxel object.

        Returns
        ---------
        volume: float, volume of filled cells
        """
        return self.filled_count * self.element_volume

    @caching.cache_decorator
    def points(self):
        """
        The center of each filled cell as a list of points.

        Returns
        ----------
        points: (self.filled, 3) float, list of points
        """
        return self._transform.transform_points(
            self.sparse_indices.astype(float))

    @property
    def sparse_indices(self):
        """(n, 3) int array of sparse indices of occupied voxels."""
        return self.encoding.sparse_indices

    def as_boxes(self, colors=None, **kwargs):
        """
        A rough Trimesh representation of the voxels with a box
        for each filled voxel.

        Parameters
        ----------
        colors : (3,) or (4,) float or uint8
                 (X, Y, Z, 3) or (X, Y, Z, 4) float or uint8
         Where matrix.shape == (X, Y, Z)

        Returns
        ---------
        mesh : trimesh.Trimesh
          Mesh with one box per filled cell.
        """

        if colors is not None:
            colors = np.asanyarray(colors)
            if colors.ndim == 4:
                encoding = self.encoding
                if colors.shape[:3] == encoding.shape:
                    # TODO jackd: more efficient implementation?
                    # encoding.as_mask?
                    colors = colors[encoding.dense]
                else:
                    log.warning('colors incorrect shape!')
                    colors = None
            elif colors.shape not in ((3,), (4,)):
                log.warning('colors incorrect shape!')
                colors = None

        mesh = ops.multibox(
            centers=self.sparse_indices.astype(float), colors=colors)

        mesh = mesh.apply_transform(self.transform)
        return mesh

    def points_to_indices(self, points):
        """
        Convert points to indices in the matrix array.

        Parameters
        ----------
        points: (n, 3) float, point in space

        Returns
        ---------
        indices: (n, 3) int array of indices into self.encoding
        """
        points = self._transform.inverse_transform_points(points)
        return np.round(points).astype(int)

    def indices_to_points(self, indices):
        return self._transform.transform_points(indices.astype(float))

    def show(self, *args, **kwargs):
        """
        Convert the current set of voxels into a trimesh for visualization
        and show that via its built- in preview method.
        """
        return self.as_boxes(kwargs.pop(
            'colors', None)).show(*args, **kwargs)

    def copy(self):
        return VoxelGrid(self.encoding.copy(),
                         self._transform.matrix.copy())

    def revoxelized(self, shape):
        """
        Create a new VoxelGrid without rotations, reflections or shearing.

        Parameters
        ----------
        shape: 3-tuple of ints denoting the shape of the returned VoxelGrid.

        Returns
        ----------
        VoxelGrid of the given shape with (possibly non-uniform) scale and
        translation transformation matrix.
        """
        from .. import util
        shape = tuple(shape)
        bounds = self.bounds.copy()
        extents = self.extents
        points = util.grid_linspace(bounds, shape).reshape(shape + (3,))
        dense = self.is_filled(points)
        scale = extents / np.asanyarray(shape)
        translate = bounds[0]
        return VoxelGrid(
            dense,
            transform=tr.scale_and_translate(scale, translate))
<|endoftext|>


<commit_before>'''
Created on Dec 1, 2014

@author: fechnert
'''

import logging
import time
from utils import Escaper

class ClientAction(object):
    ''' Represents a action for clients to treat them '''

    def __init__(self, client_obj, featurename, additional_params):
        self.client_obj = client_obj
        self.featurename = featurename
        self.additional_params = additional_params
        self._set_trigger_time()
        self._set_last_triggered()

    def _set_trigger_time(self):
        ''' Get the delay of a action and add it to current time as trigger time '''
        try: s_delay = self.additional_params['s_delay']
        except KeyError: s_delay = 0
        try: m_delay = self.additional_params['m_delay']
        except KeyError: m_delay = 0

        if s_delay and m_delay:
            logging.warn('{}: s_delay and m_delay set ... ignoring both!'.format(self.featurename))
            delay = 0
        elif m_delay:
            delay = m_delay * 60
        else:
            delay = s_delay
        self.trigger_time = time.time() + delay

    def _set_last_triggered(self):
        ''' Sets the current time as last triggered '''
        self.last_triggered = time.time()

    def execute(self):
        ''' Execute this action on the client '''
        return getattr(self.client_obj, self.additional_params['action'])(
            self.featurename,
            **self.additional_params
        )

    def __repr__(self):
        return '<{featurename}_{actionname}_clid={clid}>'.format(
            featurename=self.featurename,
            actionname=self.additional_params['action'].capitalize(),
            clid=self.client_obj.clid
        )

class MoveBackAction(object):
    ''' This is a helper class to move back clients which have been moved '''

    def __init__(self, clid, to, feature_name, trigger_time):
        ''' initialize the object '''
        self.clid = clid
        self.to = to
        self.feature_name = feature_name
        self.trigger_time = trigger_time

    def __repr__(self):
        return '<{featurename}_moveback_{clid}>'.format(
            featurename=self.feature_name,
            clid=self.clid
        )

class Client(object):
    ''' Represents the client '''

    def __init__(self, clid, socket, **kwargs):
        ''' Fill the object dynamically with client attributes got from telnet '''
        self.clid = clid
        self.socket = socket
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __repr__(self):
        return '<{}>'.format(Escaper.decode(self.client_nickname))

    @Escaper.encode_attr('reason')
    def kick(self, featurename, reasonid, reason='ByeBye', **kwargs):
        ''' Kick a client '''
        self.socket.write('clientkick reasonid={} reasonmsg={} clid={}\n'.format(reasonid, reason, self.clid))
        self.socket.read_until('msg=ok', 2)
        logging.info('Feature \'{}\' kicked {}'.format(featurename, self.client_nickname))

    def move(self, featurename, to, **kwargs):
        ''' Move a client :to: a channel '''
        if int(self.cid) != to:
            self.ocid = self.cid
            self.cid = to
            self.socket.write('clientmove cid={} clid={}\n'.format(to, self.clid))
            self.socket.read_until('msg=ok', 2)
            logging.info('Feature \'{}\' moved {} (from cid {} to {})'.format(featurename, self.client_nickname, self.ocid, to))
            return True
        else:
            self.ocid = to
            return False

    @Escaper.encode_attr('reason')
    def ban(self, featurename, time=0, reason='Kicked', **kwargs):
        ''' Ban a client for :sfor: seconds '''
        if time:
            self.socket.write('banclient clid={} banreason={} time={}\n'.format(self.clid, reason, time))
        else:
            self.socket.write('banclient clid={} banreason={}\n'.format(self.clid, reason))
        self.socket.read_until('msg=ok', 2)
        logging.info('Feature \'{}\' banned {} for {} seconds (0 = infinite)'.format(featurename, self.client_nickname, time))

    def show(self, featurename, **kwargs):
        ''' Only shows the clientname (for debugging purpose) '''
        logging.info('{}: {}'.format(featurename, Escaper.decode(self.client_nickname)))

class Channel(object):
    ''' Represents the Channel '''

    def __init__(self, socket, **kwargs):
        ''' Fill the object dynamically with channel attributes got from telnet '''
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __repr__(self):
        return '<Channel object ({})>'.format(self.channel_name)

    def delete(self):
        ''' Delete a channel '''
        raise NotImplementedError
<commit_msg>Decode nickname in log messages<commit_after>'''
Created on Dec 1, 2014

@author: fechnert
'''

import logging
import time
from utils import Escaper

class ClientAction(object):
    ''' Represents a action for clients to treat them '''

    def __init__(self, client_obj, featurename, additional_params):
        self.client_obj = client_obj
        self.featurename = featurename
        self.additional_params = additional_params
        self._set_trigger_time()
        self._set_last_triggered()

    def _set_trigger_time(self):
        ''' Get the delay of a action and add it to current time as trigger time '''
        try: s_delay = self.additional_params['s_delay']
        except KeyError: s_delay = 0
        try: m_delay = self.additional_params['m_delay']
        except KeyError: m_delay = 0

        if s_delay and m_delay:
            logging.warn('{}: s_delay and m_delay set ... ignoring both!'.format(self.featurename))
            delay = 0
        elif m_delay:
            delay = m_delay * 60
        else:
            delay = s_delay
        self.trigger_time = time.time() + delay

    def _set_last_triggered(self):
        ''' Sets the current time as last triggered '''
        self.last_triggered = time.time()

    def execute(self):
        ''' Execute this action on the client '''
        return getattr(self.client_obj, self.additional_params['action'])(
            self.featurename,
            **self.additional_params
        )

    def __repr__(self):
        return '<{featurename}_{actionname}_clid={clid}>'.format(
            featurename=self.featurename,
            actionname=self.additional_params['action'].capitalize(),
            clid=self.client_obj.clid
        )

class MoveBackAction(object):
    ''' This is a helper class to move back clients which have been moved '''

    def __init__(self, clid, to, feature_name, trigger_time):
        ''' initialize the object '''
        self.clid = clid
        self.to = to
        self.feature_name = feature_name
        self.trigger_time = trigger_time

    def __repr__(self):
        return '<{featurename}_moveback_{clid}>'.format(
            featurename=self.feature_name,
            clid=self.clid
        )

class Client(object):
    ''' Represents the client '''

    def __init__(self, clid, socket, **kwargs):
        ''' Fill the object dynamically with client attributes got from telnet '''
        self.clid = clid
        self.socket = socket
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __repr__(self):
        return '<{}>'.format(Escaper.decode(self.client_nickname))

    @Escaper.encode_attr('reason')
    def kick(self, featurename, reasonid, reason='ByeBye', **kwargs):
        ''' Kick a client '''
        self.socket.write('clientkick reasonid={} reasonmsg={} clid={}\n'.format(reasonid, reason, self.clid))
        self.socket.read_until('msg=ok', 2)
        logging.info('Feature \'{}\' kicked {}'.format(featurename, Escaper.decode(self.client_nickname)))

    def move(self, featurename, to, **kwargs):
        ''' Move a client :to: a channel '''
        if int(self.cid) != to:
            self.ocid = self.cid
            self.cid = to
            self.socket.write('clientmove cid={} clid={}\n'.format(to, self.clid))
            self.socket.read_until('msg=ok', 2)
            logging.info('Feature \'{}\' moved {} (from cid {} to {})'.format(featurename, Escaper.decode(self.client_nickname), self.ocid, to))
            return True
        else:
            self.ocid = to
            return False

    @Escaper.encode_attr('reason')
    def ban(self, featurename, time=0, reason='Kicked', **kwargs):
        ''' Ban a client for :sfor: seconds '''
        if time:
            self.socket.write('banclient clid={} banreason={} time={}\n'.format(self.clid, reason, time))
        else:
            self.socket.write('banclient clid={} banreason={}\n'.format(self.clid, reason))
        self.socket.read_until('msg=ok', 2)
        logging.info('Feature \'{}\' banned {} for {} seconds (0 = infinite)'.format(featurename, Escaper.decode(self.client_nickname), time))

    def show(self, featurename, **kwargs):
        ''' Only shows the clientname (for debugging purpose) '''
        logging.info('{}: {}'.format(featurename, Escaper.decode(self.client_nickname)))

class Channel(object):
    ''' Represents the Channel '''

    def __init__(self, socket, **kwargs):
        ''' Fill the object dynamically with channel attributes got from telnet '''
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __repr__(self):
        return '<Channel object ({})>'.format(self.channel_name)

    def delete(self):
        ''' Delete a channel '''
        raise NotImplementedError
<|endoftext|>


<commit_before>from django.utils.translation import ugettext as _
from django.template import (Library, Node, Variable, VariableDoesNotExist,
                            TemplateSyntaxError, RequestContext, Context)
from django.template.loader import get_template

register = Library()

def _get_default_letters(model_admin=None):
    """
    Returns the set of letters defined in the configuration variable
    DEFAULT_ALPHABET. DEFAULT_ALPHABET can be a callable, string, tuple, or
    list and returns a set.

    If a ModelAdmin class is passed, it will look for a DEFAULT_ALPHABET
    attribute and use it instead.
    """
    from django.conf import settings
    import string
    default_ltrs = string.digits + string.ascii_uppercase
    default_letters = getattr(settings, 'DEFAULT_ALPHABET', default_ltrs)
    if model_admin and hasattr(model_admin, 'DEFAULT_ALPHABET'):
        default_letters = model_admin.DEFAULT_ALPHABET
    if callable(default_letters):
        return set(default_letters())
    elif isinstance(default_letters, unicode):
        return set([x for x in default_letters])
    elif isinstance(default_letters, str):
        return set([x for x in default_letters.decode('utf8')])
    elif isinstance(default_letters, (tuple, list)):
        return set(default_letters)

def _get_available_letters(field_name, db_table):
    """
    Makes a query to the database to return the first character of each
    value of the field and table passed in.

    Returns a set that represents the letters that exist in the database.
    """
    from django.db import connection
    qn = connection.ops.quote_name
    sql = "SELECT DISTINCT UPPER(SUBSTR(%s, 1, 1)) as letter FROM %s" \
                % (qn(field_name), qn(db_table))
    cursor = connection.cursor()
    cursor.execute(sql)
    rows = cursor.fetchall() or ()
    return set([row[0] for row in rows if row[0] is not None])

def alphabet(cl):
    """
    The inclusion tag that renders the admin/alphabet.html template in the
    admin. Accepts a ChangeList object, which is custom to the admin.
    """
    if not getattr(cl.model_admin, 'alphabet_filter', False):
        return
    field_name = cl.model_admin.alphabet_filter
    alpha_field = '%s__istartswith' % field_name
    alpha_lookup = cl.params.get(alpha_field, '')
    link = lambda d: cl.get_query_string(d)

    letters_used = _get_available_letters(field_name, cl.model._meta.db_table)
    all_letters = list(_get_default_letters(cl.model_admin) | letters_used)
    all_letters.sort()

    choices = [{
        'link': link({alpha_field: letter}),
        'title': letter,
        'active': letter == alpha_lookup,
        'has_entries': letter in letters_used,} for letter in all_letters]
    all_letters = [{
        'link': cl.get_query_string(None,alpha_field),
        'title': _('All'),
        'active': '' == alpha_lookup,
        'has_entries': True
    },]
    return {'choices': all_letters + choices}
alphabet = register.inclusion_tag('admin/alphabet.html')(alphabet)

class AlphabetFilterNode(Node):
    """
    Provide a list of links for first characters on items in a queryset

    {% qs_alphabet_filter objects "lastname" "myapp/template.html" %}
    """
    def __init__(self, qset, field_name,
        template_name="alphafilter/alphabet.html"):
        self.qset = Variable(qset)
        self.field_name = Variable(field_name)
        self.template_name = Variable(template_name)

    def render(self, context):
        try:
            qset = self.qset.resolve(context)
        except VariableDoesNotExist:
            raise TemplateSyntaxError("Can't resolve the queryset passed")
        try:
            field_name = self.field_name.resolve(context)
        except VariableDoesNotExist:
            field_name = self.field_name.var

        if not field_name:
            return ''

        alpha_field = '%s__istartswith' % field_name
        request = context.get('request', None)

        if request is not None:
            alpha_lookup = request.GET.get(alpha_field, '')
            qstring_items = request.GET.copy()
            if alpha_field in qstring_items:
                qstring_items.pop(alpha_field)
            qstring = "&".join(["%s=%s" % (k, v) for k, v in qstring_items])
        else:
            alpha_lookup = ''
            qstring = ''

        link = lambda d: "?%s%s" % (qstring, "%s=%s" % d.items()[0])
        letters_used = _get_available_letters(
                            field_name,
                            qset.model._meta.db_table)
        all_letters = list(_get_default_letters(None) | letters_used)
        all_letters.sort()

        choices = [{
            'link': link({alpha_field: letter}),
            'title': letter,
            'active': letter == alpha_lookup,
            'has_entries': letter in letters_used,} for letter in all_letters]
        all_letters = [{
            'link': link({alpha_field: ''}),
            'title': _('All'),
            'active': '' == alpha_lookup,
            'has_entries': True
        },]
        ctxt = {'choices': all_letters + choices}

        tmpl = get_template(self.template_name)

        if request is not None:
            return tmpl.render(RequestContext(request, ctxt))
        else:
            return tmpl.render(Context(ctxt))

@register.tag
def qs_alphabet_filter(parser, token):
    """
    The parser/tokenizer for the queryset alphabet filter.

    {% qs_alphabet_filter <queryset> <field name> [<template name>] %}

    {% qs_alphabet_filter objects lastname myapp/template.html %}

    The template name is optional and uses alphafilter/alphabet.html if not
    specified
    """
    bits = token.split_contents()
    if len(bits) == 3:
        return AlphabetFilterNode(bits[1], bits[2])
    elif len(bits) == 4:
        return AlphabetFilterNode(bits[1], bits[2], bits[3])
    else:
        raise TemplateSyntaxError("%s is called with a queryset and field "
            "name, and optionally a template." % bits[0])
<commit_msg>Fixed github issue #3. Thanks Fabian!<commit_after>from django.utils.translation import ugettext as _
from django.template import (Library, Node, Variable, VariableDoesNotExist,
                            TemplateSyntaxError, RequestContext, Context)
from django.template.loader import get_template

register = Library()

def _get_default_letters(model_admin=None):
    """
    Returns the set of letters defined in the configuration variable
    DEFAULT_ALPHABET. DEFAULT_ALPHABET can be a callable, string, tuple, or
    list and returns a set.

    If a ModelAdmin class is passed, it will look for a DEFAULT_ALPHABET
    attribute and use it instead.
    """
    from django.conf import settings
    import string
    default_ltrs = string.digits + string.ascii_uppercase
    default_letters = getattr(settings, 'DEFAULT_ALPHABET', default_ltrs)
    if model_admin and hasattr(model_admin, 'DEFAULT_ALPHABET'):
        default_letters = model_admin.DEFAULT_ALPHABET
    if callable(default_letters):
        return set(default_letters())
    elif isinstance(default_letters, unicode):
        return set([x for x in default_letters])
    elif isinstance(default_letters, str):
        return set([x for x in default_letters.decode('utf8')])
    elif isinstance(default_letters, (tuple, list)):
        return set(default_letters)

def _get_available_letters(field_name, db_table):
    """
    Makes a query to the database to return the first character of each
    value of the field and table passed in.

    Returns a set that represents the letters that exist in the database.
    """
    from django.db import connection
    qn = connection.ops.quote_name
    sql = "SELECT DISTINCT UPPER(SUBSTR(%s, 1, 1)) as letter FROM %s" \
                % (qn(field_name), qn(db_table))
    cursor = connection.cursor()
    cursor.execute(sql)
    rows = cursor.fetchall() or ()
    return set([row[0] for row in rows if row[0] is not None])

def alphabet(cl):
    """
    The inclusion tag that renders the admin/alphabet.html template in the
    admin. Accepts a ChangeList object, which is custom to the admin.
    """
    if not getattr(cl.model_admin, 'alphabet_filter', False):
        return
    field_name = cl.model_admin.alphabet_filter
    alpha_field = '%s__istartswith' % field_name
    alpha_lookup = cl.params.get(alpha_field, '')
    link = lambda d: cl.get_query_string(d)

    letters_used = _get_available_letters(field_name, cl.model._meta.db_table)
    all_letters = list(_get_default_letters(cl.model_admin) | letters_used)
    all_letters.sort()

    choices = [{
        'link': link({alpha_field: letter}),
        'title': letter,
        'active': letter == alpha_lookup,
        'has_entries': letter in letters_used,} for letter in all_letters]
    all_letters = [{
        'link': cl.get_query_string(None, [alpha_field]),
        'title': _('All'),
        'active': '' == alpha_lookup,
        'has_entries': True
    },]
    return {'choices': all_letters + choices}
alphabet = register.inclusion_tag('admin/alphabet.html')(alphabet)

class AlphabetFilterNode(Node):
    """
    Provide a list of links for first characters on items in a queryset

    {% qs_alphabet_filter objects "lastname" "myapp/template.html" %}
    """
    def __init__(self, qset, field_name,
        template_name="alphafilter/alphabet.html"):
        self.qset = Variable(qset)
        self.field_name = Variable(field_name)
        self.template_name = Variable(template_name)

    def render(self, context):
        try:
            qset = self.qset.resolve(context)
        except VariableDoesNotExist:
            raise TemplateSyntaxError("Can't resolve the queryset passed")
        try:
            field_name = self.field_name.resolve(context)
        except VariableDoesNotExist:
            field_name = self.field_name.var

        if not field_name:
            return ''

        alpha_field = '%s__istartswith' % field_name
        request = context.get('request', None)

        if request is not None:
            alpha_lookup = request.GET.get(alpha_field, '')
            qstring_items = request.GET.copy()
            if alpha_field in qstring_items:
                qstring_items.pop(alpha_field)
            qstring = "&".join(["%s=%s" % (k, v) for k, v in qstring_items])
        else:
            alpha_lookup = ''
            qstring = ''

        link = lambda d: "?%s%s" % (qstring, "%s=%s" % d.items()[0])
        letters_used = _get_available_letters(
                            field_name,
                            qset.model._meta.db_table)
        all_letters = list(_get_default_letters(None) | letters_used)
        all_letters.sort()

        choices = [{
            'link': link({alpha_field: letter}),
            'title': letter,
            'active': letter == alpha_lookup,
            'has_entries': letter in letters_used,} for letter in all_letters]
        all_letters = [{
            'link': link({alpha_field: ''}),
            'title': _('All'),
            'active': '' == alpha_lookup,
            'has_entries': True
        },]
        ctxt = {'choices': all_letters + choices}

        tmpl = get_template(self.template_name)

        if request is not None:
            return tmpl.render(RequestContext(request, ctxt))
        else:
            return tmpl.render(Context(ctxt))

@register.tag
def qs_alphabet_filter(parser, token):
    """
    The parser/tokenizer for the queryset alphabet filter.

    {% qs_alphabet_filter <queryset> <field name> [<template name>] %}

    {% qs_alphabet_filter objects lastname myapp/template.html %}

    The template name is optional and uses alphafilter/alphabet.html if not
    specified
    """
    bits = token.split_contents()
    if len(bits) == 3:
        return AlphabetFilterNode(bits[1], bits[2])
    elif len(bits) == 4:
        return AlphabetFilterNode(bits[1], bits[2], bits[3])
    else:
        raise TemplateSyntaxError("%s is called with a queryset and field "
            "name, and optionally a template." % bits[0])
<|endoftext|>


<commit_before>"""
piplint
~~~~~~~

:copyright: 2012 DISQUS.
:license: Apache License 2.0, see LICENSE for more details.
"""

import re
import sys
from pkg_resources import parse_version
from subprocess import Popen, PIPE

def check_requirements(requirement_files, strict=False):
    """
    Given a list of requirements files, checks them against the installed
    packages in the currentl environment. If any are missing, or do not fit
    within the version bounds, exits with a code of 1 and outputs information
    about the missing dependency.
    """
    version_re = re.compile(r'^([^<>=\s#]+)\s*(>=|>|<|<=|==)?\s*([^<>=\s#]+)?(?:\s*#.*)?$')

    def parse_package_line(line):
        try:
            package, compare, version = version_re.split(line)[1:-1]
        except ValueError:
            raise ValueError("Unknown package line format: %r" % line)
        return (package, compare or None, parse_version(version) if version else None, line)

    def valid_version(version, compare, r_version):
        if not all([compare, version]):
            return True
        if compare == '==':
            return version == r_version
        elif compare == '<=':
            return version <= r_version
        elif compare == '>=':
            return version >= r_version
        elif compare == '<':
            return version < r_version
        elif compare == '>':
            return version > r_version
        raise ValueError("Unknown comparison operator: %r" % compare)

    frozen_reqs = []
    unknown_reqs = set()
    listed_reqs = []

    freeze = Popen(['pip freeze'], stdout=PIPE, shell=True)
    for line in freeze.communicate()[0].splitlines():
        line = line.strip()
        if not line or line.startswith('-'):
            unknown_reqs.add(line)
            continue
        frozen_reqs.append(parse_package_line(line))

    for fname in requirement_files:
        with open(fname) as fp:
            for line in fp:
                line = line.strip()
                if not line or line.startswith('-') or line.startswith('#'):
                    continue

                listed_reqs.append(parse_package_line(line))

    unknown_reqs.update(set(r[0] for r in frozen_reqs).difference(set(r[0] for r in listed_reqs)))

    for r_package, r_compare, r_version, r_line in listed_reqs:
        if not strict:
            r_package = r_package.lower()
        found = False

        for package, _, version, line in frozen_reqs:
            if not strict:
                package = package.lower()
            if found:
                continue
            if package == r_package:
                if not valid_version(version, r_compare, r_version):
                    print "Requirement %r was found in virtualenv, but is not a valid version" % r_package
                    print "Found %r, but expected %r" % (line, r_line)
                    return 1

                found = True

        if not found:
            print "Requirement %r not found in virtualenv." % r_package
            print "You must correct your environment before committing (and running tests)."
            if unknown_reqs:
                print ""
                print "For debugging purposes, the following unrecognized requirements were found:"
                print ""
                print "\n".join(sorted(unknown_reqs))
            return 1

    return 0

def main():
    import optparse
    parser = optparse.OptionParser()
    parser.add_option("--strict", dest="strict", action='store_true', default=False)
    (options, file_list) = parser.parse_args()
    if not file_list:
        print "Usage: piplint <requirements.txt>"
        sys.exit(1)
    sys.exit(check_requirements(file_list, **options.__dict__))

if __name__ == '__main__':
    main()
<commit_msg>Support requirements that start with '-e'<commit_after>"""
piplint
~~~~~~~

:copyright: 2012 DISQUS.
:license: Apache License 2.0, see LICENSE for more details.
"""

import re
import sys
from pkg_resources import parse_version
from subprocess import Popen, PIPE

def check_requirements(requirement_files, strict=False):
    """
    Given a list of requirements files, checks them against the installed
    packages in the currentl environment. If any are missing, or do not fit
    within the version bounds, exits with a code of 1 and outputs information
    about the missing dependency.
    """
    version_re = re.compile(r'^([^<>=\s#]+)\s*(>=|>|<|<=|==)?\s*([^<>=\s#]+)?(?:\s*#.*)?$')
    checkout_re = re.compile(r'[#@]')

    def parse_package_line(line):
        try:
            if line.startswith('-e'):
                return parse_checkout_line(line)
            package, compare, version = version_re.split(line)[1:-1]
        except ValueError:
            raise ValueError("Unknown package line format: %r" % line)
        return (package, compare or None, parse_version(version) if version else None, line)

    def parse_checkout_line(whole_line):
        """
        parse a line that starts with '-e'

        e.g.,
        -e git://github.com/jcrocholl/pep8.git@bb20999aefc394fb826371764146bf61d8e572e2#egg=pep8-dev
        """
        # Snip off the '-e' and any leading whitespace
        line = whole_line[2:].lstrip()

        # Check if there is a revision specified
        if '@' in line:
            (url, rev, eggname) = checkout_re.split(line)
            return (url, '==', rev, line)
        else:
            (url, eggname) = line.split('#')
            return (url, None, None, line)

    def is_requirements_line(line):
        """
        line is a valid requirement in requirements file or pip freeze output
        """
        if not line:
            return False
        if line.startswith('#'):
            return False
        if line.startswith('-e'):
            return True
        if line.startswith('-'):
            return False
        return True

    def valid_version(version, compare, r_version):
        if not all([compare, version]):
            return True
        if compare == '==':
            return version == r_version
        elif compare == '<=':
            return version <= r_version
        elif compare == '>=':
            return version >= r_version
        elif compare == '<':
            return version < r_version
        elif compare == '>':
            return version > r_version
        raise ValueError("Unknown comparison operator: %r" % compare)

    frozen_reqs = []
    unknown_reqs = set()
    listed_reqs = []

    freeze = Popen(['pip freeze'], stdout=PIPE, shell=True)
    for line in freeze.communicate()[0].splitlines():
        line = line.strip()
        if not is_requirements_line(line):
            unknown_reqs.add(line)
            continue
        frozen_reqs.append(parse_package_line(line))

    for fname in requirement_files:
        with open(fname) as fp:
            for line in fp:
                line = line.strip()
                if not is_requirements_line(line):
                    continue

                listed_reqs.append(parse_package_line(line))

    unknown_reqs.update(set(r[0] for r in frozen_reqs).difference(set(r[0] for r in listed_reqs)))

    for r_package, r_compare, r_version, r_line in listed_reqs:
        if not strict:
            r_package = r_package.lower()
        found = False

        for package, _, version, line in frozen_reqs:
            if not strict:
                package = package.lower()
            if found:
                continue
            if package == r_package:
                if not valid_version(version, r_compare, r_version):
                    print "Requirement %r was found in virtualenv, but is not a valid version" % r_package
                    print "Found %r, but expected %r" % (line, r_line)
                    return 1

                found = True

        if not found:
            print "Requirement %r not found in virtualenv." % r_package
            print "You must correct your environment before committing (and running tests)."
            if unknown_reqs:
                print ""
                print "For debugging purposes, the following unrecognized requirements were found:"
                print ""
                print "\n".join(sorted(unknown_reqs))
            return 1

    return 0

def main():
    import optparse
    parser = optparse.OptionParser()
    parser.add_option("--strict", dest="strict", action='store_true', default=False)
    (options, file_list) = parser.parse_args()
    if not file_list:
        print "Usage: piplint <requirements.txt>"
        sys.exit(1)
    sys.exit(check_requirements(file_list, **options.__dict__))

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


<commit_before># Copyright 2018 Datawire. 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

from typing import Callable, Dict, List, Optional, Union
from typing import cast as typecast

from ...ir.irtlscontext import IRTLSContext

# This stuff isn't really accurate, but it'll do for now.
EnvoyCoreSource = Dict[str, str]

EnvoyTLSCert = Dict[str, EnvoyCoreSource]
ListOfCerts = List[EnvoyTLSCert]

EnvoyValidationElements = Union[EnvoyCoreSource, bool]
EnvoyValidationContext = Dict[str, EnvoyValidationElements]

EnvoyCommonTLSElements = Union[List[str], ListOfCerts, EnvoyValidationContext]
EnvoyCommonTLSContext = Dict[str, EnvoyCommonTLSElements]

ElementHandler = Callable[[str, str], None]

class V2TLSContext(Dict):
    def __init__(self, ctx: Optional[IRTLSContext]=None, host_rewrite: Optional[str]=None) -> None:
        super().__init__()

        if ctx:
            self.add_context(ctx)

    def get_common(self) -> EnvoyCommonTLSContext:
        return self.setdefault('common_tls_context', {})

    def get_certs(self) -> ListOfCerts:
        common = self.get_common()

        # We have to explicitly cast this empty list to a list of strings.
        empty_cert_list: List[str] = []
        cert_list = common.setdefault('tls_certificates', empty_cert_list)

        # cert_list is of type EnvoyCommonTLSElements right now, so we need to cast it.
        return typecast(ListOfCerts, cert_list)

    def update_cert_zero(self, key: str, value: str) -> None:
        certs = self.get_certs()

        if not certs:
            certs.append({})

        src: EnvoyCoreSource = { 'filename': value }
        certs[0][key] = src

    def update_alpn(self, key: str, value: str) -> None:
        common = self.get_common()
        common[key] = [ value ]

    def update_tsl_version(self, key: str, value: str) -> None:
        common = self.get_common()
        if common['tls_parameters'] is None:
            common.setdefault('tls_parameters', {})

        common['tls_parameters'][key] = value

    def update_validation(self, key: str, value: str) -> None:
        empty_context: EnvoyValidationContext = {}
        validation = typecast(EnvoyValidationContext, self.get_common().setdefault('validation_context', empty_context))

        src: EnvoyCoreSource = { 'filename': value }
        validation[key] = src

    def add_context(self, ctx: IRTLSContext) -> None:
        handler: ElementHandler = self.__setitem__

        for secretinfokey, handler, hkey in [
            ( 'cert_chain_file', self.update_cert_zero, 'certificate_chain' ),
            ( 'private_key_file', self.update_cert_zero, 'private_key' ),
            ( 'cacert_chain_file', self.update_validation, 'trusted_ca' ),
        ]:
            if secretinfokey in ctx['secret_info']:
                handler(hkey, ctx['secret_info'][secretinfokey])

        for ctxkey, handler, hkey in [
            ( 'alpn_protocols', self.update_alpn, 'alpn_protocols' ),
            ( 'cert_required', self.__setitem__, 'require_client_certificate' ),
            ( 'min_tls_version', self.update_tsl_version, 'tls_minimum_protocol_version' ),
            ( 'max_tls_version', self.update_tsl_version, 'tls_maximum_protocol_version' ),
        ]:
            value = ctx.get(ctxkey, None)

            if value is not None:
                handler(hkey, value)
<commit_msg>fixed issure with v2tls<commit_after># Copyright 2018 Datawire. 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

from typing import Callable, Dict, List, Optional, Union
from typing import cast as typecast

from ...ir.irtlscontext import IRTLSContext

# This stuff isn't really accurate, but it'll do for now.
EnvoyCoreSource = Dict[str, str]

EnvoyTLSCert = Dict[str, EnvoyCoreSource]
ListOfCerts = List[EnvoyTLSCert]

EnvoyValidationElements = Union[EnvoyCoreSource, bool]
EnvoyValidationContext = Dict[str, EnvoyValidationElements]

EnvoyCommonTLSElements = Union[List[str], ListOfCerts, EnvoyValidationContext]
EnvoyCommonTLSContext = Dict[str, EnvoyCommonTLSElements]

ElementHandler = Callable[[str, str], None]

class V2TLSContext(Dict):
    def __init__(self, ctx: Optional[IRTLSContext]=None, host_rewrite: Optional[str]=None) -> None:
        super().__init__()

        if ctx:
            self.add_context(ctx)

    def get_common(self) -> EnvoyCommonTLSContext:
        return self.setdefault('common_tls_context', {})

    def get_certs(self) -> ListOfCerts:
        common = self.get_common()

        # We have to explicitly cast this empty list to a list of strings.
        empty_cert_list: List[str] = []
        cert_list = common.setdefault('tls_certificates', empty_cert_list)

        # cert_list is of type EnvoyCommonTLSElements right now, so we need to cast it.
        return typecast(ListOfCerts, cert_list)

    def update_cert_zero(self, key: str, value: str) -> None:
        certs = self.get_certs()

        if not certs:
            certs.append({})

        src: EnvoyCoreSource = { 'filename': value }
        certs[0][key] = src

    def update_alpn(self, key: str, value: str) -> None:
        common = self.get_common()
        common[key] = [ value ]

    def update_tls_version(self, key: str, value: str) -> None:
        common = self.get_common()
        common.setdefault('tls_parameters', {})
        common['tls_parameters'][key] = value

    def update_validation(self, key: str, value: str) -> None:
        empty_context: EnvoyValidationContext = {}
        validation = typecast(EnvoyValidationContext, self.get_common().setdefault('validation_context', empty_context))

        src: EnvoyCoreSource = { 'filename': value }
        validation[key] = src

    def add_context(self, ctx: IRTLSContext) -> None:
        handler: ElementHandler = self.__setitem__

        for secretinfokey, handler, hkey in [
            ( 'cert_chain_file', self.update_cert_zero, 'certificate_chain' ),
            ( 'private_key_file', self.update_cert_zero, 'private_key' ),
            ( 'cacert_chain_file', self.update_validation, 'trusted_ca' ),
        ]:
            if secretinfokey in ctx['secret_info']:
                handler(hkey, ctx['secret_info'][secretinfokey])

        for ctxkey, handler, hkey in [
            ( 'alpn_protocols', self.update_alpn, 'alpn_protocols' ),
            ( 'cert_required', self.__setitem__, 'require_client_certificate' ),
            ( 'min_tls_version', self.update_tls_version, 'tls_minimum_protocol_version' ),
            ( 'max_tls_version', self.update_tls_version, 'tls_maximum_protocol_version' ),
        ]:
            value = ctx.get(ctxkey, None)

            if value is not None:
                handler(hkey, value)
<|endoftext|>