Beispiel #1
0
    def login(self, host_spec="", username="", password=""):
        """ Authenticate with infrastructure via the Skydive analyzer

        This method will also set the authentication cookie to be used in
        the future requests
        :param host_spec: Host IP and port (e.g. 192.168.10.1:8082)
        :type host_spec: string
        :param username: Username to use for login
        :type username: string
        :param password: Password to use for login
        :type password: string
        :return: True on successful authentication, False otherwise
        """

        warnings.warn(
            "shouldn't use this function anymore ! use connect which handles"
            "handles authentication directly.",
            DeprecationWarning
        )

        scheme = "http"
        if not host_spec:
            u = urlparse(self.endpoint)
            host_spec = u.netloc
            if u.scheme == "wss":
                scheme = "https"
            if self.username:
                username = self.username
            if self.password:
                password = self.password

        auth = Authenticate(host_spec, scheme=scheme,
                            username=username, password=password)
        try:
            auth.login()
            cookie = 'authtok={}'.format(auth.authtok)
            if self.cookies:
                self.cookies.append(cookie)
            else:
                self.cookies = [cookie, ]
            return True
        except Exception:
            return False
Beispiel #2
0
    def __init__(self, endpoint, scheme="http",
                 username="", password="",
                 insecure=False, debug=0):
        self.endpoint = endpoint
        self.scheme = scheme
        self.username = username
        self.password = password
        self.insecure = insecure
        self.debug = debug

        self.auth = Authenticate(endpoint, scheme,
                                 username, password, insecure)
Beispiel #3
0
    def __init__(self, host_id, endpoint, type="",
                 protocol=WSClientDefaultProtocol,
                 username="", password="", cookie=None,
                 sync="", filter="", persistent=True,
                 insecure=False,
                 **kwargs):
        super(WSClient, self).__init__()
        self.host_id = host_id
        self.endpoint = endpoint
        self.username = username
        self.password = password
        if not cookie:
            self.cookies = None
        elif isinstance(cookie, list):
            self.cookies = cookie
        else:
            self.cookies = [cookie, ]
        self.protocol = protocol
        self.type = type
        self.filter = filter
        self.persistent = persistent
        self.sync = sync
        self.insecure = insecure
        self.kwargs = kwargs

        self.url = urlparse(self.endpoint)

        scheme = "http"
        if self.url.scheme == "wss":
            scheme = "http"

        self.auth = Authenticate(
            "%s:%s" % (self.url.hostname, self.url.port),
            scheme=scheme, username=username, password=password,
            insecure=insecure)
        # We MUST initialize the loop here as the WebSocketClientFactory
        # needs it on init
        try:
            self.loop = asyncio.get_event_loop()
        except RuntimeError:
            self.loop = asyncio.new_event_loop()
            asyncio.set_event_loop(self.loop)
Beispiel #4
0
class RESTClient:
    def __init__(self, endpoint, scheme="http",
                 username="", password="",
                 insecure=False, debug=0):
        self.endpoint = endpoint
        self.scheme = scheme
        self.username = username
        self.password = password
        self.insecure = insecure
        self.debug = debug

        self.auth = Authenticate(endpoint, scheme,
                                 username, password, insecure)

    def request(self, path, method="GET", data=None):
        if self.username and not self.auth.authenticated:
            self.auth.login()

        handlers = []
        url = "%s://%s%s" % (self.scheme, self.endpoint, path)
        handlers.append(request.HTTPHandler(debuglevel=self.debug))
        handlers.append(request.HTTPCookieProcessor(self.auth.cookie_jar))

        if self.scheme == "https":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl._create_default_context()
            handlers.append(request.HTTPSHandler(debuglevel=self.debug,
                                                 context=context))

        if data is not None:
            encoded_data = data.encode()
        else:
            encoded_data = None

        opener = request.build_opener(*handlers)

        headers = {'Content-Type': 'application/json'}
        req = request.Request(url,
                              data=encoded_data,
                              headers=headers)
        req.get_method = lambda: method

        try:
            resp = opener.open(req)
        except request.HTTPError as e:
            self.auth.logout()
            raise BadRequest(e.read())

        data = resp.read()

        # DEPRECATED: workaround for skydive < 0.17
        # See PR #941
        if method == "DELETE":
            return data

        content_type = resp.headers.get("Content-type").split(";")[0]
        if content_type == "application/json":
            return json.loads(data.decode())
        return data

    def lookup(self, gremlin, klass=None):
        data = json.dumps(
            {"GremlinQuery": gremlin}
        )

        objs = self.request("/api/topology", method="POST", data=data)

        if klass:
            return [klass.from_object(o) for o in objs]
        return objs

    def lookup_nodes(self, gremlin):
        return self.lookup(gremlin, Node)

    def lookup_edges(self, gremlin):
        return self.lookup(gremlin, Edge)

    def capture_create(self, query):
        data = json.dumps(
            {"GremlinQuery": query}
        )
        return self.request("/api/capture", method="POST", data=data)

    def capture_list(self):
        return self.request("/api/capture")

    def capture_delete(self, capture_id):
        path = "/api/capture/%s" % capture_id
        return self.request(path, method="DELETE")
