Add df_skydive_service to dragonflow

To enable skydive, one should now enable the service in the local.conf
file using the following line:
enable_service df_skydive

If you would like to install the SkyDive analyzer on the same node, the
SkyDive install lines MUST be before the DragonFlow ones!
Please see doc/source/single-node-conf/etcd_skydive_local_controller.conf
file for usage example

Change-Id: I66c3eaf18904ae1c109d0ca8007269c41261d791
Depends-On: c5921051d7bc05d2c29494be842329e2ffcc008a
Related-Bug: #1749429
This commit is contained in:
Shachar Snapiri 2018-03-19 16:32:27 +02:00
parent 439e528add
commit 7be2d258e2
6 changed files with 128 additions and 60 deletions

View File

@ -1,3 +1,4 @@
#@IgnoreInspection BashAddShebang
# dragonflow.sh - Devstack extras script to install Dragonflow
# Enable DPDK for Open vSwitch user space datapath
@ -50,6 +51,10 @@ if [[ "$ENABLE_AGING_APP" == "True" ]]; then
DEFAULT_APPS_LIST="aging,$DEFAULT_APPS_LIST"
fi
if is_service_enabled df-skydive ; then
SKYDIVE_ENDPOINT=${SKYDIVE_ENDPOINT:-$SERVICE_HOST:8082}
fi
DF_APPS_LIST=${DF_APPS_LIST:-$DEFAULT_APPS_LIST}
TUNNEL_TYPES=${TUNNEL_TYPE:-$DEFAULT_TUNNEL_TYPES}
@ -222,6 +227,19 @@ function init_neutron_sample_config {
fi
}
function configure_df_skydive {
iniset $DRAGONFLOW_CONF df_skydive analyzer_endpoint "$SKYDIVE_ENDPOINT"
if [[ -n "$DF_SKYDIVE_USER" ]]; then
iniset $DRAGONFLOW_CONF df_skydive user "$DF_SKYDIVE_USER"
fi
local DF_SKYDIVE_PASSWORD=${DF_SKYDIVE_PASSWORD:-$ADMIN_PASSWORD}
iniset $DRAGONFLOW_CONF df_skydive password "$DF_SKYDIVE_PASSWORD"
if [[ -n "$DF_SKYDIVE_UPDATE_INTERVAL" ]]; then
iniset $DRAGONFLOW_CONF df_skydive update_interval "$DF_SKYDIVE_UPDATE_INTERVAL"
fi
}
function configure_df_plugin {
echo "Configuring Neutron for Dragonflow"
@ -305,6 +323,10 @@ function configure_df_plugin {
iniset $DRAGONFLOW_CONF df enable_selective_topology_distribution \
"$DF_SELECTIVE_TOPO_DIST"
configure_df_metadata_service
if is_service_enabled df-skydive ; then
configure_df_skydive
fi
}
function install_zeromq {
@ -492,6 +514,20 @@ function start_df_bgp_service {
fi
}
function start_df_skydive {
if is_service_enabled df-skydive ; then
echo "Starting Dragonflow skydive service"
run_process df-skydive "$DF_SKYDIVE_SERVICE --config-file $NEUTRON_CONF --config-file $DRAGONFLOW_CONF"
fi
}
function stop_df_skydive {
if is_service_enabled df-skydive ; then
echo "Stopping Dragonflow skydive service"
stop_process df-skydive
fi
}
function setup_rootwrap_filters {
if [[ "$DF_INSTALL_DEBUG_ROOTWRAP_CONF" == "True" ]]; then
echo "Adding rootwrap filters"
@ -569,6 +605,7 @@ function handle_df_stack_post_install {
start_df_bgp_service
setup_rootwrap_filters
create_tables_script
start_df_skydive
}
function handle_df_stack {
@ -580,6 +617,7 @@ function handle_df_stack {
}
function handle_df_unstack {
stop_df_skydive
stop_df_bgp_service
stop_df_metadata_agent
stop_df

View File

@ -28,6 +28,10 @@ DF_BGP_SERVICE=${DF_BGP_SERVICE:-"$NEUTRON_BIN_DIR/df-bgp-service"}
# This can be overridden in the localrc file, set df-bgp to enable
DR_MODE=${DR_MODE:-no-bgp}
# df-skydive
DF_SKYDIVE_SERVICE=${DF_SKYDIVE_SERVICE:-"$NEUTRON_BIN_DIR/df-skydive-service"}
DF_L2_RESPONDER=${DF_L2_RESPONDER:-'True'}
DF_MONITOR_TABLE_POLL_TIME=${DF_MONITOR_TABLE_POLL_TIME:-30}

View File

@ -0,0 +1,35 @@
[[local|localrc]]
# These MUST come before the 'enable_plugin dragonflow' as the dragonflow
# assumes the skydive analyzer is already installed
enable_plugin skydive https://github.com/skydive-project/skydive.git
enable_service skydive-agent skydive-analyzer
DATABASE_PASSWORD=password
RABBIT_PASSWORD=password
SERVICE_PASSWORD=password
SERVICE_TOKEN=password
ADMIN_PASSWORD=password
enable_plugin dragonflow https://git.openstack.org/openstack/dragonflow
enable_service df-etcd
enable_service etcd3
enable_service df-controller
enable_service df-etcd-pubsub-service
disable_service n-net
enable_service q-svc
enable_service df-l3-agent
disable_service heat
disable_service tempest
enable_service df-skydive
# Enable df-metadata (Dragonflow metadata service proxy) once nova is being used.
enable_service df-metadata
# We have to disable the neutron L2 agent. DF does not use the L2 agent.
disable_service q-agt
# We have to disable the neutron dhcp agent. DF does not use the dhcp agent.
disable_service q-dhcp

View File

@ -9,11 +9,10 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import signal
import sys
import uuid
import cotyledon
from jsonmodels import fields
from oslo_log import log
from skydive.rest.client import RESTClient
@ -22,6 +21,7 @@ from skydive.websocket import client as skydive_client
from dragonflow.common import utils as df_utils
from dragonflow import conf as cfg
from dragonflow.controller import df_config
from dragonflow.controller import service as df_service
from dragonflow.db import api_nb
from dragonflow.db import model_framework as mf
from dragonflow.db import model_proxy
@ -32,66 +32,60 @@ LOG = log.getLogger(__name__)
DRAGONFLOW_HOST_ID = 'dragonflow-skydive'
DF_SKYDIVE_NAMESPACE_UUID = uuid.UUID('8a527b24-f0f5-4c1f-8f3d-6de400aa0145')
global_skydive_client = None
class SkydiveClient(object):
class SkydiveClient(cotyledon.Service):
"""Main class that manages all the skydive operation."""
def __init__(self, nb_api):
protocol = WSClientDragonflowProtocol(nb_api)
def __init__(self, worker_id, nb_api):
super(SkydiveClient, self).__init__(worker_id)
self.protocol = WSClientDragonflowProtocol(nb_api)
self.websocket_client = skydive_client.WSClient(
host_id=DRAGONFLOW_HOST_ID,
endpoint='ws://{0}/ws/publisher'.format(
cfg.CONF.df_skydive.analyzer_endpoint),
protocol=lambda: protocol
protocol=lambda: self.protocol,
username=cfg.CONF.df_skydive.user,
password=cfg.CONF.df_skydive.password
)
logged_in = self.websocket_client.login(
cfg.CONF.df_skydive.analyzer_endpoint,
cfg.CONF.df_skydive.user,
cfg.CONF.df_skydive.password)
if not logged_in:
# TODO(snapiri) raise an exception
LOG.error('Failed authenticating with SkyDive analyzer at %s',
cfg.CONF.df_skydive.analyzer_endpoint)
return
self.websocket_client.connect()
@staticmethod
def create():
"""Create a new SkydiveClient
:return a newly allocated SkydiveClient
:rtype SkydiveClient
"""
df_utils.config_parse()
nb_api = api_nb.NbApi.get_instance(False, True)
return SkydiveClient(nb_api)
try:
self.websocket_client.connect()
except RuntimeError:
LOG.error('Failed connecting with SkyDive analyzer at %s',
cfg.CONF.df_skydive.analyzer_endpoint)
raise
def clear_dragonflow_items(self):
"""Delete all the items created by DragonFlow"""
restclient = RESTClient(cfg.CONF.df_skydive.analyzer_endpoint)
edges = restclient.lookup_edges("G.E().Has('source': 'dragonflow')")
for edge in edges:
restclient = RESTClient(cfg.CONF.df_skydive.analyzer_endpoint,
username=cfg.CONF.df_skydive.user,
password=cfg.CONF.df_skydive.password)
items = restclient.lookup_edges("G.E().Has('source', 'dragonflow')")
for edge in items:
edge_del_msg = skydive_client.WSMessage(
"Graph",
skydive_client.EdgeDeletedMsgType,
edge
)
self.sendWSMessage(edge_del_msg)
nodes = restclient.lookup_nodes("G.V().Has('source': 'dragonflow')")
for node in nodes:
self.protocol.sendWSMessage(edge_del_msg)
items = restclient.lookup_nodes("G.V().Has('source', 'dragonflow')")
for node in items:
node_del_msg = skydive_client.WSMessage(
"Graph",
skydive_client.NodeDeletedMsgType,
node
)
self.sendWSMessage(node_del_msg)
self.protocol.sendWSMessage(node_del_msg)
def start(self):
def run(self):
"""Start communication with the SkyDive analyzer
This starts the operaiton of periodically querying the nb_api and
sending all the objects to the SkyDive analyzer.
"""
super(SkydiveClient, self).run()
# First clear all existing items
self.clear_dragonflow_items()
# Now start the loop
self.websocket_client.start()
def schedule_stop(self, wait_time):
@ -100,10 +94,11 @@ class SkydiveClient(object):
:type wait_time: int
"""
loop = self.websocket_client.loop
loop.call_later(wait_time, self.stop)
loop.call_later(wait_time, self.terminate)
def stop(self):
def terminate(self):
"""Stop the process of sending the updates to the SkyDive analyzer"""
super(SkydiveClient, self).terminate()
self.websocket_client.stop()
@ -280,31 +275,24 @@ class WSClientDragonflowProtocol(skydive_client.WSClientDebugProtocol):
super(WSClientDragonflowProtocol, self).onClose(wasClean, code, reason)
def signal_handler(signal, frame):
if global_skydive_client:
LOG.info('Stopping SkyDive service')
global_skydive_client.stop()
def set_signal_handler():
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGHUP, signal_handler)
def start(is_service):
"""main method"""
df_config.init(sys.argv)
df_utils.config_parse()
nb_api = api_nb.NbApi.get_instance(False, True)
if is_service:
df_service.register_service('df-skydive-service', nb_api)
service_manager = cotyledon.ServiceManager()
service_manager.add(SkydiveClient, workers=1, args=(nb_api,))
service_manager.run()
def main():
"""main method"""
df_config.init(sys.argv)
parser = argparse.ArgumentParser(description='SkyDive integration service')
parser.add_argument('-t', '--runtime', type=int,
help='Total runtime (default 0 = infinite)')
args = parser.parse_args()
global global_skydive_client
global_skydive_client = SkydiveClient.create()
if args.runtime:
global_skydive_client.schedule_stop(args.runtime)
global_skydive_client.clear_dragonflow_items()
set_signal_handler()
global_skydive_client.start()
start(False)
def service_main():
start(True)
if __name__ == '__main__':

View File

@ -26,9 +26,11 @@ six>=1.10.0 # MIT
httplib2>=0.9.1 # MIT
WebOb>=1.7.1 # MIT
jsonmodels>=2.1.3 # BSD License (3 clause)
skydive-client>=0.4.1 # Apache-2.0
skydive-client>=0.4.4 # Apache-2.0
cotyledon>=1.3.0 # Apache-2.0
# These repos are installed from git in OpenStack CI if the job
# configures them as required-projects:
neutron>=12.0.0 # Apache-2.0
networking-sfc>=6.0.0 # Apache-2.0

View File

@ -63,6 +63,7 @@ console_scripts =
df-l3-agent = dragonflow.cmd.eventlet.df_l3_agent:main
df-metadata-service = dragonflow.cmd.eventlet.df_metadata_service:main
df-bgp-service = dragonflow.cmd.eventlet.df_bgp_service:main
df-skydive-service= dragonflow.cmd.df_skydive_service:service_main
dragonflow.pubsub_driver =
zmq_pubsub_driver = dragonflow.db.pubsub_drivers.zmq_pubsub_driver:ZMQPubSub
zmq_pubsub_multiproc_driver = dragonflow.db.pubsub_drivers.zmq_pubsub_driver:ZMQPubSubMultiproc