def cached(ttl=600):
    def proxy(f):
        @wraps(f)
        def caching(*args, **kwargs):
            if cache_enable is False:
                return f(*args, **kwargs)
            try:
                cache_db = redis_cli.get_connection()
            except Exception, e:
                logger.exception("Error in redis_cli connection (cache database)")
                return f(*args, **kwargs)
            cache_key     = "%s:%s" % (request.environ.get("REQUEST_METHOD"), request.environ.get("PATH_INFO"))
            cache_subkey  = ";".join(["%s=%s" % (k,v) for k,v in request.query.iteritems() \
                                        if k != "ticket"])
            cache_subkey += ";".join(["%s=%s" % (k,v) for k,v in request.forms.iteritems() \
                                        if k != "ticket"])
            cache_rkey    = "cache:%s:%s" % (cache_key, sha1(cache_subkey).hexdigest())
            cached_r      = cache_db.get(cache_rkey)
            if cached_r is not None:
                logger.info("Cache HIT -- context: %s" % request["context"])
                response.set_header("X-Cached", "True")
                response.set_header("Cache-Control", "max-age=%s, must-revalidate" % int(cache_db.ttl(cache_rkey) or 0))
                return loads(cached_r)
            #logger.debug("Cache MISS (calling %s()) -- context %s" % (f_name, context))
            r = f(*args, **kwargs)
            response.set_header("X-Cached", "False")
            response.set_header("Cache-Control", "max-age=%s, must-revalidate" % ttl)
            cache_db.setex(cache_rkey, dumps(r), ttl)
            return r
        return caching
    return proxy def invalidate_cache(key=None):
    try:
        cache_db = redis_cli.get_connection()
    except Exception, e:
        logger.exception("Error in redis_cli connection (cache database)")
        return
    try:
        cache_db.delete(*cache_db.keys("cache:*:%s*" % key))
    except redis.exceptions.ResponseError:
        pass def reply_json(f):
    @wraps(f)
    def json_dumps(*args, **kwargs):
        r = f(*args, **kwargs)
        if r and type(r) in (dict, list, tuple, str, unicode):
            response.content_type = "application/json; charset=UTF-8"
            return dumps(r)
        return r
    return json_dumps def validate_input(src="query", *vargs, **vkwargs):
    """
    Usage:
    >>> @get('/test')
    ... @validate_input(source="query", name=str, age=int, email=re.compile("\w+@\w+.com"), gender=("M", "F"))
    ... def test():
    ...    return request.query.get("name")
    """
    def proxy(f):
        @wraps(f)
        def validate(*args, **kwargs):
            if src not in ("query", "forms", "GET", "POST"):
                raise RuntimeError("invalid 'source' option")
            psource = request.__getattribute__(src)
            for param, ptype in vkwargs.iteritems():
                pvalue = psource.get(param, None)
                try:
                    # lambda
                    if isinstance(ptype, type(lambda: None)):
                    #\ and ptype.__name__ == "<lambda>":
                        if not ptype(pvalue):
                            raise HTTPInvalidParameter()
                        continue
                    if pvalue is None:
                        raise HTTPNullParameter()
                    # exact match
                    if type(ptype) in (str, unicode):
                        assert pvalue == ptype
                        continue
                    # valid option list
                    if type(ptype) in (list, tuple):
                        assert pvalue in ptype
                        continue
                    # int(), str(), etc
                    if type(ptype) is type:
                        ptype(pvalue)
                        continue
                    # regexp
                    if isinstance(ptype, _pattern_type):
                        assert ptype.search(pvalue) is not None
                        continue
                except HTTPNullParameter, e:
                    logger.exception("Error: parameter '%s' is null" % param)
                    abort(400, "Error: parameter '%s' is null" % param)
                except Exception, e:
                    logger.exception("Error: parameter '%s' has an unexpected type or an invalid format" % param)
                    abort(400, "Error: parameter '%s' has an unexpected type or an invalid format" % param)
            return f(*args, **kwargs)
        return validate
    return proxy def context(f):
    @wraps(f)
    def inject_ctx(*args, **kwargs):
        truncate = lambda i: i if len(i) <= 40 else "%s..." % i[:40]
        context  = { "CTX-UUID":                 gen_context_uid(),
                     "HTTP.ENV.SERVER_PROTOCOL": request.environ.get("SERVER_PROTOCOL"),
                     "HTTP.ENV.REQUEST_METHOD":  request.environ.get("REQUEST_METHOD"),
                     "HTTP.ENV.REMOTE_ADDR":     request.environ.get("REMOTE_ADDR"),
                     "HTTP.ENV.PATH_INFO":       request.environ.get("PATH_INFO") }
        if request.headers.get("X-Real-IP"):
            context["HTTP.ENV.X-Real-IP"] = request.headers.get("X-Real-IP")
        if request.headers.get("X-Forwarded-For"):
            context["HTTP.ENV.X-Forwarded-For"] = request.headers.get("X-Forwarded-For")
        for arg, val in kwargs.iteritems():
            if arg not in ("cfg", "logger", "context"):
                context["kwargs.%s" % arg] = truncate(val)
        for arg, val in request.query.iteritems():
            context["HTTP.QUERYSTR.%s" % arg] = truncate(val)
        for arg, val in request.forms.iteritems():
            context["HTTP.FORMDATA.%s" % arg] = truncate(val)
        request["context"] = context
        return f(*args, **kwargs)
    return inject_ctx def worker():