Beispiel #5
0
class WSClient(WebSocketClientProtocol):

    def __init__(self, host_id, endpoint, type="",
                 protocol=WSClientDefaultProtocol,
                 username="", password="", cookie=None,
                 sync="", filter="", persistent=True,
                 insecure=False,
                 **kwargs):
        super(WSClient, self).__init__()
        self.host_id = host_id
        self.endpoint = endpoint
        self.username = username
        self.password = password
        if not cookie:
            self.cookies = None
        elif isinstance(cookie, list):
            self.cookies = cookie
        else:
            self.cookies = [cookie, ]
        self.protocol = protocol
        self.type = type
        self.filter = filter
        self.persistent = persistent
        self.sync = sync
        self.insecure = insecure
        self.kwargs = kwargs

        self.url = urlparse(self.endpoint)

        scheme = "http"
        if self.url.scheme == "wss":
            scheme = "http"

        self.auth = Authenticate(
            "%s:%s" % (self.url.hostname, self.url.port),
            scheme=scheme, username=username, password=password,
            insecure=insecure)
        # We MUST initialize the loop here as the WebSocketClientFactory
        # needs it on init
        try:
            self.loop = asyncio.get_event_loop()
        except RuntimeError:
            self.loop = asyncio.new_event_loop()
            asyncio.set_event_loop(self.loop)

    def connect(self):
        factory = WebSocketClientFactory(self.endpoint)
        factory.protocol = self.protocol
        factory.client = self
        factory.kwargs = self.kwargs
        factory.headers["X-Host-ID"] = self.host_id
        factory.headers["X-Client-Type"] = self.type
        factory.headers["X-Client-Protocol"] = "json"
        if self.persistent:
            factory.headers["X-Persistence-Policy"] = "Persistent"
        else:
            factory.headers["X-Persistence-Policy"] = "DeleteOnDisconnect"

        if self.username:
            if self.auth.login():
                cookie = 'authtok={}'.format(self.auth.authtok)
                if self.cookies:
                    self.cookies.append(cookie)
                else:
                    self.cookies = [cookie, ]

        if self.filter:
            factory.headers["X-Gremlin-Filter"] = self.filter

        if self.cookies:
            factory.headers['Cookie'] = ';'.join(self.cookies)

        context = None
        if self.url.scheme == "wss":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl._create_default_context()

        coro = self.loop.create_connection(factory,
                                           self.url.hostname, self.url.port,
                                           ssl=context)
        (transport, protocol) = self.loop.run_until_complete(coro)
        LOG.debug('transport, protocol: %r, %r', transport, protocol)

    def login(self, host_spec="", username="", password=""):
        """ Authenticate with infrastructure via the Skydive analyzer

        This method will also set the authentication cookie to be used in
        the future requests
        :param host_spec: Host IP and port (e.g. 192.168.10.1:8082)
        :type host_spec: string
        :param username: Username to use for login
        :type username: string
        :param password: Password to use for login
        :type password: string
        :return: True on successful authentication, False otherwise
        """

        warnings.warn(
            "shouldn't use this function anymore ! use connect which handles"
            "handles authentication directly.",
            DeprecationWarning
        )

        scheme = "http"
        if not host_spec:
            u = urlparse(self.endpoint)
            host_spec = u.netloc
            if u.scheme == "wss":
                scheme = "https"
            if self.username:
                username = self.username
            if self.password:
                password = self.password

        auth = Authenticate(host_spec, scheme=scheme,
                            username=username, password=password)
        try:
            auth.login()
            cookie = 'authtok={}'.format(auth.authtok)
            if self.cookies:
                self.cookies.append(cookie)
            else:
                self.cookies = [cookie, ]
            return True
        except Exception:
            return False

    def start(self):
        try:
            self.loop.run_forever()
        except KeyboardInterrupt:
            self.loop.close()
        finally:
            pass

    def stop(self):
        self.loop.stop()
