diff --git a/akanda/rug/api/quantum.py b/akanda/rug/api/quantum.py index 51811016..fdd6418b 100644 --- a/akanda/rug/api/quantum.py +++ b/akanda/rug/api/quantum.py @@ -1,10 +1,14 @@ import socket +import time import uuid import netaddr from quantumclient.v2_0 import client from akanda.rug.openstack.common import importutils +from akanda.rug.openstack.common import cfg +from akanda.rug.openstack.common import context +from akanda.rug.openstack.common.rpc import proxy # copied from Quantum source @@ -12,8 +16,8 @@ DEVICE_OWNER_ROUTER_MGT = "network:router_management" DEVICE_OWNER_ROUTER_INT = "network:router_interface" DEVICE_OWNER_ROUTER_GW = "network:router_gateway" DEVICE_OWNER_FLOATINGIP = "network:floatingip" - -DEVICE_OWNER_RUG = "akanda:rug" +DEVICE_OWNER_RUG = "network:akanda" +PLUGIN_RPC_TOPIC = 'q-plugin' class Router(object): @@ -266,28 +270,53 @@ class AkandaExtClientWrapper(client.Client): params=params) +class L3PluginApi(proxy.RpcProxy): + """Agent side of the Qunatum l3 agent RPC API.""" + + BASE_RPC_API_VERSION = '1.0' + + def __init__(self, topic, host): + super(L3PluginApi, self).__init__( + topic=topic, default_version=self.BASE_RPC_API_VERSION) + self.host = host + + def get_routers(self, router_id=None): + """Make a remote process call to retrieve the sync data for routers.""" + router_ids = [router_id] if router_id else None + retval = self.call(context.get_admin_context(), + self.make_msg('sync_routers', host=self.host, + router_ids=router_ids), + topic=self.topic) + return retval + + + class Quantum(object): def __init__(self, conf): self.conf = conf - self.client = AkandaExtClientWrapper( + self.api_client = AkandaExtClientWrapper( username=conf.admin_user, password=conf.admin_password, tenant_name=conf.admin_tenant_name, auth_url=conf.auth_url, auth_strategy=conf.auth_strategy, - auth_region=conf.auth_region) + auth_region=conf.auth_region + ) + self.rpc_client = L3PluginApi(PLUGIN_RPC_TOPIC, cfg.CONF.host) def get_routers(self): """Return a list of routers.""" return [Router.from_dict(r) for r in - self.client.list_routers()['routers']] + self.rpc_client.get_routers()] def get_router_detail(self, router_id): """Return detailed information about a router and it's networks.""" - return Router.from_dict(self.client.show_router(router_id)['router']) + return Router.from_dict( + self.rpc_client.get_routers(router_id=router_id)[0] + ) def get_router_for_tenant(self, tenant_id): - routers = self.client.list_routers(tenant_id=tenant_id)['routers'] + routers = self.api_client.list_routers(tenant_id=tenant_id)['routers'] if routers: return Router.from_dict(routers[0]) @@ -296,25 +325,25 @@ class Quantum(object): def get_network_ports(self, network_id): return [Port.from_dict(p) for p in - self.client.list_ports(network_id=network_id)['ports']] + self.api_client.list_ports(network_id=network_id)['ports']] def get_network_subnets(self, network_id): return [Subnet.from_dict(s) for s in - self.client.list_subnets(network_id=network_id)['subnets']] + self.api_client.list_subnets(network_id=network_id)['subnets']] def get_addressgroups(self, tenant_id): return [AddressGroup.from_dict(g) for g in - self.client.list_addressgroups( + self.api_client.list_addressgroups( tenant_id=tenant_id)['addressgroups']] def get_filterrules(self, tenant_id): return [FilterRule.from_dict(r) for r in - self.client.list_filterrules( + self.api_client.list_filterrules( tenant_id=tenant_id)['filterrules']] def get_portforwards(self, tenant_id): return [PortForward.from_dict(f) for f in - self.client.list_portforwards( + self.api_client.list_portforwards( tenant_id=tenant_id)['portforwards']] def create_router_management_port(self, router_id): @@ -322,16 +351,16 @@ class Quantum(object): network_id=self.conf.management_network_id, device_owner=DEVICE_OWNER_ROUTER_MGT ) - response = self.client.create_port(dict(port=port_dict)) + response = self.api_client.create_port(dict(port=port_dict)) port = Port.from_dict(response['port']) args = dict(port_id=port.id, owner=DEVICE_OWNER_ROUTER_MGT) - self.client.add_interface_router(router_id, args) + self.api_client.add_interface_router(router_id, args) return port def delete_router_management_port(self, router_id, port_id): args = dict(port_id=port_id, owner=DEVICE_OWNER_ROUTER_MGT) - self.client.remove_interface_router(router_id, args) + self.api_client.remove_interface_router(router_id, args) def create_router_external_port(self, router): network_args = {'network_id': self.conf.external_network_id} @@ -341,7 +370,7 @@ class Quantum(object): 'external_gateway_info': network_args } - r = self.client.update_router(router.id, body=dict(router=update_args)) + r = self.api_client.update_router(router.id, body=dict(router=update_args)) return Router.from_dict(r['router']).external_port def ensure_local_service_port(self): @@ -353,27 +382,36 @@ class Quantum(object): query_dict = dict(device_owner=DEVICE_OWNER_RUG, device_id=host_id) - ports = self.client.list_ports(**query_dict)['ports'] + ports = self.api_client.list_ports(**query_dict)['ports'] + + ip_address = get_local_service_ip(self.conf) if ports: port = Port.from_dict(ports[0]) else: # create the missing local port - port_dict = dict(admin_state_up=True, - network_id=self.conf.management_network_id, - device_owner=DEVICE_OWNER_RUG, - device_id=host_id) + port_dict = dict( + admin_state_up=True, + network_id=self.conf.management_network_id, + device_owner=DEVICE_OWNER_RUG, + device_id=host_id, + fixed_ips=[{ + 'ip_address': ip_address.split('/')[0], + 'subnet_id': self.conf.management_subnet_id + }] + ) port = Port.from_dict( - self.client.create_port(dict(port=port_dict))['port']) + self.api_client.create_port(dict(port=port_dict))['port']) driver.plug(port.network_id, port.id, driver.get_device_name(port), port.mac_address) + # add sleep to ensure that port is setup before use + time.sleep(1) - driver.init_l3(driver.get_device_name(port), - [get_local_service_ip(self.conf)]) + driver.init_l3(driver.get_device_name(port), [ip_address]) return port diff --git a/akanda/rug/manager.py b/akanda/rug/manager.py index 9088f268..04851bb2 100644 --- a/akanda/rug/manager.py +++ b/akanda/rug/manager.py @@ -22,7 +22,7 @@ LOG = logging.getLogger(__name__) OPTIONS = [ cfg.StrOpt('admin_user'), - cfg.StrOpt('admin_password'), + cfg.StrOpt('admin_password', secret=True), cfg.StrOpt('admin_tenant_name'), cfg.StrOpt('auth_url'), cfg.StrOpt('auth_strategy', default='keystone'), @@ -41,22 +41,20 @@ OPTIONS = [ cfg.StrOpt('interface_driver'), cfg.StrOpt('ovs_integration_bridge', default='br-int'), cfg.BoolOpt('ovs_use_veth', default=False), - cfg.StrOpt('root_helper', default='sudo'), cfg.IntOpt('network_device_mtu'), # listen for Quantum notification events cfg.StrOpt('notification_topic', default='notifications.info', - help='Quantum notification topic name'), - cfg.StrOpt('quantum_control_exchange', - default='openstack', - help='Quantum control exchange name'), - cfg.StrOpt('control_exchange', - default='akanda', - help='Akanda control exchange name') + help='Quantum notification topic name') +] + +AGENT_OPTIONS = [ + cfg.StrOpt('root_helper', default='sudo'), ] cfg.CONF.register_opts(OPTIONS) +cfg.CONF.register_opts(AGENT_OPTIONS, 'AGENT') class AkandaL3Manager(notification.NotificationMixin, @@ -66,39 +64,38 @@ class AkandaL3Manager(notification.NotificationMixin, self.quantum = quantum.Quantum(cfg.CONF) self.nova = nova.Nova(cfg.CONF) self.task_mgr = task.TaskManager() - self.quantum.ensure_local_service_port() - def init_host(self): + def initialize_service_hook(self, started_by): self.sync_state() self.task_mgr.start() self.create_notification_listener( cfg.CONF.notification_topic, - cfg.CONF.quantum_control_exchange) + cfg.CONF.control_exchange) self.metadata = metadata.create_metadata_signing_proxy( quantum.get_local_service_ip(cfg.CONF).split('/')[0] ) @periodic_task.periodic_task - def begin_health_check(self): + def begin_health_check(self, context): LOG.info('start health check queueing') for rtr in self.cache.routers(): self.task_mgr.put(self.check_health, rtr) @periodic_task.periodic_task(ticks_between_runs=1) - def report_bandwidth_usage(self): + def report_bandwidth_usage(self, context): LOG.info('start bandwidth usage reporting') for rtr in self.cache.routers(): self.task_mgr.put(self.report_bandwidth, rtr) @periodic_task.periodic_task(ticks_between_runs=10) - def janitor(self): + def janitor(self, context): """Periodically do a full state resync.""" LOG.debug('resync router state') self.sync_state() @periodic_task.periodic_task(ticks_between_runs=15) - def refresh_configs(self): + def refresh_configs(self, context): LOG.debug('resync configuration state') for rtr_id in self.cache.keys(): self.task_mgr.put(self.update_config, rtr_id) @@ -113,7 +110,10 @@ class AkandaL3Manager(notification.NotificationMixin, @notification.handles('subnet.create.end', 'subnet.change.end', - 'subnet.delete.end') + 'subnet.delete.end', + 'port.create.end', + 'port.change.end', + 'port.delete.end') def handle_router_subnet_change(self, tenant_id, payload): rtr = self.cache.get_by_tenant_id(tenant_id) if not rtr: diff --git a/akanda/rug/service.py b/akanda/rug/service.py index e6623752..c360fc07 100644 --- a/akanda/rug/service.py +++ b/akanda/rug/service.py @@ -1,3 +1,4 @@ +import socket import sys import eventlet @@ -5,24 +6,39 @@ import eventlet from akanda.rug import manager from akanda.rug.openstack.common import cfg from akanda.rug.openstack.common import log +from akanda.rug.openstack.common import rpc +from akanda.rug.openstack.common.rpc import service as rpc_service from akanda.rug.openstack.common import service cfg.CONF.register_opts([ cfg.IntOpt('periodic_interval', default=60, - help='seconds between running periodic tasks (ie health check)') + help='seconds between periodic task runs (ie health check)'), + cfg.StrOpt('host', + default=socket.getfqdn(), + help=_("The hostname Quantum is running on")), ]) +class PeriodicService(rpc_service.Service): + def start(self): + super(PeriodicService, self).start() + self.tg.add_timer( + cfg.CONF.periodic_interval, + self.manager.run_periodic_tasks, + None, + None + ) + + def main(): eventlet.monkey_patch() - cfg.CONF(sys.argv[1:]) + cfg.CONF(sys.argv[1:], project='akanda') log.setup('akanda') mgr = manager.AkandaL3Manager() - svc = service.Service('akanda', mgr, cfg.CONF.periodic_interval, None) - svc.start() - svc.wait() + svc = PeriodicService(host=cfg.CONF.host, topic='akanda', manager=mgr) + service.launch(svc).wait() if __name__ == '__main__': diff --git a/etc/rug.ini b/etc/rug.ini index 593df329..f4329a1f 100644 --- a/etc/rug.ini +++ b/etc/rug.ini @@ -1,27 +1,32 @@ [DEFAULT] +debug=True +versbose=True admin_user=quantum admin_password=password admin_tenant_name=service -auth_url=http://192.168.57.100:35357/v2.0/ +auth_url=http://192.168.57.200:35357/v2.0/ auth_strategy=keystone auth_region=RegionOne management_prefix=fdca:3ba5:a17a:acda::/64 akanda_mgt_service_port=5000 -management_network_id=7860030c-fc43-45d1-88d1-5863a04e9ebf -management_subnet_id=25f3586d-fa0a-434a-8001-d4849ab514fd -external_network_id=3a9a71ce-8bea-4b6f-82ca-d74ee672895c +management_network_id=fff4bc78-4a54-49ad-b4e8-5ccc5a61e10d +management_subnet_id=9e08721d-1709-4966-8c14-d6b2bcf6ac80 +external_network_id=bc42a9fa-2c54-4940-b521-d48055eaf42f -router_image_uuid=27334edd-49b8-4a2d-8dae-2f37af5126c7 +router_image_uuid=f32484e8-6d1f-4ab5-9e3b-95b8d0759e52 router_instance_flavor=1 # to plug in rug interface -root_helper=sudo interface_driver=quantum.agent.linux.interface.OVSInterfaceDriver ovs_integration_bridge=br-int rabbit_password = yetanothersecret -rabbit_host = 192.168.57.100 +rabbit_host = 192.168.57.200 -provider_rules_path=/opt/stack/akanda-rug/akanda/rug/provider_rules.json +provider_rules_path=/opt/stack/akanda-rug/etc/provider_rules.json +control_exchange = quantum + +[AGENT] +root_helper=sudo