def daemon(): def defer_save_switch_cfg(device=None):
    try:
        sw_persist_ctrl_db = redis_cli.get_connection()
    except Exception, e:
        logger_netl2server.exception("Error in Redis connection (persistence control database)")
        return
    sw_persist_ctrl_db.incr("rwopts:%s:counter" % device, amount=1) def get_switch_instance(device):
    switches = config.get_devices_cfg()
    if not switches.has_key(device):
        raise DeviceNotFound("Switch not known/configured => '%s'" % device)
    if not switches[device].get("mgmt-api") or not switches[device].get("mgmt-user") \
            or not switches[device].get("mgmt-pass"):
        raise MisconfiguredDevice("The device '%s' are misconfigured - see the devices.cfg or redis-devices.cfg" % device)
    swapi = get_sw_handler_class(switches[device]["mgmt-api"])
    return swapi(host=switches[device]["mgmt-host"], port=int(switches[device]["mgmt-port"]),
                 username=switches[device]["mgmt-user"], passwd=switches[device]["mgmt-pass"]) def get_netl2server_cfg():
    return get_cfg("netl2server", check_permission=None) def setup_netl2server_logger(cfg):
    return setup_logger(cfg, "netl2server") def get_devices_cfg():
    switches    = {}
    devices_cfg = get_cfg("devices", check_permission=600)
    for k in devices_cfg.sections():
        if k.startswith("device."):
            switches[k[7:]] = dict([(x,y) for x,y in section(devices_cfg, k).items()])
    return switches
import re
import os
import sys
import pwd
from multiprocessing import Process
from bottle import ServerAdapter, debug, run, route, get, put, delete, error, request, response, abort
from netl2api.server.http_cache import cached, invalidate_cache
from netl2api.server.http_utils import reply_json, validate_input, context
from netl2api.server.workers import switch_cfg_persistence
from netl2api.server.workers.switch_cfg_persistence_utils import defer_save_switch_cfg
from netl2api.lib.utils import get_switch_instance
from netl2api.lib.config import get_netl2server_cfg, setup_netl2server_logger, get_devices_cfg
        from paste import httpserver
            from paste.translogger import TransLogger
        from setproctitle import setproctitle
    from supay import Daemon
#!/usr/bin/python
# -*- coding: utf-8; -*-
#
# 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.
#
# @author: Eduardo S. Scarpellini
# @author: Luiz Ozaki


__copyright__ = "Copyright 2012, Locaweb IDC"



cfg          = get_netl2server_cfg()
logger       = setup_netl2server_logger(cfg)
netl2debug   = cfg.get("logger", "level").lower() == "debug"


RE_TYPE_VLAN_TAGGED = re.compile(r"^(?:True|False)$", re.IGNORECASE)


def log_request_ahead(msg=None, msg_args=None):
    """ use @log_request_ahead between @authorize and @cached """
    def proxy(f):
        def log(*args, **kwargs):
            if msg is not None:
                lmsg      = msg
                lmsg_args = msg_args
                if msg_args is not None:
                    lmsg = lmsg % tuple([kwargs.get(a) for a in lmsg_args])
                logger.info("%s -- context: %s" % (lmsg, request["context"]))
            return f(*args, **kwargs)
        return log
    return proxy


# Force Exception if using devices.cfg and permissions are wrong
dev_cfg = get_devices_cfg()

@get("/devices")
@context
@log_request_ahead("Listing available devices")
@reply_json
def devices_list():
    # MUST return ONLY switch names -- for CLI completion purpose
    #logger.info("Listing available devices -- context: %s" % request["context"])

    return get_devices_cfg().keys()