Beispiel #6
0
class WSClient(WebSocketClientProtocol):
    def __init__(self,
                 host_id,
                 endpoint,
                 protocol=WSClientDefaultProtocol,
                 username="",
                 password="",
                 cookie=None,
                 sync="",
                 filter="",
                 persistent=True,
                 insecure=False,
                 type="skydive-python-client",
                 **kwargs):
        super(WSClient, self).__init__()
        self.host_id = host_id
        self.endpoint = endpoint
        self.username = username
        self.password = password
        if not cookie:
            self.cookies = None
        elif isinstance(cookie, list):
            self.cookies = cookie
        elif isinstance(cookie, dict):
            self.cookies = []
            for k, v in cookie.items():
                self.cookies.append("{}={}".format(k, v))
        else:
            self.cookies = [
                cookie,
            ]
        self.protocol = protocol
        self.type = type
        self.filter = filter
        self.persistent = persistent
        self.sync = sync
        self.insecure = insecure
        self.kwargs = kwargs

        self.url = urlparse(self.endpoint)

        scheme = "http"
        if self.url.scheme == "wss":
            scheme = "http"

        self.auth = Authenticate("%s:%s" % (self.url.hostname, self.url.port),
                                 scheme=scheme,
                                 username=username,
                                 password=password,
                                 insecure=insecure)
        # We MUST initialize the loop here as the WebSocketClientFactory
        # needs it on init
        try:
            self.loop = asyncio.get_event_loop()
        except RuntimeError:
            self.loop = asyncio.new_event_loop()
            asyncio.set_event_loop(self.loop)

    def connect(self):
        factory = WebSocketClientFactory(self.endpoint)
        factory.protocol = self.protocol
        factory.client = self
        factory.kwargs = self.kwargs
        factory.headers["X-Host-ID"] = self.host_id
        factory.headers["X-Client-Type"] = self.type
        factory.headers["X-Client-Protocol"] = "json"
        if self.persistent:
            factory.headers["X-Persistence-Policy"] = "Persistent"
        else:
            factory.headers["X-Persistence-Policy"] = "DeleteOnDisconnect"

        if self.username:
            if self.auth.login():
                cookie = 'authtok={}'.format(self.auth.authtok)
                if self.cookies:
                    self.cookies.append(cookie)
                else:
                    self.cookies = [
                        cookie,
                    ]

        if self.filter:
            factory.headers["X-Gremlin-Filter"] = self.filter

        if self.cookies:
            factory.headers['Cookie'] = ';'.join(self.cookies)

        context = None
        if self.url.scheme == "wss":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl._create_default_context()

        coro = self.loop.create_connection(factory,
                                           self.url.hostname,
                                           self.url.port,
                                           ssl=context)
        (transport, protocol) = self.loop.run_until_complete(coro)
        LOG.debug('transport, protocol: %r, %r', transport, protocol)

    def login(self, host_spec="", username="", password=""):
        """ Authenticate with infrastructure via the Skydive analyzer

        This method will also set the authentication cookie to be used in
        the future requests
        :param host_spec: Host IP and port (e.g. 192.168.10.1:8082)
        :type host_spec: string
        :param username: Username to use for login
        :type username: string
        :param password: Password to use for login
        :type password: string
        :return: True on successful authentication, False otherwise
        """

        warnings.warn(
            "shouldn't use this function anymore ! use connect which handles"
            "handles authentication directly.", DeprecationWarning)

        scheme = "http"
        if not host_spec:
            u = urlparse(self.endpoint)
            host_spec = u.netloc
            if u.scheme == "wss":
                scheme = "https"
            if self.username:
                username = self.username
            if self.password:
                password = self.password

        auth = Authenticate(host_spec,
                            scheme=scheme,
                            username=username,
                            password=password)
        try:
            auth.login()
            cookie = 'authtok={}'.format(auth.authtok)
            if self.cookies:
                self.cookies.append(cookie)
            else:
                self.cookies = [
                    cookie,
                ]
            return True
        except Exception:
            return False

    def start(self):
        try:
            self.loop.run_forever()
        except KeyboardInterrupt:
            self.loop.close()
        finally:
            pass

    def stop(self):
        self.loop.stop()
Beispiel #7
0
class RESTClient:
    INJECTION_PATH = "/api/injectpacket"

    def __init__(self,
                 endpoint,
                 scheme="http",
                 username="",
                 password="",
                 cookies={},
                 insecure=False,
                 debug=0):
        self.endpoint = endpoint
        self.scheme = scheme
        self.username = username
        self.password = password
        self.insecure = insecure
        self.debug = debug
        self.cookies = cookies

        self.auth = Authenticate(endpoint, scheme, username, password, cookies,
                                 insecure)

    def request(self, path, method="GET", data=None):
        if self.username and not self.auth.authenticated:
            self.auth.login()

        handlers = []
        url = "%s://%s%s" % (self.scheme, self.endpoint, path)
        handlers.append(request.HTTPHandler(debuglevel=self.debug))
        handlers.append(request.HTTPCookieProcessor(self.auth.cookie_jar))

        if self.scheme == "https":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl.create_default_context()
            handlers.append(
                request.HTTPSHandler(debuglevel=self.debug, context=context))

        if data is not None:
            encoded_data = data.encode()
        else:
            encoded_data = None

        opener = request.build_opener(*handlers)
        for k, v in self.cookies.items():
            opener.append = (k, v)

        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        req = request.Request(url, data=encoded_data, headers=headers)
        req.get_method = lambda: method

        try:
            resp = opener.open(req)
        except request.HTTPError as e:
            self.auth.logout()
            raise BadRequest(e.read())

        data = resp.read()

        # DEPRECATED: workaround for skydive < 0.17
        # See PR #941
        if method == "DELETE":
            return data

        content_type = resp.headers.get("Content-type").split(";")[0]
        if content_type == "application/json":
            return json.loads(data.decode())
        return data

    def lookup(self, gremlin, klass=None):
        data = json.dumps({"GremlinQuery": gremlin})

        objs = self.request("/api/topology", method="POST", data=data)

        if klass:
            return [klass.from_object(o) for o in objs]
        return objs

    def lookup_nodes(self, gremlin):
        return self.lookup(gremlin, Node)

    def lookup_edges(self, gremlin):
        return self.lookup(gremlin, Edge)

    def capture_create(self,
                       query,
                       name="",
                       description="",
                       extra_tcp_metric=False,
                       ip_defrag=False,
                       reassemble_tcp=False,
                       layer_key_mode="L2",
                       bpf_filter="",
                       capture_type="",
                       port=0,
                       raw_pkt_limit=0,
                       header_size=0,
                       target="",
                       target_type="",
                       polling_interval=10,
                       sampling_rate=1):
        data = {
            "GremlinQuery": query,
            "LayerKeyMode": layer_key_mode,
            "PollingInterval": polling_interval,
            "SamplingRate": sampling_rate,
        }

        if name:
            data["Name"] = name
        if description:
            data["Description"] = description
        if extra_tcp_metric:
            data["ExtraTCPMetric"] = True
        if ip_defrag:
            data["IPDefrag"] = True
        if reassemble_tcp:
            data["ReassembleTCP"] = True
        if bpf_filter:
            data["BPFFilter"] = bpf_filter
        if capture_type:
            data["Type"] = capture_type
        if raw_pkt_limit:
            data["RawPacketLimit"] = raw_pkt_limit
        if header_size:
            data["HeaderSize"] = header_size
        if port:
            data["Port"] = port
        if target:
            data["Target"] = target
        if target_type:
            data["TargetType"] = target_type

        c = self.request("/api/capture", method="POST", data=json.dumps(data))
        return Capture.from_object(c)

    def capture_list(self):
        objs = self.request("/api/capture")
        return [Capture.from_object(o) for o in objs.values()]

    def capture_delete(self, capture_id):
        path = "/api/capture/%s" % capture_id
        return self.request(path, method="DELETE")

    def alert_create(self, action, expression, trigger="graph"):
        data = json.dumps({
            "Action": action,
            "Expression": expression,
            "Trigger": trigger
        })
        a = self.request("/api/alert", method="POST", data=data)
        return Alert.from_object(a)

    def alert_list(self):
        objs = self.request("/api/alert")
        return [Alert.from_object(o) for o in objs.values()]

    def alert_delete(self, alert_id):
        path = "/api/alert/%s" % alert_id
        return self.request(path, method="DELETE")

    def noderule_create(self, action, metadata=None, query=""):
        data = json.dumps({
            "Action": action,
            "Metadata": metadata,
            "Query": query
        })
        r = self.request("/api/noderule", method="POST", data=data)
        return NodeRule.from_object(r)

    def noderule_list(self):
        objs = self.request("/api/noderule")
        return [NodeRule.from_object(o) for o in objs.values()]

    def noderule_delete(self, rule_id):
        path = "/api/noderule/%s" % rule_id
        return self.request(path, method="DELETE")

    def edgerule_create(self, src, dst, metadata):
        data = json.dumps({"Src": src, "Dst": dst, "Metadata": metadata})
        r = self.request("/api/edgerule", method="POST", data=data)
        return EdgeRule.from_object(r)

    def edgerule_list(self):
        objs = self.request("/api/edgerule")
        return [EdgeRule.from_object(o) for o in objs.values()]

    def edgerule_delete(self, rule_id):
        path = "/api/edgerule/%s" % rule_id
        self.request(path, method="DELETE")

    def node_create(self, node_id=None, host=None, metadata=None):
        now = int(time() * 1000)
        if not node_id:
            node_id = str(uuid4())

        if not host:
            host = gethostname()

        data = json.dumps({
            "ID": node_id,
            "CreatedAt": now,
            "UpdatedAt": now,
            "Host": host,
            "Metadata": metadata,
            "Revision": 1
        })
        r = self.request("/api/node", method="POST", data=data)
        return Node.from_object(r)

    def node_update(self, node_id=None, patches=[]):
        data = json.dumps(patches)
        path = "/api/node/%s" % node_id
        r = self.request(path, method="PATCH", data=data)
        return Node.from_object(r)

    def node_list(self):
        objs = self.request("/api/node")
        return [Node.from_object(o) for o in objs.values()]

    def node_delete(self, node_id):
        path = "/api/node/%s" % node_id
        return self.request(path, method="DELETE")

    def edge_create(self,
                    parent_id,
                    child_id,
                    edge_id=None,
                    host=None,
                    metadata=None):
        now = int(time() * 1000)
        if not edge_id:
            edge_id = str(uuid4())

        if not host:
            host = gethostname()

        data = json.dumps({
            "ID": edge_id,
            "CreatedAt": now,
            "UpdatedAt": now,
            "Host": host,
            "Parent": parent_id,
            "Child": child_id,
            "Metadata": metadata
        })
        r = self.request("/api/edge", method="POST", data=data)
        return Edge.from_object(r)

    def edge_update(self, edge_id=None, patches=[]):
        data = json.dumps(patches)
        path = "/api/edge/%s" % edge_id
        r = self.request(path, method="PATCH", data=data)
        return Edge.from_object(r)

    def edge_list(self):
        objs = self.request("/api/edge")
        return [Edge.from_object(o) for o in objs.values()]

    def edge_delete(self, edge_id):
        path = "/api/edge/%s" % edge_id
        self.request(path, method="DELETE")

    def injection_create(self,
                         src_query="",
                         dst_query="",
                         type="icmp4",
                         payload="",
                         interval=1000,
                         src_ip="",
                         dst_ip="",
                         src_mac="",
                         dst_mac="",
                         count=1,
                         icmp_id=0,
                         src_port=0,
                         dst_port=0,
                         increment=False,
                         ttl=64):

        data = json.dumps({
            "Src": src_query,
            "Dst": dst_query,
            "SrcPort": src_port,
            "DstPort": dst_port,
            "SrcIP": src_ip,
            "DstIP": dst_ip,
            "SrcMAC": src_mac,
            "DstMAC": dst_mac,
            "Type": type,
            "Count": count,
            "ICMPID": icmp_id,
            "Interval": interval,
            "Payload": payload,
            "Increment": increment,
            "TTL": ttl
        })

        r = self.request(self.INJECTION_PATH, method="POST", data=data)
        return PacketInjection.from_object(r)

    def injection_delete(self, injection_id):
        path = self.INJECTION_PATH + "/" + injection_id
        return self.request(path, method="DELETE")

    def injection_list(self):
        objs = self.request(self.INJECTION_PATH)
        return [PacketInjection.from_object(o) for o in objs.values()]
Beispiel #8
0
class RESTClient:
    def __init__(self,
                 endpoint,
                 scheme="http",
                 username="",
                 password="",
                 insecure=False,
                 debug=0):
        self.endpoint = endpoint
        self.scheme = scheme
        self.username = username
        self.password = password
        self.insecure = insecure
        self.debug = debug

        self.auth = Authenticate(endpoint, scheme, username, password,
                                 insecure)

    def request(self, path, method="GET", data=None):
        if self.username and not self.auth.authenticated:
            self.auth.login()

        handlers = []
        url = "%s://%s%s" % (self.scheme, self.endpoint, path)
        handlers.append(request.HTTPHandler(debuglevel=self.debug))
        handlers.append(request.HTTPCookieProcessor(self.auth.cookie_jar))

        if self.scheme == "https":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl._create_default_context()
            handlers.append(
                request.HTTPSHandler(debuglevel=self.debug, context=context))

        if data is not None:
            encoded_data = data.encode()
        else:
            encoded_data = None

        opener = request.build_opener(*handlers)

        headers = {'Content-Type': 'application/json'}
        req = request.Request(url, data=encoded_data, headers=headers)
        req.get_method = lambda: method

        try:
            resp = opener.open(req)
        except request.HTTPError as e:
            self.auth.logout()
            raise BadRequest(e.read())

        data = resp.read()

        # DEPRECATED: workaround for skydive < 0.17
        # See PR #941
        if method == "DELETE":
            return data

        content_type = resp.headers.get("Content-type").split(";")[0]
        if content_type == "application/json":
            return json.loads(data.decode())
        return data

    def lookup(self, gremlin, klass=None):
        data = json.dumps({"GremlinQuery": gremlin})

        objs = self.request("/api/topology", method="POST", data=data)

        if klass:
            return [klass.from_object(o) for o in objs]
        return objs

    def lookup_nodes(self, gremlin):
        return self.lookup(gremlin, Node)

    def lookup_edges(self, gremlin):
        return self.lookup(gremlin, Edge)

    def capture_create(self, query):
        data = json.dumps({"GremlinQuery": query})
        return self.request("/api/capture", method="POST", data=data)

    def capture_list(self):
        return self.request("/api/capture")

    def capture_delete(self, capture_id):
        path = "/api/capture/%s" % capture_id
        return self.request(path, method="DELETE")
Beispiel #9
0
class RESTClient:
    def __init__(self,
                 endpoint,
                 scheme="http",
                 username="",
                 password="",
                 cookies={},
                 insecure=False,
                 debug=0):
        self.endpoint = endpoint
        self.scheme = scheme
        self.username = username
        self.password = password
        self.insecure = insecure
        self.debug = debug
        self.cookies = cookies

        self.auth = Authenticate(endpoint, scheme, username, password, cookies,
                                 insecure)

    def request(self, path, method="GET", data=None):
        if self.username and not self.auth.authenticated:
            self.auth.login()

        handlers = []
        url = "%s://%s%s" % (self.scheme, self.endpoint, path)
        handlers.append(request.HTTPHandler(debuglevel=self.debug))
        handlers.append(request.HTTPCookieProcessor(self.auth.cookie_jar))

        if self.scheme == "https":
            if self.insecure:
                context = ssl._create_unverified_context()
            else:
                context = ssl._create_default_context()
            handlers.append(
                request.HTTPSHandler(debuglevel=self.debug, context=context))

        if data is not None:
            encoded_data = data.encode()
        else:
            encoded_data = None

        opener = request.build_opener(*handlers)
        for k, v in self.cookies.items():
            opener.append = (k, v)

        headers = {'Content-Type': 'application/json'}
        req = request.Request(url, data=encoded_data, headers=headers)
        req.get_method = lambda: method

        try:
            resp = opener.open(req)
        except request.HTTPError as e:
            self.auth.logout()
            raise BadRequest(e.read())

        data = resp.read()

        # DEPRECATED: workaround for skydive < 0.17
        # See PR #941
        if method == "DELETE":
            return data

        content_type = resp.headers.get("Content-type").split(";")[0]
        if content_type == "application/json":
            return json.loads(data.decode())
        return data

    def lookup(self, gremlin, klass=None):
        data = json.dumps({"GremlinQuery": gremlin})

        objs = self.request("/api/topology", method="POST", data=data)

        if klass:
            return [klass.from_object(o) for o in objs]
        return objs

    def lookup_nodes(self, gremlin):
        return self.lookup(gremlin, Node)

    def lookup_edges(self, gremlin):
        return self.lookup(gremlin, Edge)

    def capture_create(self,
                       query,
                       name="",
                       description="",
                       extra_tcp_metric=False,
                       ip_defrag=False,
                       reassemble_tcp=False,
                       layer_key_mode="L2"):
        data = {
            "GremlinQuery": query,
            "LayerKeyMode": layer_key_mode,
        }

        if name:
            data["Name"] = name
        if description:
            data["Description"] = description
        if extra_tcp_metric:
            data["ExtraTCPMetric"] = True
        if ip_defrag:
            data["IPDefrag"] = True
        if reassemble_tcp:
            data["ReassembleTCP"] = True

        c = self.request("/api/capture", method="POST", data=json.dumps(data))
        return Capture.from_object(c)

    def capture_list(self):
        objs = self.request("/api/capture")
        return [Capture.from_object(o) for o in objs.values()]

    def capture_delete(self, capture_id):
        path = "/api/capture/%s" % capture_id
        return self.request(path, method="DELETE")

    def alert_create(self, action, expression, trigger="graph"):
        data = json.dumps({
            "Action": action,
            "Expression": expression,
            "Trigger": trigger
        })
        a = self.request("/api/alert", method="POST", data=data)
        return Alert.from_object(a)

    def alert_list(self):
        objs = self.request("/api/alert")
        return [Alert.from_object(o) for o in objs.values()]

    def alert_delete(self, alert_id):
        path = "/api/alert/%s" % alert_id
        return self.request(path, method="DELETE")

    def noderule_create(self, action, metadata=None, query=""):
        data = json.dumps({
            "Action": action,
            "Metadata": metadata,
            "Query": query
        })
        r = self.request("/api/noderule", method="POST", data=data)
        return NodeRule.from_object(r)

    def noderule_list(self):
        objs = self.request("/api/noderule")
        return [NodeRule.from_object(o) for o in objs.values()]

    def noderule_delete(self, rule_id):
        path = "/api/noderule/%s" % rule_id
        return self.request(path, method="DELETE")

    def edgerule_create(self, src, dst, metadata):
        data = json.dumps({"Src": src, "Dst": dst, "Metadata": metadata})
        r = self.request("/api/edgerule", method="POST", data=data)
        return EdgeRule.from_object(r)

    def edgerule_list(self):
        objs = self.request("/api/edgerule")
        return [EdgeRule.from_object(o) for o in objs.values()]

    def edgerule_delete(self, rule_id):
        path = "/api/edgerule/%s" % rule_id
        self.request(path, method="DELETE")